plans
2026-05-06
2026 05 06 Header Navigation Fix

Header Navigation Fix Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Replace the hidden "MENU" button pattern with directly visible nav links in the desktop header, matching the premium design system.

Architecture: Desktop header gets a horizontal nav link row below the logo. Mobile stays as-is with the bottom dock. Dropdown menu becomes a full MegaMenu that appears on hover, keeping the existing panel for its rich content layout.

Tech Stack: Next.js 16, Tailwind CSS v4, tailwindcss-animate


File Map

FileChange
apps/frontend/components/layout/header.tsxReplace MENU button with visible nav links, refactor dropdown to MegaMenu on hover
apps/frontend/components/layout/mobile-bottom-dock.tsxAdd missing nav links, fix click outside handling
apps/frontend/components/layout/nav-links.tsAdd social links and phone number as exports

Task 1: Extract config from nav-links.ts

Files:

  • Modify: apps/frontend/components/layout/nav-links.ts

  • Step 1: Add social links and phone number exports

Add at end of nav-links.ts:

export const CONTACT_INFO = {
  phone: {
    label: "+84 90 123 4567",
    href: "tel:+84901234567",
  },
  socials: {
    facebook: {
      label: "Facebook",
      href: "https://www.facebook.com/houseoflegendsvn",
    },
    instagram: {
      label: "Instagram",
      href: "https://www.instagram.com/houseoflegends.vn",
    },
    tripadvisor: {
      label: "TripAdvisor",
      href: "https://www.tripadvisor.com",
    },
  },
} as const;
  • Step 2: Commit
git add apps/frontend/components/layout/nav-links.ts
git commit -m "feat: extract contact info config from nav-links"

Task 2: Refactor desktop header — visible nav links + MegaMenu

Files:

  • Modify: apps/frontend/components/layout/header.tsx

  • Step 1: Rewrite header layout — visible nav row + MegaMenu on hover

Replace the entire header.tsx content between lines 45-137 with:

{
  /* Desktop Navigation - Visible Nav Links + MegaMenu */
}
<header
  className={cn(
    "fixed top-0 left-0 right-0 z-50 transition-colors duration-200",
    isScrolled
      ? "bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60"
      : "bg-transparent",
  )}
>
  <div className="flex flex-col">
    {/* Top bar: Logo + Nav Links + Language + CTA */}
    <div className="flex items-center justify-between px-6 h-20">
      {/* Left: Logo */}
      <div className="flex items-center gap-4">
        <LocaleLink href="/" className="flex items-center">
          <img
            src="/images/landing-page/hero-logo.png"
            alt="House of Legends"
            className="h-16 w-auto"
          />
        </LocaleLink>
      </div>
 
      {/* Center: Visible Nav Links */}
      <nav className="hidden lg:flex items-center gap-1">
        {navLinks.slice(0, 6).map((link) => (
          <LocaleLink
            key={link.href}
            href={link.href}
            className="px-4 py-2 text-sm font-medium text-[var(--color-foreground)] hover:text-[var(--color-gold)] transition-colors rounded-lg hover:bg-[var(--color-surface)]"
          >
            {link.label}
          </LocaleLink>
        ))}
        {/* "More" dropdown for remaining links */}
        <div className="relative group">
          <button
            type="button"
            className="px-4 py-2 text-sm font-medium text-[var(--color-foreground)] hover:text-[var(--color-gold)] transition-colors rounded-lg hover:bg-[var(--color-surface)] flex items-center gap-1"
          >
            More
            <ChevronDown className="w-4 h-4" />
          </button>
          {/* Dropdown panel */}
          <div className="absolute top-full left-1/2 -translate-x-1/2 pt-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200">
            <div className="w-64 bg-background border border-[var(--color-gold-border)] shadow-2xl rounded-xl p-2">
              {navLinks.slice(6).map((link) => (
                <LocaleLink
                  key={link.href}
                  href={link.href}
                  className="flex items-center gap-3 px-4 py-3 text-sm text-[var(--color-foreground)] hover:text-[var(--color-gold)] hover:bg-[var(--color-surface)] rounded-lg transition-colors"
                >
                  {link.label}
                </LocaleLink>
              ))}
            </div>
          </div>
        </div>
      </nav>
 
      {/* Right: Language + CTA */}
      <div className="hidden lg:flex items-center gap-4">
        <LanguageSwitcher currentLang={locale} />
 
        <LocaleLink
          href="/host-an-event"
          className="px-7 py-3.5 rounded-xl font-semibold text-background bg-gold hover:bg-gold-light active:scale-[0.97] transition-all duration-150"
        >
          Host An Event
        </LocaleLink>
      </div>
    </div>
  </div>
</header>;
  • Step 2: Add ChevronDown import

Find import line 19:

import * as React from "react";

Add after:

import { ChevronDown } from "lucide-react";
  • Step 3: Remove the old center menu button section and dropdown (lines 58-124)

Delete the entire lg:flex items-center div that contains the old MENU button logic.

  • Step 4: Commit
git add apps/frontend/components/layout/header.tsx
git commit -m "feat: replace hidden menu with visible nav links + hover MegaMenu"

Task 3: Fix mobile bottom dock — add missing nav links and contact info

Files:

  • Modify: apps/frontend/components/layout/mobile-bottom-dock.tsx

  • Step 1: Import contact info

Find imports (line 20-21):

import { cn } from "~/lib/utils";

Add after:

import { CONTACT_INFO } from "~/components/layout/nav-links";
  • Step 2: Replace hardcoded phone with config

Find line 161-166:

<a
  href="tel:+84901234567"
  className="flex items-center justify-center w-11 h-11 rounded-full text-foreground hover:text-[var(--color-gold)] active:scale-[0.98] transition-colors"
  aria-label="Call"
>
  <Phone className="w-5 h-5" />
</a>

Change to:

<a
  href={CONTACT_INFO.phone.href}
  className="flex items-center justify-center w-11 h-11 rounded-full text-foreground hover:text-[var(--color-gold)] active:scale-[0.98] transition-colors"
  aria-label="Call"
>
  <Phone className="w-5 h-5" />
</a>
  • Step 3: Replace hardcoded social URLs

Find lines 183-206 — replace the entire social links section with:

<div className="flex items-center justify-center gap-2">
  <a
    href={CONTACT_INFO.socials.facebook.href}
    target="_blank"
    rel="noopener noreferrer"
    className="flex items-center justify-center w-11 h-11 rounded-full text-[var(--color-muted-foreground)] hover:text-foreground hover:bg-[var(--color-surface-hover)] transition-colors"
    aria-label={CONTACT_INFO.socials.facebook.label}
  >
    {SOCIAL_ICONS.facebook}
  </a>
  <a
    href={CONTACT_INFO.socials.instagram.href}
    target="_blank"
    rel="noopener noreferrer"
    className="flex items-center justify-center w-11 h-11 rounded-full text-[var(--color-muted-foreground)] hover:text-foreground hover:bg-[var(--color-surface-hover)] transition-colors"
    aria-label={CONTACT_INFO.socials.instagram.label}
  >
    {SOCIAL_ICONS.instagram}
  </a>
  <a
    href={CONTACT_INFO.socials.tripadvisor.href}
    target="_blank"
    rel="noopener noreferrer"
    className="flex items-center justify-center w-11 h-11 rounded-full text-[var(--color-muted-foreground)] hover:text-foreground hover:bg-[var(--color-surface-hover)] transition-colors"
    aria-label={CONTACT_INFO.socials.tripadvisor.label}
  >
    {SOCIAL_ICONS.tripadvisor}
  </a>
</div>
  • Step 4: Commit
git add apps/frontend/components/layout/mobile-bottom-dock.tsx
git commit -m "fix: use contact info config in mobile bottom dock"

Task 4: Add all 10 mobile nav links

Files:

  • Modify: apps/frontend/components/layout/mobile-bottom-dock.tsx

  • Step 1: Update NAV_LINKS to 10 items

Find lines 29-36:

const NAV_LINKS: NavLink[] = [
  { href: "/", icon: Home, key: "home" },
  { href: "/experiences/dinner-theater", icon: UtensilsCrossed, key: "shows" },
  { href: "/private-events", icon: Briefcase, key: "private" },
  { href: "/experiences/creative-workshop", icon: Settings, key: "workshop" },
  { href: "/experiences/artist-performances", icon: Mic2, key: "performances" },
  { href: "/venue-rental", icon: MapPin, key: "venue" },
];

Change to:

const NAV_LINKS: NavLink[] = [
  { href: "/", icon: Home, key: "home" },
  { href: "/experiences/dinner-theater", icon: UtensilsCrossed, key: "shows" },
  { href: "/private-events", icon: Briefcase, key: "private" },
  { href: "/experiences/creative-workshop", icon: Settings, key: "workshop" },
  { href: "/experiences/artist-performances", icon: Mic2, key: "performances" },
  { href: "/venue-rental", icon: MapPin, key: "venue" },
  { href: "/reviews", icon: Star, key: "reviews" },
  { href: "/about", icon: Info, key: "about" },
  { href: "/contact", icon: Mail, key: "contact" },
  { href: "/faq", icon: HelpCircle, key: "faq" },
];
  • Step 2: Add missing icon imports

Find imports (lines 10-18):

import {
  Home,
  Settings,
  Briefcase,
  Phone,
  Menu,
  X,
  UtensilsCrossed,
  Mic2,
  MapPin,
} from "lucide-react";

Change to:

import {
  Home,
  Settings,
  Briefcase,
  Phone,
  Menu,
  X,
  UtensilsCrossed,
  Mic2,
  MapPin,
  Star,
  Info,
  Mail,
  HelpCircle,
} from "lucide-react";
  • Step 3: Add missing labels to NAV_LABELS

Find lines 38-55:

const NAV_LABELS: Record<string, Record<string, string>> = {
  en: {
    home: "Home",
    shows: "Shows",
    private: "Private",
    workshop: "Workshop",
    performances: "Artists",
    venue: "Venue",
  },
  vi: {
    home: "Trang chủ",
    shows: "Suất diễn",
    private: "Sự kiện",
    workshop: "Workshop",
    performances: "Nghệ sĩ",
    venue: "Thuê venue",
  },
};

Change to:

const NAV_LABELS: Record<string, Record<string, string>> = {
  en: {
    home: "Home",
    shows: "Shows",
    private: "Private",
    workshop: "Workshop",
    performances: "Artists",
    venue: "Venue",
    reviews: "Reviews",
    about: "About",
    contact: "Contact",
    faq: "FAQ",
  },
  vi: {
    home: "Trang chủ",
    shows: "Suất diễn",
    private: "Sự kiện",
    workshop: "Workshop",
    performances: "Nghệ sĩ",
    venue: "Thuê venue",
    reviews: "Đánh giá",
    about: "Giới thiệu",
    contact: "Liên hệ",
    faq: "Câu hỏi",
  },
};
  • Step 4: Adjust grid for 10 items

Find line 210:

<div className="grid grid-cols-3 gap-3">

Change to:

<div className="grid grid-cols-3 gap-3 max-h-[50vh] overflow-y-auto">
  • Step 5: Commit
git add apps/frontend/components/layout/mobile-bottom-dock.tsx
git commit -m "feat: add all missing nav links to mobile dock"

Task 5: Fix click-outside for mobile nav

Files:

  • Modify: apps/frontend/components/layout/mobile-bottom-dock.tsx:117-127

  • Step 1: Replace mousedown with pointerdown

Find lines 117-127:

// Close on click outside
useEffect(() => {
  if (!expanded) return;
  const handleClickOutside = (e: MouseEvent) => {
    if (dockRef.current && !dockRef.current.contains(e.target as Node)) {
      setExpanded(false);
    }
  };
  document.addEventListener("mousedown", handleClickOutside);
  return () => document.removeEventListener("mousedown", handleClickOutside);
}, [expanded]);

Change to:

// Close on click outside (pointerdown handles both mouse and touch)
useEffect(() => {
  if (!expanded) return;
  const handlePointerDown = (e: PointerEvent) => {
    if (dockRef.current && !dockRef.current.contains(e.target as Node)) {
      setExpanded(false);
    }
  };
  document.addEventListener("pointerdown", handlePointerDown);
  return () => document.removeEventListener("pointerdown", handlePointerDown);
}, [expanded]);
  • Step 2: Commit
git add apps/frontend/components/layout/mobile-bottom-dock.tsx
git commit -m "fix: use pointerdown instead of mousedown for click-outside"

Verification

  • Step 1: Run type check
cd apps/frontend && npx tsc --noEmit

Expected: No errors

  • Step 2: Run lint
cd apps/frontend && npm run lint

Expected: No errors

  • Step 3: Start dev server and verify visually
cd apps/frontend && npm run dev

Check:

  • Desktop: Nav links visible directly in header (no MENU button)
  • Desktop: Hover on "More" shows dropdown with remaining 4 links
  • Mobile: FAB opens bottom sheet with all 10 nav items
  • Mobile: Social links and phone use config values

Summary of Changes

TaskWhat Changed
1Added CONTACT_INFO export to nav-links.ts
2Replaced hidden MENU button with visible nav links + hover MegaMenu for "More"
3Mobile dock uses CONTACT_INFO for phone and socials
4Mobile dock shows all 10 nav links with labels
5Mobile click-outside uses pointerdown instead of mousedown