[Next.js][React][TypeScript] 2.建置Header導覽列、Footer

文、意如

建立導覽列

src 目錄下建立components 再建立 Navbar.tsx

// src/components/Navbar.tsx
"use client";
import { useState } from "react";
import { ChevronDown, ChevronRight, Menu } from "lucide-react";

const menuItems = [
  { title: "關於我們", href: "#" },
  { title: "文章列表", href: "#" },
  {
    title: "產品資訊",
    submenu: [
      { title: "電子產品", href: "#" },
      { title: "服飾", href: "#" },
      {
        title: "居家用品",
        submenu: [
          { title: "燈具", href: "#" },
          { title: "餐具", href: "#" },
        ],
      },
    ],
  },
  { title: "聯絡我們", href: "#" },
];

export default function Navbar() {
  const [mobileOpen, setMobileOpen] = useState(false);
  const toggleMobile = () => setMobileOpen(!mobileOpen);

  const renderSubMenu = (submenu: any[]) => (
    <ul className="ml-4 space-y-1">
      {submenu.map((item) =>
        item.submenu ? (
          <li key={item.title}>
            <div className="flex items-center gap-1 font-medium text-gray-700 hover:bg-gray-100 px-3 py-2 rounded-md">
              <ChevronRight size={14} />
              {item.title}
            </div>
            <ul className="ml-4">{renderSubMenu(item.submenu)}</ul>
          </li>
        ) : (
          <li key={item.title}>
            <a
              href={item.href}
              className="block px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md"
            >
              {item.title}
            </a>
          </li>
        )
      )}
    </ul>
  );

  return (
    <header className="bg-white border-b fixed top-0 left-0 w-full z-50 bg-white shadow">
      <div className="max-w-7xl mx-auto px-4">
        <div className="flex justify-between items-center h-16">
          {/* Logo */}
          <div className="text-lg font-bold text-gray-800">MyLogo</div>

          {/* 漢堡選單 (手機) */}
          <div className="lg:hidden">
            <Menu className="w-6 h-6 text-gray-700" onClick={toggleMobile} />
          </div>

          {/* 導覽項目(桌機) */}
          <nav className="hidden lg:flex space-x-6 items-center">
            {menuItems.map((item) =>
              item.submenu ? (
                <div className="relative group" key={item.title}>
                  <button className="flex items-center gap-1 font-medium text-gray-700 hover:text-blue-600">
                    {item.title}
                    <ChevronDown size={14} />
                  </button>
                  {/* 第二層 */}
                  <div className="absolute top-full left-0 mt-2 bg-white border shadow rounded-md opacity-0 group-hover:opacity-100 transition pointer-events-none group-hover:pointer-events-auto z-10 min-w-[160px]">
                    {renderSubMenu(item.submenu)}
                  </div>
                </div>
              ) : (
                <a
                  key={item.title}
                  href={item.href}
                  className="text-gray-700 hover:text-blue-600 font-medium"
                >
                  {item.title}
                </a>
              )
            )}
          </nav>
        </div>
      </div>

      {/* 手機版下拉 */}
      {mobileOpen && (
        <div className="lg:hidden px-4 py-2 space-y-2 border-t">
          {menuItems.map((item) =>
            item.submenu ? (
              <div key={item.title}>
                <div className="font-semibold text-gray-800">{item.title}</div>
                {renderSubMenu(item.submenu)}
              </div>
            ) : (
              <a
                key={item.title}
                href={item.href}
                className="block text-gray-700 px-2 py-1 rounded hover:bg-gray-100"
              >
                {item.title}
              </a>
            )
          )}
        </div>
      )}
    </header>
  );
}

src/app/page.tsx

import Navbar from "@/components/Navbar";

export default function Home() {
  return (
    <>
      <Navbar />
      <main className="min-h-screen p-8 pt-20">
        <h1 className="text-3xl font-bold">首頁內容</h1>
      </main>
    </>
  );
}
建立Footer

src/components/Footer.tsx

//src/components/Footer.tsx
export default function Footer() {
  return (
    <footer className="bg-gray-800 text-white py-10">
      <div className="max-w-screen-xl mx-auto px-4 md:px-8 grid grid-cols-1 md:grid-cols-3 gap-8">
        
        {/* 區塊 1:LOGO 與描述 */}
        <div>
          <h3 className="text-xl font-bold mb-2">MyWebsite</h3>
          <p className="text-gray-300 text-sm">
            提供專業網站建置與數位行銷服務,協助企業邁向線上成功。
          </p>
        </div>

        {/* 區塊 2:導覽連結 */}
        <div>
          <h4 className="font-semibold mb-2">快速連結</h4>
          <ul className="space-y-1 text-sm text-gray-300">
            <li><a href="#" className="hover:text-white">首頁</a></li>
            <li><a href="#" className="hover:text-white">關於我們</a></li>
            <li><a href="#" className="hover:text-white">產品資訊</a></li>
            <li><a href="#" className="hover:text-white">聯絡我們</a></li>
          </ul>
        </div>

        {/* 區塊 3:聯絡資訊 */}
        <div>
          <h4 className="font-semibold mb-2">聯絡方式</h4>
          <p className="text-sm text-gray-300">Email:info@example.com</p>
          <p className="text-sm text-gray-300">電話:02-1234-5678</p>
          <p className="text-sm text-gray-300">地址:台北市大安區...</p>
        </div>
      </div>

      {/* 最底部:版權 */}
      <div className="text-center text-gray-400 text-xs mt-10">
        &copy; {new Date().getFullYear()} MyWebsite. All rights reserved.
      </div>
    </footer>
  );
}

src/app/page.tsx

// src/app/page.tsx
import Navbar from "@/components/Navbar";
import HeroCarousel from "@/components/HeroCarousel";
import NewsSection from "@/components/NewsSection";
import ProductSection from "@/components/ProductSection";
import ContactSection from "@/components/ContactSection";
import Footer from "@/components/Footer";

export default function Home() {
  return (
    <>
      <Navbar />
      <main className="pt-15 min-h-screen">
        <HeroCarousel />
        <NewsSection />
        <ProductSection />
        <ContactSection />
        <Footer />
      </main>
    </>
  );
}

Yiru@Studio - 關於我 - 意如