octocms 0.3.3 → 0.3.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.
@@ -2,17 +2,14 @@
2
2
 
3
3
  import React from 'react';
4
4
  import { CircleCheck, Info, LoaderCircle, OctagonX, TriangleAlert } from 'lucide-react';
5
- import { useTheme } from 'next-themes';
6
5
  import { Toaster as Sonner } from 'sonner';
7
6
 
8
7
  type ToasterProps = React.ComponentProps<typeof Sonner>;
9
8
 
10
9
  const Toaster = ({ ...props }: ToasterProps) => {
11
- const { theme = 'system' } = useTheme();
12
-
13
10
  return (
14
11
  <Sonner
15
- theme={theme as ToasterProps['theme']}
12
+ theme="system"
16
13
  className="toaster group"
17
14
  icons={{
18
15
  success: <CircleCheck className="h-4 w-4" />,
package/dist/cli/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "../chunk-33PHLOAE.js";
9
9
 
10
10
  // package.json
11
- var version = "0.3.3";
11
+ var version = "0.3.4";
12
12
 
13
13
  // cli/index.ts
14
14
  var HELP = `
@@ -1 +1 @@
1
- {"version":3,"sources":["../../package.json","../../cli/index.ts"],"sourcesContent":["{\n \"name\": \"octocms\",\n \"version\": \"0.3.3\",\n \"description\": \"A file-based CMS for Next.js — schema-driven, Git-backed, no database\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"keywords\": [\n \"cms\",\n \"nextjs\",\n \"headless-cms\",\n \"git-cms\",\n \"content-management\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/octocms/octocms.git\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./query\": {\n \"types\": \"./dist/query.d.ts\",\n \"import\": \"./dist/query.js\"\n },\n \"./config\": {\n \"types\": \"./dist/config.d.ts\",\n \"import\": \"./dist/config.js\"\n },\n \"./defineConfig\": {\n \"types\": \"./dist/defineConfig.d.ts\",\n \"import\": \"./dist/defineConfig.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"import\": \"./dist/types.js\"\n },\n \"./withOctoCMS\": {\n \"types\": \"./dist/withOctoCMS.d.ts\",\n \"import\": \"./dist/withOctoCMS.js\"\n },\n \"./components/public\": {\n \"types\": \"./dist/components/public/index.d.ts\",\n \"import\": \"./dist/components/public/index.js\"\n },\n \"./admin/AdminApp\": \"./admin/AdminApp.tsx\",\n \"./admin/pages/AdminLayout\": \"./admin/pages/AdminLayout.tsx\",\n \"./globals.css\": \"./globals.css\",\n \"./docs/*\": \"./docs/*\"\n },\n \"bin\": {\n \"octocms\": \"dist/cli/index.js\"\n },\n \"files\": [\n \"dist\",\n \"docs\",\n \"globals.css\",\n \"admin\",\n \"components\",\n \"hooks\",\n \"lib\",\n \"index.ts\",\n \"query.ts\",\n \"config.ts\",\n \"defineConfig.ts\",\n \"types.ts\",\n \"withOctoCMS.ts\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"prepublishOnly\": \"npm run checks && npm run build\",\n \"lint\": \"oxlint .\",\n \"lint:fix\": \"oxlint --fix .\",\n \"fmt\": \"oxfmt .\",\n \"fmt:check\": \"oxfmt --check .\",\n \"test\": \"vitest\",\n \"test:run\": \"vitest run\",\n \"ts-check\": \"tsc --noEmit --incremental false\",\n \"checks\": \"npm run lint && npm run ts-check && npm run fmt:check && npm run test:run\",\n \"checks:fix\": \"npm run lint:fix && npm run fmt && npm run test:run\"\n },\n \"peerDependencies\": {\n \"next\": \">=15\",\n \"react\": \">=18\",\n \"react-dom\": \">=18\"\n },\n \"dependencies\": {\n \"@mdxeditor/editor\": \"^3.11.4\",\n \"@radix-ui/react-avatar\": \"^1.1.11\",\n \"@radix-ui/react-dialog\": \"^1.1.15\",\n \"@radix-ui/react-dropdown-menu\": \"^2.1.16\",\n \"@radix-ui/react-label\": \"^2.1.8\",\n \"@radix-ui/react-select\": \"^2.2.6\",\n \"@radix-ui/react-slot\": \"^1.2.4\",\n \"@radix-ui/react-tabs\": \"^1.1.13\",\n \"@radix-ui/react-toast\": \"^1.2.15\",\n \"class-variance-authority\": \"^0.7.1\",\n \"clsx\": \"^2.1.1\",\n \"glob\": \"^11.0.0\",\n \"lucide-react\": \"^1.7.0\",\n \"minisearch\": \"^7.2.0\",\n \"next-auth\": \"^4.24.13\",\n \"octokit\": \"^4.1.4\",\n \"react-markdown\": \"^10.1.0\",\n \"rehype-sanitize\": \"^6.0.0\",\n \"remark-gfm\": \"^4.0.1\",\n \"remark-mdx\": \"^3.1.1\",\n \"sharp\": \"^0.34.5\",\n \"slugify\": \"^1.6.9\",\n \"sonner\": \"^2.0.7\",\n \"tailwind-merge\": \"^3.5.0\",\n \"zod\": \"^4.3.6\"\n },\n \"devDependencies\": {\n \"@testing-library/dom\": \"^10.4.1\",\n \"@testing-library/react\": \"^16.3.2\",\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19.2.14\",\n \"@types/react-dom\": \"^19.2.3\",\n \"@vitejs/plugin-react\": \"^6.0.1\",\n \"jsdom\": \"^29.0.1\",\n \"oxfmt\": \"^0.11.0\",\n \"oxlint\": \"^0.17.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.9.3\",\n \"vite-tsconfig-paths\": \"^6.1.1\",\n \"vitest\": \"^4.1.2\"\n }\n}\n","#!/usr/bin/env node\n/* eslint-disable no-console */\n\n/**\n * OctoCMS CLI — command-line tools for managing an OctoCMS project.\n *\n * Commands:\n * init Initialize OctoCMS in a Next.js project\n * dev Start development server with config watching\n * types:gen Generate TypeScript types from next.config.ts\n * validate Validate all content entries against the schema\n * update Regenerate admin route files\n * agent-docs Inject AI agent doc links into AGENTS.md\n *\n * Usage:\n * octocms <command> [options]\n * octocms --help\n * octocms --version\n */\n\nimport { fmt, log } from './lib/logger';\nimport { resolveProjectRoot } from './lib/project';\nimport { version as VERSION } from '../package.json';\n\nconst HELP = `\n ${fmt.bold('OctoCMS CLI')} v${VERSION}\n\n Usage: octocms <command> [options]\n\n ${fmt.bold('Commands:')}\n init Initialize OctoCMS in a Next.js project\n dev Start development server with config watching\n types:gen Generate TypeScript types from next.config.ts\n validate Validate all content entries against the schema\n update Regenerate admin route files\n agent-docs Inject AI agent doc links into AGENTS.md\n\n ${fmt.bold('Options:')}\n --help Show this help message\n --version Show version number\n\n Run ${fmt.cyan('octocms <command> --help')} for command-specific help.\n`;\n\nconst COMMAND_HELP: Record<string, string> = {\n init: `\n ${fmt.bold('octocms init')} — Initialize OctoCMS in a Next.js project\n\n Creates next.config.ts, admin route files, demo content, and updates\n next.config.ts and tsconfig.json with required configuration.\n\n ${fmt.bold('Usage:')} octocms init [options]\n\n ${fmt.bold('Options:')}\n --yes, -y Accept all defaults (non-interactive)\n --help Show this help message\n`,\n dev: `\n ${fmt.bold('octocms dev')} — Start development server with config watching\n\n Spawns Next.js dev server and watches next.config.ts. When the config\n changes, types are automatically regenerated.\n\n ${fmt.bold('Usage:')} octocms dev [options]\n\n ${fmt.bold('Options:')}\n --port <n> Port number (default: 3000)\n --help Show this help message\n`,\n 'types:gen': `\n ${fmt.bold('octocms types:gen')} — Generate TypeScript types from next.config.ts\n\n Produces cms/__generated__/types.ts, enums.ts, content.d.ts, and index.ts.\n Validates the config before generating.\n\n ${fmt.bold('Usage:')} octocms types:gen\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n validate: `\n ${fmt.bold('octocms validate')} — Validate all content entries against the schema\n\n Reads every JSON file in cms/content/, validates structure, field types,\n required fields, select option values, reference targets, and companion files.\n\n ${fmt.bold('Usage:')} octocms validate\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n 'agent-docs': `\n ${fmt.bold('octocms agent-docs')} — Inject AI agent doc links into AGENTS.md\n\n Creates AGENTS.md if it doesn't exist, or appends the OctoCMS section\n if the file exists but doesn't reference the agent docs yet.\n\n ${fmt.bold('Usage:')} octocms agent-docs\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n update: `\n ${fmt.bold('octocms update')} — Regenerate admin route files\n\n Ensures src/app/cms/layout.tsx and the catch-all page re-export are\n up-to-date with the latest OctoCMS version.\n\n ${fmt.bold('Usage:')} octocms update\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n};\n\nfunction parseArgs(argv: string[]): { command: string | null; flags: Record<string, string | boolean> } {\n const args = argv.slice(2); // skip node + script path\n const flags: Record<string, string | boolean> = {};\n let command: string | null = null;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--help' || arg === '-h') {\n flags.help = true;\n } else if (arg === '--version' || arg === '-v') {\n flags.version = true;\n } else if (arg === '--yes' || arg === '-y') {\n flags.yes = true;\n } else if (arg === '--port') {\n flags.port = args[++i] ?? '';\n } else if (arg.startsWith('--port=')) {\n flags.port = arg.slice(7);\n } else if (!arg.startsWith('-') && !command) {\n // Handle compound commands as single tokens\n if (arg === 'types:gen' || arg === 'agent-docs') {\n command = arg;\n } else {\n command = arg;\n }\n }\n }\n\n return { command, flags };\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv);\n\n if (flags.version) {\n console.log(VERSION);\n return;\n }\n\n if (!command || flags.help) {\n if (command && COMMAND_HELP[command]) {\n console.log(COMMAND_HELP[command]);\n } else {\n console.log(HELP);\n }\n return;\n }\n\n if (COMMAND_HELP[command] && flags.help) {\n console.log(COMMAND_HELP[command]);\n return;\n }\n\n try {\n switch (command) {\n case 'init': {\n // init doesn't need an existing project root — use cwd\n const { initCommand } = await import('./commands/init');\n await initCommand(process.cwd(), { yes: flags.yes === true });\n break;\n }\n case 'dev': {\n const projectRoot = resolveProjectRoot();\n const { devCommand } = await import('./commands/dev');\n const port = flags.port ? Number(flags.port) : undefined;\n await devCommand(projectRoot, { port });\n break;\n }\n case 'types:gen': {\n const projectRoot = resolveProjectRoot();\n const { typesGenCommand } = await import('./commands/typesGen');\n await typesGenCommand(projectRoot);\n break;\n }\n case 'validate': {\n const projectRoot = resolveProjectRoot();\n const { validateCommand } = await import('./commands/validate');\n await validateCommand(projectRoot);\n break;\n }\n case 'update': {\n const projectRoot = resolveProjectRoot();\n const { updateCommand } = await import('./commands/update');\n await updateCommand(projectRoot);\n break;\n }\n case 'agent-docs': {\n const projectRoot = resolveProjectRoot();\n const { agentDocsCommand } = await import('./commands/agentDocs');\n await agentDocsCommand(projectRoot);\n break;\n }\n default:\n log.error(`Unknown command: ${command}`);\n console.log(HELP);\n process.exitCode = 1;\n }\n } catch (e) {\n log.error((e as Error).message);\n process.exitCode = 1;\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../package.json","../../cli/index.ts"],"sourcesContent":["{\n \"name\": \"octocms\",\n \"version\": \"0.3.4\",\n \"description\": \"A file-based CMS for Next.js — schema-driven, Git-backed, no database\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"keywords\": [\n \"cms\",\n \"nextjs\",\n \"headless-cms\",\n \"git-cms\",\n \"content-management\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/octocms/octocms.git\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"require\": \"./dist/index.cjs\",\n \"import\": \"./dist/index.js\"\n },\n \"./query\": {\n \"types\": \"./dist/query.d.ts\",\n \"require\": \"./dist/query.cjs\",\n \"import\": \"./dist/query.js\"\n },\n \"./config\": {\n \"types\": \"./dist/config.d.ts\",\n \"require\": \"./dist/config.cjs\",\n \"import\": \"./dist/config.js\"\n },\n \"./defineConfig\": {\n \"types\": \"./dist/defineConfig.d.ts\",\n \"require\": \"./dist/defineConfig.cjs\",\n \"import\": \"./dist/defineConfig.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"require\": \"./dist/types.cjs\",\n \"import\": \"./dist/types.js\"\n },\n \"./withOctoCMS\": {\n \"types\": \"./dist/withOctoCMS.d.ts\",\n \"require\": \"./dist/withOctoCMS.cjs\",\n \"import\": \"./dist/withOctoCMS.js\"\n },\n \"./components/public\": {\n \"types\": \"./dist/components/public/index.d.ts\",\n \"require\": \"./dist/components/public/index.cjs\",\n \"import\": \"./dist/components/public/index.js\"\n },\n \"./admin/AdminApp\": \"./admin/AdminApp.tsx\",\n \"./admin/pages/AdminLayout\": \"./admin/pages/AdminLayout.tsx\",\n \"./globals.css\": \"./globals.css\",\n \"./docs/*\": \"./docs/*\"\n },\n \"bin\": {\n \"octocms\": \"dist/cli/index.js\"\n },\n \"files\": [\n \"dist\",\n \"docs\",\n \"globals.css\",\n \"admin\",\n \"components\",\n \"hooks\",\n \"lib\",\n \"index.ts\",\n \"query.ts\",\n \"config.ts\",\n \"defineConfig.ts\",\n \"types.ts\",\n \"withOctoCMS.ts\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"prepublishOnly\": \"npm run checks && npm run build\",\n \"lint\": \"oxlint .\",\n \"lint:fix\": \"oxlint --fix .\",\n \"fmt\": \"oxfmt .\",\n \"fmt:check\": \"oxfmt --check .\",\n \"test\": \"vitest\",\n \"test:run\": \"vitest run\",\n \"ts-check\": \"tsc --noEmit --incremental false\",\n \"checks\": \"npm run lint && npm run ts-check && npm run fmt:check && npm run test:run\",\n \"checks:fix\": \"npm run lint:fix && npm run fmt && npm run test:run\"\n },\n \"peerDependencies\": {\n \"next\": \">=15\",\n \"react\": \">=18\",\n \"react-dom\": \">=18\"\n },\n \"dependencies\": {\n \"@mdxeditor/editor\": \"^3.11.4\",\n \"@radix-ui/react-avatar\": \"^1.1.11\",\n \"@radix-ui/react-dialog\": \"^1.1.15\",\n \"@radix-ui/react-dropdown-menu\": \"^2.1.16\",\n \"@radix-ui/react-label\": \"^2.1.8\",\n \"@radix-ui/react-select\": \"^2.2.6\",\n \"@radix-ui/react-slot\": \"^1.2.4\",\n \"@radix-ui/react-tabs\": \"^1.1.13\",\n \"@radix-ui/react-toast\": \"^1.2.15\",\n \"class-variance-authority\": \"^0.7.1\",\n \"clsx\": \"^2.1.1\",\n \"glob\": \"^11.0.0\",\n \"lucide-react\": \"^1.7.0\",\n \"minisearch\": \"^7.2.0\",\n \"next-auth\": \"^4.24.13\",\n \"octokit\": \"^4.1.4\",\n \"react-markdown\": \"^10.1.0\",\n \"rehype-sanitize\": \"^6.0.0\",\n \"remark-gfm\": \"^4.0.1\",\n \"remark-mdx\": \"^3.1.1\",\n \"sharp\": \"^0.34.5\",\n \"slugify\": \"^1.6.9\",\n \"sonner\": \"^2.0.7\",\n \"tailwind-merge\": \"^3.5.0\",\n \"zod\": \"^4.3.6\"\n },\n \"devDependencies\": {\n \"@testing-library/dom\": \"^10.4.1\",\n \"@testing-library/react\": \"^16.3.2\",\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19.2.14\",\n \"@types/react-dom\": \"^19.2.3\",\n \"@vitejs/plugin-react\": \"^6.0.1\",\n \"jsdom\": \"^29.0.1\",\n \"oxfmt\": \"^0.11.0\",\n \"oxlint\": \"^0.17.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.9.3\",\n \"vite-tsconfig-paths\": \"^6.1.1\",\n \"vitest\": \"^4.1.2\"\n }\n}\n","#!/usr/bin/env node\n/* eslint-disable no-console */\n\n/**\n * OctoCMS CLI — command-line tools for managing an OctoCMS project.\n *\n * Commands:\n * init Initialize OctoCMS in a Next.js project\n * dev Start development server with config watching\n * types:gen Generate TypeScript types from next.config.ts\n * validate Validate all content entries against the schema\n * update Regenerate admin route files\n * agent-docs Inject AI agent doc links into AGENTS.md\n *\n * Usage:\n * octocms <command> [options]\n * octocms --help\n * octocms --version\n */\n\nimport { fmt, log } from './lib/logger';\nimport { resolveProjectRoot } from './lib/project';\nimport { version as VERSION } from '../package.json';\n\nconst HELP = `\n ${fmt.bold('OctoCMS CLI')} v${VERSION}\n\n Usage: octocms <command> [options]\n\n ${fmt.bold('Commands:')}\n init Initialize OctoCMS in a Next.js project\n dev Start development server with config watching\n types:gen Generate TypeScript types from next.config.ts\n validate Validate all content entries against the schema\n update Regenerate admin route files\n agent-docs Inject AI agent doc links into AGENTS.md\n\n ${fmt.bold('Options:')}\n --help Show this help message\n --version Show version number\n\n Run ${fmt.cyan('octocms <command> --help')} for command-specific help.\n`;\n\nconst COMMAND_HELP: Record<string, string> = {\n init: `\n ${fmt.bold('octocms init')} — Initialize OctoCMS in a Next.js project\n\n Creates next.config.ts, admin route files, demo content, and updates\n next.config.ts and tsconfig.json with required configuration.\n\n ${fmt.bold('Usage:')} octocms init [options]\n\n ${fmt.bold('Options:')}\n --yes, -y Accept all defaults (non-interactive)\n --help Show this help message\n`,\n dev: `\n ${fmt.bold('octocms dev')} — Start development server with config watching\n\n Spawns Next.js dev server and watches next.config.ts. When the config\n changes, types are automatically regenerated.\n\n ${fmt.bold('Usage:')} octocms dev [options]\n\n ${fmt.bold('Options:')}\n --port <n> Port number (default: 3000)\n --help Show this help message\n`,\n 'types:gen': `\n ${fmt.bold('octocms types:gen')} — Generate TypeScript types from next.config.ts\n\n Produces cms/__generated__/types.ts, enums.ts, content.d.ts, and index.ts.\n Validates the config before generating.\n\n ${fmt.bold('Usage:')} octocms types:gen\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n validate: `\n ${fmt.bold('octocms validate')} — Validate all content entries against the schema\n\n Reads every JSON file in cms/content/, validates structure, field types,\n required fields, select option values, reference targets, and companion files.\n\n ${fmt.bold('Usage:')} octocms validate\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n 'agent-docs': `\n ${fmt.bold('octocms agent-docs')} — Inject AI agent doc links into AGENTS.md\n\n Creates AGENTS.md if it doesn't exist, or appends the OctoCMS section\n if the file exists but doesn't reference the agent docs yet.\n\n ${fmt.bold('Usage:')} octocms agent-docs\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n update: `\n ${fmt.bold('octocms update')} — Regenerate admin route files\n\n Ensures src/app/cms/layout.tsx and the catch-all page re-export are\n up-to-date with the latest OctoCMS version.\n\n ${fmt.bold('Usage:')} octocms update\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n};\n\nfunction parseArgs(argv: string[]): { command: string | null; flags: Record<string, string | boolean> } {\n const args = argv.slice(2); // skip node + script path\n const flags: Record<string, string | boolean> = {};\n let command: string | null = null;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--help' || arg === '-h') {\n flags.help = true;\n } else if (arg === '--version' || arg === '-v') {\n flags.version = true;\n } else if (arg === '--yes' || arg === '-y') {\n flags.yes = true;\n } else if (arg === '--port') {\n flags.port = args[++i] ?? '';\n } else if (arg.startsWith('--port=')) {\n flags.port = arg.slice(7);\n } else if (!arg.startsWith('-') && !command) {\n // Handle compound commands as single tokens\n if (arg === 'types:gen' || arg === 'agent-docs') {\n command = arg;\n } else {\n command = arg;\n }\n }\n }\n\n return { command, flags };\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv);\n\n if (flags.version) {\n console.log(VERSION);\n return;\n }\n\n if (!command || flags.help) {\n if (command && COMMAND_HELP[command]) {\n console.log(COMMAND_HELP[command]);\n } else {\n console.log(HELP);\n }\n return;\n }\n\n if (COMMAND_HELP[command] && flags.help) {\n console.log(COMMAND_HELP[command]);\n return;\n }\n\n try {\n switch (command) {\n case 'init': {\n // init doesn't need an existing project root — use cwd\n const { initCommand } = await import('./commands/init');\n await initCommand(process.cwd(), { yes: flags.yes === true });\n break;\n }\n case 'dev': {\n const projectRoot = resolveProjectRoot();\n const { devCommand } = await import('./commands/dev');\n const port = flags.port ? Number(flags.port) : undefined;\n await devCommand(projectRoot, { port });\n break;\n }\n case 'types:gen': {\n const projectRoot = resolveProjectRoot();\n const { typesGenCommand } = await import('./commands/typesGen');\n await typesGenCommand(projectRoot);\n break;\n }\n case 'validate': {\n const projectRoot = resolveProjectRoot();\n const { validateCommand } = await import('./commands/validate');\n await validateCommand(projectRoot);\n break;\n }\n case 'update': {\n const projectRoot = resolveProjectRoot();\n const { updateCommand } = await import('./commands/update');\n await updateCommand(projectRoot);\n break;\n }\n case 'agent-docs': {\n const projectRoot = resolveProjectRoot();\n const { agentDocsCommand } = await import('./commands/agentDocs');\n await agentDocsCommand(projectRoot);\n break;\n }\n default:\n log.error(`Unknown command: ${command}`);\n console.log(HELP);\n process.exitCode = 1;\n }\n } catch (e) {\n log.error((e as Error).message);\n process.exitCode = 1;\n }\n}\n\nmain();\n"],"mappings":";;;;;;;;;;AAEE,cAAW;;;ACsBb,IAAM,OAAO;AAAA,IACT,IAAI,KAAK,aAAa,CAAC,KAAK,OAAO;AAAA;AAAA;AAAA;AAAA,IAInC,IAAI,KAAK,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQrB,IAAI,KAAK,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA,QAIhB,IAAI,KAAK,0BAA0B,CAAC;AAAA;AAG5C,IAAM,eAAuC;AAAA,EAC3C,MAAM;AAAA,IACJ,IAAI,KAAK,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAKxB,IAAI,KAAK,QAAQ,CAAC;AAAA;AAAA,IAElB,IAAI,KAAK,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA,EAItB,KAAK;AAAA,IACH,IAAI,KAAK,aAAa,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAKvB,IAAI,KAAK,QAAQ,CAAC;AAAA;AAAA,IAElB,IAAI,KAAK,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA,EAItB,aAAa;AAAA,IACX,IAAI,KAAK,mBAAmB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAK7B,IAAI,KAAK,QAAQ,CAAC;AAAA;AAAA,IAElB,IAAI,KAAK,UAAU,CAAC;AAAA;AAAA;AAAA,EAGtB,UAAU;AAAA,IACR,IAAI,KAAK,kBAAkB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAK5B,IAAI,KAAK,QAAQ,CAAC;AAAA;AAAA,IAElB,IAAI,KAAK,UAAU,CAAC;AAAA;AAAA;AAAA,EAGtB,cAAc;AAAA,IACZ,IAAI,KAAK,oBAAoB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAK9B,IAAI,KAAK,QAAQ,CAAC;AAAA;AAAA,IAElB,IAAI,KAAK,UAAU,CAAC;AAAA;AAAA;AAAA,EAGtB,QAAQ;AAAA,IACN,IAAI,KAAK,gBAAgB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAK1B,IAAI,KAAK,QAAQ,CAAC;AAAA;AAAA,IAElB,IAAI,KAAK,UAAU,CAAC;AAAA;AAAA;AAGxB;AAEA,SAAS,UAAU,MAAqF;AAnHxG;AAoHE,QAAM,OAAO,KAAK,MAAM,CAAC;AACzB,QAAM,QAA0C,CAAC;AACjD,MAAI,UAAyB;AAE7B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAElB,QAAI,QAAQ,YAAY,QAAQ,MAAM;AACpC,YAAM,OAAO;AAAA,IACf,WAAW,QAAQ,eAAe,QAAQ,MAAM;AAC9C,YAAM,UAAU;AAAA,IAClB,WAAW,QAAQ,WAAW,QAAQ,MAAM;AAC1C,YAAM,MAAM;AAAA,IACd,WAAW,QAAQ,UAAU;AAC3B,YAAM,QAAO,UAAK,EAAE,CAAC,MAAR,YAAa;AAAA,IAC5B,WAAW,IAAI,WAAW,SAAS,GAAG;AACpC,YAAM,OAAO,IAAI,MAAM,CAAC;AAAA,IAC1B,WAAW,CAAC,IAAI,WAAW,GAAG,KAAK,CAAC,SAAS;AAE3C,UAAI,QAAQ,eAAe,QAAQ,cAAc;AAC/C,kBAAU;AAAA,MACZ,OAAO;AACL,kBAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,MAAM;AAC1B;AAEA,eAAe,OAAsB;AACnC,QAAM,EAAE,SAAS,MAAM,IAAI,UAAU,QAAQ,IAAI;AAEjD,MAAI,MAAM,SAAS;AACjB,YAAQ,IAAI,OAAO;AACnB;AAAA,EACF;AAEA,MAAI,CAAC,WAAW,MAAM,MAAM;AAC1B,QAAI,WAAW,aAAa,OAAO,GAAG;AACpC,cAAQ,IAAI,aAAa,OAAO,CAAC;AAAA,IACnC,OAAO;AACL,cAAQ,IAAI,IAAI;AAAA,IAClB;AACA;AAAA,EACF;AAEA,MAAI,aAAa,OAAO,KAAK,MAAM,MAAM;AACvC,YAAQ,IAAI,aAAa,OAAO,CAAC;AACjC;AAAA,EACF;AAEA,MAAI;AACF,YAAQ,SAAS;AAAA,MACf,KAAK,QAAQ;AAEX,cAAM,EAAE,YAAY,IAAI,MAAM,OAAO,qBAAiB;AACtD,cAAM,YAAY,QAAQ,IAAI,GAAG,EAAE,KAAK,MAAM,QAAQ,KAAK,CAAC;AAC5D;AAAA,MACF;AAAA,MACA,KAAK,OAAO;AACV,cAAM,cAAc,mBAAmB;AACvC,cAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAgB;AACpD,cAAM,OAAO,MAAM,OAAO,OAAO,MAAM,IAAI,IAAI;AAC/C,cAAM,WAAW,aAAa,EAAE,KAAK,CAAC;AACtC;AAAA,MACF;AAAA,MACA,KAAK,aAAa;AAChB,cAAM,cAAc,mBAAmB;AACvC,cAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,yBAAqB;AAC9D,cAAM,gBAAgB,WAAW;AACjC;AAAA,MACF;AAAA,MACA,KAAK,YAAY;AACf,cAAM,cAAc,mBAAmB;AACvC,cAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,yBAAqB;AAC9D,cAAM,gBAAgB,WAAW;AACjC;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,cAAM,cAAc,mBAAmB;AACvC,cAAM,EAAE,cAAc,IAAI,MAAM,OAAO,uBAAmB;AAC1D,cAAM,cAAc,WAAW;AAC/B;AAAA,MACF;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,cAAc,mBAAmB;AACvC,cAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,0BAAsB;AAChE,cAAM,iBAAiB,WAAW;AAClC;AAAA,MACF;AAAA,MACA;AACE,YAAI,MAAM,oBAAoB,OAAO,EAAE;AACvC,gBAAQ,IAAI,IAAI;AAChB,gBAAQ,WAAW;AAAA,IACvB;AAAA,EACF,SAAS,GAAG;AACV,QAAI,MAAO,EAAY,OAAO;AAC9B,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,KAAK;","names":[]}
@@ -0,0 +1,452 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __spreadValues = (a, b) => {
14
+ for (var prop in b || (b = {}))
15
+ if (__hasOwnProp.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ if (__getOwnPropSymbols)
18
+ for (var prop of __getOwnPropSymbols(b)) {
19
+ if (__propIsEnum.call(b, prop))
20
+ __defNormalProp(a, prop, b[prop]);
21
+ }
22
+ return a;
23
+ };
24
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __export = (target, all) => {
26
+ for (var name in all)
27
+ __defProp(target, name, { get: all[name], enumerable: true });
28
+ };
29
+ var __copyProps = (to, from, except, desc) => {
30
+ if (from && typeof from === "object" || typeof from === "function") {
31
+ for (let key of __getOwnPropNames(from))
32
+ if (!__hasOwnProp.call(to, key) && key !== except)
33
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
34
+ }
35
+ return to;
36
+ };
37
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
38
+ // If the importer is in node compatibility mode or this is not an ESM
39
+ // file that has been converted to a CommonJS file using a Babel-
40
+ // compatible transform (i.e. "__esModule" has not been set), then set
41
+ // "default" to the CommonJS "module.exports" for node compatibility.
42
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
43
+ mod
44
+ ));
45
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
46
+
47
+ // components/public/index.ts
48
+ var public_exports = {};
49
+ __export(public_exports, {
50
+ MarkdownContent: () => MarkdownContent_default,
51
+ RichTextContent: () => RichTextContent_default,
52
+ SearchBox: () => SearchBox
53
+ });
54
+ module.exports = __toCommonJS(public_exports);
55
+
56
+ // components/public/MarkdownContent.tsx
57
+ var import_react_markdown = __toESM(require("react-markdown"), 1);
58
+ var import_rehype_sanitize = __toESM(require("rehype-sanitize"), 1);
59
+ var import_remark_gfm = __toESM(require("remark-gfm"), 1);
60
+
61
+ // lib/utils.ts
62
+ var import_clsx = require("clsx");
63
+ var import_tailwind_merge = require("tailwind-merge");
64
+ var cn = (...inputs) => (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
65
+
66
+ // components/public/MarkdownContent.tsx
67
+ var import_jsx_runtime = require("react/jsx-runtime");
68
+ var _a, _b, _c;
69
+ var sanitizeSchema = __spreadProps(__spreadValues({}, import_rehype_sanitize.defaultSchema), {
70
+ tagNames: [
71
+ ...(_a = import_rehype_sanitize.defaultSchema.tagNames) != null ? _a : [],
72
+ "u"
73
+ // underline — not in GitHub default
74
+ ],
75
+ attributes: __spreadProps(__spreadValues({}, import_rehype_sanitize.defaultSchema.attributes), {
76
+ code: [...(_c = (_b = import_rehype_sanitize.defaultSchema.attributes) == null ? void 0 : _b.code) != null ? _c : [], "className"],
77
+ img: ["src", "alt", "title"]
78
+ })
79
+ });
80
+ var MarkdownContent = ({ children, className }) => {
81
+ if (!children) {
82
+ return null;
83
+ }
84
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn(className), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], rehypePlugins: [[import_rehype_sanitize.default, sanitizeSchema]], children }) });
85
+ };
86
+ var MarkdownContent_default = MarkdownContent;
87
+
88
+ // components/public/RichTextContent.tsx
89
+ var import_image = __toESM(require("next/image"), 1);
90
+ var import_jsx_runtime2 = require("react/jsx-runtime");
91
+ var RichTextContent = ({ document: document2, components, variables, conditions, className }) => {
92
+ var _a2;
93
+ if (!document2 || !((_a2 = document2.content) == null ? void 0 : _a2.length)) return null;
94
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn(className), children: document2.content.map((node, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderNode, { node, components, variables, conditions }, i)) });
95
+ };
96
+ var RichTextContent_default = RichTextContent;
97
+ function RenderNode({ node, components, variables, conditions }) {
98
+ var _a2;
99
+ switch (node.type) {
100
+ case "paragraph":
101
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderChildren, { nodes: node.children, components, variables, conditions }) });
102
+ case "heading": {
103
+ const Tag = `h${node.level}`;
104
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Tag, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderChildren, { nodes: node.children, components, variables, conditions }) });
105
+ }
106
+ case "blockquote":
107
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("blockquote", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderChildren, { nodes: node.children, components, variables, conditions }) });
108
+ case "list":
109
+ if (node.ordered) {
110
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ol", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
111
+ RenderChildren,
112
+ {
113
+ nodes: node.children,
114
+ components,
115
+ variables,
116
+ conditions
117
+ }
118
+ ) });
119
+ }
120
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderChildren, { nodes: node.children, components, variables, conditions }) });
121
+ case "listItem":
122
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderChildren, { nodes: node.children, components, variables, conditions }) });
123
+ case "thematicBreak":
124
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("hr", {});
125
+ case "code":
126
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("pre", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { className: node.lang ? `language-${node.lang}` : void 0, children: node.value }) });
127
+ case "text":
128
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderText, { node });
129
+ case "link":
130
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: node.url, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderChildren, { nodes: node.children, components, variables, conditions }) });
131
+ case "image":
132
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderImage, { image: node.image });
133
+ case "break":
134
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("br", {});
135
+ case "html":
136
+ return null;
137
+ case "variable": {
138
+ const value = variables == null ? void 0 : variables[node.name];
139
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: value != null ? value : `{${node.name}}` });
140
+ }
141
+ case "component": {
142
+ const Component = components == null ? void 0 : components[node.name];
143
+ if (!Component) return null;
144
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component, __spreadProps(__spreadValues({}, node.props), { children: ((_a2 = node.children) == null ? void 0 : _a2.length) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
145
+ RenderChildren,
146
+ {
147
+ nodes: node.children,
148
+ components,
149
+ variables,
150
+ conditions
151
+ }
152
+ ) : null }));
153
+ }
154
+ case "reference":
155
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderReference, { node, components });
156
+ case "condition":
157
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderCondition, { node, components, variables, conditions });
158
+ default:
159
+ return null;
160
+ }
161
+ }
162
+ function RenderText({ node }) {
163
+ let element = node.value;
164
+ if (node.marks) {
165
+ for (const mark of node.marks) {
166
+ switch (mark) {
167
+ case "bold":
168
+ element = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: element });
169
+ break;
170
+ case "italic":
171
+ element = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("em", { children: element });
172
+ break;
173
+ case "underline":
174
+ element = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("u", { children: element });
175
+ break;
176
+ case "code":
177
+ element = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: element });
178
+ break;
179
+ }
180
+ }
181
+ }
182
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: element });
183
+ }
184
+ function RenderImage({ image }) {
185
+ if (!image.src) return null;
186
+ const hasSize = image.width != null && image.height != null;
187
+ if (hasSize) {
188
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
189
+ import_image.default,
190
+ __spreadValues({
191
+ src: image.src,
192
+ alt: image.alt,
193
+ width: image.width,
194
+ height: image.height
195
+ }, image.blurDataURL ? { placeholder: "blur", blurDataURL: image.blurDataURL } : {})
196
+ );
197
+ }
198
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "relative block w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
199
+ import_image.default,
200
+ __spreadValues({
201
+ src: image.src,
202
+ alt: image.alt,
203
+ fill: true,
204
+ className: "object-cover"
205
+ }, image.blurDataURL ? { placeholder: "blur", blurDataURL: image.blurDataURL } : {})
206
+ ) });
207
+ }
208
+ function RenderReference({
209
+ node,
210
+ components
211
+ }) {
212
+ var _a2, _b2;
213
+ const entry = node.entry;
214
+ if (!entry) return null;
215
+ const collectionType = (_a2 = entry.sys) == null ? void 0 : _a2.type;
216
+ if (collectionType && (components == null ? void 0 : components[collectionType])) {
217
+ const Component = components[collectionType];
218
+ return node.display === "inline" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component, { entry, display: node.display }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component, { entry, display: node.display }) });
219
+ }
220
+ const title = entry.fields ? Object.values(entry.fields).find((v) => typeof v === "string" && v.length > 0) : null;
221
+ if (node.display === "inline") {
222
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: (_b2 = title != null ? title : collectionType) != null ? _b2 : "Reference" });
223
+ }
224
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "rounded border border-border p-3 my-2 bg-muted/30", children: [
225
+ collectionType && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs text-muted-foreground block mb-0.5", children: collectionType }),
226
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm font-medium", children: title != null ? title : "Untitled entry" })
227
+ ] });
228
+ }
229
+ function RenderCondition({
230
+ node,
231
+ components,
232
+ variables,
233
+ conditions
234
+ }) {
235
+ var _a2;
236
+ const branches = node.branches;
237
+ if (!branches || typeof branches !== "object") return null;
238
+ const selectedKey = node.field && conditions ? conditions[node.field] : void 0;
239
+ if (selectedKey) {
240
+ const doc = branches[selectedKey];
241
+ if (!doc || !((_a2 = doc.content) == null ? void 0 : _a2.length)) return null;
242
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: doc.content.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderNode, { node: child, components, variables, conditions }, i)) });
243
+ }
244
+ return null;
245
+ }
246
+ function RenderChildren({
247
+ nodes,
248
+ components,
249
+ variables,
250
+ conditions
251
+ }) {
252
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: nodes.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RenderNode, { node: child, components, variables, conditions }, i)) });
253
+ }
254
+
255
+ // components/public/SearchBox.tsx
256
+ var import_react = require("react");
257
+ var import_lucide_react = require("lucide-react");
258
+ var import_jsx_runtime3 = require("react/jsx-runtime");
259
+ function escapeRegex(s) {
260
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
261
+ }
262
+ function highlightTerms(text, terms) {
263
+ const filtered = terms.filter((t) => t.length > 0);
264
+ if (filtered.length === 0) return text;
265
+ const pattern = filtered.map((t) => escapeRegex(t) + "\\w*").join("|");
266
+ const parts = text.split(new RegExp(`(${pattern})`, "gi"));
267
+ return parts.map(
268
+ (part, i) => i % 2 === 1 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("mark", { className: "bg-yellow-200 dark:bg-yellow-800 text-inherit rounded-sm px-0.5", children: part }, i) : part
269
+ );
270
+ }
271
+ function SearchBox({ placeholder = "Search...", className = "" }) {
272
+ const inputRef = (0, import_react.useRef)(null);
273
+ const dropdownRef = (0, import_react.useRef)(null);
274
+ const [query, setQuery] = (0, import_react.useState)("");
275
+ const [results, setResults] = (0, import_react.useState)([]);
276
+ const [isOpen, setIsOpen] = (0, import_react.useState)(false);
277
+ const [isSearching, setIsSearching] = (0, import_react.useState)(false);
278
+ const [selectedIndex, setSelectedIndex] = (0, import_react.useState)(-1);
279
+ const debounceRef = (0, import_react.useRef)(void 0);
280
+ const doSearch = (0, import_react.useCallback)(async (q) => {
281
+ if (!q.trim()) {
282
+ setResults([]);
283
+ setIsOpen(false);
284
+ setSelectedIndex(-1);
285
+ return;
286
+ }
287
+ setIsSearching(true);
288
+ try {
289
+ const response = await fetch(`/api/search?q=${encodeURIComponent(q)}&limit=10`);
290
+ if (response.ok) {
291
+ const data = await response.json();
292
+ setResults(data.results || []);
293
+ setIsOpen(true);
294
+ setSelectedIndex(-1);
295
+ } else {
296
+ setResults([]);
297
+ setIsOpen(false);
298
+ }
299
+ } catch (e) {
300
+ setResults([]);
301
+ setIsOpen(false);
302
+ } finally {
303
+ setIsSearching(false);
304
+ }
305
+ }, []);
306
+ const handleChange = (e) => {
307
+ const value = e.target.value;
308
+ setQuery(value);
309
+ if (debounceRef.current) clearTimeout(debounceRef.current);
310
+ debounceRef.current = setTimeout(() => doSearch(value), 300);
311
+ };
312
+ const handleKeyDown = (e) => {
313
+ if (!isOpen || results.length === 0) {
314
+ return;
315
+ }
316
+ switch (e.key) {
317
+ case "ArrowDown":
318
+ e.preventDefault();
319
+ setSelectedIndex((prev) => prev < results.length - 1 ? prev + 1 : 0);
320
+ break;
321
+ case "ArrowUp":
322
+ e.preventDefault();
323
+ setSelectedIndex((prev) => prev > 0 ? prev - 1 : results.length - 1);
324
+ break;
325
+ case "Enter":
326
+ e.preventDefault();
327
+ if (selectedIndex >= 0 && results[selectedIndex]) {
328
+ navigateToResult(results[selectedIndex]);
329
+ }
330
+ break;
331
+ case "Escape":
332
+ e.preventDefault();
333
+ setIsOpen(false);
334
+ setSelectedIndex(-1);
335
+ break;
336
+ default:
337
+ break;
338
+ }
339
+ };
340
+ const navigateToResult = (result) => {
341
+ window.location.href = result.url;
342
+ };
343
+ (0, import_react.useEffect)(() => {
344
+ const handleClickOutside = (event) => {
345
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) {
346
+ setIsOpen(false);
347
+ }
348
+ };
349
+ document.addEventListener("mousedown", handleClickOutside);
350
+ return () => document.removeEventListener("mousedown", handleClickOutside);
351
+ }, []);
352
+ (0, import_react.useEffect)(() => {
353
+ if (selectedIndex >= 0 && dropdownRef.current) {
354
+ const items = dropdownRef.current.querySelectorAll("[data-result-item]");
355
+ if (items[selectedIndex]) {
356
+ items[selectedIndex].scrollIntoView({ block: "nearest" });
357
+ }
358
+ }
359
+ }, [selectedIndex]);
360
+ const handleClear = () => {
361
+ var _a2;
362
+ setQuery("");
363
+ setResults([]);
364
+ setIsOpen(false);
365
+ setSelectedIndex(-1);
366
+ (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
367
+ };
368
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: cn("relative w-full", className), children: [
369
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative", children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 text-gray-400", size: 18 }),
371
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
372
+ "input",
373
+ {
374
+ ref: inputRef,
375
+ type: "text",
376
+ value: query,
377
+ onChange: handleChange,
378
+ onKeyDown: handleKeyDown,
379
+ onFocus: () => {
380
+ if (query.trim() && results.length > 0) {
381
+ setIsOpen(true);
382
+ }
383
+ },
384
+ placeholder,
385
+ className: cn(
386
+ "w-full pl-10 pr-10 py-2 text-sm border border-gray-200 rounded-lg",
387
+ "bg-white text-gray-900 placeholder-gray-400",
388
+ "focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",
389
+ "dark:bg-gray-900 dark:border-gray-700 dark:text-gray-100 dark:placeholder-gray-500"
390
+ ),
391
+ autoComplete: "off"
392
+ }
393
+ ),
394
+ query && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
395
+ "button",
396
+ {
397
+ type: "button",
398
+ onClick: handleClear,
399
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors",
400
+ "aria-label": "Clear search",
401
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.X, { size: 18 })
402
+ }
403
+ )
404
+ ] }),
405
+ isOpen && (results.length > 0 || isSearching) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
406
+ "div",
407
+ {
408
+ ref: dropdownRef,
409
+ className: cn(
410
+ "absolute top-full left-0 right-0 mt-2 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700",
411
+ "rounded-lg shadow-lg z-50 max-h-96 overflow-y-auto"
412
+ ),
413
+ children: [
414
+ isSearching && results.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center", children: "Searching..." }),
415
+ results.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "divide-y divide-gray-100 dark:divide-gray-800", children: results.map((result, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
416
+ "li",
417
+ {
418
+ "data-result-item": true,
419
+ className: cn(
420
+ "p-0 transition-colors",
421
+ index === selectedIndex ? "bg-blue-50 dark:bg-blue-900/30" : "bg-white dark:bg-gray-900 hover:bg-gray-50 dark:hover:bg-gray-800"
422
+ ),
423
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
424
+ "button",
425
+ {
426
+ type: "button",
427
+ onClick: () => navigateToResult(result),
428
+ className: "w-full text-left px-4 py-3 flex flex-col gap-1",
429
+ children: [
430
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
431
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "font-medium text-gray-900 dark:text-gray-100 truncate text-sm", children: highlightTerms(result.title, Object.keys(result.match)) }),
432
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "shrink-0 text-xs text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded", children: result.typeLabel })
433
+ ] }),
434
+ Object.values(result.match).flat().includes("content") && result.snippet && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400 line-clamp-2 text-left", children: highlightTerms(result.snippet, Object.keys(result.match)) })
435
+ ]
436
+ }
437
+ )
438
+ },
439
+ result.id
440
+ )) })
441
+ ]
442
+ }
443
+ )
444
+ ] });
445
+ }
446
+ // Annotate the CommonJS export names for ESM import in node:
447
+ 0 && (module.exports = {
448
+ MarkdownContent,
449
+ RichTextContent,
450
+ SearchBox
451
+ });
452
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../components/public/index.ts","../../../components/public/MarkdownContent.tsx","../../../lib/utils.ts","../../../components/public/RichTextContent.tsx","../../../components/public/SearchBox.tsx"],"sourcesContent":["export { default as MarkdownContent } from './MarkdownContent';\nexport { default as RichTextContent } from './RichTextContent';\nexport { default as SearchBox } from './SearchBox';\nexport type { SearchBoxProps } from './SearchBox';\n","import React from 'react';\n\nimport Markdown from 'react-markdown';\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize';\nimport remarkGfm from 'remark-gfm';\n\nimport { cn } from '../../lib/utils';\n\n/**\n * Sanitization schema: extends the default GitHub-flavoured schema with\n * the same tag/attribute allowlist that was previously applied via sanitize-html.\n */\nconst sanitizeSchema = {\n ...defaultSchema,\n tagNames: [\n ...(defaultSchema.tagNames ?? []),\n 'u', // underline — not in GitHub default\n ],\n attributes: {\n ...defaultSchema.attributes,\n code: [...(defaultSchema.attributes?.code ?? []), 'className'],\n img: ['src', 'alt', 'title'],\n },\n};\n\ntype MarkdownContentProps = {\n children: string | undefined | null;\n className?: string;\n};\n\n/**\n * Renders raw Markdown as React elements using react-markdown with GFM support\n * and HTML sanitization. Replaces the previous `dangerouslySetInnerHTML` approach.\n */\nconst MarkdownContent = ({ children, className }: MarkdownContentProps) => {\n if (!children) {\n return null;\n }\n\n return (\n <div className={cn(className)}>\n <Markdown remarkPlugins={[remarkGfm]} rehypePlugins={[[rehypeSanitize, sanitizeSchema]]}>\n {children}\n </Markdown>\n </div>\n );\n};\n\nexport default MarkdownContent;\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge Tailwind classes with clsx — the standard utility for Radix UI + Tailwind components.\n * Handles conditional classes, deduplication, and conflict resolution.\n *\n * @example\n * cn('px-4 py-2', isActive && 'bg-primary text-primary-foreground', className)\n */\nexport const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs));\n","import React from 'react';\nimport Image from 'next/image';\n\nimport type { RichTextDocument, RichTextNode, ResolvedImageField } from '../../types';\nimport { cn } from '../../lib/utils';\n\ntype RichTextContentProps = {\n document: RichTextDocument | null | undefined;\n /** Map custom component names to React components for rendering `{ type: 'component' }` nodes. */\n components?: Record<string, React.ComponentType<any>>;\n /** Variable substitutions for `{ type: 'variable' }` nodes. */\n variables?: Record<string, string>;\n /** Condition branch selections: map condition field names to the branch key to render. */\n conditions?: Record<string, string>;\n className?: string;\n};\n\n/**\n * Renders a `RichTextDocument` AST to React elements.\n *\n * Standard markdown nodes become HTML elements.\n * `CmsImage` embeds render as `next/image`.\n * Custom components and variables are resolved from the provided props.\n */\nconst RichTextContent = ({ document, components, variables, conditions, className }: RichTextContentProps) => {\n if (!document || !document.content?.length) return null;\n return (\n <div className={cn(className)}>\n {document.content.map((node, i) => (\n <RenderNode key={i} node={node} components={components} variables={variables} conditions={conditions} />\n ))}\n </div>\n );\n};\n\nexport default RichTextContent;\n\n// ---------------------------------------------------------------------------\n// Internal node renderer\n// ---------------------------------------------------------------------------\n\ntype NodeProps = {\n node: RichTextNode;\n components?: Record<string, React.ComponentType<any>>;\n variables?: Record<string, string>;\n conditions?: Record<string, string>;\n};\n\nfunction RenderNode({ node, components, variables, conditions }: NodeProps) {\n switch (node.type) {\n case 'paragraph':\n return (\n <p>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </p>\n );\n\n case 'heading': {\n const Tag = `h${node.level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n return (\n <Tag>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </Tag>\n );\n }\n\n case 'blockquote':\n return (\n <blockquote>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </blockquote>\n );\n\n case 'list':\n if (node.ordered) {\n return (\n <ol>\n <RenderChildren\n nodes={node.children}\n components={components}\n variables={variables}\n conditions={conditions}\n />\n </ol>\n );\n }\n return (\n <ul>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </ul>\n );\n\n case 'listItem':\n return (\n <li>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </li>\n );\n\n case 'thematicBreak':\n return <hr />;\n\n case 'code':\n return (\n <pre>\n <code className={node.lang ? `language-${node.lang}` : undefined}>{node.value}</code>\n </pre>\n );\n\n case 'text':\n return <RenderText node={node} />;\n\n case 'link':\n return (\n <a href={node.url}>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </a>\n );\n\n case 'image':\n return <RenderImage image={node.image} />;\n\n case 'break':\n return <br />;\n\n case 'html':\n return null;\n\n case 'variable': {\n const value = variables?.[node.name];\n return <>{value ?? `{${node.name}}`}</>;\n }\n\n case 'component': {\n const Component = components?.[node.name];\n if (!Component) return null;\n return (\n <Component {...node.props}>\n {node.children?.length ? (\n <RenderChildren\n nodes={node.children}\n components={components}\n variables={variables}\n conditions={conditions}\n />\n ) : null}\n </Component>\n );\n }\n\n case 'reference':\n return <RenderReference node={node} components={components} />;\n\n case 'condition':\n return <RenderCondition node={node} components={components} variables={variables} conditions={conditions} />;\n\n default:\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Inline text with marks\n// ---------------------------------------------------------------------------\n\nfunction RenderText({ node }: { node: Extract<RichTextNode, { type: 'text' }> }) {\n let element: React.ReactNode = node.value;\n if (node.marks) {\n for (const mark of node.marks) {\n switch (mark) {\n case 'bold':\n element = <strong>{element}</strong>;\n break;\n case 'italic':\n element = <em>{element}</em>;\n break;\n case 'underline':\n element = <u>{element}</u>;\n break;\n case 'code':\n element = <code>{element}</code>;\n break;\n }\n }\n }\n return <>{element}</>;\n}\n\n// ---------------------------------------------------------------------------\n// Image rendering via next/image\n// ---------------------------------------------------------------------------\n\nfunction RenderImage({ image }: { image: ResolvedImageField }) {\n if (!image.src) return null;\n\n const hasSize = image.width != null && image.height != null;\n\n if (hasSize) {\n return (\n <Image\n src={image.src}\n alt={image.alt}\n width={image.width!}\n height={image.height!}\n {...(image.blurDataURL ? { placeholder: 'blur' as const, blurDataURL: image.blurDataURL } : {})}\n />\n );\n }\n\n // Fallback for images without dimensions — use fill with a container\n return (\n <span className=\"relative block w-full\" style={{ aspectRatio: '16/9' }}>\n <Image\n src={image.src}\n alt={image.alt}\n fill\n className=\"object-cover\"\n {...(image.blurDataURL ? { placeholder: 'blur' as const, blurDataURL: image.blurDataURL } : {})}\n />\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Reference rendering — embedded entry references\n// ---------------------------------------------------------------------------\n\ntype ReferenceNode = Extract<RichTextNode, { type: 'reference' }>;\n\nfunction RenderReference({\n node,\n components,\n}: {\n node: ReferenceNode;\n components?: Record<string, React.ComponentType<any>>;\n}) {\n const entry = node.entry as { sys?: { type?: string }; fields?: Record<string, unknown> } | null;\n if (!entry) return null;\n\n const collectionType = entry.sys?.type;\n\n // If consumer provided a custom component for this collection type, use it\n if (collectionType && components?.[collectionType]) {\n const Component = components[collectionType];\n return node.display === 'inline' ? (\n <Component entry={entry} display={node.display} />\n ) : (\n <div>\n <Component entry={entry} display={node.display} />\n </div>\n );\n }\n\n // Default fallback: show the entry's title field if available\n const title = entry.fields\n ? (Object.values(entry.fields).find((v) => typeof v === 'string' && v.length > 0) as string | undefined)\n : null;\n\n if (node.display === 'inline') {\n return <span>{title ?? collectionType ?? 'Reference'}</span>;\n }\n\n return (\n <div className=\"rounded border border-border p-3 my-2 bg-muted/30\">\n {collectionType && <span className=\"text-xs text-muted-foreground block mb-0.5\">{collectionType}</span>}\n <span className=\"text-sm font-medium\">{title ?? 'Untitled entry'}</span>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Condition rendering — select and render the appropriate branch\n// ---------------------------------------------------------------------------\n\ntype ConditionNode = Extract<RichTextNode, { type: 'condition' }>;\n\nfunction RenderCondition({\n node,\n components,\n variables,\n conditions,\n}: {\n node: ConditionNode;\n components?: Record<string, React.ComponentType<any>>;\n variables?: Record<string, string>;\n conditions?: Record<string, string>;\n}) {\n const branches = node.branches;\n if (!branches || typeof branches !== 'object') return null;\n\n // If a condition selection was provided, render only the selected branch\n const selectedKey = node.field && conditions ? conditions[node.field] : undefined;\n\n if (selectedKey) {\n const doc = (branches as Record<string, RichTextDocument>)[selectedKey];\n if (!doc || !doc.content?.length) return null;\n return (\n <>\n {doc.content.map((child, i) => (\n <RenderNode key={i} node={child} components={components} variables={variables} conditions={conditions} />\n ))}\n </>\n );\n }\n\n // No condition provided — render nothing (consumer must specify which branch to show)\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Helper: render a list of child nodes\n// ---------------------------------------------------------------------------\n\nfunction RenderChildren({\n nodes,\n components,\n variables,\n conditions,\n}: { nodes: RichTextNode[] } & Pick<NodeProps, 'components' | 'variables' | 'conditions'>) {\n return (\n <>\n {nodes.map((child, i) => (\n <RenderNode key={i} node={child} components={components} variables={variables} conditions={conditions} />\n ))}\n </>\n );\n}\n","'use client';\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { Search, X } from 'lucide-react';\n\nimport type { SearchResult } from '../../lib/searchIndex';\nimport { cn } from '../../lib/utils';\n\n/** Escape special regex characters in a string. */\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Split text into alternating non-match/match segments and wrap matches in <mark>.\n * Uses prefix matching (term\\w*) to support MiniSearch's prefix: true behavior.\n */\nfunction highlightTerms(text: string, terms: string[]): React.ReactNode {\n const filtered = terms.filter((t) => t.length > 0);\n if (filtered.length === 0) return text;\n\n const pattern = filtered.map((t) => escapeRegex(t) + '\\\\w*').join('|');\n const parts = text.split(new RegExp(`(${pattern})`, 'gi'));\n\n return parts.map((part, i) =>\n i % 2 === 1 ? (\n <mark key={i} className=\"bg-yellow-200 dark:bg-yellow-800 text-inherit rounded-sm px-0.5\">\n {part}\n </mark>\n ) : (\n part\n ),\n );\n}\n\nexport interface SearchBoxProps {\n placeholder?: string;\n className?: string;\n}\n\nexport default function SearchBox({ placeholder = 'Search...', className = '' }: SearchBoxProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const [query, setQuery] = useState('');\n const [results, setResults] = useState<SearchResult[]>([]);\n const [isOpen, setIsOpen] = useState(false);\n const [isSearching, setIsSearching] = useState(false);\n const [selectedIndex, setSelectedIndex] = useState(-1);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n // Fetch search results\n const doSearch = useCallback(async (q: string) => {\n if (!q.trim()) {\n setResults([]);\n setIsOpen(false);\n setSelectedIndex(-1);\n return;\n }\n\n setIsSearching(true);\n try {\n const response = await fetch(`/api/search?q=${encodeURIComponent(q)}&limit=10`);\n if (response.ok) {\n const data = await response.json();\n setResults(data.results || []);\n setIsOpen(true);\n setSelectedIndex(-1);\n } else {\n setResults([]);\n setIsOpen(false);\n }\n } catch {\n setResults([]);\n setIsOpen(false);\n } finally {\n setIsSearching(false);\n }\n }, []);\n\n // Handle input change with debounce\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value;\n setQuery(value);\n\n if (debounceRef.current) clearTimeout(debounceRef.current);\n debounceRef.current = setTimeout(() => doSearch(value), 300);\n };\n\n // Handle keyboard navigation\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isOpen || results.length === 0) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n setSelectedIndex((prev) => (prev < results.length - 1 ? prev + 1 : 0));\n break;\n case 'ArrowUp':\n e.preventDefault();\n setSelectedIndex((prev) => (prev > 0 ? prev - 1 : results.length - 1));\n break;\n case 'Enter':\n e.preventDefault();\n if (selectedIndex >= 0 && results[selectedIndex]) {\n navigateToResult(results[selectedIndex]);\n }\n break;\n case 'Escape':\n e.preventDefault();\n setIsOpen(false);\n setSelectedIndex(-1);\n break;\n default:\n break;\n }\n };\n\n // Navigate to a result\n const navigateToResult = (result: SearchResult) => {\n window.location.href = result.url;\n };\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node) &&\n inputRef.current &&\n !inputRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Scroll selected result into view\n useEffect(() => {\n if (selectedIndex >= 0 && dropdownRef.current) {\n const items = dropdownRef.current.querySelectorAll('[data-result-item]');\n if (items[selectedIndex]) {\n items[selectedIndex].scrollIntoView({ block: 'nearest' });\n }\n }\n }, [selectedIndex]);\n\n const handleClear = () => {\n setQuery('');\n setResults([]);\n setIsOpen(false);\n setSelectedIndex(-1);\n inputRef.current?.focus();\n };\n\n return (\n <div className={cn('relative w-full', className)}>\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 text-gray-400\" size={18} />\n <input\n ref={inputRef}\n type=\"text\"\n value={query}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n if (query.trim() && results.length > 0) {\n setIsOpen(true);\n }\n }}\n placeholder={placeholder}\n className={cn(\n 'w-full pl-10 pr-10 py-2 text-sm border border-gray-200 rounded-lg',\n 'bg-white text-gray-900 placeholder-gray-400',\n 'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent',\n 'dark:bg-gray-900 dark:border-gray-700 dark:text-gray-100 dark:placeholder-gray-500',\n )}\n autoComplete=\"off\"\n />\n {query && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors\"\n aria-label=\"Clear search\"\n >\n <X size={18} />\n </button>\n )}\n </div>\n\n {/* Dropdown results */}\n {isOpen && (results.length > 0 || isSearching) && (\n <div\n ref={dropdownRef}\n className={cn(\n 'absolute top-full left-0 right-0 mt-2 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700',\n 'rounded-lg shadow-lg z-50 max-h-96 overflow-y-auto',\n )}\n >\n {isSearching && results.length === 0 && (\n <div className=\"px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center\">Searching...</div>\n )}\n\n {results.length > 0 && (\n <ul className=\"divide-y divide-gray-100 dark:divide-gray-800\">\n {results.map((result, index) => (\n <li\n key={result.id}\n data-result-item\n className={cn(\n 'p-0 transition-colors',\n index === selectedIndex\n ? 'bg-blue-50 dark:bg-blue-900/30'\n : 'bg-white dark:bg-gray-900 hover:bg-gray-50 dark:hover:bg-gray-800',\n )}\n >\n <button\n type=\"button\"\n onClick={() => navigateToResult(result)}\n className=\"w-full text-left px-4 py-3 flex flex-col gap-1\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"font-medium text-gray-900 dark:text-gray-100 truncate text-sm\">\n {highlightTerms(result.title, Object.keys(result.match))}\n </span>\n <span className=\"shrink-0 text-xs text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded\">\n {result.typeLabel}\n </span>\n </div>\n {Object.values(result.match).flat().includes('content') && result.snippet && (\n <p className=\"text-xs text-gray-500 dark:text-gray-400 line-clamp-2 text-left\">\n {highlightTerms(result.snippet, Object.keys(result.match))}\n </p>\n )}\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["Markdown","remarkGfm","rehypeSanitize","import_jsx_runtime","document","_a","Image","_b","import_jsx_runtime","_a"]}