ナビゲーション/

サイドバーナビゲーション

Preview

メニューボタンからスライドインするサイドバー型ナビゲーション。番号付きリンクと控えめな装飾で洗練された印象

Source Code
tsx
169 lines
1"use client";
2
3import { useState } from "react";
4import Link from "next/link";
5
6export function NavigationSidebar001() {
7 const [sidebarOpen, setSidebarOpen] = useState(false);
8
9 const navLinks = [
10 { label: "ホーム", href: "#" },
11 { label: "サービス", href: "#" },
12 { label: "プロジェクト", href: "#" },
13 { label: "チーム", href: "#" },
14 { label: "ブログ", href: "#" },
15 { label: "お問い合わせ", href: "#" },
16 ];
17
18 return (
19 <header className="relative z-50 w-full">
20 <nav className="mx-auto flex max-w-7xl items-center justify-between px-4 py-5 sm:px-6 lg:px-8">
21 {/* ロゴ */}
22 <Link href="#" className="flex items-center gap-3">
23 <div className="flex h-8 w-8 items-center justify-center rounded-md border border-border">
24 <div className="h-1.5 w-1.5 rounded-full bg-foreground" />
25 </div>
26 <span className="text-sm font-medium uppercase tracking-[0.2em] text-foreground">
27 Atelier
28 </span>
29 </Link>
30
31 {/* デスクトップ右側 */}
32 <div className="hidden items-center gap-6 md:flex">
33 <Link
34 href="#"
35 className="text-xs font-medium uppercase tracking-[0.15em] text-muted-foreground transition-colors duration-300 hover:text-foreground"
36 >
37 ログイン
38 </Link>
39 <button
40 onClick={() => setSidebarOpen(true)}
41 className="flex items-center gap-2 rounded-full border border-border px-5 py-2 text-xs font-medium uppercase tracking-[0.15em] text-foreground transition-all duration-300 hover:bg-foreground hover:text-background"
42 >
43 <span>メニュー</span>
44 <svg
45 className="h-3.5 w-3.5"
46 fill="none"
47 stroke="currentColor"
48 viewBox="0 0 24 24"
49 >
50 <path
51 strokeLinecap="round"
52 strokeLinejoin="round"
53 strokeWidth={1.5}
54 d="M4 8h16M4 16h16"
55 />
56 </svg>
57 </button>
58 </div>
59
60 {/* モバイルメニューボタン */}
61 <button
62 className="rounded-full p-2 text-muted-foreground transition-colors duration-200 hover:text-foreground md:hidden"
63 onClick={() => setSidebarOpen(true)}
64 >
65 <svg
66 className="h-5 w-5"
67 fill="none"
68 stroke="currentColor"
69 viewBox="0 0 24 24"
70 >
71 <path
72 strokeLinecap="round"
73 strokeLinejoin="round"
74 strokeWidth={1.5}
75 d="M4 8h16M4 16h16"
76 />
77 </svg>
78 </button>
79 </nav>
80
81 {/* オーバーレイ */}
82 {sidebarOpen && (
83 <div
84 className="fixed inset-0 z-40 bg-foreground/10 backdrop-blur-sm transition-opacity duration-300"
85 onClick={() => setSidebarOpen(false)}
86 />
87 )}
88
89 {/* サイドバーパネル */}
90 <div
91 className={`fixed inset-y-0 right-0 z-50 w-full max-w-sm border-l border-border bg-background transition-transform duration-500 ease-out ${
92 sidebarOpen ? "translate-x-0" : "translate-x-full"
93 }`}
94 >
95 <div className="flex h-full flex-col px-8 py-8">
96 {/* 閉じるボタン */}
97 <div className="flex justify-end">
98 <button
99 onClick={() => setSidebarOpen(false)}
100 className="rounded-full p-2 text-muted-foreground transition-colors duration-200 hover:text-foreground"
101 >
102 <svg
103 className="h-5 w-5"
104 fill="none"
105 stroke="currentColor"
106 viewBox="0 0 24 24"
107 >
108 <path
109 strokeLinecap="round"
110 strokeLinejoin="round"
111 strokeWidth={1.5}
112 d="M6 18L18 6M6 6l12 12"
113 />
114 </svg>
115 </button>
116 </div>
117
118 {/* ラベル */}
119 <div className="mt-12">
120 <span className="text-[10px] uppercase tracking-[0.3em] text-muted-foreground">
121 ナビゲーション
122 </span>
123 <div className="mt-3 h-px bg-border/40" />
124 </div>
125
126 {/* ナビリンク */}
127 <nav className="mt-8 flex flex-1 flex-col gap-1">
128 {navLinks.map((link, index) => (
129 <Link
130 key={link.label}
131 href={link.href}
132 className="group flex items-center gap-4 rounded-lg px-2 py-3 transition-colors duration-200 hover:bg-muted/50"
133 >
134 <span className="text-[10px] tabular-nums tracking-wider text-muted-foreground/40">
135 {String(index + 1).padStart(2, "0")}
136 </span>
137 <span className="text-sm font-medium tracking-wide text-foreground/80 transition-colors duration-200 group-hover:text-foreground">
138 {link.label}
139 </span>
140 </Link>
141 ))}
142 </nav>
143
144 {/* フッター */}
145 <div className="mt-auto">
146 <div className="h-px bg-border/40" />
147 <div className="mt-6 flex items-center justify-between">
148 <span className="text-[10px] uppercase tracking-[0.2em] text-muted-foreground/60">
149 &copy; 2026 Atelier
150 </span>
151 <div className="flex items-center gap-4">
152 {/* SNSアイコン(プレースホルダー) */}
153 {["X", "IG", "LI"].map((label) => (
154 <Link
155 key={label}
156 href="#"
157 className="text-[10px] uppercase tracking-[0.15em] text-muted-foreground/60 transition-colors duration-200 hover:text-foreground"
158 >
159 {label}
160 </Link>
161 ))}
162 </div>
163 </div>
164 </div>
165 </div>
166 </div>
167 </header>
168 );
169}