@orangecheck/app-design 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +39 -2
- package/dist/brand.d.mts +46 -0
- package/dist/brand.d.ts +46 -0
- package/dist/brand.js +142 -0
- package/dist/brand.js.map +1 -0
- package/dist/brand.mjs +134 -0
- package/dist/brand.mjs.map +1 -0
- package/dist/chrome.d.mts +64 -0
- package/dist/chrome.d.ts +64 -0
- package/dist/chrome.js +479 -0
- package/dist/chrome.js.map +1 -0
- package/dist/chrome.mjs +447 -0
- package/dist/chrome.mjs.map +1 -0
- package/dist/components.d.mts +474 -0
- package/dist/components.d.ts +474 -0
- package/dist/components.js +619 -0
- package/dist/components.js.map +1 -0
- package/dist/components.mjs +588 -0
- package/dist/components.mjs.map +1 -0
- package/dist/index.d.mts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +1595 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1446 -0
- package/dist/index.mjs.map +1 -0
- package/dist/primitives.d.mts +140 -0
- package/dist/primitives.d.ts +140 -0
- package/dist/primitives.js +706 -0
- package/dist/primitives.js.map +1 -0
- package/dist/primitives.mjs +606 -0
- package/dist/primitives.mjs.map +1 -0
- package/dist/styles/fonts/inter-latin-ext.woff2 +0 -0
- package/dist/styles/fonts/inter-latin.woff2 +0 -0
- package/dist/styles/fonts/jetbrains-mono-latin-ext.woff2 +0 -0
- package/dist/styles/fonts/jetbrains-mono-latin.woff2 +0 -0
- package/dist/styles/fonts.css +74 -0
- package/dist/styles/motion.css +80 -0
- package/dist/styles/theme.css +226 -0
- package/dist/styles/tokens.css +152 -0
- package/dist/styles.css +14 -0
- package/dist/tokens.d.mts +42 -0
- package/dist/tokens.d.ts +42 -0
- package/dist/tokens.js +50 -0
- package/dist/tokens.js.map +1 -0
- package/dist/tokens.mjs +45 -0
- package/dist/tokens.mjs.map +1 -0
- package/package.json +114 -4
package/dist/chrome.mjs
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
import { X, Menu, Sun, Moon, SunMoon } from 'lucide-react';
|
|
2
|
+
import Link2 from 'next/link';
|
|
3
|
+
import { forwardRef, useState, useEffect } from 'react';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { extendTailwindMerge } from 'tailwind-merge';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
8
|
+
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
9
|
+
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
10
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
11
|
+
import { useTheme } from 'next-themes';
|
|
12
|
+
|
|
13
|
+
var merge = extendTailwindMerge({
|
|
14
|
+
extend: {
|
|
15
|
+
classGroups: {
|
|
16
|
+
"oca-type": [
|
|
17
|
+
"oca-display-1",
|
|
18
|
+
"oca-display-2",
|
|
19
|
+
"oca-display-3",
|
|
20
|
+
"oca-title",
|
|
21
|
+
"oca-title-sm",
|
|
22
|
+
"oca-eyebrow",
|
|
23
|
+
"oca-lead",
|
|
24
|
+
"oca-body",
|
|
25
|
+
"oca-numeral"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
function cn(...inputs) {
|
|
31
|
+
return merge(clsx(inputs));
|
|
32
|
+
}
|
|
33
|
+
var TOP = "0,3 2,2 6,4 14,0 16,1 6,6";
|
|
34
|
+
var LEFT = "0,3 6,6 6,8 0,5";
|
|
35
|
+
var RIGHT = "6,6 16,1 16,3 6,8";
|
|
36
|
+
var MARK_FACES = { top: "#FED8AB", left: "#FB933C", right: "#EA580B" };
|
|
37
|
+
function AppIcon({ title, size = 32, className, ...rest }) {
|
|
38
|
+
return /* @__PURE__ */ jsxs(
|
|
39
|
+
"svg",
|
|
40
|
+
{
|
|
41
|
+
viewBox: "0 0 24 24",
|
|
42
|
+
width: size,
|
|
43
|
+
height: size,
|
|
44
|
+
role: title ? "img" : void 0,
|
|
45
|
+
"aria-hidden": title ? void 0 : true,
|
|
46
|
+
className: cn("shrink-0", className),
|
|
47
|
+
...rest,
|
|
48
|
+
children: [
|
|
49
|
+
title ? /* @__PURE__ */ jsx("title", { children: title }) : null,
|
|
50
|
+
/* @__PURE__ */ jsx(
|
|
51
|
+
"rect",
|
|
52
|
+
{
|
|
53
|
+
width: "24",
|
|
54
|
+
height: "24",
|
|
55
|
+
rx: "6.25",
|
|
56
|
+
style: { fill: "var(--oca-icon-tile, #0A0A0A)", stroke: "var(--oca-icon-ring, transparent)" },
|
|
57
|
+
strokeWidth: "0.5"
|
|
58
|
+
}
|
|
59
|
+
),
|
|
60
|
+
/* @__PURE__ */ jsxs("g", { transform: "translate(4.25 8.1) scale(0.97)", children: [
|
|
61
|
+
/* @__PURE__ */ jsx("polygon", { points: LEFT, fill: MARK_FACES.left }),
|
|
62
|
+
/* @__PURE__ */ jsx("polygon", { points: RIGHT, fill: MARK_FACES.right }),
|
|
63
|
+
/* @__PURE__ */ jsx("polygon", { points: TOP, fill: MARK_FACES.top })
|
|
64
|
+
] })
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
function Lockup({ name = "orangecheck", size = 28, className }) {
|
|
70
|
+
return /* @__PURE__ */ jsxs(
|
|
71
|
+
"span",
|
|
72
|
+
{
|
|
73
|
+
className: cn("inline-flex items-center font-medium tracking-[-0.01em]", className),
|
|
74
|
+
style: { gap: size * 0.32, fontSize: size * 0.56 },
|
|
75
|
+
children: [
|
|
76
|
+
/* @__PURE__ */ jsx(AppIcon, { size }),
|
|
77
|
+
/* @__PURE__ */ jsx("span", { children: name })
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
var overlayClass = "oca-animate-fade fixed inset-0 z-50 bg-[rgb(10_10_10/0.38)] backdrop-blur-[2px] data-[state=closed]:opacity-0";
|
|
83
|
+
forwardRef(function DialogContent2({ className, children, hideClose, ...props }, ref) {
|
|
84
|
+
return /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
|
|
85
|
+
/* @__PURE__ */ jsx(DialogPrimitive.Overlay, { className: overlayClass }),
|
|
86
|
+
/* @__PURE__ */ jsxs(
|
|
87
|
+
DialogPrimitive.Content,
|
|
88
|
+
{
|
|
89
|
+
ref,
|
|
90
|
+
className: cn(
|
|
91
|
+
"oca-animate-rise fixed left-1/2 top-1/2 z-50 w-[min(92vw,34rem)] -translate-x-1/2 -translate-y-1/2",
|
|
92
|
+
"max-h-[88vh] overflow-y-auto rounded-[1.5rem] border border-border bg-popover p-6 text-popover-foreground shadow-xl md:p-8",
|
|
93
|
+
"outline-none",
|
|
94
|
+
className
|
|
95
|
+
),
|
|
96
|
+
...props,
|
|
97
|
+
children: [
|
|
98
|
+
children,
|
|
99
|
+
hideClose ? null : /* @__PURE__ */ jsx(
|
|
100
|
+
DialogPrimitive.Close,
|
|
101
|
+
{
|
|
102
|
+
className: "absolute right-4 top-4 inline-flex size-9 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
103
|
+
"aria-label": "Close",
|
|
104
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-4" })
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
] });
|
|
111
|
+
});
|
|
112
|
+
var DialogTitle = forwardRef(function DialogTitle2({ className, ...props }, ref) {
|
|
113
|
+
return /* @__PURE__ */ jsx(
|
|
114
|
+
DialogPrimitive.Title,
|
|
115
|
+
{
|
|
116
|
+
ref,
|
|
117
|
+
className: cn("text-[1.5rem] font-normal leading-tight tracking-[-0.02em]", className),
|
|
118
|
+
...props
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
forwardRef(function DialogDescription2({ className, ...props }, ref) {
|
|
123
|
+
return /* @__PURE__ */ jsx(DialogPrimitive.Description, { ref, className: cn("oca-body", className), ...props });
|
|
124
|
+
});
|
|
125
|
+
var Sheet = DialogPrimitive.Root;
|
|
126
|
+
var SheetTrigger = DialogPrimitive.Trigger;
|
|
127
|
+
var SheetTitle = DialogTitle;
|
|
128
|
+
var sheetSide = {
|
|
129
|
+
right: "inset-y-0 right-0 h-full w-[min(88vw,24rem)] border-l",
|
|
130
|
+
left: "inset-y-0 left-0 h-full w-[min(88vw,24rem)] border-r",
|
|
131
|
+
bottom: "inset-x-0 bottom-0 max-h-[88vh] rounded-t-[1.5rem] border-t"
|
|
132
|
+
};
|
|
133
|
+
var SheetContent = forwardRef(function SheetContent2({ className, children, side = "right", ...props }, ref) {
|
|
134
|
+
return /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
|
|
135
|
+
/* @__PURE__ */ jsx(DialogPrimitive.Overlay, { className: overlayClass }),
|
|
136
|
+
/* @__PURE__ */ jsxs(
|
|
137
|
+
DialogPrimitive.Content,
|
|
138
|
+
{
|
|
139
|
+
ref,
|
|
140
|
+
className: cn(
|
|
141
|
+
"oca-animate-fade fixed z-50 flex flex-col gap-4 overflow-y-auto border-border bg-popover p-6 text-popover-foreground shadow-xl outline-none",
|
|
142
|
+
sheetSide[side],
|
|
143
|
+
className
|
|
144
|
+
),
|
|
145
|
+
...props,
|
|
146
|
+
children: [
|
|
147
|
+
children,
|
|
148
|
+
/* @__PURE__ */ jsx(
|
|
149
|
+
DialogPrimitive.Close,
|
|
150
|
+
{
|
|
151
|
+
className: "absolute right-4 top-4 inline-flex size-9 items-center justify-center rounded-full text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
152
|
+
"aria-label": "Close",
|
|
153
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-4" })
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
] });
|
|
160
|
+
});
|
|
161
|
+
forwardRef(function PopoverContent2({ className, align = "center", sideOffset = 8, ...props }, ref) {
|
|
162
|
+
return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
163
|
+
PopoverPrimitive.Content,
|
|
164
|
+
{
|
|
165
|
+
ref,
|
|
166
|
+
align,
|
|
167
|
+
sideOffset,
|
|
168
|
+
className: cn(
|
|
169
|
+
"oca-animate-fade z-50 w-72 rounded-2xl border border-border bg-popover p-4 text-popover-foreground shadow-lg outline-none",
|
|
170
|
+
className
|
|
171
|
+
),
|
|
172
|
+
...props
|
|
173
|
+
}
|
|
174
|
+
) });
|
|
175
|
+
});
|
|
176
|
+
forwardRef(function TooltipContent2({ className, sideOffset = 6, ...props }, ref) {
|
|
177
|
+
return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
178
|
+
TooltipPrimitive.Content,
|
|
179
|
+
{
|
|
180
|
+
ref,
|
|
181
|
+
sideOffset,
|
|
182
|
+
className: cn(
|
|
183
|
+
"oca-animate-fade z-50 max-w-xs rounded-lg bg-oca-ink px-2.5 py-1.5 text-[0.8125rem] leading-snug text-oca-ink-foreground",
|
|
184
|
+
className
|
|
185
|
+
),
|
|
186
|
+
...props
|
|
187
|
+
}
|
|
188
|
+
) });
|
|
189
|
+
});
|
|
190
|
+
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
191
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
192
|
+
var DropdownMenuContent = forwardRef(function DropdownMenuContent2({ className, sideOffset = 8, ...props }, ref) {
|
|
193
|
+
return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
194
|
+
DropdownMenuPrimitive.Content,
|
|
195
|
+
{
|
|
196
|
+
ref,
|
|
197
|
+
sideOffset,
|
|
198
|
+
className: cn(
|
|
199
|
+
"oca-animate-fade z-50 min-w-56 overflow-hidden rounded-2xl border border-border bg-popover p-1.5 text-popover-foreground shadow-lg",
|
|
200
|
+
className
|
|
201
|
+
),
|
|
202
|
+
...props
|
|
203
|
+
}
|
|
204
|
+
) });
|
|
205
|
+
});
|
|
206
|
+
var DropdownMenuItem = forwardRef(function DropdownMenuItem2({ className, destructive, ...props }, ref) {
|
|
207
|
+
return /* @__PURE__ */ jsx(
|
|
208
|
+
DropdownMenuPrimitive.Item,
|
|
209
|
+
{
|
|
210
|
+
ref,
|
|
211
|
+
className: cn(
|
|
212
|
+
"flex h-10 cursor-default select-none items-center gap-2.5 rounded-xl px-3 text-[0.9375rem] outline-none",
|
|
213
|
+
"data-[highlighted]:bg-accent data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:text-muted-foreground",
|
|
214
|
+
destructive && "text-destructive [&_svg]:text-destructive",
|
|
215
|
+
className
|
|
216
|
+
),
|
|
217
|
+
...props
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
});
|
|
221
|
+
var DropdownMenuLabel = forwardRef(function DropdownMenuLabel2({ className, ...props }, ref) {
|
|
222
|
+
return /* @__PURE__ */ jsx(
|
|
223
|
+
DropdownMenuPrimitive.Label,
|
|
224
|
+
{
|
|
225
|
+
ref,
|
|
226
|
+
className: cn("px-3 pb-1.5 pt-2 text-[0.8125rem] text-muted-foreground", className),
|
|
227
|
+
...props
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
});
|
|
231
|
+
var DropdownMenuSeparator = forwardRef(function DropdownMenuSeparator2({ className, ...props }, ref) {
|
|
232
|
+
return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Separator, { ref, className: cn("my-1.5 h-px bg-border", className), ...props });
|
|
233
|
+
});
|
|
234
|
+
function NavLink({ item, className, onNavigate }) {
|
|
235
|
+
const cls = cn(
|
|
236
|
+
"rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
|
|
237
|
+
item.active ? "text-foreground" : "text-muted-foreground hover:text-foreground",
|
|
238
|
+
className
|
|
239
|
+
);
|
|
240
|
+
if (item.external) {
|
|
241
|
+
return /* @__PURE__ */ jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: item.label });
|
|
242
|
+
}
|
|
243
|
+
return /* @__PURE__ */ jsx(Link2, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: item.label });
|
|
244
|
+
}
|
|
245
|
+
function SiteHeader({
|
|
246
|
+
home = "/",
|
|
247
|
+
brand,
|
|
248
|
+
nav = [],
|
|
249
|
+
actions,
|
|
250
|
+
className
|
|
251
|
+
}) {
|
|
252
|
+
const [open, setOpen] = useState(false);
|
|
253
|
+
return /* @__PURE__ */ jsx(
|
|
254
|
+
"header",
|
|
255
|
+
{
|
|
256
|
+
className: cn(
|
|
257
|
+
"sticky top-0 z-40 w-full border-b border-transparent bg-background/85 backdrop-blur-md supports-[backdrop-filter]:bg-background/70",
|
|
258
|
+
className
|
|
259
|
+
),
|
|
260
|
+
children: /* @__PURE__ */ jsxs("div", { className: "oca-container flex h-16 items-center justify-between gap-4 md:h-[4.5rem]", children: [
|
|
261
|
+
/* @__PURE__ */ jsx(Link2, { href: home, className: "-ml-1 rounded-lg p-1", "aria-label": "Home", children: brand ?? /* @__PURE__ */ jsx(Lockup, { size: 28 }) }),
|
|
262
|
+
nav.length > 0 ? /* @__PURE__ */ jsx("nav", { "aria-label": "Main", className: "hidden items-center gap-1 md:flex", children: nav.map((n) => /* @__PURE__ */ jsx(NavLink, { item: n }, n.href)) }) : null,
|
|
263
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
264
|
+
actions,
|
|
265
|
+
nav.length > 0 ? /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
|
|
266
|
+
/* @__PURE__ */ jsx(
|
|
267
|
+
SheetTrigger,
|
|
268
|
+
{
|
|
269
|
+
className: "inline-flex size-10 items-center justify-center rounded-full text-foreground hover:bg-accent md:hidden",
|
|
270
|
+
"aria-label": "Open menu",
|
|
271
|
+
children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
|
|
272
|
+
}
|
|
273
|
+
),
|
|
274
|
+
/* @__PURE__ */ jsxs(SheetContent, { side: "right", className: "pt-16", children: [
|
|
275
|
+
/* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Menu" }),
|
|
276
|
+
/* @__PURE__ */ jsx("nav", { "aria-label": "Main", className: "flex flex-col", children: nav.map((n) => /* @__PURE__ */ jsx(
|
|
277
|
+
NavLink,
|
|
278
|
+
{
|
|
279
|
+
item: n,
|
|
280
|
+
className: "rounded-xl px-3 py-3 text-[1.0625rem]",
|
|
281
|
+
onNavigate: () => setOpen(false)
|
|
282
|
+
},
|
|
283
|
+
n.href
|
|
284
|
+
)) })
|
|
285
|
+
] })
|
|
286
|
+
] }) : null
|
|
287
|
+
] })
|
|
288
|
+
] })
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
function SiteFooter({
|
|
293
|
+
columns = [],
|
|
294
|
+
fineprint,
|
|
295
|
+
meta,
|
|
296
|
+
className
|
|
297
|
+
}) {
|
|
298
|
+
return /* @__PURE__ */ jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
|
|
299
|
+
/* @__PURE__ */ jsxs("div", { className: "oca-container grid gap-10 py-14 md:grid-cols-[1.3fr_repeat(3,1fr)] md:py-16", children: [
|
|
300
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
301
|
+
/* @__PURE__ */ jsx(Lockup, { size: 26 }),
|
|
302
|
+
fineprint ? /* @__PURE__ */ jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
|
|
303
|
+
] }),
|
|
304
|
+
columns.map((col) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
305
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
|
|
306
|
+
col.links.map((l) => /* @__PURE__ */ jsx(
|
|
307
|
+
NavLink,
|
|
308
|
+
{
|
|
309
|
+
item: l,
|
|
310
|
+
className: "-mx-3 py-2.5 text-[0.9375rem] md:py-1.5"
|
|
311
|
+
},
|
|
312
|
+
l.href
|
|
313
|
+
))
|
|
314
|
+
] }, col.heading))
|
|
315
|
+
] }),
|
|
316
|
+
meta ? /* @__PURE__ */ jsx("div", { className: "oca-container border-t border-border py-6 text-[0.875rem] text-muted-foreground", children: meta }) : null
|
|
317
|
+
] });
|
|
318
|
+
}
|
|
319
|
+
function SideNav({ groups, onNavigate }) {
|
|
320
|
+
return /* @__PURE__ */ jsx("nav", { "aria-label": "Sections", className: "flex flex-col gap-6", children: groups.map((g, gi) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
321
|
+
g.label ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-1.5 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
|
|
322
|
+
g.items.map((it) => /* @__PURE__ */ jsxs(
|
|
323
|
+
Link2,
|
|
324
|
+
{
|
|
325
|
+
href: it.href,
|
|
326
|
+
onClick: onNavigate,
|
|
327
|
+
"aria-current": it.active ? "page" : void 0,
|
|
328
|
+
className: cn(
|
|
329
|
+
"flex h-10 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
|
|
330
|
+
"[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
|
|
331
|
+
it.active ? "bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
332
|
+
),
|
|
333
|
+
children: [
|
|
334
|
+
it.icon,
|
|
335
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: it.label }),
|
|
336
|
+
it.badge ? /* @__PURE__ */ jsx("span", { className: "shrink-0", children: it.badge }) : null
|
|
337
|
+
]
|
|
338
|
+
},
|
|
339
|
+
it.href
|
|
340
|
+
))
|
|
341
|
+
] }, g.label ?? gi)) });
|
|
342
|
+
}
|
|
343
|
+
function AppShell({
|
|
344
|
+
nav,
|
|
345
|
+
home = "/",
|
|
346
|
+
account,
|
|
347
|
+
banner,
|
|
348
|
+
footer,
|
|
349
|
+
children,
|
|
350
|
+
className
|
|
351
|
+
}) {
|
|
352
|
+
const [open, setOpen] = useState(false);
|
|
353
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("min-h-dvh bg-background", className), children: [
|
|
354
|
+
/* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-40 flex h-14 items-center justify-between border-b border-border bg-background/85 px-4 backdrop-blur-md lg:hidden", children: [
|
|
355
|
+
/* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
|
|
356
|
+
/* @__PURE__ */ jsx(
|
|
357
|
+
SheetTrigger,
|
|
358
|
+
{
|
|
359
|
+
className: "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
|
|
360
|
+
"aria-label": "Open navigation",
|
|
361
|
+
children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
|
|
362
|
+
}
|
|
363
|
+
),
|
|
364
|
+
/* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "p-4 pt-16", children: [
|
|
365
|
+
/* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
|
|
366
|
+
/* @__PURE__ */ jsx(SideNav, { groups: nav, onNavigate: () => setOpen(false) })
|
|
367
|
+
] })
|
|
368
|
+
] }),
|
|
369
|
+
/* @__PURE__ */ jsx(Link2, { href: home, "aria-label": "Home", children: /* @__PURE__ */ jsx(AppIcon, { size: 28 }) }),
|
|
370
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center", children: account })
|
|
371
|
+
] }),
|
|
372
|
+
/* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
|
|
373
|
+
/* @__PURE__ */ jsxs("aside", { className: "sticky top-0 hidden h-dvh w-64 shrink-0 flex-col gap-8 overflow-y-auto px-4 py-6 lg:flex", children: [
|
|
374
|
+
/* @__PURE__ */ jsx(Link2, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsx(Lockup, { size: 26 }) }),
|
|
375
|
+
/* @__PURE__ */ jsx(SideNav, { groups: nav }),
|
|
376
|
+
/* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
|
|
377
|
+
] }),
|
|
378
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
379
|
+
/* @__PURE__ */ jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
|
|
380
|
+
banner ? /* @__PURE__ */ jsx("div", { className: "px-4 pb-2 pt-4 md:px-8 lg:pt-0", children: banner }) : null,
|
|
381
|
+
/* @__PURE__ */ jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children })
|
|
382
|
+
] })
|
|
383
|
+
] })
|
|
384
|
+
] });
|
|
385
|
+
}
|
|
386
|
+
function AccountMenu({
|
|
387
|
+
name,
|
|
388
|
+
detail,
|
|
389
|
+
items
|
|
390
|
+
}) {
|
|
391
|
+
const initial = name.trim().charAt(0).toUpperCase() || "\xB7";
|
|
392
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
393
|
+
/* @__PURE__ */ jsxs(
|
|
394
|
+
DropdownMenuTrigger,
|
|
395
|
+
{
|
|
396
|
+
className: "inline-flex h-10 items-center gap-2.5 rounded-full border border-border bg-card pl-1 pr-3.5 text-[0.9375rem] outline-none transition-colors hover:border-oca-hairline-strong focus-visible:ring-2 focus-visible:ring-ring",
|
|
397
|
+
"aria-label": `Account: ${name}`,
|
|
398
|
+
children: [
|
|
399
|
+
/* @__PURE__ */ jsx("span", { className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background", children: initial }),
|
|
400
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-[10rem] truncate", children: name })
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
),
|
|
404
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-64", children: [
|
|
405
|
+
/* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "flex flex-col gap-0.5", children: [
|
|
406
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-[0.9375rem] font-medium text-foreground", children: name }),
|
|
407
|
+
detail ? /* @__PURE__ */ jsx("span", { className: "truncate font-mono text-[0.75rem]", children: detail }) : null
|
|
408
|
+
] }),
|
|
409
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
410
|
+
items.map(
|
|
411
|
+
(it, i) => it === "separator" ? /* @__PURE__ */ jsx(DropdownMenuSeparator, {}, `sep-${i}`) : it.href ? /* @__PURE__ */ jsx(DropdownMenuItem, { asChild: true, destructive: it.destructive, children: /* @__PURE__ */ jsxs(Link2, { href: it.href, children: [
|
|
412
|
+
it.icon,
|
|
413
|
+
it.label
|
|
414
|
+
] }) }, it.label) : /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: it.onSelect, destructive: it.destructive, children: [
|
|
415
|
+
it.icon,
|
|
416
|
+
it.label
|
|
417
|
+
] }, it.label)
|
|
418
|
+
)
|
|
419
|
+
] })
|
|
420
|
+
] });
|
|
421
|
+
}
|
|
422
|
+
function ThemeToggle({ className }) {
|
|
423
|
+
const { theme, setTheme } = useTheme();
|
|
424
|
+
const [mounted, setMounted] = useState(false);
|
|
425
|
+
useEffect(() => setMounted(true), []);
|
|
426
|
+
const current = mounted ? theme ?? "system" : "system";
|
|
427
|
+
const next = current === "light" ? "dark" : current === "dark" ? "system" : "light";
|
|
428
|
+
const Icon = current === "light" ? Sun : current === "dark" ? Moon : SunMoon;
|
|
429
|
+
return /* @__PURE__ */ jsx(
|
|
430
|
+
"button",
|
|
431
|
+
{
|
|
432
|
+
type: "button",
|
|
433
|
+
onClick: () => setTheme(next),
|
|
434
|
+
"aria-label": `Theme: ${current}. Switch to ${next}`,
|
|
435
|
+
title: `Theme: ${current}`,
|
|
436
|
+
className: cn(
|
|
437
|
+
"inline-flex size-10 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
438
|
+
className
|
|
439
|
+
),
|
|
440
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-[1.125rem]" })
|
|
441
|
+
}
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export { AccountMenu, AppShell, SiteFooter, SiteHeader, ThemeToggle };
|
|
446
|
+
//# sourceMappingURL=chrome.mjs.map
|
|
447
|
+
//# sourceMappingURL=chrome.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/cn.ts","../src/brand/mark.tsx","../src/primitives/overlay.tsx","../src/chrome/site.tsx","../src/chrome/app-shell.tsx"],"names":["DialogContent","jsxs","jsx","DialogTitle","DialogDescription","SheetContent","PopoverContent","TooltipContent","DropdownMenuContent","DropdownMenuItem","DropdownMenuLabel","DropdownMenuSeparator","Link","useState","Menu"],"mappings":"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","file":"chrome.mjs","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n// tailwind-merge would treat `oca-display-1` and `text-foreground` as the same\n// group and drop one; teach it the package's own type utilities.\nconst merge = extendTailwindMerge<'oca-type'>({\n extend: {\n classGroups: {\n 'oca-type': [\n 'oca-display-1',\n 'oca-display-2',\n 'oca-display-3',\n 'oca-title',\n 'oca-title-sm',\n 'oca-eyebrow',\n 'oca-lead',\n 'oca-body',\n 'oca-numeral',\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]): string {\n return merge(clsx(inputs));\n}\n","import type { SVGProps } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/*\n * The isometric check, measured from Sou's deck (slide 9) onto a 16×8 grid:\n * a chevron with a 3-unit short arm and a 5-unit long arm, one unit thick,\n * extruded two units. Three faces, three oranges.\n */\n\nconst TOP = '0,3 2,2 6,4 14,0 16,1 6,6';\nconst LEFT = '0,3 6,6 6,8 0,5';\nconst RIGHT = '6,6 16,1 16,3 6,8';\n\nexport const MARK_FACES = { top: '#FED8AB', left: '#FB933C', right: '#EA580B' } as const;\n\nexport interface MarkProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n /** Accessible name. Omit to render the mark as decoration. */\n title?: string;\n /** Rendered width in px; height follows the 2:1 grid. */\n size?: number;\n}\n\nexport function Mark({ title, size, className, ...rest }: MarkProps) {\n return (\n <svg\n viewBox=\"0 0 16 8\"\n width={size}\n height={size ? size / 2 : undefined}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </svg>\n );\n}\n\nexport interface AppIconProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {\n title?: string;\n size?: number;\n}\n\n/** The app icon: the mark on an ink squircle, as in the deck's lockup. */\nexport function AppIcon({ title, size = 32, className, ...rest }: AppIconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n width={size}\n height={size}\n role={title ? 'img' : undefined}\n aria-hidden={title ? undefined : true}\n className={cn('shrink-0', className)}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n <rect\n width=\"24\"\n height=\"24\"\n rx=\"6.25\"\n style={{ fill: 'var(--oca-icon-tile, #0A0A0A)', stroke: 'var(--oca-icon-ring, transparent)' }}\n strokeWidth=\"0.5\"\n />\n <g transform=\"translate(4.25 8.1) scale(0.97)\">\n <polygon points={LEFT} fill={MARK_FACES.left} />\n <polygon points={RIGHT} fill={MARK_FACES.right} />\n <polygon points={TOP} fill={MARK_FACES.top} />\n </g>\n </svg>\n );\n}\n\nexport interface LockupProps {\n /** The word beside the icon. */\n name?: string;\n /** Icon size in px; the word scales with it. */\n size?: number;\n className?: string;\n}\n\n/** Icon and wordmark, lowercase, as the deck sets it. */\nexport function Lockup({ name = 'orangecheck', size = 28, className }: LockupProps) {\n return (\n <span\n className={cn('inline-flex items-center font-medium tracking-[-0.01em]', className)}\n style={{ gap: size * 0.32, fontSize: size * 0.56 }}\n >\n <AppIcon size={size} />\n <span>{name}</span>\n </span>\n );\n}\n","import * as DialogPrimitive from '@radix-ui/react-dialog';\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip';\nimport { X } from 'lucide-react';\nimport { forwardRef, type ComponentPropsWithoutRef, type ElementRef, type HTMLAttributes } from 'react';\n\nimport { cn } from '../lib/cn';\n\n/* ── Dialog ───────────────────────────────────────────────────────────── */\n\nexport const Dialog = DialogPrimitive.Root;\nexport const DialogTrigger = DialogPrimitive.Trigger;\nexport const DialogClose = DialogPrimitive.Close;\n\nconst overlayClass =\n 'oca-animate-fade fixed inset-0 z-50 bg-[rgb(10_10_10/0.38)] backdrop-blur-[2px] data-[state=closed]:opacity-0';\n\nexport const DialogContent = forwardRef<\n ElementRef<typeof DialogPrimitive.Content>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & { hideClose?: boolean }\n>(function DialogContent({ className, children, hideClose, ...props }, ref) {\n return (\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay className={overlayClass} />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n 'oca-animate-rise fixed left-1/2 top-1/2 z-50 w-[min(92vw,34rem)] -translate-x-1/2 -translate-y-1/2',\n 'max-h-[88vh] overflow-y-auto rounded-[1.5rem] border border-border bg-popover p-6 text-popover-foreground shadow-xl md:p-8',\n 'outline-none',\n className\n )}\n {...props}\n >\n {children}\n {hideClose ? null : (\n <DialogPrimitive.Close\n className=\"absolute right-4 top-4 inline-flex size-9 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n aria-label=\"Close\"\n >\n <X className=\"size-4\" />\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n});\n\nexport function DialogHeader({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('mb-5 flex flex-col gap-2 pr-8', className)} {...props} />;\n}\n\nexport function DialogFooter({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('mt-7 flex flex-col-reverse gap-3 sm:flex-row sm:justify-end', className)} {...props} />;\n}\n\nexport const DialogTitle = forwardRef<\n ElementRef<typeof DialogPrimitive.Title>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(function DialogTitle({ className, ...props }, ref) {\n return (\n <DialogPrimitive.Title\n ref={ref}\n className={cn('text-[1.5rem] font-normal leading-tight tracking-[-0.02em]', className)}\n {...props}\n />\n );\n});\n\nexport const DialogDescription = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(function DialogDescription({ className, ...props }, ref) {\n return <DialogPrimitive.Description ref={ref} className={cn('oca-body', className)} {...props} />;\n});\n\n/* ── Sheet: a dialog from an edge ────────────────────────────────────── */\n\nexport const Sheet = DialogPrimitive.Root;\nexport const SheetTrigger = DialogPrimitive.Trigger;\nexport const SheetClose = DialogPrimitive.Close;\nexport const SheetTitle = DialogTitle;\nexport const SheetDescription = DialogDescription;\n\nconst sheetSide = {\n right: 'inset-y-0 right-0 h-full w-[min(88vw,24rem)] border-l',\n left: 'inset-y-0 left-0 h-full w-[min(88vw,24rem)] border-r',\n bottom: 'inset-x-0 bottom-0 max-h-[88vh] rounded-t-[1.5rem] border-t',\n} as const;\n\nexport const SheetContent = forwardRef<\n ElementRef<typeof DialogPrimitive.Content>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & { side?: keyof typeof sheetSide }\n>(function SheetContent({ className, children, side = 'right', ...props }, ref) {\n return (\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay className={overlayClass} />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n 'oca-animate-fade fixed z-50 flex flex-col gap-4 overflow-y-auto border-border bg-popover p-6 text-popover-foreground shadow-xl outline-none',\n sheetSide[side],\n className\n )}\n {...props}\n >\n {children}\n <DialogPrimitive.Close\n className=\"absolute right-4 top-4 inline-flex size-9 items-center justify-center rounded-full text-muted-foreground hover:bg-accent hover:text-foreground\"\n aria-label=\"Close\"\n >\n <X className=\"size-4\" />\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n});\n\n/* ── Popover ──────────────────────────────────────────────────────────── */\n\nexport const Popover = PopoverPrimitive.Root;\nexport const PopoverTrigger = PopoverPrimitive.Trigger;\nexport const PopoverAnchor = PopoverPrimitive.Anchor;\n\nexport const PopoverContent = forwardRef<\n ElementRef<typeof PopoverPrimitive.Content>,\n ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(function PopoverContent({ className, align = 'center', sideOffset = 8, ...props }, ref) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n className={cn(\n 'oca-animate-fade z-50 w-72 rounded-2xl border border-border bg-popover p-4 text-popover-foreground shadow-lg outline-none',\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n );\n});\n\n/* ── Tooltip: ink, small, quick ───────────────────────────────────────── */\n\nexport const TooltipProvider = TooltipPrimitive.Provider;\nexport const Tooltip = TooltipPrimitive.Root;\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\nexport const TooltipContent = forwardRef<\n ElementRef<typeof TooltipPrimitive.Content>,\n ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(function TooltipContent({ className, sideOffset = 6, ...props }, ref) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'oca-animate-fade z-50 max-w-xs rounded-lg bg-oca-ink px-2.5 py-1.5 text-[0.8125rem] leading-snug text-oca-ink-foreground',\n className\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n );\n});\n\n/* ── Menu ─────────────────────────────────────────────────────────────── */\n\nexport const DropdownMenu = DropdownMenuPrimitive.Root;\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\nexport const DropdownMenuContent = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Content>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(function DropdownMenuContent({ className, sideOffset = 8, ...props }, ref) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'oca-animate-fade z-50 min-w-56 overflow-hidden rounded-2xl border border-border bg-popover p-1.5 text-popover-foreground shadow-lg',\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n});\n\nexport const DropdownMenuItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Item>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { destructive?: boolean }\n>(function DropdownMenuItem({ className, destructive, ...props }, ref) {\n return (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n 'flex h-10 cursor-default select-none items-center gap-2.5 rounded-xl px-3 text-[0.9375rem] outline-none',\n 'data-[highlighted]:bg-accent data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:text-muted-foreground',\n destructive && 'text-destructive [&_svg]:text-destructive',\n className\n )}\n {...props}\n />\n );\n});\n\nexport const DropdownMenuLabel = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Label>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label>\n>(function DropdownMenuLabel({ className, ...props }, ref) {\n return (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn('px-3 pb-1.5 pt-2 text-[0.8125rem] text-muted-foreground', className)}\n {...props}\n />\n );\n});\n\nexport const DropdownMenuSeparator = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Separator>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(function DropdownMenuSeparator({ className, ...props }, ref) {\n return <DropdownMenuPrimitive.Separator ref={ref} className={cn('my-1.5 h-px bg-border', className)} {...props} />;\n});\n","import { Menu } from 'lucide-react';\nimport Link from 'next/link';\nimport { useState, type ReactNode } from 'react';\n\nimport { Lockup } from '../brand/mark';\nimport { cn } from '../lib/cn';\nimport { Sheet, SheetContent, SheetTitle, SheetTrigger } from '../primitives/overlay';\n\nexport interface NavItem {\n href: string;\n label: ReactNode;\n /** Marks the current section for styling and aria-current. */\n active?: boolean;\n external?: boolean;\n}\n\nfunction NavLink({ item, className, onNavigate }: { item: NavItem; className?: string; onNavigate?: () => void }) {\n const cls = cn(\n 'rounded-full px-3 py-2 text-[0.9375rem] transition-colors',\n item.active ? 'text-foreground' : 'text-muted-foreground hover:text-foreground',\n className\n );\n if (item.external) {\n return (\n <a href={item.href} className={cls} rel=\"noreferrer\" onClick={onNavigate}>\n {item.label}\n </a>\n );\n }\n return (\n <Link href={item.href} className={cls} aria-current={item.active ? 'page' : undefined} onClick={onNavigate}>\n {item.label}\n </Link>\n );\n}\n\n/**\n * The public header: lockup, a few words of navigation, actions on the right.\n * Below md the navigation moves into a sheet; the actions stay.\n */\nexport function SiteHeader({\n home = '/',\n brand,\n nav = [],\n actions,\n className,\n}: {\n home?: string;\n brand?: ReactNode;\n nav?: NavItem[];\n actions?: ReactNode;\n className?: string;\n}) {\n const [open, setOpen] = useState(false);\n return (\n <header\n className={cn(\n 'sticky top-0 z-40 w-full border-b border-transparent bg-background/85 backdrop-blur-md supports-[backdrop-filter]:bg-background/70',\n className\n )}\n >\n <div className=\"oca-container flex h-16 items-center justify-between gap-4 md:h-[4.5rem]\">\n <Link href={home} className=\"-ml-1 rounded-lg p-1\" aria-label=\"Home\">\n {brand ?? <Lockup size={28} />}\n </Link>\n {nav.length > 0 ? (\n <nav aria-label=\"Main\" className=\"hidden items-center gap-1 md:flex\">\n {nav.map((n) => (\n <NavLink key={n.href} item={n} />\n ))}\n </nav>\n ) : null}\n <div className=\"flex items-center gap-2\">\n {actions}\n {nav.length > 0 ? (\n <Sheet open={open} onOpenChange={setOpen}>\n <SheetTrigger\n className=\"inline-flex size-10 items-center justify-center rounded-full text-foreground hover:bg-accent md:hidden\"\n aria-label=\"Open menu\"\n >\n <Menu className=\"size-5\" />\n </SheetTrigger>\n <SheetContent side=\"right\" className=\"pt-16\">\n <SheetTitle className=\"sr-only\">Menu</SheetTitle>\n <nav aria-label=\"Main\" className=\"flex flex-col\">\n {nav.map((n) => (\n <NavLink\n key={n.href}\n item={n}\n className=\"rounded-xl px-3 py-3 text-[1.0625rem]\"\n onNavigate={() => setOpen(false)}\n />\n ))}\n </nav>\n </SheetContent>\n </Sheet>\n ) : null}\n </div>\n </div>\n </header>\n );\n}\n\nexport interface FooterColumn {\n heading: string;\n links: NavItem[];\n}\n\n/**\n * The footer, in the deck's register: a line of fine print, the support credit,\n * and a few columns of links. Links are 44px tall on phones.\n */\nexport function SiteFooter({\n columns = [],\n fineprint,\n meta,\n className,\n}: {\n columns?: FooterColumn[];\n fineprint?: ReactNode;\n meta?: ReactNode;\n className?: string;\n}) {\n return (\n <footer className={cn('border-t border-border bg-background', className)}>\n <div className=\"oca-container grid gap-10 py-14 md:grid-cols-[1.3fr_repeat(3,1fr)] md:py-16\">\n <div className=\"flex flex-col gap-4\">\n <Lockup size={26} />\n {fineprint ? <p className=\"max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground\">{fineprint}</p> : null}\n </div>\n {columns.map((col) => (\n <div key={col.heading} className=\"flex flex-col gap-1\">\n <p className=\"mb-2 text-[0.875rem] font-medium\">{col.heading}</p>\n {col.links.map((l) => (\n <NavLink\n key={l.href}\n item={l}\n className=\"-mx-3 py-2.5 text-[0.9375rem] md:py-1.5\"\n />\n ))}\n </div>\n ))}\n </div>\n {meta ? (\n <div className=\"oca-container border-t border-border py-6 text-[0.875rem] text-muted-foreground\">{meta}</div>\n ) : null}\n </footer>\n );\n}\n","import { Menu, Moon, Sun, SunMoon } from 'lucide-react';\nimport Link from 'next/link';\nimport { useTheme } from 'next-themes';\nimport { useEffect, useState, type ReactNode } from 'react';\n\nimport { AppIcon, Lockup } from '../brand/mark';\nimport { cn } from '../lib/cn';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Sheet,\n SheetContent,\n SheetTitle,\n SheetTrigger,\n} from '../primitives/overlay';\n\nexport interface ShellNavItem {\n href: string;\n label: string;\n icon?: ReactNode;\n active?: boolean;\n /** A count or a dot beside the label (unread, needs attention). */\n badge?: ReactNode;\n}\n\nexport interface ShellNavGroup {\n /** Omit for the first, unlabeled group. */\n label?: string;\n items: ShellNavItem[];\n}\n\nfunction SideNav({ groups, onNavigate }: { groups: ShellNavGroup[]; onNavigate?: () => void }) {\n return (\n <nav aria-label=\"Sections\" className=\"flex flex-col gap-6\">\n {groups.map((g, gi) => (\n <div key={g.label ?? gi} className=\"flex flex-col gap-0.5\">\n {g.label ? <p className=\"px-3 pb-1.5 text-[0.8125rem] text-muted-foreground\">{g.label}</p> : null}\n {g.items.map((it) => (\n <Link\n key={it.href}\n href={it.href}\n onClick={onNavigate}\n aria-current={it.active ? 'page' : undefined}\n className={cn(\n 'flex h-10 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors',\n '[&_svg]:size-[1.125rem] [&_svg]:shrink-0',\n it.active\n ? 'bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground'\n : 'text-muted-foreground hover:bg-accent hover:text-foreground'\n )}\n >\n {it.icon}\n <span className=\"min-w-0 flex-1 truncate\">{it.label}</span>\n {it.badge ? <span className=\"shrink-0\">{it.badge}</span> : null}\n </Link>\n ))}\n </div>\n ))}\n </nav>\n );\n}\n\n/**\n * The signed-in frame: a quiet sidebar on the canvas, content on the right. On\n * phones the sidebar becomes a sheet behind a top bar. The account control and\n * any banner are slots, so the shell knows nothing about sessions.\n */\nexport function AppShell({\n nav,\n home = '/',\n account,\n banner,\n footer,\n children,\n className,\n}: {\n nav: ShellNavGroup[];\n home?: string;\n account?: ReactNode;\n banner?: ReactNode;\n footer?: ReactNode;\n children: ReactNode;\n className?: string;\n}) {\n const [open, setOpen] = useState(false);\n return (\n <div className={cn('min-h-dvh bg-background', className)}>\n <div className=\"sticky top-0 z-40 flex h-14 items-center justify-between border-b border-border bg-background/85 px-4 backdrop-blur-md lg:hidden\">\n <Sheet open={open} onOpenChange={setOpen}>\n <SheetTrigger\n className=\"inline-flex size-10 items-center justify-center rounded-full hover:bg-accent\"\n aria-label=\"Open navigation\"\n >\n <Menu className=\"size-5\" />\n </SheetTrigger>\n <SheetContent side=\"left\" className=\"p-4 pt-16\">\n <SheetTitle className=\"sr-only\">Navigation</SheetTitle>\n <SideNav groups={nav} onNavigate={() => setOpen(false)} />\n </SheetContent>\n </Sheet>\n <Link href={home} aria-label=\"Home\">\n <AppIcon size={28} />\n </Link>\n <div className=\"flex items-center\">{account}</div>\n </div>\n <div className=\"mx-auto flex w-full max-w-[90rem]\">\n <aside className=\"sticky top-0 hidden h-dvh w-64 shrink-0 flex-col gap-8 overflow-y-auto px-4 py-6 lg:flex\">\n <Link href={home} className=\"px-2\" aria-label=\"Home\">\n <Lockup size={26} />\n </Link>\n <SideNav groups={nav} />\n <div className=\"mt-auto flex flex-col gap-3\">{footer}</div>\n </aside>\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex\">{account}</div>\n {banner ? <div className=\"px-4 pb-2 pt-4 md:px-8 lg:pt-0\">{banner}</div> : null}\n <main id=\"main-content\" className=\"flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2\">\n {children}\n </main>\n </div>\n </div>\n </div>\n );\n}\n\nexport interface AccountMenuItem {\n label: string;\n href?: string;\n onSelect?: () => void;\n icon?: ReactNode;\n destructive?: boolean;\n}\n\n/** The account button: initial + short id, a menu of items. */\nexport function AccountMenu({\n name,\n detail,\n items,\n}: {\n name: string;\n /** A second line: the short did, an address. */\n detail?: string;\n items: (AccountMenuItem | 'separator')[];\n}) {\n const initial = name.trim().charAt(0).toUpperCase() || '·';\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n className=\"inline-flex h-10 items-center gap-2.5 rounded-full border border-border bg-card pl-1 pr-3.5 text-[0.9375rem] outline-none transition-colors hover:border-oca-hairline-strong focus-visible:ring-2 focus-visible:ring-ring\"\n aria-label={`Account: ${name}`}\n >\n <span className=\"flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background\">\n {initial}\n </span>\n <span className=\"max-w-[10rem] truncate\">{name}</span>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-64\">\n <DropdownMenuLabel className=\"flex flex-col gap-0.5\">\n <span className=\"truncate text-[0.9375rem] font-medium text-foreground\">{name}</span>\n {detail ? <span className=\"truncate font-mono text-[0.75rem]\">{detail}</span> : null}\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n {items.map((it, i) =>\n it === 'separator' ? (\n <DropdownMenuSeparator key={`sep-${i}`} />\n ) : it.href ? (\n <DropdownMenuItem key={it.label} asChild destructive={it.destructive}>\n <Link href={it.href}>\n {it.icon}\n {it.label}\n </Link>\n </DropdownMenuItem>\n ) : (\n <DropdownMenuItem key={it.label} onSelect={it.onSelect} destructive={it.destructive}>\n {it.icon}\n {it.label}\n </DropdownMenuItem>\n )\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\n/** Light, dark, or follow the system: one button that cycles. */\nexport function ThemeToggle({ className }: { className?: string }) {\n const { theme, setTheme } = useTheme();\n const [mounted, setMounted] = useState(false);\n useEffect(() => setMounted(true), []);\n const current = mounted ? (theme ?? 'system') : 'system';\n const next = current === 'light' ? 'dark' : current === 'dark' ? 'system' : 'light';\n const Icon = current === 'light' ? Sun : current === 'dark' ? Moon : SunMoon;\n return (\n <button\n type=\"button\"\n onClick={() => setTheme(next)}\n aria-label={`Theme: ${current}. Switch to ${next}`}\n title={`Theme: ${current}`}\n className={cn(\n 'inline-flex size-10 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground',\n className\n )}\n >\n <Icon className=\"size-[1.125rem]\" />\n </button>\n );\n}\n"]}
|