@medialane/ui 0.5.2 → 0.5.4
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/dist/components/nav-command-menu.cjs +48 -41
- package/dist/components/nav-command-menu.cjs.map +1 -1
- package/dist/components/nav-command-menu.d.cts +13 -2
- package/dist/components/nav-command-menu.d.ts +13 -2
- package/dist/components/nav-command-menu.js +48 -41
- package/dist/components/nav-command-menu.js.map +1 -1
- package/dist/components/page-container.cjs +4 -1
- package/dist/components/page-container.cjs.map +1 -1
- package/dist/components/page-container.js +4 -1
- package/dist/components/page-container.js.map +1 -1
- package/package.json +1 -1
|
@@ -48,7 +48,7 @@ function useNavCommandMenu() {
|
|
|
48
48
|
close: () => document.dispatchEvent(new CustomEvent(ML_NAV_CLOSE))
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
function NavCommandMenu({ commands, trigger, accountSlot }) {
|
|
51
|
+
function NavCommandMenu({ commands, trigger, accountSlot, footerSlot }) {
|
|
52
52
|
const [open, setOpen] = React.useState(false);
|
|
53
53
|
const router = (0, import_navigation.useRouter)();
|
|
54
54
|
const inputRef = React.useRef(null);
|
|
@@ -153,14 +153,14 @@ function NavCommandMenu({ commands, trigger, accountSlot }) {
|
|
|
153
153
|
className: "w-full max-w-lg bg-background/90 border border-border/40 rounded-2xl overflow-hidden shadow-2xl",
|
|
154
154
|
onClick: (e) => e.stopPropagation(),
|
|
155
155
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_cmdk.Command, { shouldFilter: true, label: "Medialane navigation", children: [
|
|
156
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-border/40", children: [
|
|
157
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Search, { className: "h-
|
|
156
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3 px-4 py-3.5 border-b border-border/40", children: [
|
|
157
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Search, { className: "h-[18px] w-[18px] text-muted-foreground shrink-0" }),
|
|
158
158
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
159
159
|
import_cmdk.Command.Input,
|
|
160
160
|
{
|
|
161
161
|
ref: inputRef,
|
|
162
162
|
placeholder: "Type a command or search\u2026",
|
|
163
|
-
className: "flex-1 bg-transparent text-
|
|
163
|
+
className: "flex-1 bg-transparent text-[15px] outline-none placeholder:text-muted-foreground"
|
|
164
164
|
}
|
|
165
165
|
),
|
|
166
166
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -175,45 +175,52 @@ function NavCommandMenu({ commands, trigger, accountSlot }) {
|
|
|
175
175
|
] }),
|
|
176
176
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_cmdk.Command.List, { className: "max-h-[60vh] overflow-y-auto p-2", children: [
|
|
177
177
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_cmdk.Command.Empty, { className: "py-8 text-center text-sm text-muted-foreground", children: "No results found." }),
|
|
178
|
-
commands.map((group, i) =>
|
|
179
|
-
|
|
180
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
181
|
-
import_cmdk.Command.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
178
|
+
commands.map((group, i) => {
|
|
179
|
+
const primary = !group.heading;
|
|
180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(React.Fragment, { children: [
|
|
181
|
+
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_cmdk.Command.Separator, { className: "my-1.5 h-px bg-border/40" }),
|
|
182
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
183
|
+
import_cmdk.Command.Group,
|
|
184
|
+
{
|
|
185
|
+
heading: group.heading,
|
|
186
|
+
className: (0, import_cn.cn)(
|
|
187
|
+
"[&_[cmdk-group-heading]]:px-2",
|
|
188
|
+
"[&_[cmdk-group-heading]]:pt-1.5",
|
|
189
|
+
"[&_[cmdk-group-heading]]:pb-1",
|
|
190
|
+
"[&_[cmdk-group-heading]]:text-[11px]",
|
|
191
|
+
"[&_[cmdk-group-heading]]:font-semibold",
|
|
192
|
+
"[&_[cmdk-group-heading]]:uppercase",
|
|
193
|
+
"[&_[cmdk-group-heading]]:tracking-wider",
|
|
194
|
+
"[&_[cmdk-group-heading]]:text-muted-foreground/70"
|
|
195
|
+
),
|
|
196
|
+
children: group.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
197
|
+
import_cmdk.Command.Item,
|
|
198
|
+
{
|
|
199
|
+
value: [item.label, ...item.keywords ?? []].join(" "),
|
|
200
|
+
onSelect: () => runCommand(item),
|
|
201
|
+
className: (0, import_cn.cn)(
|
|
202
|
+
"group/item flex items-center gap-3 rounded-xl cursor-pointer",
|
|
203
|
+
"transition-colors duration-150",
|
|
204
|
+
"aria-selected:bg-primary/10",
|
|
205
|
+
primary ? "px-2.5 py-2.5 text-[15px] font-medium" : "px-3 py-2 text-sm"
|
|
206
|
+
),
|
|
207
|
+
children: [
|
|
208
|
+
primary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-muted/50 group-aria-selected/item:bg-primary/15 transition-colors shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(item.icon, { className: "h-[18px] w-[18px] text-foreground/80 group-aria-selected/item:text-primary transition-colors" }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(item.icon, { className: "h-4 w-4 text-muted-foreground group-aria-selected/item:text-foreground transition-colors shrink-0" }),
|
|
209
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex-1 truncate", children: item.label }),
|
|
210
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "h-3.5 w-3.5 text-muted-foreground/30 group-aria-selected/item:text-primary/70 transition-colors shrink-0" })
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
item.id
|
|
214
|
+
))
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
] }, group.heading ?? `__primary-${i}`);
|
|
218
|
+
})
|
|
212
219
|
] }),
|
|
213
220
|
accountSlot && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border-t border-border/40 bg-background/40 px-3 py-3", children: accountSlot }),
|
|
214
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-
|
|
215
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[10px] text-muted-foreground/50", children: "medialane" }),
|
|
216
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("kbd", { className: "text-[10px] text-muted-foreground/50 font-mono", children: "\u2318K" })
|
|
221
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-3 py-2 border-t border-border/40 flex items-center justify-between gap-3", children: [
|
|
222
|
+
footerSlot ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[10px] text-muted-foreground/50 pl-1", children: "medialane" }),
|
|
223
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("kbd", { className: "text-[10px] text-muted-foreground/50 font-mono shrink-0", children: "\u2318K" })
|
|
217
224
|
] })
|
|
218
225
|
] })
|
|
219
226
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/nav-command-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Command } from \"cmdk\";\nimport { useRouter } from \"next/navigation\";\nimport { Search, X, ArrowRight } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { cn } from \"../utils/cn.js\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface NavCommand {\n id: string;\n label: string;\n icon: React.ComponentType<{ className?: string }>;\n href?: string;\n action?: () => void;\n /** Extra search terms beyond the label */\n keywords?: string[];\n}\n\nexport interface NavCommandGroup {\n heading: string;\n items: NavCommand[];\n}\n\nexport interface NavCommandMenuProps {\n commands: NavCommandGroup[];\n /**\n * Optional trigger element rendered inline at the component's mount point.\n * For most apps, omit this and call `useNavCommandMenu().open()` from a\n * separate button — that keeps the trigger in the right place in the layout.\n */\n trigger?: React.ReactNode;\n /**\n * Optional pinned account/connect area rendered below command results.\n * Apps own the auth implementation here (Clerk, ChipiPay, wallet connectors,\n * Privy, Cartridge, etc.) so the shared nav stays framework-agnostic.\n */\n accountSlot?: React.ReactNode;\n}\n\n// ── Singleton hook ─────────────────────────────────────────────────────────────\n\nconst ML_NAV_OPEN = \"ml:nav-open\";\nconst ML_NAV_CLOSE = \"ml:nav-close\";\n\nexport function useNavCommandMenu() {\n return {\n open: () => document.dispatchEvent(new CustomEvent(ML_NAV_OPEN)),\n close: () => document.dispatchEvent(new CustomEvent(ML_NAV_CLOSE)),\n };\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport function NavCommandMenu({ commands, trigger, accountSlot }: NavCommandMenuProps) {\n const [open, setOpen] = React.useState(false);\n const router = useRouter();\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const t = setTimeout(() => inputRef.current?.focus(), 60);\n return () => clearTimeout(t);\n }, [open]);\n\n React.useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"k\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n setOpen((prev) => !prev);\n }\n if (e.key === \"Escape\") setOpen(false);\n };\n const onOpen = () => setOpen(true);\n const onClose = () => setOpen(false);\n\n document.addEventListener(\"keydown\", onKey);\n document.addEventListener(ML_NAV_OPEN, onOpen);\n document.addEventListener(ML_NAV_CLOSE, onClose);\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n document.removeEventListener(ML_NAV_OPEN, onOpen);\n document.removeEventListener(ML_NAV_CLOSE, onClose);\n };\n }, []);\n\n const runCommand = React.useCallback(\n (cmd: NavCommand) => {\n setOpen(false);\n if (cmd.href) router.push(cmd.href);\n else cmd.action?.();\n },\n [router]\n );\n\n return (\n <>\n {trigger}\n\n <AnimatePresence>\n {open && (\n <>\n {/* Aurora blobs — vivid intensity */}\n <motion.div\n className=\"nav-canvas-aurora\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n <div className=\"aurora-purple animate-blob w-[60vw] h-[60vw] -top-[10vw] -left-[10vw]\"\n style={{ opacity: 0.25 }} />\n <div className=\"aurora-blue animate-blob-slow w-[50vw] h-[50vw] -top-[5vw] -right-[10vw]\"\n style={{ opacity: 0.2 }} />\n <div className=\"aurora-rose animate-blob w-[45vw] h-[45vw] bottom-[5vw] -left-[5vw]\"\n style={{ opacity: 0.15 }} />\n <div className=\"aurora-orange animate-blob-slow w-[40vw] h-[40vw] -bottom-[5vw] -right-[5vw]\"\n style={{ opacity: 0.15 }} />\n </motion.div>\n\n {/* Backdrop blur */}\n <motion.div\n className=\"nav-canvas-overlay\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n onClick={() => setOpen(false)}\n />\n\n {/* Command panel */}\n <motion.div\n className=\"fixed inset-0 z-[101] flex items-center justify-center p-4\"\n initial={{ opacity: 0, scale: 0.97 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.97 }}\n transition={{ duration: 0.15, ease: \"easeOut\" }}\n onClick={() => setOpen(false)}\n >\n <div\n className=\"w-full max-w-lg bg-background/90 border border-border/40 rounded-2xl overflow-hidden shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <Command shouldFilter label=\"Medialane navigation\">\n {/* Search bar */}\n <div className=\"flex items-center gap-3 px-4 py-3 border-b border-border/40\">\n <Search className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <Command.Input\n ref={inputRef}\n placeholder=\"Type a command or search…\"\n className=\"flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground\"\n />\n <button\n onClick={() => setOpen(false)}\n className=\"p-1 rounded-md hover:bg-muted/50 transition-colors\"\n aria-label=\"Close\"\n >\n <X className=\"h-4 w-4 text-muted-foreground\" />\n </button>\n </div>\n\n {/* Results */}\n <Command.List className=\"max-h-[60vh] overflow-y-auto p-2\">\n <Command.Empty className=\"py-8 text-center text-sm text-muted-foreground\">\n No results found.\n </Command.Empty>\n\n {commands.map((group, i) => (\n <React.Fragment key={group.heading}>\n {i > 0 && (\n <Command.Separator className=\"my-1 h-px bg-border/40\" />\n )}\n <Command.Group\n heading={group.heading}\n className={cn(\n \"[&_[cmdk-group-heading]]:px-2\",\n \"[&_[cmdk-group-heading]]:py-1.5\",\n \"[&_[cmdk-group-heading]]:text-xs\",\n \"[&_[cmdk-group-heading]]:font-medium\",\n \"[&_[cmdk-group-heading]]:text-muted-foreground\"\n )}\n >\n {group.items.map((item) => (\n <Command.Item\n key={item.id}\n value={[item.label, ...(item.keywords ?? [])].join(\" \")}\n onSelect={() => runCommand(item)}\n className={cn(\n \"flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm cursor-pointer\",\n \"transition-colors\",\n \"aria-selected:bg-muted/60\"\n )}\n >\n <item.icon className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"flex-1\">{item.label}</span>\n <ArrowRight className=\"h-3.5 w-3.5 text-muted-foreground/40 shrink-0\" />\n </Command.Item>\n ))}\n </Command.Group>\n </React.Fragment>\n ))}\n </Command.List>\n\n {accountSlot && (\n <div className=\"border-t border-border/40 bg-background/40 px-3 py-3\">\n {accountSlot}\n </div>\n )}\n\n {/* Footer */}\n <div className=\"px-4 py-2.5 border-t border-border/40 flex items-center justify-between\">\n <span className=\"text-[10px] text-muted-foreground/50\">medialane</span>\n <kbd className=\"text-[10px] text-muted-foreground/50 font-mono\">⌘K</kbd>\n </div>\n </Command>\n </div>\n </motion.div>\n </>\n )}\n </AnimatePresence>\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/nav-command-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Command } from \"cmdk\";\nimport { useRouter } from \"next/navigation\";\nimport { Search, X, ArrowRight } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { cn } from \"../utils/cn.js\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface NavCommand {\n id: string;\n label: string;\n icon: React.ComponentType<{ className?: string }>;\n href?: string;\n action?: () => void;\n /** Extra search terms beyond the label */\n keywords?: string[];\n}\n\nexport interface NavCommandGroup {\n /**\n * Optional group heading. Omit it for the primary group so its items\n * read as the top-level menu — they render first, emphasized, with no\n * label, separated from the headed groups below.\n */\n heading?: string;\n items: NavCommand[];\n}\n\nexport interface NavCommandMenuProps {\n commands: NavCommandGroup[];\n /**\n * Optional trigger element rendered inline at the component's mount point.\n * For most apps, omit this and call `useNavCommandMenu().open()` from a\n * separate button — that keeps the trigger in the right place in the layout.\n */\n trigger?: React.ReactNode;\n /**\n * Optional pinned account/connect area rendered below command results.\n * Apps own the auth implementation here (Clerk, ChipiPay, wallet connectors,\n * Privy, Cartridge, etc.) so the shared nav stays framework-agnostic.\n */\n accountSlot?: React.ReactNode;\n /**\n * Optional control rendered in the footer row (e.g. a theme toggle).\n * Apps own theme state (next-themes etc.) so the shared nav stays\n * framework-agnostic — same pattern as `accountSlot`.\n */\n footerSlot?: React.ReactNode;\n}\n\n// ── Singleton hook ─────────────────────────────────────────────────────────────\n\nconst ML_NAV_OPEN = \"ml:nav-open\";\nconst ML_NAV_CLOSE = \"ml:nav-close\";\n\nexport function useNavCommandMenu() {\n return {\n open: () => document.dispatchEvent(new CustomEvent(ML_NAV_OPEN)),\n close: () => document.dispatchEvent(new CustomEvent(ML_NAV_CLOSE)),\n };\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport function NavCommandMenu({ commands, trigger, accountSlot, footerSlot }: NavCommandMenuProps) {\n const [open, setOpen] = React.useState(false);\n const router = useRouter();\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const t = setTimeout(() => inputRef.current?.focus(), 60);\n return () => clearTimeout(t);\n }, [open]);\n\n React.useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"k\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n setOpen((prev) => !prev);\n }\n if (e.key === \"Escape\") setOpen(false);\n };\n const onOpen = () => setOpen(true);\n const onClose = () => setOpen(false);\n\n document.addEventListener(\"keydown\", onKey);\n document.addEventListener(ML_NAV_OPEN, onOpen);\n document.addEventListener(ML_NAV_CLOSE, onClose);\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n document.removeEventListener(ML_NAV_OPEN, onOpen);\n document.removeEventListener(ML_NAV_CLOSE, onClose);\n };\n }, []);\n\n const runCommand = React.useCallback(\n (cmd: NavCommand) => {\n setOpen(false);\n if (cmd.href) router.push(cmd.href);\n else cmd.action?.();\n },\n [router]\n );\n\n return (\n <>\n {trigger}\n\n <AnimatePresence>\n {open && (\n <>\n {/* Aurora blobs — vivid intensity */}\n <motion.div\n className=\"nav-canvas-aurora\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n <div className=\"aurora-purple animate-blob w-[60vw] h-[60vw] -top-[10vw] -left-[10vw]\"\n style={{ opacity: 0.25 }} />\n <div className=\"aurora-blue animate-blob-slow w-[50vw] h-[50vw] -top-[5vw] -right-[10vw]\"\n style={{ opacity: 0.2 }} />\n <div className=\"aurora-rose animate-blob w-[45vw] h-[45vw] bottom-[5vw] -left-[5vw]\"\n style={{ opacity: 0.15 }} />\n <div className=\"aurora-orange animate-blob-slow w-[40vw] h-[40vw] -bottom-[5vw] -right-[5vw]\"\n style={{ opacity: 0.15 }} />\n </motion.div>\n\n {/* Backdrop blur */}\n <motion.div\n className=\"nav-canvas-overlay\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n onClick={() => setOpen(false)}\n />\n\n {/* Command panel */}\n <motion.div\n className=\"fixed inset-0 z-[101] flex items-center justify-center p-4\"\n initial={{ opacity: 0, scale: 0.97 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.97 }}\n transition={{ duration: 0.15, ease: \"easeOut\" }}\n onClick={() => setOpen(false)}\n >\n <div\n className=\"w-full max-w-lg bg-background/90 border border-border/40 rounded-2xl overflow-hidden shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <Command shouldFilter label=\"Medialane navigation\">\n {/* Search bar */}\n <div className=\"flex items-center gap-3 px-4 py-3.5 border-b border-border/40\">\n <Search className=\"h-[18px] w-[18px] text-muted-foreground shrink-0\" />\n <Command.Input\n ref={inputRef}\n placeholder=\"Type a command or search…\"\n className=\"flex-1 bg-transparent text-[15px] outline-none placeholder:text-muted-foreground\"\n />\n <button\n onClick={() => setOpen(false)}\n className=\"p-1 rounded-md hover:bg-muted/50 transition-colors\"\n aria-label=\"Close\"\n >\n <X className=\"h-4 w-4 text-muted-foreground\" />\n </button>\n </div>\n\n {/* Results */}\n <Command.List className=\"max-h-[60vh] overflow-y-auto p-2\">\n <Command.Empty className=\"py-8 text-center text-sm text-muted-foreground\">\n No results found.\n </Command.Empty>\n\n {commands.map((group, i) => {\n const primary = !group.heading;\n return (\n <React.Fragment key={group.heading ?? `__primary-${i}`}>\n {i > 0 && (\n <Command.Separator className=\"my-1.5 h-px bg-border/40\" />\n )}\n <Command.Group\n heading={group.heading}\n className={cn(\n \"[&_[cmdk-group-heading]]:px-2\",\n \"[&_[cmdk-group-heading]]:pt-1.5\",\n \"[&_[cmdk-group-heading]]:pb-1\",\n \"[&_[cmdk-group-heading]]:text-[11px]\",\n \"[&_[cmdk-group-heading]]:font-semibold\",\n \"[&_[cmdk-group-heading]]:uppercase\",\n \"[&_[cmdk-group-heading]]:tracking-wider\",\n \"[&_[cmdk-group-heading]]:text-muted-foreground/70\"\n )}\n >\n {group.items.map((item) => (\n <Command.Item\n key={item.id}\n value={[item.label, ...(item.keywords ?? [])].join(\" \")}\n onSelect={() => runCommand(item)}\n className={cn(\n \"group/item flex items-center gap-3 rounded-xl cursor-pointer\",\n \"transition-colors duration-150\",\n \"aria-selected:bg-primary/10\",\n primary\n ? \"px-2.5 py-2.5 text-[15px] font-medium\"\n : \"px-3 py-2 text-sm\"\n )}\n >\n {primary ? (\n <span className=\"flex h-8 w-8 items-center justify-center rounded-lg bg-muted/50 group-aria-selected/item:bg-primary/15 transition-colors shrink-0\">\n <item.icon className=\"h-[18px] w-[18px] text-foreground/80 group-aria-selected/item:text-primary transition-colors\" />\n </span>\n ) : (\n <item.icon className=\"h-4 w-4 text-muted-foreground group-aria-selected/item:text-foreground transition-colors shrink-0\" />\n )}\n <span className=\"flex-1 truncate\">{item.label}</span>\n <ArrowRight className=\"h-3.5 w-3.5 text-muted-foreground/30 group-aria-selected/item:text-primary/70 transition-colors shrink-0\" />\n </Command.Item>\n ))}\n </Command.Group>\n </React.Fragment>\n );\n })}\n </Command.List>\n\n {accountSlot && (\n <div className=\"border-t border-border/40 bg-background/40 px-3 py-3\">\n {accountSlot}\n </div>\n )}\n\n {/* Footer */}\n <div className=\"px-3 py-2 border-t border-border/40 flex items-center justify-between gap-3\">\n {footerSlot ?? (\n <span className=\"text-[10px] text-muted-foreground/50 pl-1\">medialane</span>\n )}\n <kbd className=\"text-[10px] text-muted-foreground/50 font-mono shrink-0\">⌘K</kbd>\n </div>\n </Command>\n </div>\n </motion.div>\n </>\n )}\n </AnimatePresence>\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -13,7 +13,12 @@ interface NavCommand {
|
|
|
13
13
|
keywords?: string[];
|
|
14
14
|
}
|
|
15
15
|
interface NavCommandGroup {
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Optional group heading. Omit it for the primary group so its items
|
|
18
|
+
* read as the top-level menu — they render first, emphasized, with no
|
|
19
|
+
* label, separated from the headed groups below.
|
|
20
|
+
*/
|
|
21
|
+
heading?: string;
|
|
17
22
|
items: NavCommand[];
|
|
18
23
|
}
|
|
19
24
|
interface NavCommandMenuProps {
|
|
@@ -30,11 +35,17 @@ interface NavCommandMenuProps {
|
|
|
30
35
|
* Privy, Cartridge, etc.) so the shared nav stays framework-agnostic.
|
|
31
36
|
*/
|
|
32
37
|
accountSlot?: React.ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Optional control rendered in the footer row (e.g. a theme toggle).
|
|
40
|
+
* Apps own theme state (next-themes etc.) so the shared nav stays
|
|
41
|
+
* framework-agnostic — same pattern as `accountSlot`.
|
|
42
|
+
*/
|
|
43
|
+
footerSlot?: React.ReactNode;
|
|
33
44
|
}
|
|
34
45
|
declare function useNavCommandMenu(): {
|
|
35
46
|
open: () => boolean;
|
|
36
47
|
close: () => boolean;
|
|
37
48
|
};
|
|
38
|
-
declare function NavCommandMenu({ commands, trigger, accountSlot }: NavCommandMenuProps): react_jsx_runtime.JSX.Element;
|
|
49
|
+
declare function NavCommandMenu({ commands, trigger, accountSlot, footerSlot }: NavCommandMenuProps): react_jsx_runtime.JSX.Element;
|
|
39
50
|
|
|
40
51
|
export { type NavCommand, type NavCommandGroup, NavCommandMenu, type NavCommandMenuProps, useNavCommandMenu };
|
|
@@ -13,7 +13,12 @@ interface NavCommand {
|
|
|
13
13
|
keywords?: string[];
|
|
14
14
|
}
|
|
15
15
|
interface NavCommandGroup {
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Optional group heading. Omit it for the primary group so its items
|
|
18
|
+
* read as the top-level menu — they render first, emphasized, with no
|
|
19
|
+
* label, separated from the headed groups below.
|
|
20
|
+
*/
|
|
21
|
+
heading?: string;
|
|
17
22
|
items: NavCommand[];
|
|
18
23
|
}
|
|
19
24
|
interface NavCommandMenuProps {
|
|
@@ -30,11 +35,17 @@ interface NavCommandMenuProps {
|
|
|
30
35
|
* Privy, Cartridge, etc.) so the shared nav stays framework-agnostic.
|
|
31
36
|
*/
|
|
32
37
|
accountSlot?: React.ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Optional control rendered in the footer row (e.g. a theme toggle).
|
|
40
|
+
* Apps own theme state (next-themes etc.) so the shared nav stays
|
|
41
|
+
* framework-agnostic — same pattern as `accountSlot`.
|
|
42
|
+
*/
|
|
43
|
+
footerSlot?: React.ReactNode;
|
|
33
44
|
}
|
|
34
45
|
declare function useNavCommandMenu(): {
|
|
35
46
|
open: () => boolean;
|
|
36
47
|
close: () => boolean;
|
|
37
48
|
};
|
|
38
|
-
declare function NavCommandMenu({ commands, trigger, accountSlot }: NavCommandMenuProps): react_jsx_runtime.JSX.Element;
|
|
49
|
+
declare function NavCommandMenu({ commands, trigger, accountSlot, footerSlot }: NavCommandMenuProps): react_jsx_runtime.JSX.Element;
|
|
39
50
|
|
|
40
51
|
export { type NavCommand, type NavCommandGroup, NavCommandMenu, type NavCommandMenuProps, useNavCommandMenu };
|
|
@@ -14,7 +14,7 @@ function useNavCommandMenu() {
|
|
|
14
14
|
close: () => document.dispatchEvent(new CustomEvent(ML_NAV_CLOSE))
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
function NavCommandMenu({ commands, trigger, accountSlot }) {
|
|
17
|
+
function NavCommandMenu({ commands, trigger, accountSlot, footerSlot }) {
|
|
18
18
|
const [open, setOpen] = React.useState(false);
|
|
19
19
|
const router = useRouter();
|
|
20
20
|
const inputRef = React.useRef(null);
|
|
@@ -119,14 +119,14 @@ function NavCommandMenu({ commands, trigger, accountSlot }) {
|
|
|
119
119
|
className: "w-full max-w-lg bg-background/90 border border-border/40 rounded-2xl overflow-hidden shadow-2xl",
|
|
120
120
|
onClick: (e) => e.stopPropagation(),
|
|
121
121
|
children: /* @__PURE__ */ jsxs(Command, { shouldFilter: true, label: "Medialane navigation", children: [
|
|
122
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-border/40", children: [
|
|
123
|
-
/* @__PURE__ */ jsx(Search, { className: "h-
|
|
122
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 py-3.5 border-b border-border/40", children: [
|
|
123
|
+
/* @__PURE__ */ jsx(Search, { className: "h-[18px] w-[18px] text-muted-foreground shrink-0" }),
|
|
124
124
|
/* @__PURE__ */ jsx(
|
|
125
125
|
Command.Input,
|
|
126
126
|
{
|
|
127
127
|
ref: inputRef,
|
|
128
128
|
placeholder: "Type a command or search\u2026",
|
|
129
|
-
className: "flex-1 bg-transparent text-
|
|
129
|
+
className: "flex-1 bg-transparent text-[15px] outline-none placeholder:text-muted-foreground"
|
|
130
130
|
}
|
|
131
131
|
),
|
|
132
132
|
/* @__PURE__ */ jsx(
|
|
@@ -141,45 +141,52 @@ function NavCommandMenu({ commands, trigger, accountSlot }) {
|
|
|
141
141
|
] }),
|
|
142
142
|
/* @__PURE__ */ jsxs(Command.List, { className: "max-h-[60vh] overflow-y-auto p-2", children: [
|
|
143
143
|
/* @__PURE__ */ jsx(Command.Empty, { className: "py-8 text-center text-sm text-muted-foreground", children: "No results found." }),
|
|
144
|
-
commands.map((group, i) =>
|
|
145
|
-
|
|
146
|
-
/* @__PURE__ */
|
|
147
|
-
Command.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
144
|
+
commands.map((group, i) => {
|
|
145
|
+
const primary = !group.heading;
|
|
146
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
147
|
+
i > 0 && /* @__PURE__ */ jsx(Command.Separator, { className: "my-1.5 h-px bg-border/40" }),
|
|
148
|
+
/* @__PURE__ */ jsx(
|
|
149
|
+
Command.Group,
|
|
150
|
+
{
|
|
151
|
+
heading: group.heading,
|
|
152
|
+
className: cn(
|
|
153
|
+
"[&_[cmdk-group-heading]]:px-2",
|
|
154
|
+
"[&_[cmdk-group-heading]]:pt-1.5",
|
|
155
|
+
"[&_[cmdk-group-heading]]:pb-1",
|
|
156
|
+
"[&_[cmdk-group-heading]]:text-[11px]",
|
|
157
|
+
"[&_[cmdk-group-heading]]:font-semibold",
|
|
158
|
+
"[&_[cmdk-group-heading]]:uppercase",
|
|
159
|
+
"[&_[cmdk-group-heading]]:tracking-wider",
|
|
160
|
+
"[&_[cmdk-group-heading]]:text-muted-foreground/70"
|
|
161
|
+
),
|
|
162
|
+
children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
163
|
+
Command.Item,
|
|
164
|
+
{
|
|
165
|
+
value: [item.label, ...item.keywords ?? []].join(" "),
|
|
166
|
+
onSelect: () => runCommand(item),
|
|
167
|
+
className: cn(
|
|
168
|
+
"group/item flex items-center gap-3 rounded-xl cursor-pointer",
|
|
169
|
+
"transition-colors duration-150",
|
|
170
|
+
"aria-selected:bg-primary/10",
|
|
171
|
+
primary ? "px-2.5 py-2.5 text-[15px] font-medium" : "px-3 py-2 text-sm"
|
|
172
|
+
),
|
|
173
|
+
children: [
|
|
174
|
+
primary ? /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-muted/50 group-aria-selected/item:bg-primary/15 transition-colors shrink-0", children: /* @__PURE__ */ jsx(item.icon, { className: "h-[18px] w-[18px] text-foreground/80 group-aria-selected/item:text-primary transition-colors" }) }) : /* @__PURE__ */ jsx(item.icon, { className: "h-4 w-4 text-muted-foreground group-aria-selected/item:text-foreground transition-colors shrink-0" }),
|
|
175
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: item.label }),
|
|
176
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "h-3.5 w-3.5 text-muted-foreground/30 group-aria-selected/item:text-primary/70 transition-colors shrink-0" })
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
item.id
|
|
180
|
+
))
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
] }, group.heading ?? `__primary-${i}`);
|
|
184
|
+
})
|
|
178
185
|
] }),
|
|
179
186
|
accountSlot && /* @__PURE__ */ jsx("div", { className: "border-t border-border/40 bg-background/40 px-3 py-3", children: accountSlot }),
|
|
180
|
-
/* @__PURE__ */ jsxs("div", { className: "px-
|
|
181
|
-
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/50", children: "medialane" }),
|
|
182
|
-
/* @__PURE__ */ jsx("kbd", { className: "text-[10px] text-muted-foreground/50 font-mono", children: "\u2318K" })
|
|
187
|
+
/* @__PURE__ */ jsxs("div", { className: "px-3 py-2 border-t border-border/40 flex items-center justify-between gap-3", children: [
|
|
188
|
+
footerSlot ?? /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/50 pl-1", children: "medialane" }),
|
|
189
|
+
/* @__PURE__ */ jsx("kbd", { className: "text-[10px] text-muted-foreground/50 font-mono shrink-0", children: "\u2318K" })
|
|
183
190
|
] })
|
|
184
191
|
] })
|
|
185
192
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/nav-command-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Command } from \"cmdk\";\nimport { useRouter } from \"next/navigation\";\nimport { Search, X, ArrowRight } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { cn } from \"../utils/cn.js\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface NavCommand {\n id: string;\n label: string;\n icon: React.ComponentType<{ className?: string }>;\n href?: string;\n action?: () => void;\n /** Extra search terms beyond the label */\n keywords?: string[];\n}\n\nexport interface NavCommandGroup {\n heading: string;\n items: NavCommand[];\n}\n\nexport interface NavCommandMenuProps {\n commands: NavCommandGroup[];\n /**\n * Optional trigger element rendered inline at the component's mount point.\n * For most apps, omit this and call `useNavCommandMenu().open()` from a\n * separate button — that keeps the trigger in the right place in the layout.\n */\n trigger?: React.ReactNode;\n /**\n * Optional pinned account/connect area rendered below command results.\n * Apps own the auth implementation here (Clerk, ChipiPay, wallet connectors,\n * Privy, Cartridge, etc.) so the shared nav stays framework-agnostic.\n */\n accountSlot?: React.ReactNode;\n}\n\n// ── Singleton hook ─────────────────────────────────────────────────────────────\n\nconst ML_NAV_OPEN = \"ml:nav-open\";\nconst ML_NAV_CLOSE = \"ml:nav-close\";\n\nexport function useNavCommandMenu() {\n return {\n open: () => document.dispatchEvent(new CustomEvent(ML_NAV_OPEN)),\n close: () => document.dispatchEvent(new CustomEvent(ML_NAV_CLOSE)),\n };\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport function NavCommandMenu({ commands, trigger, accountSlot }: NavCommandMenuProps) {\n const [open, setOpen] = React.useState(false);\n const router = useRouter();\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const t = setTimeout(() => inputRef.current?.focus(), 60);\n return () => clearTimeout(t);\n }, [open]);\n\n React.useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"k\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n setOpen((prev) => !prev);\n }\n if (e.key === \"Escape\") setOpen(false);\n };\n const onOpen = () => setOpen(true);\n const onClose = () => setOpen(false);\n\n document.addEventListener(\"keydown\", onKey);\n document.addEventListener(ML_NAV_OPEN, onOpen);\n document.addEventListener(ML_NAV_CLOSE, onClose);\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n document.removeEventListener(ML_NAV_OPEN, onOpen);\n document.removeEventListener(ML_NAV_CLOSE, onClose);\n };\n }, []);\n\n const runCommand = React.useCallback(\n (cmd: NavCommand) => {\n setOpen(false);\n if (cmd.href) router.push(cmd.href);\n else cmd.action?.();\n },\n [router]\n );\n\n return (\n <>\n {trigger}\n\n <AnimatePresence>\n {open && (\n <>\n {/* Aurora blobs — vivid intensity */}\n <motion.div\n className=\"nav-canvas-aurora\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n <div className=\"aurora-purple animate-blob w-[60vw] h-[60vw] -top-[10vw] -left-[10vw]\"\n style={{ opacity: 0.25 }} />\n <div className=\"aurora-blue animate-blob-slow w-[50vw] h-[50vw] -top-[5vw] -right-[10vw]\"\n style={{ opacity: 0.2 }} />\n <div className=\"aurora-rose animate-blob w-[45vw] h-[45vw] bottom-[5vw] -left-[5vw]\"\n style={{ opacity: 0.15 }} />\n <div className=\"aurora-orange animate-blob-slow w-[40vw] h-[40vw] -bottom-[5vw] -right-[5vw]\"\n style={{ opacity: 0.15 }} />\n </motion.div>\n\n {/* Backdrop blur */}\n <motion.div\n className=\"nav-canvas-overlay\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n onClick={() => setOpen(false)}\n />\n\n {/* Command panel */}\n <motion.div\n className=\"fixed inset-0 z-[101] flex items-center justify-center p-4\"\n initial={{ opacity: 0, scale: 0.97 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.97 }}\n transition={{ duration: 0.15, ease: \"easeOut\" }}\n onClick={() => setOpen(false)}\n >\n <div\n className=\"w-full max-w-lg bg-background/90 border border-border/40 rounded-2xl overflow-hidden shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <Command shouldFilter label=\"Medialane navigation\">\n {/* Search bar */}\n <div className=\"flex items-center gap-3 px-4 py-3 border-b border-border/40\">\n <Search className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <Command.Input\n ref={inputRef}\n placeholder=\"Type a command or search…\"\n className=\"flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground\"\n />\n <button\n onClick={() => setOpen(false)}\n className=\"p-1 rounded-md hover:bg-muted/50 transition-colors\"\n aria-label=\"Close\"\n >\n <X className=\"h-4 w-4 text-muted-foreground\" />\n </button>\n </div>\n\n {/* Results */}\n <Command.List className=\"max-h-[60vh] overflow-y-auto p-2\">\n <Command.Empty className=\"py-8 text-center text-sm text-muted-foreground\">\n No results found.\n </Command.Empty>\n\n {commands.map((group, i) => (\n <React.Fragment key={group.heading}>\n {i > 0 && (\n <Command.Separator className=\"my-1 h-px bg-border/40\" />\n )}\n <Command.Group\n heading={group.heading}\n className={cn(\n \"[&_[cmdk-group-heading]]:px-2\",\n \"[&_[cmdk-group-heading]]:py-1.5\",\n \"[&_[cmdk-group-heading]]:text-xs\",\n \"[&_[cmdk-group-heading]]:font-medium\",\n \"[&_[cmdk-group-heading]]:text-muted-foreground\"\n )}\n >\n {group.items.map((item) => (\n <Command.Item\n key={item.id}\n value={[item.label, ...(item.keywords ?? [])].join(\" \")}\n onSelect={() => runCommand(item)}\n className={cn(\n \"flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm cursor-pointer\",\n \"transition-colors\",\n \"aria-selected:bg-muted/60\"\n )}\n >\n <item.icon className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"flex-1\">{item.label}</span>\n <ArrowRight className=\"h-3.5 w-3.5 text-muted-foreground/40 shrink-0\" />\n </Command.Item>\n ))}\n </Command.Group>\n </React.Fragment>\n ))}\n </Command.List>\n\n {accountSlot && (\n <div className=\"border-t border-border/40 bg-background/40 px-3 py-3\">\n {accountSlot}\n </div>\n )}\n\n {/* Footer */}\n <div className=\"px-4 py-2.5 border-t border-border/40 flex items-center justify-between\">\n <span className=\"text-[10px] text-muted-foreground/50\">medialane</span>\n <kbd className=\"text-[10px] text-muted-foreground/50 font-mono\">⌘K</kbd>\n </div>\n </Command>\n </div>\n </motion.div>\n </>\n )}\n </AnimatePresence>\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/nav-command-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Command } from \"cmdk\";\nimport { useRouter } from \"next/navigation\";\nimport { Search, X, ArrowRight } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { cn } from \"../utils/cn.js\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface NavCommand {\n id: string;\n label: string;\n icon: React.ComponentType<{ className?: string }>;\n href?: string;\n action?: () => void;\n /** Extra search terms beyond the label */\n keywords?: string[];\n}\n\nexport interface NavCommandGroup {\n /**\n * Optional group heading. Omit it for the primary group so its items\n * read as the top-level menu — they render first, emphasized, with no\n * label, separated from the headed groups below.\n */\n heading?: string;\n items: NavCommand[];\n}\n\nexport interface NavCommandMenuProps {\n commands: NavCommandGroup[];\n /**\n * Optional trigger element rendered inline at the component's mount point.\n * For most apps, omit this and call `useNavCommandMenu().open()` from a\n * separate button — that keeps the trigger in the right place in the layout.\n */\n trigger?: React.ReactNode;\n /**\n * Optional pinned account/connect area rendered below command results.\n * Apps own the auth implementation here (Clerk, ChipiPay, wallet connectors,\n * Privy, Cartridge, etc.) so the shared nav stays framework-agnostic.\n */\n accountSlot?: React.ReactNode;\n /**\n * Optional control rendered in the footer row (e.g. a theme toggle).\n * Apps own theme state (next-themes etc.) so the shared nav stays\n * framework-agnostic — same pattern as `accountSlot`.\n */\n footerSlot?: React.ReactNode;\n}\n\n// ── Singleton hook ─────────────────────────────────────────────────────────────\n\nconst ML_NAV_OPEN = \"ml:nav-open\";\nconst ML_NAV_CLOSE = \"ml:nav-close\";\n\nexport function useNavCommandMenu() {\n return {\n open: () => document.dispatchEvent(new CustomEvent(ML_NAV_OPEN)),\n close: () => document.dispatchEvent(new CustomEvent(ML_NAV_CLOSE)),\n };\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport function NavCommandMenu({ commands, trigger, accountSlot, footerSlot }: NavCommandMenuProps) {\n const [open, setOpen] = React.useState(false);\n const router = useRouter();\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const t = setTimeout(() => inputRef.current?.focus(), 60);\n return () => clearTimeout(t);\n }, [open]);\n\n React.useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"k\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n setOpen((prev) => !prev);\n }\n if (e.key === \"Escape\") setOpen(false);\n };\n const onOpen = () => setOpen(true);\n const onClose = () => setOpen(false);\n\n document.addEventListener(\"keydown\", onKey);\n document.addEventListener(ML_NAV_OPEN, onOpen);\n document.addEventListener(ML_NAV_CLOSE, onClose);\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n document.removeEventListener(ML_NAV_OPEN, onOpen);\n document.removeEventListener(ML_NAV_CLOSE, onClose);\n };\n }, []);\n\n const runCommand = React.useCallback(\n (cmd: NavCommand) => {\n setOpen(false);\n if (cmd.href) router.push(cmd.href);\n else cmd.action?.();\n },\n [router]\n );\n\n return (\n <>\n {trigger}\n\n <AnimatePresence>\n {open && (\n <>\n {/* Aurora blobs — vivid intensity */}\n <motion.div\n className=\"nav-canvas-aurora\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n <div className=\"aurora-purple animate-blob w-[60vw] h-[60vw] -top-[10vw] -left-[10vw]\"\n style={{ opacity: 0.25 }} />\n <div className=\"aurora-blue animate-blob-slow w-[50vw] h-[50vw] -top-[5vw] -right-[10vw]\"\n style={{ opacity: 0.2 }} />\n <div className=\"aurora-rose animate-blob w-[45vw] h-[45vw] bottom-[5vw] -left-[5vw]\"\n style={{ opacity: 0.15 }} />\n <div className=\"aurora-orange animate-blob-slow w-[40vw] h-[40vw] -bottom-[5vw] -right-[5vw]\"\n style={{ opacity: 0.15 }} />\n </motion.div>\n\n {/* Backdrop blur */}\n <motion.div\n className=\"nav-canvas-overlay\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n onClick={() => setOpen(false)}\n />\n\n {/* Command panel */}\n <motion.div\n className=\"fixed inset-0 z-[101] flex items-center justify-center p-4\"\n initial={{ opacity: 0, scale: 0.97 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.97 }}\n transition={{ duration: 0.15, ease: \"easeOut\" }}\n onClick={() => setOpen(false)}\n >\n <div\n className=\"w-full max-w-lg bg-background/90 border border-border/40 rounded-2xl overflow-hidden shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <Command shouldFilter label=\"Medialane navigation\">\n {/* Search bar */}\n <div className=\"flex items-center gap-3 px-4 py-3.5 border-b border-border/40\">\n <Search className=\"h-[18px] w-[18px] text-muted-foreground shrink-0\" />\n <Command.Input\n ref={inputRef}\n placeholder=\"Type a command or search…\"\n className=\"flex-1 bg-transparent text-[15px] outline-none placeholder:text-muted-foreground\"\n />\n <button\n onClick={() => setOpen(false)}\n className=\"p-1 rounded-md hover:bg-muted/50 transition-colors\"\n aria-label=\"Close\"\n >\n <X className=\"h-4 w-4 text-muted-foreground\" />\n </button>\n </div>\n\n {/* Results */}\n <Command.List className=\"max-h-[60vh] overflow-y-auto p-2\">\n <Command.Empty className=\"py-8 text-center text-sm text-muted-foreground\">\n No results found.\n </Command.Empty>\n\n {commands.map((group, i) => {\n const primary = !group.heading;\n return (\n <React.Fragment key={group.heading ?? `__primary-${i}`}>\n {i > 0 && (\n <Command.Separator className=\"my-1.5 h-px bg-border/40\" />\n )}\n <Command.Group\n heading={group.heading}\n className={cn(\n \"[&_[cmdk-group-heading]]:px-2\",\n \"[&_[cmdk-group-heading]]:pt-1.5\",\n \"[&_[cmdk-group-heading]]:pb-1\",\n \"[&_[cmdk-group-heading]]:text-[11px]\",\n \"[&_[cmdk-group-heading]]:font-semibold\",\n \"[&_[cmdk-group-heading]]:uppercase\",\n \"[&_[cmdk-group-heading]]:tracking-wider\",\n \"[&_[cmdk-group-heading]]:text-muted-foreground/70\"\n )}\n >\n {group.items.map((item) => (\n <Command.Item\n key={item.id}\n value={[item.label, ...(item.keywords ?? [])].join(\" \")}\n onSelect={() => runCommand(item)}\n className={cn(\n \"group/item flex items-center gap-3 rounded-xl cursor-pointer\",\n \"transition-colors duration-150\",\n \"aria-selected:bg-primary/10\",\n primary\n ? \"px-2.5 py-2.5 text-[15px] font-medium\"\n : \"px-3 py-2 text-sm\"\n )}\n >\n {primary ? (\n <span className=\"flex h-8 w-8 items-center justify-center rounded-lg bg-muted/50 group-aria-selected/item:bg-primary/15 transition-colors shrink-0\">\n <item.icon className=\"h-[18px] w-[18px] text-foreground/80 group-aria-selected/item:text-primary transition-colors\" />\n </span>\n ) : (\n <item.icon className=\"h-4 w-4 text-muted-foreground group-aria-selected/item:text-foreground transition-colors shrink-0\" />\n )}\n <span className=\"flex-1 truncate\">{item.label}</span>\n <ArrowRight className=\"h-3.5 w-3.5 text-muted-foreground/30 group-aria-selected/item:text-primary/70 transition-colors shrink-0\" />\n </Command.Item>\n ))}\n </Command.Group>\n </React.Fragment>\n );\n })}\n </Command.List>\n\n {accountSlot && (\n <div className=\"border-t border-border/40 bg-background/40 px-3 py-3\">\n {accountSlot}\n </div>\n )}\n\n {/* Footer */}\n <div className=\"px-3 py-2 border-t border-border/40 flex items-center justify-between gap-3\">\n {footerSlot ?? (\n <span className=\"text-[10px] text-muted-foreground/50 pl-1\">medialane</span>\n )}\n <kbd className=\"text-[10px] text-muted-foreground/50 font-mono shrink-0\">⌘K</kbd>\n </div>\n </Command>\n </div>\n </motion.div>\n </>\n )}\n </AnimatePresence>\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -39,7 +39,10 @@ function PageContainer({
|
|
|
39
39
|
{
|
|
40
40
|
className: (0, import_cn.cn)(
|
|
41
41
|
variantClass[variant],
|
|
42
|
-
|
|
42
|
+
// Horizontal padding matches the fixed NavTrigger logo offset
|
|
43
|
+
// (left-4 sm:left-6 lg:left-8) so page content aligns with the
|
|
44
|
+
// logo at every breakpoint. Keep this responsive, not a flat px.
|
|
45
|
+
"px-4 sm:px-6 lg:px-8 pt-10 pb-16",
|
|
43
46
|
className
|
|
44
47
|
),
|
|
45
48
|
...props,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/page-container.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface PageContainerProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Controls the page width contract.\n * - app: full available canvas for sidebar/dashboard shells.\n * - content: standard editorial max width.\n * - narrow: focused forms and legal/content pages.\n */\n variant?: \"app\" | \"content\" | \"narrow\";\n}\n\nconst variantClass = {\n app: \"w-full max-w-none\",\n content: \"mx-auto w-full max-w-[1400px]\",\n narrow: \"mx-auto w-full max-w-5xl\",\n};\n\nexport function PageContainer({\n variant = \"app\",\n className,\n children,\n ...props\n}: PageContainerProps) {\n return (\n <div\n className={cn(\n variantClass[variant],\n \"px-4 pt-10 pb-16\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BI;AAzBJ,gBAAmB;AAYnB,MAAM,eAAe;AAAA,EACnB,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AACV;AAEO,SAAS,cAAc;AAAA,EAC5B,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,QACT,aAAa,OAAO;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../src/components/page-container.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface PageContainerProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Controls the page width contract.\n * - app: full available canvas for sidebar/dashboard shells.\n * - content: standard editorial max width.\n * - narrow: focused forms and legal/content pages.\n */\n variant?: \"app\" | \"content\" | \"narrow\";\n}\n\nconst variantClass = {\n app: \"w-full max-w-none\",\n content: \"mx-auto w-full max-w-[1400px]\",\n narrow: \"mx-auto w-full max-w-5xl\",\n};\n\nexport function PageContainer({\n variant = \"app\",\n className,\n children,\n ...props\n}: PageContainerProps) {\n return (\n <div\n className={cn(\n variantClass[variant],\n // Horizontal padding matches the fixed NavTrigger logo offset\n // (left-4 sm:left-6 lg:left-8) so page content aligns with the\n // logo at every breakpoint. Keep this responsive, not a flat px.\n \"px-4 sm:px-6 lg:px-8 pt-10 pb-16\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BI;AAzBJ,gBAAmB;AAYnB,MAAM,eAAe;AAAA,EACnB,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AACV;AAEO,SAAS,cAAc;AAAA,EAC5B,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,QACT,aAAa,OAAO;AAAA;AAAA;AAAA;AAAA,QAIpB;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -16,7 +16,10 @@ function PageContainer({
|
|
|
16
16
|
{
|
|
17
17
|
className: cn(
|
|
18
18
|
variantClass[variant],
|
|
19
|
-
|
|
19
|
+
// Horizontal padding matches the fixed NavTrigger logo offset
|
|
20
|
+
// (left-4 sm:left-6 lg:left-8) so page content aligns with the
|
|
21
|
+
// logo at every breakpoint. Keep this responsive, not a flat px.
|
|
22
|
+
"px-4 sm:px-6 lg:px-8 pt-10 pb-16",
|
|
20
23
|
className
|
|
21
24
|
),
|
|
22
25
|
...props,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/page-container.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface PageContainerProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Controls the page width contract.\n * - app: full available canvas for sidebar/dashboard shells.\n * - content: standard editorial max width.\n * - narrow: focused forms and legal/content pages.\n */\n variant?: \"app\" | \"content\" | \"narrow\";\n}\n\nconst variantClass = {\n app: \"w-full max-w-none\",\n content: \"mx-auto w-full max-w-[1400px]\",\n narrow: \"mx-auto w-full max-w-5xl\",\n};\n\nexport function PageContainer({\n variant = \"app\",\n className,\n children,\n ...props\n}: PageContainerProps) {\n return (\n <div\n className={cn(\n variantClass[variant],\n \"px-4 pt-10 pb-16\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":"AA0BI;AAzBJ,SAAS,UAAU;AAYnB,MAAM,eAAe;AAAA,EACnB,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AACV;AAEO,SAAS,cAAc;AAAA,EAC5B,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT,aAAa,OAAO;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../src/components/page-container.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface PageContainerProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Controls the page width contract.\n * - app: full available canvas for sidebar/dashboard shells.\n * - content: standard editorial max width.\n * - narrow: focused forms and legal/content pages.\n */\n variant?: \"app\" | \"content\" | \"narrow\";\n}\n\nconst variantClass = {\n app: \"w-full max-w-none\",\n content: \"mx-auto w-full max-w-[1400px]\",\n narrow: \"mx-auto w-full max-w-5xl\",\n};\n\nexport function PageContainer({\n variant = \"app\",\n className,\n children,\n ...props\n}: PageContainerProps) {\n return (\n <div\n className={cn(\n variantClass[variant],\n // Horizontal padding matches the fixed NavTrigger logo offset\n // (left-4 sm:left-6 lg:left-8) so page content aligns with the\n // logo at every breakpoint. Keep this responsive, not a flat px.\n \"px-4 sm:px-6 lg:px-8 pt-10 pb-16\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":"AA0BI;AAzBJ,SAAS,UAAU;AAYnB,MAAM,eAAe;AAAA,EACnB,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AACV;AAEO,SAAS,cAAc;AAAA,EAC5B,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT,aAAa,OAAO;AAAA;AAAA;AAAA;AAAA,QAIpB;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;","names":[]}
|