@naeil/ui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/DESIGN.md +186 -0
  3. package/LICENSE +21 -0
  4. package/README.md +77 -53
  5. package/THIRD_PARTY_NOTICES.md +49 -0
  6. package/dist/{chunk-SYI3IKIC.js → chunk-QKVN6Q6C.js} +102 -19
  7. package/dist/components/index.d.ts +2 -2
  8. package/dist/components/index.js +9 -9
  9. package/dist/components/ui/index.d.ts +26 -4
  10. package/dist/components/ui/index.js +288 -33
  11. package/dist/source/components/footer.d.ts +15 -0
  12. package/dist/source/components/footer.js +172 -0
  13. package/dist/source/components/index.d.ts +11 -0
  14. package/dist/source/components/index.js +26 -0
  15. package/dist/source/components/locale-switcher.d.ts +17 -0
  16. package/dist/source/components/locale-switcher.js +66 -0
  17. package/dist/source/components/logo.d.ts +9 -0
  18. package/dist/source/components/logo.js +52 -0
  19. package/dist/source/components/nav.d.ts +39 -0
  20. package/dist/source/components/nav.js +412 -0
  21. package/dist/source/components/theme-provider.d.ts +6 -0
  22. package/dist/source/components/theme-provider.js +45 -0
  23. package/dist/source/components/theme-toggle-icon.d.ts +5 -0
  24. package/dist/source/components/theme-toggle-icon.js +62 -0
  25. package/dist/source/components/theme-toggle.d.ts +5 -0
  26. package/dist/source/components/theme-toggle.js +34 -0
  27. package/dist/source/components/typography.d.ts +12 -0
  28. package/dist/source/components/typography.js +49 -0
  29. package/dist/source/components/ui/avatar.d.ts +14 -0
  30. package/dist/source/components/ui/avatar.js +137 -0
  31. package/dist/source/components/ui/badge.d.ts +13 -0
  32. package/dist/source/components/ui/badge.js +76 -0
  33. package/dist/source/components/ui/button.d.ts +14 -0
  34. package/dist/source/components/ui/button.js +88 -0
  35. package/dist/source/components/ui/card.d.ts +13 -0
  36. package/dist/source/components/ui/card.js +135 -0
  37. package/dist/source/components/ui/checkbox.d.ts +7 -0
  38. package/dist/source/components/ui/checkbox.js +58 -0
  39. package/dist/source/components/ui/dialog.d.ts +20 -0
  40. package/dist/source/components/ui/dialog.js +182 -0
  41. package/dist/source/components/ui/dropdown-menu.d.ts +28 -0
  42. package/dist/source/components/ui/dropdown-menu.js +282 -0
  43. package/dist/source/components/ui/index.d.ts +19 -0
  44. package/dist/source/components/ui/index.js +131 -0
  45. package/dist/source/components/ui/input.d.ts +6 -0
  46. package/dist/source/components/ui/input.js +49 -0
  47. package/dist/source/components/ui/select.d.ts +16 -0
  48. package/dist/source/components/ui/select.js +197 -0
  49. package/dist/source/components/ui/sonner.d.ts +6 -0
  50. package/dist/source/components/ui/sonner.js +80 -0
  51. package/dist/source/components/ui/switch.d.ts +7 -0
  52. package/dist/source/components/ui/switch.js +54 -0
  53. package/dist/source/components/ui/tabs.d.ts +10 -0
  54. package/dist/source/components/ui/tabs.js +57 -0
  55. package/dist/source/components/ui/textarea.d.ts +6 -0
  56. package/dist/source/components/ui/textarea.js +46 -0
  57. package/dist/source/i18n/config.d.ts +6 -0
  58. package/dist/source/i18n/config.js +12 -0
  59. package/dist/source/i18n/routing.d.ts +371 -0
  60. package/dist/source/i18n/routing.js +17 -0
  61. package/dist/source/lib/design/modal-inert.d.ts +6 -0
  62. package/dist/source/lib/design/modal-inert.js +73 -0
  63. package/dist/source/lib/utils.d.ts +5 -0
  64. package/dist/source/lib/utils.js +8 -0
  65. package/dist/tokens.ts +217 -0
  66. package/docs/components/README.md +21 -0
  67. package/docs/components/avatar.md +47 -0
  68. package/docs/components/badge.md +29 -0
  69. package/docs/components/button.md +39 -0
  70. package/docs/components/card.md +32 -0
  71. package/docs/components/checkbox.md +35 -0
  72. package/docs/components/common.md +31 -0
  73. package/docs/components/composition.md +68 -0
  74. package/docs/components/dialog.md +41 -0
  75. package/docs/components/dropdown-menu.md +38 -0
  76. package/docs/components/input.md +32 -0
  77. package/docs/components/select.md +39 -0
  78. package/docs/components/sonner.md +37 -0
  79. package/docs/components/switch.md +33 -0
  80. package/docs/components/tabs.md +40 -0
  81. package/docs/components/textarea.md +35 -0
  82. package/docs/design/component-demand.md +30 -0
  83. package/docs/design/public-ui-final-verification.md +96 -0
  84. package/docs/design/public-ui-release-validation.md +86 -0
  85. package/docs/design/public-ui-stage3-verification.md +98 -0
  86. package/docs/design/public-ui-stage4-verification.md +129 -0
  87. package/docs/design/public-ui-support.md +40 -0
  88. package/docs/design/v2-migration.md +199 -0
  89. package/docs/package-release.md +89 -0
  90. package/licenses/Noto-Sans-JP-OFL.txt +93 -0
  91. package/licenses/Nunito-Sans-OFL.txt +93 -0
  92. package/licenses/Pretendard-OFL.txt +94 -0
  93. package/licenses/React-MIT.txt +21 -0
  94. package/licenses/Storybook-MIT.txt +21 -0
  95. package/licenses/popper-MIT.txt +25 -0
  96. package/licenses/react-remove-scroll-bar-MIT.txt +21 -0
  97. package/licenses/store2-MIT.txt +22 -0
  98. package/licenses/toggle-selection-MIT.txt +21 -0
  99. package/package.json +182 -34
  100. package/src/styles/components.css +276 -0
  101. package/src/styles/globals.css +18 -0
  102. package/src/styles/theme.css +185 -98
  103. package/messages/en.json +0 -221
  104. package/messages/ja.json +0 -221
  105. package/messages/ko.json +0 -221
  106. package/src/app/globals.css +0 -32
@@ -0,0 +1,66 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ DropdownMenu,
5
+ DropdownMenuTrigger,
6
+ DropdownMenuContent,
7
+ DropdownMenuItem
8
+ } from "./ui/dropdown-menu.js";
9
+ function LocaleSwitcher({
10
+ locales,
11
+ currentLocale,
12
+ onLocaleChange
13
+ }) {
14
+ var _a, _b;
15
+ const current = locales.find((l) => l.code === currentLocale);
16
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
17
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
18
+ "button",
19
+ {
20
+ className: "text-muted-foreground hover:text-foreground flex items-center gap-1.5 text-sm transition-colors focus:outline-none",
21
+ "aria-label": `Change language \u2014 current: ${(_a = current == null ? void 0 : current.short) != null ? _a : currentLocale}`,
22
+ children: [
23
+ /* @__PURE__ */ jsx(GlobeIcon, {}),
24
+ (_b = current == null ? void 0 : current.short) != null ? _b : currentLocale.toUpperCase()
25
+ ]
26
+ }
27
+ ) }),
28
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", className: "min-w-[120px]", children: locales.map((l) => /* @__PURE__ */ jsxs(
29
+ DropdownMenuItem,
30
+ {
31
+ onClick: () => onLocaleChange(l.code),
32
+ className: l.code === currentLocale ? "font-medium" : "",
33
+ children: [
34
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground mr-2 w-5 text-xs", children: l.short }),
35
+ l.full
36
+ ]
37
+ },
38
+ l.code
39
+ )) })
40
+ ] });
41
+ }
42
+ function GlobeIcon() {
43
+ return /* @__PURE__ */ jsxs(
44
+ "svg",
45
+ {
46
+ xmlns: "http://www.w3.org/2000/svg",
47
+ width: "14",
48
+ height: "14",
49
+ viewBox: "0 0 24 24",
50
+ fill: "none",
51
+ stroke: "currentColor",
52
+ strokeWidth: "1.5",
53
+ strokeLinecap: "round",
54
+ strokeLinejoin: "round",
55
+ className: "shrink-0",
56
+ children: [
57
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
58
+ /* @__PURE__ */ jsx("path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" }),
59
+ /* @__PURE__ */ jsx("path", { d: "M2 12h20" })
60
+ ]
61
+ }
62
+ );
63
+ }
64
+ export {
65
+ LocaleSwitcher
66
+ };
@@ -0,0 +1,9 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ declare function Logo({ size, mono, className, }: {
4
+ size?: number;
5
+ mono?: boolean;
6
+ className?: string;
7
+ }): react_jsx_runtime.JSX.Element;
8
+
9
+ export { Logo };
@@ -0,0 +1,52 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ function Logo({
3
+ size = 20,
4
+ mono = false,
5
+ className
6
+ }) {
7
+ const id = `naeil-logo-${size}`;
8
+ return /* @__PURE__ */ jsxs(
9
+ "svg",
10
+ {
11
+ width: size,
12
+ height: size,
13
+ viewBox: "0 0 24 24",
14
+ fill: "none",
15
+ "aria-label": "naeil",
16
+ className,
17
+ children: [
18
+ /* @__PURE__ */ jsx(
19
+ "path",
20
+ {
21
+ d: "M6 4 L6 16 L20 16",
22
+ stroke: "currentColor",
23
+ strokeWidth: "2",
24
+ strokeLinecap: "square",
25
+ strokeLinejoin: "miter"
26
+ }
27
+ ),
28
+ mono ? /* @__PURE__ */ jsx("circle", { cx: "15", cy: "16", r: "3.5", fill: "currentColor", mask: `url(#${id})` }) : /* @__PURE__ */ jsx("circle", { cx: "15", cy: "16", r: "3.5", fill: `url(#${id}-grad)`, mask: `url(#${id})` }),
29
+ /* @__PURE__ */ jsxs("defs", { children: [
30
+ !mono && /* @__PURE__ */ jsxs(
31
+ "linearGradient",
32
+ {
33
+ id: `${id}-grad`,
34
+ x1: "15",
35
+ y1: "12.5",
36
+ x2: "15",
37
+ y2: "16",
38
+ children: [
39
+ /* @__PURE__ */ jsx("stop", { stopColor: "#eab308" }),
40
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#dc2626" })
41
+ ]
42
+ }
43
+ ),
44
+ /* @__PURE__ */ jsx("mask", { id, children: /* @__PURE__ */ jsx("rect", { x: "0", y: "0", width: "24", height: "16", fill: "white" }) })
45
+ ] })
46
+ ]
47
+ }
48
+ );
49
+ }
50
+ export {
51
+ Logo
52
+ };
@@ -0,0 +1,39 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface NavProps {
4
+ /** Internal Link component (from consumer's next-intl routing) */
5
+ Link: React.ComponentType<React.ComponentPropsWithoutRef<"a"> & {
6
+ href: string;
7
+ }>;
8
+ /** Current pathname value (already resolved, not a hook) */
9
+ usePathname: () => string;
10
+ /** Where the .naeil logo links to. Default: "/" */
11
+ brandHref?: string;
12
+ /** Whether brandHref is external (renders <a>) or internal (renders Link). Default: false */
13
+ brandExternal?: boolean;
14
+ /** Custom brand content (replaces default Logo + ".naeil" text) */
15
+ brandSlot?: React.ReactNode;
16
+ /** When true, project links (except current) are rendered as external <a> to externalBaseUrl. Default: false */
17
+ projectsExternal?: boolean;
18
+ /** Base URL for external project links. Default: "https://naeil.dev" */
19
+ externalBaseUrl?: string;
20
+ /** Override href for the current project in the dropdown */
21
+ currentProjectKey?: string;
22
+ currentProjectHref?: string;
23
+ /** App-specific sub-navigation items after the project dropdown */
24
+ subNav?: Array<{
25
+ label: string;
26
+ href: string;
27
+ }>;
28
+ /** React node for auth UI (rendered in desktop right side + mobile bottom) */
29
+ authSlot?: React.ReactNode;
30
+ /** Show Projects dropdown in nav. Default: true */
31
+ showProjects?: boolean;
32
+ /** Show blog link in nav. Default: true */
33
+ showBlog?: boolean;
34
+ /** Right-side toolbar (theme toggle, locale switcher, etc.) */
35
+ toolbarSlot?: React.ReactNode;
36
+ }
37
+ declare function Nav({ Link, usePathname, brandHref, brandExternal, brandSlot, projectsExternal, externalBaseUrl, currentProjectKey, currentProjectHref, subNav, authSlot, showProjects, showBlog, toolbarSlot, }: NavProps): react_jsx_runtime.JSX.Element;
38
+
39
+ export { Nav };
@@ -0,0 +1,412 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { useTranslations } from "next-intl";
5
+ import { Badge } from "./ui/badge.js";
6
+ import Image from "next/image";
7
+ const PROJECTS = [
8
+ {
9
+ key: "cc",
10
+ href: "/cc",
11
+ accent: "oklch(0.704 0.140 181)",
12
+ icon: "/images/coral.png",
13
+ status: "active"
14
+ },
15
+ {
16
+ key: "pkm",
17
+ href: "/pkm",
18
+ accent: "oklch(0.702 0.183 293)",
19
+ icon: "/images/jellyfish.png",
20
+ status: "coming"
21
+ },
22
+ {
23
+ key: "naeilUi",
24
+ href: "/design",
25
+ accent: "oklch(0.623 0.214 259)",
26
+ icon: "/images/whale.png",
27
+ status: "active"
28
+ },
29
+ {
30
+ key: "sa",
31
+ href: "/sa",
32
+ accent: "oklch(0.723 0.219 149)",
33
+ icon: "/images/fish.png",
34
+ status: "active"
35
+ },
36
+ {
37
+ key: "babyAgent",
38
+ href: "/baby-agent",
39
+ accent: "oklch(0.769 0.188 70.08)",
40
+ icon: "/images/turtle.png",
41
+ status: "coming"
42
+ }
43
+ ];
44
+ function Nav({
45
+ Link,
46
+ usePathname,
47
+ brandHref = "/",
48
+ brandExternal = false,
49
+ brandSlot,
50
+ projectsExternal = false,
51
+ externalBaseUrl = "https://naeil.dev",
52
+ currentProjectKey,
53
+ currentProjectHref,
54
+ subNav,
55
+ authSlot,
56
+ showProjects = true,
57
+ showBlog = true,
58
+ toolbarSlot
59
+ }) {
60
+ const t = useTranslations("nav");
61
+ const pt = useTranslations("projects");
62
+ const pathname = usePathname();
63
+ const [scrolled, setScrolled] = useState(false);
64
+ const [mobileOpen, setMobileOpen] = useState(false);
65
+ const [projectsOpen, setProjectsOpen] = useState(false);
66
+ useEffect(() => {
67
+ const onScroll = () => setScrolled(window.scrollY > 16);
68
+ window.addEventListener("scroll", onScroll, { passive: true });
69
+ return () => window.removeEventListener("scroll", onScroll);
70
+ }, []);
71
+ useEffect(() => {
72
+ setMobileOpen(false);
73
+ setProjectsOpen(false);
74
+ }, [pathname]);
75
+ useEffect(() => {
76
+ document.body.style.overflow = mobileOpen ? "hidden" : "";
77
+ return () => {
78
+ document.body.style.overflow = "";
79
+ };
80
+ }, [mobileOpen]);
81
+ const linkClass = (href) => {
82
+ const isActive = pathname === href;
83
+ return [
84
+ "text-sm font-medium transition-colors",
85
+ isActive ? "text-foreground" : "text-muted-foreground hover:text-foreground"
86
+ ].join(" ");
87
+ };
88
+ const isProjectActive = pathname.startsWith("/projects") || pathname.startsWith("/cc") || pathname.startsWith("/pkm") || pathname.startsWith("/sa") || pathname.startsWith("/design");
89
+ function getProjectLink(project) {
90
+ if (currentProjectKey && project.key === currentProjectKey) {
91
+ return { href: currentProjectHref || "/", external: false };
92
+ }
93
+ if (projectsExternal) {
94
+ return { href: `${externalBaseUrl}${project.href}`, external: true };
95
+ }
96
+ return { href: project.href, external: false };
97
+ }
98
+ const brandContent = brandSlot != null ? brandSlot : /* @__PURE__ */ jsxs("span", { className: "text-foreground flex items-center gap-3 text-xl font-semibold tracking-tight", children: [
99
+ /* @__PURE__ */ jsx(Logo, { size: 28 }),
100
+ ".naeil"
101
+ ] });
102
+ const brandElement = brandExternal ? /* @__PURE__ */ jsx("a", { href: brandHref, children: brandContent }) : /* @__PURE__ */ jsx(Link, { href: brandHref, children: brandContent });
103
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
104
+ /* @__PURE__ */ jsx(
105
+ "nav",
106
+ {
107
+ className: [
108
+ "fixed top-0 z-50 w-full transition-[background-color,border-color] duration-300",
109
+ scrolled || mobileOpen ? "border-b border-border/40 bg-background/80 backdrop-blur-md" : "border-b border-transparent bg-transparent"
110
+ ].join(" "),
111
+ children: /* @__PURE__ */ jsxs("div", { className: "mx-auto flex h-[58px] max-w-7xl items-center px-6", children: [
112
+ /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center md:w-[200px]", children: brandElement }),
113
+ /* @__PURE__ */ jsxs("div", { className: "hidden flex-1 items-center gap-6 md:flex", children: [
114
+ showProjects && /* @__PURE__ */ jsxs("div", { className: "group relative", children: [
115
+ /* @__PURE__ */ jsxs(
116
+ "button",
117
+ {
118
+ className: [
119
+ "text-sm font-medium transition-colors",
120
+ isProjectActive ? "text-foreground" : "text-muted-foreground hover:text-foreground"
121
+ ].join(" "),
122
+ children: [
123
+ t("projects"),
124
+ /* @__PURE__ */ jsx(
125
+ "svg",
126
+ {
127
+ width: "10",
128
+ height: "10",
129
+ viewBox: "0 0 24 24",
130
+ fill: "none",
131
+ stroke: "currentColor",
132
+ strokeWidth: "2",
133
+ strokeLinecap: "round",
134
+ strokeLinejoin: "round",
135
+ className: "ml-1 inline-block transition-transform group-hover:rotate-180",
136
+ children: /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6" })
137
+ }
138
+ )
139
+ ]
140
+ }
141
+ ),
142
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute left-0 top-full pt-3 opacity-0 transition-opacity duration-150 group-hover:pointer-events-auto group-hover:opacity-100", children: /* @__PURE__ */ jsx("div", { className: "border-border/40 bg-background/95 w-[520px] rounded-xl border p-4 shadow-xl backdrop-blur-md", children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-1", children: PROJECTS.map((project) => {
143
+ const { href, external } = getProjectLink(project);
144
+ const inner = /* @__PURE__ */ jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-3.5 rounded-lg px-3 py-3 transition-colors", children: [
145
+ /* @__PURE__ */ jsx(
146
+ "div",
147
+ {
148
+ className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg border",
149
+ style: {
150
+ borderColor: `color-mix(in oklch, ${project.accent} 30%, transparent)`,
151
+ backgroundColor: `color-mix(in oklch, ${project.accent} 8%, transparent)`
152
+ },
153
+ children: /* @__PURE__ */ jsx(
154
+ Image,
155
+ {
156
+ src: project.icon,
157
+ alt: "",
158
+ width: 24,
159
+ height: 24,
160
+ className: "object-contain"
161
+ }
162
+ )
163
+ }
164
+ ),
165
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 pt-0.5", children: [
166
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
167
+ /* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: pt(`${project.key}.name`) }),
168
+ project.status === "coming" && /* @__PURE__ */ jsx(
169
+ Badge,
170
+ {
171
+ variant: "outline",
172
+ className: "text-muted-foreground px-1 py-0 text-[9px]",
173
+ children: pt("status.coming")
174
+ }
175
+ )
176
+ ] }),
177
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mt-0.5 text-xs leading-snug", children: pt(`${project.key}.description`) })
178
+ ] })
179
+ ] });
180
+ if (external) {
181
+ return /* @__PURE__ */ jsx("a", { href, children: inner }, project.key);
182
+ }
183
+ return /* @__PURE__ */ jsx(Link, { href, children: inner }, project.key);
184
+ }) }) }) })
185
+ ] }),
186
+ showBlog && /* @__PURE__ */ jsx(Fragment, { children: projectsExternal ? /* @__PURE__ */ jsx(
187
+ "a",
188
+ {
189
+ href: `${externalBaseUrl}/blog`,
190
+ className: "text-sm font-medium text-muted-foreground transition-colors hover:text-foreground",
191
+ children: t("blog")
192
+ }
193
+ ) : /* @__PURE__ */ jsx(Link, { href: "/blog", className: linkClass("/blog"), children: t("blog") }) }),
194
+ subNav && subNav.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
195
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-border/40" }),
196
+ subNav.map((item) => /* @__PURE__ */ jsx(
197
+ Link,
198
+ {
199
+ href: item.href,
200
+ className: linkClass(item.href),
201
+ children: item.label
202
+ },
203
+ item.href
204
+ ))
205
+ ] })
206
+ ] }),
207
+ /* @__PURE__ */ jsxs("div", { className: "hidden items-center gap-3 md:flex", children: [
208
+ authSlot,
209
+ authSlot && toolbarSlot && /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-border/40" }),
210
+ toolbarSlot && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4", children: toolbarSlot })
211
+ ] }),
212
+ /* @__PURE__ */ jsx(
213
+ "button",
214
+ {
215
+ className: "text-muted-foreground hover:text-foreground ml-auto transition-colors md:hidden",
216
+ onClick: () => setMobileOpen(!mobileOpen),
217
+ "aria-label": "Menu",
218
+ children: mobileOpen ? /* @__PURE__ */ jsx(CloseIcon, {}) : /* @__PURE__ */ jsx(MenuIcon, {})
219
+ }
220
+ )
221
+ ] })
222
+ }
223
+ ),
224
+ mobileOpen && /* @__PURE__ */ jsx("div", { className: "bg-background/95 fixed inset-0 z-40 overflow-y-auto pt-[58px] backdrop-blur-md md:hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col px-6 py-6", children: [
225
+ showProjects && /* @__PURE__ */ jsxs(Fragment, { children: [
226
+ /* @__PURE__ */ jsxs(
227
+ "button",
228
+ {
229
+ className: "text-foreground flex items-center justify-between py-3 text-base font-medium",
230
+ onClick: () => setProjectsOpen(!projectsOpen),
231
+ children: [
232
+ t("projects"),
233
+ /* @__PURE__ */ jsx(
234
+ "svg",
235
+ {
236
+ width: "14",
237
+ height: "14",
238
+ viewBox: "0 0 24 24",
239
+ fill: "none",
240
+ stroke: "currentColor",
241
+ strokeWidth: "2",
242
+ strokeLinecap: "round",
243
+ strokeLinejoin: "round",
244
+ className: [
245
+ "transition-transform duration-200",
246
+ projectsOpen ? "rotate-180" : ""
247
+ ].join(" "),
248
+ children: /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6" })
249
+ }
250
+ )
251
+ ]
252
+ }
253
+ ),
254
+ projectsOpen && /* @__PURE__ */ jsx("div", { className: "mb-2 flex flex-col gap-1 pl-1", children: PROJECTS.map((project) => {
255
+ const { href, external } = getProjectLink(project);
256
+ const inner = /* @__PURE__ */ jsxs("div", { className: "hover:bg-muted/50 flex items-center gap-3 rounded-lg px-3 py-3 transition-colors", children: [
257
+ /* @__PURE__ */ jsx(
258
+ "div",
259
+ {
260
+ className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border",
261
+ style: {
262
+ borderColor: `color-mix(in oklch, ${project.accent} 30%, transparent)`,
263
+ backgroundColor: `color-mix(in oklch, ${project.accent} 8%, transparent)`
264
+ },
265
+ children: /* @__PURE__ */ jsx(
266
+ Image,
267
+ {
268
+ src: project.icon,
269
+ alt: "",
270
+ width: 20,
271
+ height: 20,
272
+ className: "object-contain"
273
+ }
274
+ )
275
+ }
276
+ ),
277
+ /* @__PURE__ */ jsxs("div", { children: [
278
+ /* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: pt(`${project.key}.name`) }),
279
+ project.status === "coming" && /* @__PURE__ */ jsx(
280
+ Badge,
281
+ {
282
+ variant: "outline",
283
+ className: "text-muted-foreground ml-2 px-1 py-0 text-[9px]",
284
+ children: pt("status.coming")
285
+ }
286
+ )
287
+ ] })
288
+ ] });
289
+ if (external) {
290
+ return /* @__PURE__ */ jsx(
291
+ "a",
292
+ {
293
+ href,
294
+ onClick: () => setMobileOpen(false),
295
+ children: inner
296
+ },
297
+ project.key
298
+ );
299
+ }
300
+ return /* @__PURE__ */ jsx(
301
+ Link,
302
+ {
303
+ href,
304
+ onClick: () => setMobileOpen(false),
305
+ children: inner
306
+ },
307
+ project.key
308
+ );
309
+ }) })
310
+ ] }),
311
+ showBlog && /* @__PURE__ */ jsx(Fragment, { children: projectsExternal ? /* @__PURE__ */ jsx(
312
+ "a",
313
+ {
314
+ href: `${externalBaseUrl}/blog`,
315
+ className: "text-foreground border-border/40 border-t py-3 text-base font-medium",
316
+ onClick: () => setMobileOpen(false),
317
+ children: t("blog")
318
+ }
319
+ ) : /* @__PURE__ */ jsx(
320
+ Link,
321
+ {
322
+ href: "/blog",
323
+ className: "text-foreground border-border/40 border-t py-3 text-base font-medium",
324
+ onClick: () => setMobileOpen(false),
325
+ children: t("blog")
326
+ }
327
+ ) }),
328
+ subNav && subNav.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-border/40 border-t", children: subNav.map((item) => /* @__PURE__ */ jsx(
329
+ Link,
330
+ {
331
+ href: item.href,
332
+ className: "text-foreground block py-3 text-base font-medium",
333
+ onClick: () => setMobileOpen(false),
334
+ children: item.label
335
+ },
336
+ item.href
337
+ )) }),
338
+ authSlot && /* @__PURE__ */ jsx("div", { className: "border-border/40 border-t pt-4", children: authSlot }),
339
+ toolbarSlot && /* @__PURE__ */ jsx("div", { className: "border-border/40 flex items-center gap-4 border-t pt-4 mt-2", children: toolbarSlot })
340
+ ] }) })
341
+ ] });
342
+ }
343
+ function Logo({
344
+ size = 20
345
+ }) {
346
+ const id = `naeil-nav-logo-${size}`;
347
+ return /* @__PURE__ */ jsxs(
348
+ "svg",
349
+ {
350
+ width: size,
351
+ height: size,
352
+ viewBox: "0 0 24 24",
353
+ fill: "none",
354
+ "aria-label": "naeil",
355
+ children: [
356
+ /* @__PURE__ */ jsx(
357
+ "path",
358
+ {
359
+ d: "M6 4 L6 16 L20 16",
360
+ stroke: "currentColor",
361
+ strokeWidth: "2",
362
+ strokeLinecap: "square",
363
+ strokeLinejoin: "miter"
364
+ }
365
+ ),
366
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "16", r: "3.5", fill: `url(#${id}-grad)`, mask: `url(#${id})` }),
367
+ /* @__PURE__ */ jsxs("defs", { children: [
368
+ /* @__PURE__ */ jsxs("linearGradient", { id: `${id}-grad`, x1: "15", y1: "12.5", x2: "15", y2: "16", children: [
369
+ /* @__PURE__ */ jsx("stop", { stopColor: "#eab308" }),
370
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#dc2626" })
371
+ ] }),
372
+ /* @__PURE__ */ jsx("mask", { id, children: /* @__PURE__ */ jsx("rect", { x: "0", y: "0", width: "24", height: "16", fill: "white" }) })
373
+ ] })
374
+ ]
375
+ }
376
+ );
377
+ }
378
+ function MenuIcon() {
379
+ return /* @__PURE__ */ jsx(
380
+ "svg",
381
+ {
382
+ width: "22",
383
+ height: "22",
384
+ viewBox: "0 0 24 24",
385
+ fill: "none",
386
+ stroke: "currentColor",
387
+ strokeWidth: "1.5",
388
+ strokeLinecap: "round",
389
+ strokeLinejoin: "round",
390
+ children: /* @__PURE__ */ jsx("path", { d: "M4 6h16M4 12h16M4 18h16" })
391
+ }
392
+ );
393
+ }
394
+ function CloseIcon() {
395
+ return /* @__PURE__ */ jsx(
396
+ "svg",
397
+ {
398
+ width: "22",
399
+ height: "22",
400
+ viewBox: "0 0 24 24",
401
+ fill: "none",
402
+ stroke: "currentColor",
403
+ strokeWidth: "1.5",
404
+ strokeLinecap: "round",
405
+ strokeLinejoin: "round",
406
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
407
+ }
408
+ );
409
+ }
410
+ export {
411
+ Nav
412
+ };
@@ -0,0 +1,6 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ThemeProvider as ThemeProvider$1 } from 'next-themes';
3
+
4
+ declare function ThemeProvider({ children, ...props }: React.ComponentProps<typeof ThemeProvider$1>): react_jsx_runtime.JSX.Element;
5
+
6
+ export { ThemeProvider };
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
20
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
+ var __objRest = (source, exclude) => {
22
+ var target = {};
23
+ for (var prop in source)
24
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
25
+ target[prop] = source[prop];
26
+ if (source != null && __getOwnPropSymbols)
27
+ for (var prop of __getOwnPropSymbols(source)) {
28
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
29
+ target[prop] = source[prop];
30
+ }
31
+ return target;
32
+ };
33
+ import { jsx } from "react/jsx-runtime";
34
+ import { ThemeProvider as NextThemesProvider } from "next-themes";
35
+ function ThemeProvider(_a) {
36
+ var _b = _a, {
37
+ children
38
+ } = _b, props = __objRest(_b, [
39
+ "children"
40
+ ]);
41
+ return /* @__PURE__ */ jsx(NextThemesProvider, __spreadProps(__spreadValues({}, props), { children }));
42
+ }
43
+ export {
44
+ ThemeProvider
45
+ };
@@ -0,0 +1,5 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ declare function ThemeToggleIcon(): react_jsx_runtime.JSX.Element;
4
+
5
+ export { ThemeToggleIcon };