From 1f859921cb26c93eb53acdbce55f9d68a437eb70 Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Sat, 13 Jun 2026 17:47:40 +0700 Subject: [PATCH] feat(header): add UtilityBar + Marquee + Navigation from v6-nav MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UtilityBar.astro (v6-utility): phone, clock, date, email from site settings Clock updated by fxClock() in src/lib/fx-animations.ts - Marquee.astro (v6-marquee): log ticker with 4 entries (animated horizontally) Content duplicated for seamless loop - Navigation.astro (v6-nav): REPLACED legacy. Adds 'บริการ' dropdown (4 services) + 'บทความ' link per plan round 2. Click-to-toggle on mobile. - src/data/nav.ts: single source of truth for mainLinks + servicesDropdown - fx-system.css: +27 lines for dropdown styles + active link underline (v6-nav originally had no dropdown — we added per spec) Refs: .hermes/plans/2026-06-13_124000-moreminimore-v7-5-migration.md Task 2.1-2.4 --- src/components/Marquee.astro | 30 ++ src/components/Navigation.astro | 581 ++++---------------------------- src/components/UtilityBar.astro | 30 ++ src/data/nav.ts | 43 +++ src/styles/fx-system.css | 28 +- 5 files changed, 197 insertions(+), 515 deletions(-) create mode 100644 src/components/Marquee.astro create mode 100644 src/components/UtilityBar.astro create mode 100644 src/data/nav.ts diff --git a/src/components/Marquee.astro b/src/components/Marquee.astro new file mode 100644 index 0000000..c36cf40 --- /dev/null +++ b/src/components/Marquee.astro @@ -0,0 +1,30 @@ +--- +/** + * MOREMINIMORE - Marquee (from v6-marquee) + * Extracted from Desktop/moreminomore-mockup-v7-5.html lines 590-609 + * + * Log ticker — animates horizontally (marquee 40s linear infinite in fx-system.css) + * Content is hardcoded ticker entries (not dynamic) — same as v7-5 design + * + * Duplicate content to achieve seamless loop (track is rendered twice) + */ +const tickerEntries = [ + { ts: '[2026-06-13]', text: '$ build/deploy ' }, + { ts: '[log]', text: 'Dataroot +373% Impression ' }, + { ts: '[2026-06-13]', text: '$ contact/free 30 min ' }, + { ts: '[log]', text: '9 case studies, 0 fabricated ' }, +]; +--- + +
+
+ {/* First copy */} + {tickerEntries.map((entry) => ( + {entry.ts} + ))} + {/* Second copy (duplicated for seamless loop) */} + {tickerEntries.map((entry) => ( + {entry.ts} + ))} +
+
diff --git a/src/components/Navigation.astro b/src/components/Navigation.astro index d484888..9743070 100644 --- a/src/components/Navigation.astro +++ b/src/components/Navigation.astro @@ -1,529 +1,82 @@ --- /** - * MOREMINIMORE - NAVIGATION COMPONENT (LIGHT THEME) - * Light bg + dark text nav links + white logo banner + * MOREMINIMORE - NAVIGATION (from v6-nav, enhanced) + * Extracted from Desktop/moreminomore-mockup-v7-5.html lines 662-684 + * + * Per plan 2026-06-13 round 2: + * - v6-nav structure: logo + menu + CTA + * - Enhancement A: dropdown 'บริการ' (4 sub-items from servicesDropdown) + * - Enhancement C: add 'บทความ' link (blog) — not in original v6-nav + * - Social icons: not in v6-nav itself; they live in UtilityBar (per plan) + * + * Props: + * - currentPath: string — for active link highlighting (optional, defaults to Astro.url.pathname) */ +import { mainLinks, servicesDropdown } from '../data/nav'; -const services = [ - { label: 'Website Development', href: '/services/webdev' }, - { label: 'Marketing Automation', href: '/services/marketing' }, - { label: 'AI Automation', href: '/services/automation' }, - { label: 'Tech Consult', href: '/services/ai-consult' }, -]; +interface Props { + currentPath?: string; +} + +const { currentPath = Astro.url.pathname } = Astro.props; +const isActive = (href: string) => { + if (href === '/') return currentPath === '/'; + return currentPath.startsWith(href); +}; --- - - - -
- - + diff --git a/src/components/UtilityBar.astro b/src/components/UtilityBar.astro new file mode 100644 index 0000000..d57dbb7 --- /dev/null +++ b/src/components/UtilityBar.astro @@ -0,0 +1,30 @@ +--- +/** + * MOREMINIMORE - UtilityBar (from v6-utility) + * Extracted from Desktop/moreminomore-mockup-v7-5.html lines 571-589 + * + * Top info bar — phone + clock + date + mode indicator + email + * Phone/email pulled from src/content/settings/site.md (single source of truth) + * + * Clock/date are updated by fx-animations.ts → fxClock() (id="fx-time", id="fx-date") + */ +import { getEntry } from 'astro:content'; +import type { CollectionEntry } from 'astro:content'; + +const site = (await getEntry('settings', 'site')) as CollectionEntry<'settings'>; +const phone = site?.data?.phone ?? '080-995-5945'; +const email = site?.data?.email ?? 'contact@moreminimore.com'; +--- + +
+
+ 📞 {phone} + ⏱ — : — : — + 📅 — — — +
+
+ system + ◐ auto + ✉ {email} +
+
diff --git a/src/data/nav.ts b/src/data/nav.ts new file mode 100644 index 0000000..6e55442 --- /dev/null +++ b/src/data/nav.ts @@ -0,0 +1,43 @@ +/** + * MOREMINIMORE - Nav data (single source of truth) + * Used by Navigation.astro and Footer.astro + * + * Per plan 2026-06-13 round 2: + * - Main menu: 7 items including 'บทความ' (blog) + 'FAQ' + 'ติดต่อ' + * - Services dropdown: 4 services (matched to content collection slugs) + * - Social: facebook, line, linkedin (from settings collection at runtime) + * + * Slugs match src/content/services/*-new.mdx: + * - ai-consult-new → /services/ai-consult + * - marketing-new → /services/marketing + * - automation-new → /services/automation + * - webdev-new → /services/webdev + * + * Href uses /services/{slug-without-new} to match the [slug].astro route. + */ +export const mainLinks = [ + { label: 'หน้าแรก', href: '/' }, + { label: 'บริการ', href: '/services', hasDropdown: true }, + { label: 'ผลงาน', href: '/portfolio' }, + { label: 'บทความ', href: '/blog' }, + { label: 'เกี่ยวกับ', href: '/about' }, + { label: 'FAQ', href: '/faq' }, + { label: 'ติดต่อ', href: '/contact' }, +]; + +export const servicesDropdown = [ + { label: 'AI Consult', href: '/services/ai-consult' }, + { label: 'Marketing Automation', href: '/services/marketing' }, + { label: 'AI Automation', href: '/services/automation' }, + { label: 'Website Development', href: '/services/webdev' }, +]; + +/** + * Social links are passed as props to the component + * (because they come from the settings collection which is loaded async) + */ +export interface SocialLinks { + facebook?: string; + line?: string; + linkedin?: string; +} diff --git a/src/styles/fx-system.css b/src/styles/fx-system.css index 887e521..f3eb646 100644 --- a/src/styles/fx-system.css +++ b/src/styles/fx-system.css @@ -482,4 +482,30 @@ img{max-width:100%;display:block} .fx-btn.coral:hover{background:linear-gradient(135deg,var(--ink) 0%,var(--coral) 100%)} .fx-marquee-track{animation:none} .fx-faq-a::after{display:none} -.fx-hero::after{display:none} \ No newline at end of file +.fx-hero::after{display:none} + +/* ============================================ + NAV DROPDOWN ENHANCEMENT (added 2026-06-13, plan round 2) + v6-nav didn't have a dropdown originally; we added + 'บริการ' dropdown per user spec. Active link styling too. + ============================================ */ +.fx-nav-menu{position:relative} +.fx-nav-menu li{position:relative} +.fx-nav-dropdown{position:absolute;top:100%;left:0;min-width:240px;background:var(--paper);border:1.5px solid var(--ink);box-shadow:4px 4px 0 var(--ink);list-style:none;padding:8px 0;margin:0;opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity 0.18s,transform 0.18s,visibility 0.18s;z-index:60} +.fx-nav-has-dropdown:hover>.fx-nav-dropdown, +.fx-nav-dropdown-open>.fx-nav-dropdown{opacity:1;visibility:visible;transform:translateY(0)} +.fx-nav-dropdown li{margin:0} +.fx-nav-dropdown a{display:block;padding:10px 18px;font:600 12px/1.3 'JetBrains Mono',monospace;text-transform:uppercase;letter-spacing:0.3px;color:var(--ink);text-decoration:none;transition:background 0.15s,color 0.15s} +.fx-nav-dropdown a:hover{background:var(--brand-yellow);color:var(--ink)} +.fx-nav-dropdown a.active{background:var(--coral);color:#FAFAFA} +.fx-nav-menu a.active{color:var(--coral)} +.fx-nav-menu a.active::after{content:'';display:block;height:2px;background:var(--coral);margin-top:4px} +@media (max-width:768px){ + .fx-nav-inner{flex-direction:column;align-items:flex-start;padding:12px 16px} + .fx-nav-menu{flex-direction:column;width:100%;gap:0} + .fx-nav-menu>li{width:100%;border-bottom:1px solid var(--line-2)} + .fx-nav-menu>li>a{display:block;padding:12px 0} + .fx-nav-dropdown{position:static;box-shadow:none;border:none;background:var(--paper-2);opacity:1;visibility:visible;transform:none;max-height:0;overflow:hidden;padding:0;transition:max-height 0.25s,padding 0.25s} + .fx-nav-dropdown-open>.fx-nav-dropdown{max-height:400px;padding:8px 0} + .fx-nav-cta{margin-top:12px;align-self:flex-start} +} \ No newline at end of file