@vp-tw/dirwell 0.0.0-stage → 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +182 -2
  4. package/THEME_PACKAGE_CONTRACT.md +64 -0
  5. package/THEMING.md +88 -0
  6. package/THIRD_PARTY_NOTICES.md +14 -0
  7. package/dist/bin.d.mts +1 -0
  8. package/dist/bin.mjs +306 -0
  9. package/dist/bin.mjs.map +1 -0
  10. package/dist/bun.d.mts +7 -0
  11. package/dist/bun.mjs +7 -0
  12. package/dist/bun.mjs.map +1 -0
  13. package/dist/config-BJG2Zc3Q.d.mts +34 -0
  14. package/dist/dev-server-Q7NC1wiB.mjs +132 -0
  15. package/dist/dev-server-Q7NC1wiB.mjs.map +1 -0
  16. package/dist/esbuild.d.mts +7 -0
  17. package/dist/esbuild.mjs +7 -0
  18. package/dist/esbuild.mjs.map +1 -0
  19. package/dist/farm.d.mts +7 -0
  20. package/dist/farm.mjs +7 -0
  21. package/dist/farm.mjs.map +1 -0
  22. package/dist/generator-CtX3iHhK.mjs +1783 -0
  23. package/dist/generator-CtX3iHhK.mjs.map +1 -0
  24. package/dist/index.d.mts +47 -0
  25. package/dist/index.mjs +74 -0
  26. package/dist/index.mjs.map +1 -0
  27. package/dist/model-CWjYM17j.d.mts +100 -0
  28. package/dist/rolldown.d.mts +7 -0
  29. package/dist/rolldown.mjs +7 -0
  30. package/dist/rolldown.mjs.map +1 -0
  31. package/dist/rollup.d.mts +7 -0
  32. package/dist/rollup.mjs +7 -0
  33. package/dist/rollup.mjs.map +1 -0
  34. package/dist/rsbuild.d.mts +7 -0
  35. package/dist/rsbuild.mjs +7 -0
  36. package/dist/rsbuild.mjs.map +1 -0
  37. package/dist/rspack.d.mts +7 -0
  38. package/dist/rspack.mjs +7 -0
  39. package/dist/rspack.mjs.map +1 -0
  40. package/dist/theme-components-CXzvdQY-.mjs +8 -0
  41. package/dist/theme-components-CXzvdQY-.mjs.map +1 -0
  42. package/dist/theme-components-DW0fv9_C.d.mts +141 -0
  43. package/dist/theme-components.d.mts +2 -0
  44. package/dist/theme-components.mjs +2 -0
  45. package/dist/theme-runtime.js +1128 -0
  46. package/dist/theme-worker.js +27 -0
  47. package/dist/unplugin-CKRUCTgW.d.mts +16 -0
  48. package/dist/unplugin-p6AXhL4F.mjs +421 -0
  49. package/dist/unplugin-p6AXhL4F.mjs.map +1 -0
  50. package/dist/unplugin.d.mts +2 -0
  51. package/dist/unplugin.mjs +2 -0
  52. package/dist/vite-JBsvRvuW.mjs +282 -0
  53. package/dist/vite-JBsvRvuW.mjs.map +1 -0
  54. package/dist/vite.d.mts +12 -0
  55. package/dist/vite.mjs +2 -0
  56. package/dist/vscode-icons/NOTICE.txt +16 -0
  57. package/dist/vscode-icons/default_file.svg +1 -0
  58. package/dist/vscode-icons/default_folder.svg +1 -0
  59. package/dist/vscode-icons/file_type_css.svg +1 -0
  60. package/dist/vscode-icons/file_type_html.svg +1 -0
  61. package/dist/vscode-icons/file_type_image.svg +1 -0
  62. package/dist/vscode-icons/file_type_js.svg +1 -0
  63. package/dist/vscode-icons/file_type_json.svg +1 -0
  64. package/dist/vscode-icons/file_type_markdown.svg +1 -0
  65. package/dist/vscode-icons/file_type_pdf2.svg +1 -0
  66. package/dist/vscode-icons/file_type_shell.svg +1 -0
  67. package/dist/vscode-icons/file_type_text.svg +1 -0
  68. package/dist/vscode-icons/file_type_typescript.svg +1 -0
  69. package/dist/vscode-icons/file_type_yaml.svg +1 -0
  70. package/dist/vscode-icons/file_type_zip.svg +1 -0
  71. package/dist/webpack.d.mts +7 -0
  72. package/dist/webpack.mjs +7 -0
  73. package/dist/webpack.mjs.map +1 -0
  74. package/package.json +133 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator-CtX3iHhK.mjs","names":[],"sources":["../src/filters.ts","../src/config.ts","../src/timestamp.ts","../src/theme-default/components.ts","../src/theme-default/styles.ts","../src/theme-project.ts","../src/theme-default/vscode-icons.ts","../src/theme-default/icon-set.ts","../src/theme-default.ts","../src/generator.ts"],"sourcesContent":["import { readdir, readlink } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport picomatch from \"picomatch\";\n\nexport function normalizePathPatterns(value: unknown, name: string): readonly string[] {\n if (value === undefined) return [];\n const patterns = typeof value === \"string\" ? [value] : value;\n if (\n !Array.isArray(patterns) ||\n patterns.some(\n (pattern) =>\n typeof pattern !== \"string\" ||\n pattern.length === 0 ||\n pattern.startsWith(\"/\") ||\n /^[A-Za-z]:/.test(pattern) ||\n pattern.startsWith(\"!\") ||\n pattern.includes(\"\\\\\") ||\n pattern.split(\"/\").some((segment) => segment === \".\" || segment === \"..\"),\n )\n ) {\n throw new TypeError(`${name} must contain root-relative glob patterns using forward slashes`);\n }\n return patterns as readonly string[];\n}\n\nfunction isWithin(parent: string, candidate: string): boolean {\n const relative = path.relative(parent, candidate);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nexport interface SourceSelection {\n readonly selected: ReadonlySet<string>;\n readonly symlinks: ReadonlySet<string>;\n readonly mirroredSymlinks: ReadonlySet<string>;\n}\n\n/** Select physical source paths; parent directories remain when a descendant matches. */\nexport async function selectSourcePaths(\n sourceDir: string,\n outputDir: string,\n include: unknown,\n exclude: unknown,\n ignoredPaths: readonly string[] = [],\n): Promise<SourceSelection> {\n const ignored = ignoredPaths.map((value) => path.resolve(value));\n const included = normalizePathPatterns(include, \"include\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const excluded = normalizePathPatterns(exclude, \"exclude\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const selected = new Set<string>([\"\"]);\n const symlinks = new Map<string, string>();\n\n async function visit(\n directory: string,\n relativeDir: string,\n inheritedInclude: boolean,\n ): Promise<boolean> {\n let hasSelected = false;\n for (const entry of await readdir(directory, { withFileTypes: true })) {\n const absolutePath = path.join(directory, entry.name);\n if (\n isWithin(outputDir, absolutePath) ||\n ignored.some((value) => isWithin(value, absolutePath))\n )\n continue;\n const relativePath = path.posix.join(relativeDir, entry.name);\n const directoryLike = entry.isDirectory();\n const matches = (matcher: (value: string) => boolean) =>\n matcher(relativePath) || (directoryLike && matcher(`${relativePath}/`));\n if (excluded.some(matches)) continue;\n const includedHere = inheritedInclude || included.some(matches);\n if (directoryLike) {\n const hasSelectedChild = await visit(absolutePath, relativePath, includedHere);\n if (included.length === 0 || includedHere || hasSelectedChild) {\n selected.add(relativePath);\n hasSelected = true;\n }\n } else if (included.length === 0 || includedHere) {\n selected.add(relativePath);\n hasSelected = true;\n if (entry.isSymbolicLink()) symlinks.set(relativePath, await readlink(absolutePath));\n }\n }\n return hasSelected;\n }\n\n await visit(sourceDir, \"\", false);\n // Absolute, escaping, and filtered targets cannot remain valid inside the copied tree.\n const mirroredSymlinks = new Set<string>();\n for (const [relativePath, target] of symlinks) {\n if (path.isAbsolute(target)) continue;\n const targetPath = path.resolve(sourceDir, path.dirname(relativePath), target);\n if (!isWithin(sourceDir, targetPath)) continue;\n const targetRelativePath = path.relative(sourceDir, targetPath).split(path.sep).join(\"/\");\n if (selected.has(targetRelativePath)) mirroredSymlinks.add(relativePath);\n }\n return { selected, symlinks: new Set(symlinks.keys()), mirroredSymlinks };\n}\n","import { loadConfig } from \"c12\";\nimport path from \"node:path\";\nimport type { ExplorerTheme, GenerateOptions, SortOptions } from \"./model.ts\";\nimport { normalizePathPatterns } from \"./filters.ts\";\n\nexport interface DirwellConfig {\n readonly base?: string;\n readonly include?: GenerateOptions[\"include\"];\n readonly exclude?: GenerateOptions[\"exclude\"];\n readonly extends?: string | readonly string[];\n readonly mode?: \"mpa\" | \"ssg\";\n readonly mirror?: boolean;\n readonly outDir?: string;\n readonly outputName?: GenerateOptions[\"outputName\"];\n readonly root?: string;\n readonly server?: {\n readonly host?: string;\n readonly port?: number;\n };\n readonly symlinks?: GenerateOptions[\"symlinks\"];\n readonly sort?: SortOptions;\n readonly theme?: ExplorerTheme;\n readonly urls?: \"base\" | \"html-base\" | \"relative\";\n}\n\nexport interface DirwellConfigContext {\n readonly command: \"build\" | \"daemon\" | \"serve\";\n}\n\nexport type DirwellConfigInput =\n | DirwellConfig\n | ((context: DirwellConfigContext) => DirwellConfig | Promise<DirwellConfig>);\n\nexport function defineConfig<const T extends DirwellConfigInput>(config: T): T {\n return config;\n}\n\nfunction assertOptionalBoolean(value: unknown, key: string): asserts value is boolean | undefined {\n if (value !== undefined && typeof value !== \"boolean\") {\n throw new TypeError(`${key} must be a boolean`);\n }\n}\n\nfunction assertOptionalString(value: unknown, key: string): asserts value is string | undefined {\n if (value !== undefined && (typeof value !== \"string\" || value.length === 0)) {\n throw new TypeError(`${key} must be a non-empty string`);\n }\n}\n\nexport function validateConfig(value: unknown): asserts value is DirwellConfig {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new TypeError(\"Dirwell config must resolve to an object\");\n }\n const config = value as Record<string, unknown>;\n assertOptionalString(config.root, \"root\");\n assertOptionalString(config.outDir, \"outDir\");\n assertOptionalString(config.base, \"base\");\n normalizePathPatterns(config.include, \"include\");\n normalizePathPatterns(config.exclude, \"exclude\");\n if (\n config.extends !== undefined &&\n typeof config.extends !== \"string\" &&\n (!Array.isArray(config.extends) ||\n config.extends.some((entry) => typeof entry !== \"string\" || entry.length === 0))\n ) {\n throw new TypeError(\"extends must be a string or an array of non-empty strings\");\n }\n assertOptionalBoolean(config.mirror, \"mirror\");\n if (config.mode !== undefined && config.mode !== \"mpa\" && config.mode !== \"ssg\") {\n throw new TypeError('mode must be either \"ssg\" or \"mpa\"');\n }\n if (\n config.urls !== undefined &&\n config.urls !== \"relative\" &&\n config.urls !== \"base\" &&\n config.urls !== \"html-base\"\n ) {\n throw new TypeError('urls must be \"relative\", \"base\", or \"html-base\"');\n }\n if (\n config.outputName !== undefined &&\n typeof config.outputName !== \"function\" &&\n (typeof config.outputName !== \"string\" || config.outputName.length === 0)\n ) {\n throw new TypeError(\"outputName must be a non-empty string or function\");\n }\n if (config.theme !== undefined) {\n const theme = config.theme as Record<string, unknown>;\n if (typeof theme !== \"object\" || theme === null || typeof theme.render !== \"function\") {\n throw new TypeError(\"theme must implement render(context)\");\n }\n }\n if (config.server !== undefined) {\n if (typeof config.server !== \"object\" || config.server === null) {\n throw new TypeError(\"server must be an object\");\n }\n const server = config.server as Record<string, unknown>;\n assertOptionalString(server.host, \"server.host\");\n if (\n server.port !== undefined &&\n (typeof server.port !== \"number\" || !Number.isInteger(server.port) || server.port < 0)\n ) {\n throw new TypeError(\"server.port must be a non-negative integer\");\n }\n }\n if (config.sort !== undefined) {\n if (typeof config.sort !== \"object\" || config.sort === null) {\n throw new TypeError(\"sort must be an object\");\n }\n const sort = config.sort as Record<string, unknown>;\n if (\n sort.field !== undefined &&\n (typeof sort.field !== \"string\" || ![\"name\", \"modified\", \"size\"].includes(sort.field))\n ) {\n throw new TypeError('sort.field must be \"name\", \"modified\", or \"size\"');\n }\n if (\n sort.nameMode !== undefined &&\n (typeof sort.nameMode !== \"string\" ||\n ![\"unicode\", \"locale\", \"natural\"].includes(sort.nameMode))\n ) {\n throw new TypeError('sort.nameMode must be \"unicode\", \"locale\", or \"natural\"');\n }\n if (sort.direction !== undefined && sort.direction !== \"asc\" && sort.direction !== \"desc\") {\n throw new TypeError('sort.direction must be \"asc\" or \"desc\"');\n }\n assertOptionalBoolean(sort.directoriesFirst, \"sort.directoriesFirst\");\n }\n}\n\nexport async function loadDirwellConfig(\n cwd: string,\n command: DirwellConfigContext[\"command\"],\n): Promise<{ config: DirwellConfig; configFile: string | null }> {\n const loaded = await loadConfig<DirwellConfig>({\n name: \"dirwell\",\n cwd,\n context: { command } satisfies DirwellConfigContext,\n defaults: {},\n rcFile: false,\n globalRc: false,\n });\n validateConfig(loaded.config);\n return {\n config: loaded.config,\n configFile: loaded._configFile ?? null,\n };\n}\n\nexport function resolveGenerateOptions(\n cwd: string,\n config: DirwellConfig,\n overrides: Partial<Pick<DirwellConfig, \"base\" | \"mode\" | \"outDir\" | \"root\" | \"urls\">> = {},\n): GenerateOptions {\n const sourceDir = path.resolve(cwd, overrides.root ?? config.root ?? \".\");\n const outputDir = path.resolve(cwd, overrides.outDir ?? config.outDir ?? \"dist\");\n return {\n sourceDir,\n outputDir,\n ...(overrides.base === undefined && config.base === undefined\n ? {}\n : { base: overrides.base ?? config.base }),\n ...(overrides.mode === undefined && config.mode === undefined\n ? {}\n : { mode: overrides.mode ?? config.mode }),\n ...(config.mirror === undefined ? {} : { mirror: config.mirror }),\n ...(config.include === undefined ? {} : { include: config.include }),\n ...(config.exclude === undefined ? {} : { exclude: config.exclude }),\n ...(config.outputName === undefined ? {} : { outputName: config.outputName }),\n ...(config.symlinks === undefined ? {} : { symlinks: config.symlinks }),\n ...(config.sort === undefined ? {} : { sort: config.sort }),\n ...(config.theme === undefined ? {} : { theme: config.theme }),\n ...(overrides.urls === undefined && config.urls === undefined\n ? {}\n : { urlStrategy: overrides.urls ?? config.urls }),\n };\n}\n","/** Keep generated dates readable without JavaScript or a viewer-specific time zone. */\nexport function utcTimestamp(\n value: string | null | undefined,\n): { readonly datetime: string; readonly label: string } | null {\n if (\n typeof value !== \"string\" ||\n !/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/.test(value)\n )\n return null;\n const instant = new Date(value);\n if (Number.isNaN(instant.getTime())) return null;\n const datetime = instant.toISOString();\n return { datetime, label: `${datetime.slice(0, 16).replace(\"T\", \" \")} UTC` };\n}\n","import type { DirwellThemeComponents, IconName } from \"../theme-components.ts\";\nimport type { FileSystemEntry } from \"../model.ts\";\nimport { utcTimestamp } from \"../timestamp.ts\";\n\nexport function escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\");\n}\n\ntype SelectControlName = \"color-scheme\" | \"sort-field\" | \"name-mode\" | \"sort-direction\";\n\nfunction renderSelectControl(\n name: SelectControlName,\n options: readonly (readonly [value: string, label: string])[],\n): string {\n const choices = options\n .map(([value, label]) => `<option value=\"${escapeHtml(value)}\">${escapeHtml(label)}</option>`)\n .join(\"\");\n return `<select data-${name}>${choices}</select>`;\n}\n\nfunction renderTypeFilters(): string {\n return `<fieldset class=\"type-filters\" data-type-filters><legend class=\"visually-hidden\">Show file types</legend>${(\n [\n [\"directory\", \"Folders\"],\n [\"file\", \"Files\"],\n [\"link\", \"Links\"],\n ] as const\n )\n .map(\n ([value, label]) =>\n `<label><input type=\"checkbox\" value=\"${value}\" data-type-filter checked><span>${label}</span></label>`,\n )\n .join(\"\")}</fieldset>`;\n}\n\nfunction formatSize(bytes: number): string {\n const units = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"] as const;\n let value = bytes;\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit += 1;\n }\n return `${value.toFixed(unit === 0 || value >= 100 ? 0 : 1)} ${units[unit]}`;\n}\n\nfunction renderSize(entry: FileSystemEntry): string {\n if (entry.symlink === null) {\n return entry.kind === \"directory\" ? \"directory\" : formatSize(entry.metadata.size);\n }\n const symlink = entry.symlink;\n const targetUnavailable = symlink.isBroken || symlink.isOutsideRoot || symlink.isTargetExcluded;\n const targetSize =\n !targetUnavailable && symlink.targetKind === \"directory\"\n ? \"folder\"\n : symlink.targetSize === null || symlink.targetSize === undefined\n ? null\n : formatSize(symlink.targetSize);\n return `<span class=\"size-stack\"><span>Link <b>${formatSize(entry.metadata.size)}</b></span>${targetSize === null ? \"\" : `<span>Target <b>${targetSize}</b></span>`}</span>`;\n}\n\nconst iconPaths: Record<IconName, string> = {\n \"arrow-up\": '<path d=\"M12 19V5m-7 7 7-7 7 7\"/>',\n \"chevron-right\": '<path d=\"m9 18 6-6-6-6\"/>',\n file: '<path d=\"M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5z\"/><polyline points=\"14 2 14 8 20 8\"/>',\n folder:\n '<path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.9 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\"/>',\n link: '<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/>',\n moon: '<path d=\"M20.99 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 20.99 12.79z\"/>',\n search: '<circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"m21 21-4.3-4.3\"/>',\n sun: '<circle cx=\"12\" cy=\"12\" r=\"4\"/><path d=\"M12 2v2M12 20v2M4.93 4.93l1.42 1.42M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.42\"/>',\n};\n\nfunction safeExternalHref(value: string | undefined): string | null {\n if (value === undefined) return null;\n try {\n const url = new URL(value);\n return url.protocol === \"https:\" || url.protocol === \"http:\" ? url.href : null;\n } catch {\n return null;\n }\n}\n\nconst ledgerReadmeUrl = \"https://github.com/vp-tw/dirwell/blob/main/src/theme-default/README.md\";\n\nfunction controlIcon(name: IconName, size = 16): string {\n return `<svg class=\"icon\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">${iconPaths[name]}</svg>`;\n}\n\nexport const defaultThemeComponents: DirwellThemeComponents = {\n Icon: ({ label, name, size = 16, src, darkSrc }) =>\n src === undefined\n ? label === undefined\n ? controlIcon(name, size)\n : `<svg class=\"icon\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" role=\"img\" aria-label=\"${escapeHtml(label)}\">${iconPaths[name]}</svg>`\n : `<img class=\"icon file-icon${darkSrc === undefined ? \"\" : \" file-icon--light\"}\" width=\"20\" height=\"20\" src=\"${escapeHtml(src)}\" alt=\"\" loading=\"lazy\">${darkSrc === undefined ? \"\" : `<img class=\"icon file-icon file-icon--dark\" width=\"20\" height=\"20\" src=\"${escapeHtml(darkSrc)}\" alt=\"\" loading=\"lazy\">`}`,\n Breadcrumbs: ({ items }) =>\n `<nav class=\"breadcrumbs\" aria-label=\"Breadcrumb\">${items\n .map((item) =>\n item.href === null\n ? `<span aria-current=\"page\">${escapeHtml(item.label)}</span>`\n : `<a href=\"${escapeHtml(item.href)}\">${escapeHtml(item.label)}</a>`,\n )\n .join('<span class=\"separator\" aria-hidden=\"true\">/</span>')}</nav>`,\n Toolbar: ({\n colorScheme,\n fuzzySearch,\n globalSearch,\n keyboardNavigation,\n searchIcon,\n sorting,\n }) => {\n const shortcutAttributes = keyboardNavigation\n ? ' aria-keyshortcuts=\"/\" aria-describedby=\"keyboard-shortcuts\"'\n : \"\";\n const searchAll = globalSearch\n ? `<button class=\"search-all\" type=\"button\" data-global-open>Search all files</button>`\n : \"\";\n const search = fuzzySearch\n ? `<div class=\"search-cluster\"><label class=\"search\">${searchIcon}<span class=\"visually-hidden\">Search this folder</span><input type=\"search\" autocomplete=\"off\" placeholder=\"Search this folder\"${shortcutAttributes} data-search-input></label>${renderTypeFilters()}${searchAll}</div>`\n : searchAll;\n const scheme = colorScheme\n ? `<label class=\"scheme\">Theme${renderSelectControl(\"color-scheme\", [\n [\"system\", \"System\"],\n [\"light\", \"Light\"],\n [\"dark\", \"Dark\"],\n ])}</label>`\n : \"\";\n const sort = sorting\n ? `<details class=\"sort-panel\"><summary>Sort</summary><div class=\"sort-menu\"><label>Sort by${renderSelectControl(\n \"sort-field\",\n [\n [\"name\", \"Name\"],\n [\"modified\", \"Modified\"],\n [\"size\", \"Size\"],\n ],\n )}</label><label data-name-mode-control>Name order${renderSelectControl(\"name-mode\", [\n [\"natural\", \"Natural (numbers)\"],\n [\"locale\", \"Locale\"],\n [\"unicode\", \"Unicode\"],\n ])}</label><label>Direction${renderSelectControl(\"sort-direction\", [\n [\"asc\", \"Ascending\"],\n [\"desc\", \"Descending\"],\n ])}</label><label><input type=\"checkbox\" data-directories-first> Folders first</label></div></details>`\n : \"\";\n return search || scheme || sort\n ? `<div class=\"toolbar\">${search}<div class=\"toolbar-actions\">${sort}${scheme}</div></div>`\n : \"\";\n },\n EntryRow: ({ entry, icon, index, navigation }) => {\n const directoryLike = entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n const size = renderSize(entry);\n const modified = utcTimestamp(entry.metadata.times.modifiedAt);\n const linkAttributes = navigation.exitsExplorer ? ' target=\"_blank\" rel=\"noopener\"' : \"\";\n const label = `${escapeHtml(entry.name)}${directoryLike ? \"/\" : \"\"}`;\n const unavailable =\n entry.symlink?.isBroken || entry.symlink?.isOutsideRoot || entry.symlink?.isTargetExcluded;\n const target =\n entry.symlink === null\n ? \"\"\n : unavailable\n ? `<span class=\"target\"><span class=\"target-status\">Target unavailable</span> · <span class=\"target-unavailable\">${escapeHtml(entry.symlink.target)}</span></span>`\n : entry.symlink.isCycle\n ? `<span class=\"target\"><span class=\"target-status\">Cycle</span> · ${escapeHtml(entry.symlink.target)}</span>`\n : `<span class=\"target\">→ ${escapeHtml(entry.symlink.target)}</span>`;\n const searchText = escapeHtml(`${entry.name} ${entry.symlink?.target ?? \"\"}`.toLowerCase());\n const name = `<span class=\"entry-name\">${icon}<span>${label}</span></span>`;\n const kind = directoryLike\n ? \"directory\"\n : entry.kind === \"symlink\" && entry.symlink?.targetKind === null\n ? \"link\"\n : \"file\";\n return `<li class=\"entry\" data-entry data-order=\"${index}\" data-search=\"${searchText}\" data-name=\"${escapeHtml(entry.name)}\" data-size=\"${entry.kind === \"directory\" ? 0 : entry.metadata.size}\" data-modified=\"${modified === null ? 0 : Date.parse(modified.datetime)}\" data-directory=\"${String(directoryLike)}\" data-link=\"${String(entry.kind === \"symlink\")}\" data-kind=\"${kind}\">\n <span class=\"identity\">${navigation.href === null ? `<span class=\"name unavailable\">${name}</span>` : `<a class=\"name\" href=\"${escapeHtml(navigation.href)}\"${linkAttributes}>${name}</a>`}${target}</span>\n <span class=\"kind\">${size}</span>\n ${modified === null ? '<span class=\"modified\">Unknown</span>' : `<time datetime=\"${modified.datetime}\">${modified.label}</time>`}\n </li>`;\n },\n EntryList: ({ directory, parentHref, rows, sorting }) => {\n const headings = ([\"name\", \"size\", \"modified\"] as const)\n .map((field) =>\n sorting\n ? `<button class=\"sort-heading\" type=\"button\" data-sort-heading=\"${field}\">${field}<span class=\"sort-indicator\">${controlIcon(\"arrow-up\", 14)}</span></button>`\n : `<span class=\"sort-heading\">${field}</span>`,\n )\n .join(\"\");\n return `<div class=\"entry-head\">${headings}</div><ul class=\"entries\" data-entry-list>${directory.depth > 0 && parentHref !== null ? `<li class=\"entry\" data-parent><a class=\"name\" href=\"${escapeHtml(parentHref)}\">../</a><span class=\"kind\">parent</span><span></span></li>` : \"\"}${rows}</ul>`;\n },\n EmptyState: ({ message }) => `<p class=\"empty\" data-empty hidden>${escapeHtml(message)}</p>`,\n Footer: ({ iconNoticeHref, iconNoticeKind, keyboardNavigation, parentHref, project }) => {\n const shortcuts = keyboardNavigation\n ? `<p class=\"shortcuts\" id=\"keyboard-shortcuts\"><kbd>/</kbd> search <kbd>↑</kbd><kbd>↓</kbd> browse <kbd>Esc</kbd> clear${parentHref === null ? \"\" : \" <kbd>Backspace</kbd> parent\"}</p>`\n : \"\";\n const authorHref = safeExternalHref(project.authorUrl);\n const author =\n authorHref === null\n ? escapeHtml(project.author)\n : `<a href=\"${escapeHtml(authorHref)}\" target=\"_blank\" rel=\"noopener\">${escapeHtml(project.author)}</a>`;\n const name = `<a href=\"${escapeHtml(project.repositoryUrl)}\" target=\"_blank\" rel=\"noopener\">${escapeHtml(project.name)}</a>`;\n const ledger = `<a href=\"${ledgerReadmeUrl}\" target=\"_blank\" rel=\"noopener\">Ledger</a>`;\n const defaultIdentity = project.name === \"Dirwell\" && project.author === \"VdustR\";\n const attribution = defaultIdentity\n ? `${name} <span class=\"meta-item\">· ${ledger} by ${author}</span>`\n : `<span class=\"project-credit\">${name} by ${author}</span> <span class=\"meta-item\">· ${ledger}</span>`;\n const iconNotice =\n iconNoticeHref !== undefined && iconNoticeKind !== \"built-in\"\n ? ` <span class=\"meta-item\">· <a href=\"${escapeHtml(iconNoticeHref)}\" target=\"_blank\" rel=\"noopener\">Icon licenses</a></span>`\n : \"\";\n return `<footer><p class=\"project-meta\">${attribution}${iconNotice}</p>${shortcuts}</footer>`;\n },\n PageShell: ({\n assets,\n breadcrumbs,\n directory,\n documentBaseHref,\n emptyState,\n entryList,\n footer,\n parentHref,\n runtimeConfig,\n styles,\n toolbar,\n visiblePath,\n }) => `<!doctype html>\n<html lang=\"en\" data-theme=\"system\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><meta name=\"color-scheme\" content=\"light dark\">${documentBaseHref === null ? \"\" : `<base href=\"${escapeHtml(documentBaseHref)}\">`}<title>${escapeHtml(visiblePath)} · Files</title><style>${styles}</style></head>\n<body><main data-explorer data-config=\"${escapeHtml(JSON.stringify(runtimeConfig))}\"${parentHref === null ? \"\" : ` data-parent-href=\"${escapeHtml(parentHref)}\"`}>\n<header><div class=\"chrome\">${breadcrumbs}<p class=\"summary\"><span data-visible-count>${directory.entries.length}</span> <span data-count-label>${directory.entries.length === 1 ? \"entry\" : \"entries\"}</span></p></div><h1 class=\"visually-hidden\">${escapeHtml(visiblePath)}</h1></header>\n${toolbar}${entryList}${runtimeConfig.entriesHref ? '<p class=\"folder-loading\" data-folder-loading>Loading this folder…</p><noscript><style>[data-folder-loading]{display:none}</style><p class=\"folder-loading\">This large folder needs JavaScript. Use SSG mode for a complete HTML listing.</p></noscript>' : \"\"}${emptyState}<p class=\"visually-hidden\" aria-live=\"polite\" data-live-status></p>${footer}</main>${\n runtimeConfig.globalSearch\n ? `<dialog class=\"global-search\" data-global-dialog aria-labelledby=\"global-search-title\"><div class=\"global-search-head\"><h2 id=\"global-search-title\">Search all files</h2><button type=\"button\" class=\"dialog-close\" data-global-close aria-label=\"Close search\">Close</button></div><p>Search across the published directory. The index loads only after you type.</p><div class=\"global-search-controls\"><label class=\"search\"><span class=\"visually-hidden\">Search all files</span><input type=\"search\" autocomplete=\"off\" placeholder=\"Type a name or path\" data-global-input></label>${renderTypeFilters()}</div><p class=\"global-search-status\" data-global-status role=\"status\">Enter a search to begin.</p><ul class=\"entries global-results\" data-global-results></ul></dialog>`\n : \"\"\n }${assets}</body></html>`,\n};\n","export const defaultStyles = `\n:root {\n color-scheme: light dark;\n --dw-control-height: 2.75rem;\n --dw-sticky-header-height: 3.4rem;\n --dw-sticky-columns-height: calc(var(--dw-control-height) + 2px);\n --paper: #f3f0e8;\n --surface: #fbfaf6;\n --ink: #171815;\n --muted: #64655f;\n --rule: #c9c5ba;\n --soft-rule: #e3dfd5;\n --accent: #174ea6;\n --accent-strong: #103973;\n --focus: #005fcc;\n --hover: #f0eee7;\n --control: #fff;\n --status: #34705c;\n --warning: #9a4616;\n --shadow: 0 30px 80px rgba(46, 46, 40, 0.14);\n}\n:root[data-theme=\"light\"] {\n color-scheme: light;\n --paper: #f3f0e8;\n --surface: #fbfaf6;\n --ink: #171815;\n --muted: #64655f;\n --rule: #c9c5ba;\n --soft-rule: #e3dfd5;\n --accent: #174ea6;\n --accent-strong: #103973;\n --focus: #005fcc;\n --hover: #f0eee7;\n --control: #fff;\n --status: #34705c;\n --warning: #9a4616;\n --shadow: 0 30px 80px rgba(46, 46, 40, 0.14);\n}\n:root[data-theme=\"dark\"] {\n color-scheme: dark;\n --paper: #11130f;\n --surface: #191b17;\n --ink: #f2f0e8;\n --muted: #b1b4ab;\n --rule: #474a42;\n --soft-rule: #30332d;\n --accent: #91bff0;\n --accent-strong: #b7d5f4;\n --focus: #78b7f4;\n --hover: #22251f;\n --control: #10120f;\n --status: #8bc0aa;\n --warning: #f0a06d;\n --shadow: 0 30px 80px rgba(0, 0, 0, 0.28);\n}\n@media (prefers-color-scheme: dark) {\n :root[data-theme=\"system\"] {\n --paper: #11130f;\n --surface: #191b17;\n --ink: #f2f0e8;\n --muted: #b1b4ab;\n --rule: #474a42;\n --soft-rule: #30332d;\n --accent: #91bff0;\n --accent-strong: #b7d5f4;\n --focus: #78b7f4;\n --hover: #22251f;\n --control: #10120f;\n --status: #8bc0aa;\n --warning: #f0a06d;\n --shadow: 0 30px 80px rgba(0, 0, 0, 0.28);\n }\n}\n* {\n box-sizing: border-box;\n}\nhtml {\n min-height: 100%;\n scroll-padding-top: calc(\n var(--dw-sticky-header-height) + var(--dw-sticky-columns-height) + 0.5rem\n );\n background: var(--paper);\n color: var(--ink);\n}\nbody {\n min-width: 0;\n margin: 0;\n padding: clamp(1rem, 5vw, 4rem);\n font:\n 15px/1.45 ui-sans-serif,\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n \"Segoe UI\",\n sans-serif;\n font-variant-numeric: tabular-nums;\n}\nbutton,\ninput,\nselect {\n font: inherit;\n}\nmain {\n width: min(72rem, 100%);\n margin: 0 auto;\n background: var(--surface);\n border: 1px solid var(--rule);\n border-radius: 0.875rem;\n box-shadow: var(--shadow);\n overflow: visible;\n}\nmain > header {\n position: sticky;\n top: 0;\n z-index: 3;\n background: var(--surface);\n border-radius: calc(0.875rem - 1px) calc(0.875rem - 1px) 0 0;\n}\nmain[data-sticky-header-disabled] > header {\n position: static;\n}\n.chrome {\n display: flex;\n flex-wrap: wrap;\n min-height: 3.4rem;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n padding: 0 1.4rem;\n border-bottom: 1px solid var(--soft-rule);\n}\n.breadcrumbs {\n display: flex;\n min-width: 0;\n align-items: center;\n flex-wrap: wrap;\n gap: 0.15rem;\n font-size: 0.95rem;\n font-weight: 650;\n}\n.breadcrumbs a,\n.breadcrumbs span {\n color: inherit;\n overflow-wrap: anywhere;\n min-width: 0;\n}\n.breadcrumbs a {\n color: var(--accent);\n text-decoration-thickness: 0.08em;\n display: inline-flex;\n min-height: var(--dw-control-height);\n align-items: center;\n padding: 0 0.2rem;\n}\n.separator {\n display: inline-flex;\n color: var(--muted);\n font-weight: 400;\n}\n.summary {\n margin: 0;\n color: var(--muted);\n font-size: 0.76rem;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n white-space: nowrap;\n}\n.toolbar {\n display: flex;\n justify-content: space-between;\n gap: 1rem;\n padding: 1.25rem 1.4rem;\n align-items: flex-start;\n}\n.search-cluster {\n display: flex;\n flex-wrap: wrap;\n min-width: 0;\n flex: 1;\n gap: 0.6rem;\n align-items: center;\n}\n.search {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: min(28rem, 100%);\n min-height: var(--dw-control-height);\n padding: 0.5rem 0.7rem;\n border: 1px solid var(--rule);\n border-radius: 0.5rem;\n background: var(--control);\n}\n.search:focus-within {\n outline: 3px solid var(--focus);\n outline-offset: 2px;\n}\n.search input {\n width: 100%;\n min-width: 0;\n border: 0;\n outline: 0;\n background: transparent;\n color: var(--ink);\n}\n.search input::placeholder {\n color: var(--muted);\n opacity: 1;\n}\n.type-filters {\n display: flex;\n flex-wrap: nowrap;\n align-items: center;\n min-width: 0;\n min-height: var(--dw-control-height);\n max-width: 100%;\n margin: 0;\n padding: 0;\n border: 1px solid var(--rule);\n border-radius: 0.5rem;\n background: var(--control);\n color: var(--ink);\n font-size: 0.78rem;\n overflow: hidden;\n}\n.type-filters label {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-height: calc(var(--dw-control-height) - 2px);\n padding: 0.35rem 0.7rem;\n white-space: nowrap;\n cursor: pointer;\n}\n.type-filters label + label {\n border-left: 1px solid var(--rule);\n}\n.type-filters label:hover {\n background: var(--hover);\n}\n.type-filters label:has(input:checked) {\n background: color-mix(in srgb, var(--accent) 16%, var(--control));\n color: var(--accent-strong);\n}\n.type-filters label:has(input:focus-visible) {\n box-shadow: inset 0 0 0 3px var(--focus);\n}\n.type-filters input {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: 0;\n opacity: 0;\n}\n.sort-menu select {\n min-height: var(--dw-control-height);\n border: 1px solid var(--rule);\n border-radius: 0.5rem;\n background: var(--control);\n color: var(--ink);\n padding: 0.35rem 1.8rem 0.35rem 0.55rem;\n}\n.search-all,\n.dialog-close {\n min-height: var(--dw-control-height);\n border: 1px solid var(--rule);\n border-radius: 0.5rem;\n padding: 0.4rem 0.75rem;\n background: var(--control);\n color: var(--accent);\n white-space: nowrap;\n cursor: pointer;\n}\n.search-all:hover,\n.dialog-close:hover {\n background: var(--hover);\n}\n.global-search {\n width: min(58rem, calc(100vw - 2rem));\n max-height: min(85vh, 55rem);\n padding: 0;\n border: 1px solid var(--rule);\n border-radius: 0.875rem;\n background: var(--surface);\n color: var(--ink);\n box-shadow: var(--shadow);\n}\n.global-search::backdrop {\n background: rgba(10, 12, 10, 0.62);\n}\n.global-search-head,\n.global-search-controls {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 1rem 1.25rem;\n}\n.global-search-head {\n flex-wrap: wrap;\n justify-content: space-between;\n border-bottom: 1px solid var(--soft-rule);\n}\n.global-search h2 {\n margin: 0;\n font-size: 1.2rem;\n}\n.global-search > p {\n margin: 0;\n padding: 0.75rem 1.25rem;\n color: var(--muted);\n}\n.global-search-controls .search {\n flex: 1;\n}\n.global-results {\n max-height: 50vh;\n overflow: auto;\n}\n.virtual-spacer {\n display: block;\n padding: 0;\n margin: 0;\n border: 0;\n pointer-events: none;\n}\n.toolbar-actions {\n display: flex;\n align-items: flex-start;\n gap: 0.6rem;\n}\n.scheme {\n display: inline-flex;\n align-items: center;\n gap: 0.45rem;\n color: var(--muted);\n font-size: 0.78rem;\n white-space: nowrap;\n}\n.scheme select {\n min-height: var(--dw-control-height);\n border: 1px solid var(--rule);\n border-radius: 0.5rem;\n padding: 0.35rem 1.65rem 0.35rem 0.6rem;\n background: var(--control);\n color: var(--ink);\n cursor: pointer;\n}\n.sort-panel {\n position: relative;\n}\n.sort-panel > summary {\n display: flex;\n min-height: var(--dw-control-height);\n align-items: center;\n list-style: none;\n border: 1px solid var(--rule);\n border-radius: 0.5rem;\n background: var(--control);\n padding: 0.45rem 0.7rem;\n cursor: pointer;\n}\n.sort-panel > summary::-webkit-details-marker {\n display: none;\n}\n.sort-panel[open] > summary {\n outline: 2px solid var(--focus);\n outline-offset: 1px;\n}\n.sort-menu {\n position: absolute;\n z-index: 2;\n right: 0;\n top: calc(100% + 0.4rem);\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n width: 16rem;\n gap: 0.7rem;\n padding: 1rem;\n border: 1px solid var(--rule);\n border-radius: 0.75rem;\n background: var(--surface);\n box-shadow: var(--shadow);\n}\n.sort-menu select {\n min-width: 0;\n width: 100%;\n}\n.sort-menu label {\n display: grid;\n gap: 0.3rem;\n color: var(--muted);\n font-size: 0.76rem;\n}\n.sort-menu label[hidden] {\n display: none;\n}\n.sort-menu label:last-child {\n display: flex;\n align-items: center;\n color: var(--ink);\n}\n.entry-head,\n.entry {\n display: grid;\n grid-template-columns: minmax(12rem, 1fr) minmax(8rem, auto) 12rem;\n gap: 1.25rem;\n}\n.entry-head {\n position: sticky;\n top: var(--dw-sticky-header-height);\n z-index: 2;\n min-height: var(--dw-control-height);\n align-items: center;\n padding: 0 1.4rem;\n border-top: 1px solid var(--soft-rule);\n border-bottom: 1px solid var(--soft-rule);\n background: var(--paper);\n}\n.sort-heading {\n display: inline-flex;\n min-height: var(--dw-control-height);\n align-items: center;\n gap: 0.25rem;\n width: max-content;\n border: 0;\n background: transparent;\n color: var(--muted);\n padding: 0;\n font-size: 0.68rem;\n font-weight: 720;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n cursor: pointer;\n}\nbutton.sort-heading {\n min-width: var(--dw-control-height);\n}\n.sort-heading[aria-pressed=\"true\"] {\n color: var(--accent);\n}\n.sort-indicator {\n display: none;\n align-items: center;\n}\n.sort-heading[aria-pressed=\"true\"] .sort-indicator {\n display: inline-flex;\n}\n.sort-heading[data-direction=\"desc\"] .sort-indicator {\n transform: rotate(180deg);\n}\n.sort-heading .sort-indicator .icon {\n color: currentColor;\n}\n.entries {\n list-style: none;\n margin: 0;\n padding: 0;\n overflow-anchor: none;\n}\n.entry {\n min-height: 3.25rem;\n align-items: center;\n padding: 0.72rem 1.4rem;\n border-bottom: 1px solid var(--soft-rule);\n}\n.entry:hover,\n.entry[data-active=\"true\"] {\n background: var(--hover);\n}\n.entry[hidden] {\n display: none;\n}\na {\n color: var(--accent);\n text-decoration-thickness: 0.08em;\n text-underline-offset: 0.22em;\n}\n.identity {\n display: flex;\n min-width: 0;\n flex-wrap: wrap;\n row-gap: 0.15rem;\n}\n.entry-name {\n display: inline-flex;\n align-items: center;\n gap: 0.55rem;\n}\n.name {\n font-weight: 650;\n overflow-wrap: anywhere;\n}\n.entry .name {\n text-decoration: none;\n}\n.entry .name:hover,\n.entry .name:focus-visible {\n text-decoration: underline;\n}\n.icon {\n display: inline-block;\n flex: none;\n vertical-align: -0.15em;\n color: var(--status);\n}\n.file-icon {\n width: 1.25rem;\n height: 1.25rem;\n object-fit: contain;\n}\n.file-icon--dark,\n:root[data-theme=\"dark\"] .file-icon--light {\n display: none;\n}\n:root[data-theme=\"dark\"] .file-icon--dark {\n display: inline-block;\n}\n@media (prefers-color-scheme: dark) {\n :root[data-theme=\"system\"] .file-icon--light {\n display: none;\n }\n :root[data-theme=\"system\"] .file-icon--dark {\n display: inline-block;\n }\n}\n.target {\n flex-basis: 100%;\n padding-left: 1.8rem;\n color: var(--muted);\n font:\n 500 0.8rem/1.6 ui-monospace,\n SFMono-Regular,\n monospace;\n overflow-wrap: anywhere;\n}\n.target-status {\n font-family: ui-sans-serif, system-ui, sans-serif;\n font-weight: 650;\n}\n.target-unavailable {\n text-decoration: line-through;\n text-decoration-thickness: 1px;\n}\n.unavailable {\n color: var(--muted);\n text-decoration: line-through;\n text-decoration-thickness: 1px;\n}\n.kind,\ntime {\n color: var(--muted);\n font-size: 0.82rem;\n}\n.timestamp-button {\n border: 0;\n padding: 0;\n background: transparent;\n text-align: left;\n cursor: pointer;\n min-height: 2.75rem;\n width: fit-content;\n font: inherit;\n}\n.timestamp-button:hover time {\n text-decoration: underline;\n text-underline-offset: 0.2em;\n}\n.timestamp-zone {\n font-weight: 500;\n letter-spacing: 0;\n text-transform: none;\n}\n.timestamp-details {\n position: fixed;\n z-index: 10;\n width: min(26rem, calc(100vw - 1rem));\n max-height: calc(100vh - 1rem);\n overflow: auto;\n padding: 1rem;\n border: 1px solid var(--rule);\n border-radius: 0.75rem;\n background: var(--paper);\n color: var(--ink);\n font-size: 0.85rem;\n}\n.timestamp-details-head {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 1rem;\n}\n.timestamp-details dl {\n margin: 0.75rem 0 0;\n}\n.timestamp-details dt {\n margin-top: 0.75rem;\n color: var(--muted);\n}\n.timestamp-details dd {\n margin: 0.25rem 0 0;\n overflow-wrap: anywhere;\n font-variant-numeric: tabular-nums;\n}\n.size-stack {\n display: grid;\n gap: 0.1rem;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n.size-stack b {\n color: var(--ink);\n font-weight: 650;\n}\na:focus-visible,\nbutton:focus-visible,\nselect:focus-visible,\nsummary:focus-visible {\n outline: 3px solid var(--focus);\n outline-offset: 3px;\n}\n.empty {\n margin: 0;\n padding: 2rem 1.4rem;\n color: var(--muted);\n border-bottom: 1px solid var(--soft-rule);\n}\n.folder-loading {\n margin: 0;\n padding: 2rem 1.4rem;\n color: var(--muted);\n}\n::selection {\n background: var(--accent);\n color: var(--surface);\n}\nfooter {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n padding: 0.7rem 1.4rem;\n color: var(--muted);\n font-size: 0.78rem;\n}\n.project-meta,\n.shortcuts {\n margin: 0;\n}\n.project-meta {\n line-height: 1.9;\n}\n.meta-item,\n.project-credit {\n white-space: nowrap;\n}\n.shortcuts {\n text-align: right;\n}\nkbd {\n display: inline-block;\n min-width: 1.6em;\n margin: 0 0.12rem;\n padding: 0.02rem 0.3rem;\n border: 1px solid var(--rule);\n border-radius: 0.2rem;\n background: var(--control);\n text-align: center;\n font: inherit;\n}\n.visually-hidden {\n position: absolute !important;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n.sort-heading:not(button) {\n cursor: default;\n}\n@media (max-width: 60rem) {\n .toolbar {\n align-items: stretch;\n flex-direction: column;\n }\n .search-cluster {\n align-items: stretch;\n flex-wrap: wrap;\n }\n .search {\n width: 100%;\n }\n .toolbar-actions {\n width: 100%;\n justify-content: space-between;\n }\n .sort-menu {\n right: auto;\n left: 0;\n }\n}\n@media (max-width: 42rem) {\n :root {\n --dw-sticky-columns-height: 0px;\n }\n body {\n padding: 0;\n background: var(--surface);\n }\n main {\n min-height: 100vh;\n border: 0;\n border-radius: 0;\n box-shadow: none;\n }\n main > header {\n border-radius: 0;\n }\n .chrome {\n padding-inline: 1rem;\n }\n .breadcrumbs {\n flex: 1 1 auto;\n }\n .summary {\n margin-left: auto;\n }\n .toolbar {\n padding: 1rem;\n }\n .toolbar-actions {\n flex-wrap: wrap;\n }\n .sort-menu {\n width: min(16rem, calc(100vw - 2rem));\n }\n .global-search-controls {\n flex-wrap: wrap;\n }\n .global-search-controls .search {\n flex-basis: 100%;\n }\n .entry-head {\n display: none;\n }\n .entry {\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 0.25rem 1rem;\n padding: 0.78rem 1rem;\n }\n .entry .name {\n display: inline-flex;\n min-height: 2.75rem;\n align-items: center;\n }\n .entry time,\n .entry .timestamp-button {\n grid-column: 1/-1;\n }\n .kind {\n text-align: right;\n }\n footer {\n display: flex;\n flex-direction: column-reverse;\n align-items: flex-start;\n gap: 0.25rem;\n padding: 0.3rem 1rem;\n }\n .project-meta a {\n display: inline-flex;\n min-height: 2.75rem;\n align-items: center;\n }\n .shortcuts {\n margin: 0;\n text-align: left;\n }\n}\n@media (max-width: 19.5rem) {\n .search-cluster {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n }\n}\n@media (pointer: coarse) {\n .entry .name,\n .project-meta a {\n display: inline-flex;\n min-height: 2.75rem;\n align-items: center;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n * {\n scroll-behavior: auto !important;\n }\n}\n`;\n","export interface ThemeProject {\n readonly author: string;\n readonly authorUrl?: string;\n readonly license: string;\n readonly licenseUrl: string;\n readonly name: string;\n readonly repositoryUrl: string;\n}\n\nexport type ThemeProjectOptions = Readonly<Partial<ThemeProject>>;\n\nconst defaultProject: ThemeProject = {\n author: \"VdustR\",\n authorUrl: \"https://github.com/VdustR\",\n license: \"MIT License\",\n licenseUrl: \"https://github.com/vp-tw/dirwell/blob/main/LICENSE\",\n name: \"Dirwell\",\n repositoryUrl: \"https://github.com/vp-tw/dirwell\",\n};\n\nexport function resolveThemeProject(options?: ThemeProjectOptions): ThemeProject {\n const author = options?.author ?? defaultProject.author;\n return {\n author,\n ...(options?.authorUrl !== undefined\n ? { authorUrl: options.authorUrl }\n : author === defaultProject.author\n ? { authorUrl: defaultProject.authorUrl }\n : {}),\n license: options?.license ?? defaultProject.license,\n licenseUrl: options?.licenseUrl ?? defaultProject.licenseUrl,\n name: options?.name ?? defaultProject.name,\n repositoryUrl: options?.repositoryUrl ?? defaultProject.repositoryUrl,\n };\n}\n","import type { FileSystemEntry } from \"../model.ts\";\n\nexport const vscodeIconNames = [\n \"default_file\",\n \"default_folder\",\n \"file_type_css\",\n \"file_type_html\",\n \"file_type_image\",\n \"file_type_js\",\n \"file_type_json\",\n \"file_type_markdown\",\n \"file_type_pdf2\",\n \"file_type_shell\",\n \"file_type_text\",\n \"file_type_typescript\",\n \"file_type_yaml\",\n \"file_type_zip\",\n] as const;\n\nexport type VscodeIconName = (typeof vscodeIconNames)[number];\n\nexport const vscodeIconsByExtension: Readonly<Record<string, VscodeIconName>> = {\n bash: \"file_type_shell\",\n cjs: \"file_type_js\",\n css: \"file_type_css\",\n cts: \"file_type_typescript\",\n gif: \"file_type_image\",\n gz: \"file_type_zip\",\n htm: \"file_type_html\",\n html: \"file_type_html\",\n jpeg: \"file_type_image\",\n jpg: \"file_type_image\",\n js: \"file_type_js\",\n json: \"file_type_json\",\n jsonc: \"file_type_json\",\n log: \"file_type_text\",\n md: \"file_type_markdown\",\n mjs: \"file_type_js\",\n mts: \"file_type_typescript\",\n pdf: \"file_type_pdf2\",\n png: \"file_type_image\",\n sh: \"file_type_shell\",\n svg: \"file_type_image\",\n tar: \"file_type_zip\",\n text: \"file_type_text\",\n ts: \"file_type_typescript\",\n tsx: \"file_type_typescript\",\n txt: \"file_type_text\",\n webp: \"file_type_image\",\n yaml: \"file_type_yaml\",\n yml: \"file_type_yaml\",\n zip: \"file_type_zip\",\n zsh: \"file_type_shell\",\n};\n\nexport function vscodeIconForEntry(entry: FileSystemEntry): VscodeIconName {\n if (entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\") {\n return \"default_folder\";\n }\n const extension = entry.name.slice(entry.name.lastIndexOf(\".\") + 1).toLowerCase();\n return vscodeIconsByExtension[extension] ?? \"default_file\";\n}\n\nexport function vscodeIconAssetName(name: VscodeIconName): string {\n return `vscode-${name}.svg`;\n}\n","import { createHash } from \"node:crypto\";\nimport type { FileSystemEntry } from \"../model.ts\";\nimport { vscodeIconAssetName, vscodeIconsByExtension } from \"./vscode-icons.ts\";\n\nexport interface DefaultThemeIconVariant {\n /** SVG markup for entries without a matching extension. */\n readonly file: string;\n /** SVG markup for directories. */\n readonly folder: string;\n /** SVG markup keyed by lowercase file extension, without the leading dot. */\n readonly byExtension?: Readonly<Record<string, string>>;\n}\n\nexport interface DefaultThemeIconSet {\n readonly light: DefaultThemeIconVariant;\n /** Omit to use the light icons in both color schemes. */\n readonly dark?: DefaultThemeIconVariant;\n /** Optional attribution included in generated sites and linked as Notices. */\n readonly notice?: string;\n}\n\nexport interface ResolvedIconVariant {\n readonly file: string;\n readonly folder: string;\n readonly byExtension: Readonly<Record<string, string>>;\n}\n\nexport interface ResolvedIconSet {\n readonly light: ResolvedIconVariant;\n readonly dark?: ResolvedIconVariant;\n}\n\nexport interface PreparedIconSet {\n readonly assets: Readonly<Record<string, string>>;\n readonly names: ResolvedIconSet;\n readonly noticeName?: string;\n}\n\nfunction assetName(svg: string): string {\n return `theme-icon-${createHash(\"sha256\").update(svg).digest(\"hex\")}.svg`;\n}\n\nfunction prepareVariant(\n variant: DefaultThemeIconVariant,\n assets: Record<string, string>,\n): ResolvedIconVariant {\n const add = (svg: string): string => {\n if (typeof svg !== \"string\" || !/^\\s*<svg\\b/.test(svg)) {\n throw new TypeError(\"Theme icons must be SVG markup\");\n }\n const name = assetName(svg);\n assets[name] = svg;\n return name;\n };\n const byExtension = Object.fromEntries(\n Object.entries(variant.byExtension ?? {}).map(([extension, svg]) => {\n if (!/^[a-z0-9][a-z0-9+_-]*$/.test(extension)) {\n throw new TypeError(`Invalid icon extension: ${extension}`);\n }\n return [extension, add(svg)];\n }),\n );\n return { file: add(variant.file), folder: add(variant.folder), byExtension };\n}\n\nexport function prepareIconSet(\n icons: DefaultThemeIconSet | undefined,\n vscodeIconAssets: Readonly<Record<string, string>>,\n vscodeIconNotice: string,\n): PreparedIconSet {\n if (icons === undefined) {\n return {\n assets: { ...vscodeIconAssets, \"vscode-icons-NOTICE.txt\": vscodeIconNotice },\n names: {\n light: {\n file: vscodeIconAssetName(\"default_file\"),\n folder: vscodeIconAssetName(\"default_folder\"),\n byExtension: Object.fromEntries(\n Object.entries(vscodeIconsByExtension).map(([extension, name]) => [\n extension,\n vscodeIconAssetName(name),\n ]),\n ),\n },\n },\n noticeName: \"vscode-icons-NOTICE.txt\",\n };\n }\n if (\n icons.notice !== undefined &&\n (typeof icons.notice !== \"string\" || icons.notice.trim() === \"\")\n ) {\n throw new TypeError(\"Theme icon attribution notice must be non-empty text\");\n }\n const assets: Record<string, string> =\n icons.notice === undefined ? {} : { \"theme-icons-NOTICE.txt\": icons.notice };\n const light = prepareVariant(icons.light, assets);\n const dark = icons.dark === undefined ? undefined : prepareVariant(icons.dark, assets);\n return {\n assets,\n names: { light, ...(dark === undefined ? {} : { dark }) },\n ...(icons.notice === undefined ? {} : { noticeName: \"theme-icons-NOTICE.txt\" }),\n };\n}\n\nexport function iconNameForEntry(entry: FileSystemEntry, variant: ResolvedIconVariant): string {\n if (entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\") {\n return variant.folder;\n }\n const extension = entry.name.slice(entry.name.lastIndexOf(\".\") + 1).toLowerCase();\n return Object.hasOwn(variant.byExtension, extension)\n ? variant.byExtension[extension]!\n : variant.file;\n}\n\nexport function iconHrefs(\n names: ResolvedIconSet,\n assetHref: (assetName: string) => string,\n): ResolvedIconSet {\n const resolve = (variant: ResolvedIconVariant): ResolvedIconVariant => ({\n file: assetHref(variant.file),\n folder: assetHref(variant.folder),\n byExtension: Object.fromEntries(\n Object.entries(variant.byExtension).map(([extension, name]) => [extension, assetHref(name)]),\n ),\n });\n return {\n light: resolve(names.light),\n ...(names.dark === undefined ? {} : { dark: resolve(names.dark) }),\n };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport type { ExplorerTheme } from \"./model.ts\";\nimport {\n resolveThemeComponents,\n type BreadcrumbItem,\n type DirwellThemeComponentOverrides,\n} from \"./theme-components.ts\";\nimport { defaultThemeComponents, escapeHtml } from \"./theme-default/components.ts\";\nimport { defaultStyles } from \"./theme-default/styles.ts\";\nimport { resolveThemeProject, type ThemeProjectOptions } from \"./theme-project.ts\";\nimport {\n iconHrefs,\n iconNameForEntry,\n prepareIconSet,\n type DefaultThemeIconSet,\n} from \"./theme-default/icon-set.ts\";\nimport { vscodeIconAssetName, vscodeIconNames } from \"./theme-default/vscode-icons.ts\";\n\nexport { defaultThemeComponents, escapeHtml } from \"./theme-default/components.ts\";\nexport type { DefaultThemeIconSet, DefaultThemeIconVariant } from \"./theme-default/icon-set.ts\";\n\nconst runtimeSource = await readFile(new URL(\"./theme-runtime.js\", import.meta.url), \"utf8\");\nconst workerSource = await readFile(new URL(\"./theme-worker.js\", import.meta.url), \"utf8\");\nconst vscodeIconAssets = Object.fromEntries(\n await Promise.all(\n vscodeIconNames.map(\n async (name) =>\n [\n vscodeIconAssetName(name),\n await readFile(new URL(`./vscode-icons/${name}.svg`, import.meta.url), \"utf8\"),\n ] as const,\n ),\n ),\n);\nconst vscodeIconNotice = await readFile(\n new URL(\"./vscode-icons/NOTICE.txt\", import.meta.url),\n \"utf8\",\n);\n\nexport interface DefaultThemeOptions {\n readonly colorScheme?: boolean;\n readonly components?: DirwellThemeComponentOverrides | readonly DirwellThemeComponentOverrides[];\n readonly fuzzySearch?: boolean;\n readonly globalSearch?: boolean;\n readonly keyboardNavigation?: boolean;\n readonly icons?: DefaultThemeIconSet;\n readonly project?: ThemeProjectOptions;\n readonly sorting?: boolean;\n /** MPA directories above this size load rows from an asset and render a measured window. */\n readonly virtualizeAfter?: number;\n}\n\nfunction createBreadcrumbs(\n relativePath: string,\n hrefForDirectory: (relativePath: string) => string,\n): readonly BreadcrumbItem[] {\n const segments = relativePath === \"\" ? [] : relativePath.split(\"/\");\n return [\n {\n href: segments.length === 0 ? null : hrefForDirectory(\"\"),\n isCurrent: segments.length === 0,\n label: segments.length === 0 ? \"/\" : \"Home\",\n },\n ...segments.map((label, index) => ({\n href:\n index === segments.length - 1\n ? null\n : hrefForDirectory(segments.slice(0, index + 1).join(\"/\")),\n isCurrent: index === segments.length - 1,\n label,\n })),\n ];\n}\n\nexport function createDefaultTheme(options: DefaultThemeOptions = {}): ExplorerTheme {\n const colorScheme = options.colorScheme ?? true;\n const fuzzySearch = options.fuzzySearch ?? true;\n const globalSearch = options.globalSearch ?? true;\n const keyboardNavigation = options.keyboardNavigation ?? true;\n const sorting = options.sorting ?? true;\n const virtualizeAfter = options.virtualizeAfter ?? 500;\n const project = resolveThemeProject(options.project);\n if (!Number.isSafeInteger(virtualizeAfter) || virtualizeAfter < 0) {\n throw new RangeError(\"virtualizeAfter must be a non-negative integer\");\n }\n const interactive = colorScheme || fuzzySearch || globalSearch || keyboardNavigation || sorting;\n const layers =\n options.components === undefined\n ? []\n : Array.isArray(options.components)\n ? options.components\n : [options.components];\n const components = resolveThemeComponents(defaultThemeComponents, ...layers);\n const iconSet = prepareIconSet(options.icons, vscodeIconAssets, vscodeIconNotice);\n\n return {\n name: \"ledger\",\n render({\n assetHref,\n directory,\n documentBaseHref,\n exitsExplorerFor,\n hrefFor,\n hrefForDirectory,\n searchIndexHref,\n sort,\n mode,\n }) {\n const visiblePath =\n directory.current.relativePath === \"\" ? \"/\" : `/${directory.current.relativePath}/`;\n const virtualized =\n mode === \"mpa\" &&\n interactive &&\n directory.entries.length > virtualizeAfter &&\n components.EntryList === defaultThemeComponents.EntryList &&\n components.EntryRow === defaultThemeComponents.EntryRow;\n const renderedRows = virtualized\n ? []\n : directory.entries.map((entry, index) => {\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n const iconName = entry.kind === \"symlink\" ? \"link\" : directoryLike ? \"folder\" : \"file\";\n return components.EntryRow({\n entry,\n icon: components.Icon({\n name: iconName,\n src: assetHref(iconNameForEntry(entry, iconSet.names.light)),\n ...(iconSet.names.dark === undefined\n ? {}\n : { darkSrc: assetHref(iconNameForEntry(entry, iconSet.names.dark)) }),\n }),\n index,\n navigation: { exitsExplorer: exitsExplorerFor(entry), href: hrefFor(entry) },\n });\n });\n const entriesAssetName = virtualized\n ? `entries-${createHash(\"sha256\").update(directory.current.relativePath).digest(\"hex\").slice(0, 16)}.json`\n : null;\n const rows = renderedRows.join(\"\");\n const assets = interactive\n ? `<script src=\"${escapeHtml(assetHref(\"dirwell.runtime.js\"))}\" type=\"module\"></script>`\n : \"\";\n const runtimeConfig = {\n colorScheme,\n fuzzySearch,\n globalSearch,\n keyboardNavigation,\n icons: iconHrefs(iconSet.names, assetHref),\n searchIndexHref,\n ...(entriesAssetName === null ? {} : { entriesHref: assetHref(entriesAssetName) }),\n ...(entriesAssetName === null ? {} : { workerHref: assetHref(\"dirwell.worker.js\") }),\n sort,\n sorting,\n };\n const parentHref =\n directory.parent === null ? null : hrefForDirectory(directory.parent.relativePath);\n const html = components.PageShell({\n assets,\n breadcrumbs: components.Breadcrumbs({\n items: createBreadcrumbs(directory.current.relativePath, hrefForDirectory),\n }),\n directory,\n documentBaseHref,\n emptyState: components.EmptyState({ message: \"No matching entries.\" }),\n entryList: components.EntryList({ directory, parentHref, rows, sorting }),\n footer: components.Footer({\n ...(iconSet.noticeName === undefined\n ? {}\n : {\n iconNoticeHref: assetHref(iconSet.noticeName),\n iconNoticeKind: options.icons === undefined ? \"built-in\" : \"custom\",\n }),\n keyboardNavigation,\n parentHref,\n project,\n }),\n parentHref,\n runtimeConfig,\n styles: defaultStyles,\n toolbar: components.Toolbar({\n colorScheme,\n fuzzySearch,\n globalSearch,\n keyboardNavigation,\n searchIcon: components.Icon({ name: \"search\" }),\n sorting,\n }),\n visiblePath,\n });\n return {\n html,\n assets: {\n ...iconSet.assets,\n ...(interactive ? { \"dirwell.runtime.js\": runtimeSource } : {}),\n ...(entriesAssetName === null ? {} : { \"dirwell.worker.js\": workerSource }),\n ...(entriesAssetName === null\n ? {}\n : {\n [entriesAssetName]: JSON.stringify({\n rows: directory.entries.map((entry) => ({\n name: entry.name,\n size: entry.metadata.size,\n modifiedAt: entry.metadata.times.modifiedAt,\n kind: entry.kind,\n targetKind: entry.symlink?.targetKind ?? null,\n targetSize: entry.symlink?.targetSize ?? null,\n target: entry.symlink?.target ?? null,\n isCycle: entry.symlink?.isCycle ?? false,\n isBroken: entry.symlink?.isBroken ?? false,\n isOutsideRoot: entry.symlink?.isOutsideRoot ?? false,\n isTargetUnavailable: Boolean(\n entry.symlink?.isBroken ||\n entry.symlink?.isOutsideRoot ||\n entry.symlink?.isTargetExcluded,\n ),\n href: hrefFor(entry),\n exitsExplorer: exitsExplorerFor(entry),\n })),\n version: 2,\n }),\n }),\n },\n };\n },\n };\n}\n\nexport const defaultTheme = createDefaultTheme();\n","import {\n cp,\n lstat,\n mkdtemp,\n mkdir,\n readFile,\n readdir,\n readlink,\n realpath,\n rename,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport type { Stats } from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport type {\n DirectoryData,\n EntryKind,\n ExplorerTheme,\n FileMetadata,\n FileSystemEntry,\n GenerateOptions,\n NameSortMode,\n OutputNameResolver,\n SortOptions,\n SymlinkMetadata,\n} from \"./model.ts\";\nimport { defaultTheme } from \"./theme-default.ts\";\nimport { selectSourcePaths } from \"./filters.ts\";\n\nconst indexPattern = /^index\\.html?$/i;\n\nconst defaultSort = {\n direction: \"asc\",\n directoriesFirst: true,\n field: \"name\",\n nameMode: \"natural\",\n} as const satisfies Required<SortOptions>;\n\nexport const defaultOutputName: OutputNameResolver = ({ entries }) =>\n entries.some((entry) => entry.kind === \"file\" && indexPattern.test(entry.name))\n ? entries.some((entry) => entry.name.toLowerCase() === \"_dirwell.html\")\n ? null\n : \"_dirwell.html\"\n : \"index.html\";\n\nfunction entryKind(stats: Stats): EntryKind {\n if (stats.isDirectory()) return \"directory\";\n if (stats.isFile()) return \"file\";\n if (stats.isSymbolicLink()) return \"symlink\";\n return \"other\";\n}\n\nfunction metadata(stats: Stats): FileMetadata {\n return {\n device: stats.dev,\n groupId: stats.gid,\n hardLinkCount: stats.nlink,\n inode: stats.ino,\n mode: stats.mode,\n ownerId: stats.uid,\n size: stats.size,\n times: {\n accessedAt: stats.atime.toISOString(),\n changedAt: stats.ctime.toISOString(),\n createdAt: stats.birthtime.toISOString(),\n modifiedAt: stats.mtime.toISOString(),\n },\n };\n}\n\nfunction isInsideRoot(rootPath: string, candidatePath: string): boolean {\n const relative = path.relative(rootPath, candidatePath);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nasync function describeEntry({\n absolutePath,\n relativePath,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths,\n}: {\n absolutePath: string;\n relativePath: string;\n rootRealPath: string;\n ancestors: ReadonlySet<string>;\n followSymlinks: boolean;\n selectedPaths: ReadonlySet<string> | null;\n}): Promise<FileSystemEntry> {\n const linkStats = await lstat(absolutePath);\n const kind = entryKind(linkStats);\n let symlink: SymlinkMetadata | null = null;\n\n if (kind === \"symlink\") {\n const target = await readlink(absolutePath);\n let resolvedPath: string | null = null;\n let targetKind: Exclude<EntryKind, \"symlink\"> | null = null;\n let targetSize: number | null = null;\n try {\n resolvedPath = await realpath(absolutePath);\n const targetStats = await stat(absolutePath);\n targetKind = entryKind(targetStats) as Exclude<EntryKind, \"symlink\">;\n targetSize = targetStats.size;\n } catch {\n // Broken and inaccessible links are represented as data.\n }\n const isOutsideRoot = resolvedPath === null || !isInsideRoot(rootRealPath, resolvedPath);\n const isCycle = resolvedPath !== null && ancestors.has(resolvedPath);\n const targetRelativePath =\n resolvedPath !== null && !isOutsideRoot\n ? path.relative(rootRealPath, resolvedPath).split(path.sep).join(\"/\")\n : null;\n const isTargetExcluded =\n targetRelativePath !== null &&\n selectedPaths !== null &&\n !selectedPaths.has(targetRelativePath);\n symlink = {\n target,\n resolvedPath,\n targetRelativePath,\n targetKind,\n targetSize:\n isOutsideRoot || isTargetExcluded || targetKind === \"directory\" ? null : targetSize,\n isBroken: resolvedPath === null,\n isCycle,\n isOutsideRoot,\n isTargetExcluded,\n wasFollowed:\n followSymlinks &&\n targetKind === \"directory\" &&\n !isCycle &&\n !isOutsideRoot &&\n !isTargetExcluded,\n };\n }\n\n return {\n name: path.basename(absolutePath),\n absolutePath,\n relativePath,\n kind,\n metadata: metadata(linkStats),\n symlink,\n };\n}\n\nfunction assertSafeOutputName(name: string): void {\n if (name.length === 0 || path.basename(name) !== name || name === \".\" || name === \"..\") {\n throw new Error(`Output name must be a single safe filename: ${name}`);\n }\n}\n\nfunction normalizeBase(value: string): string {\n if (value.includes(\"?\") || value.includes(\"#\")) {\n throw new TypeError(\"base must not contain a query string or fragment\");\n }\n if (/^https?:\\/\\//i.test(value)) {\n const url = new URL(value);\n url.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/`;\n return url.href;\n }\n if (!value.startsWith(\"/\")) {\n throw new TypeError('base must start with \"/\" or be an absolute HTTP(S) URL');\n }\n return `${value.replace(/\\/+$/, \"\")}/`;\n}\n\nfunction encodeLogicalPath(value: string): string {\n return value\n .split(\"/\")\n .filter((segment) => segment.length > 0)\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n}\n\nfunction isDirectoryLike(entry: FileSystemEntry): boolean {\n return entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n}\n\nfunction isUnavailableSymlink(entry: FileSystemEntry): boolean {\n return Boolean(\n entry.symlink?.isBroken || entry.symlink?.isOutsideRoot || entry.symlink?.isTargetExcluded,\n );\n}\n\nfunction compareUnicode(left: string, right: string): number {\n const leftPoints = [...left];\n const rightPoints = [...right];\n const length = Math.min(leftPoints.length, rightPoints.length);\n for (let index = 0; index < length; index += 1) {\n const difference =\n (leftPoints[index]?.codePointAt(0) ?? 0) - (rightPoints[index]?.codePointAt(0) ?? 0);\n if (difference !== 0) return difference;\n }\n return leftPoints.length - rightPoints.length;\n}\n\nfunction compareNames(left: string, right: string, mode: NameSortMode): number {\n if (mode === \"unicode\") return compareUnicode(left, right);\n return left.localeCompare(right, undefined, {\n numeric: mode === \"natural\",\n sensitivity: \"base\",\n });\n}\n\nexport function compareEntries(\n left: FileSystemEntry,\n right: FileSystemEntry,\n options: SortOptions = {},\n): number {\n const resolved = { ...defaultSort, ...options };\n if (resolved.directoriesFirst && isDirectoryLike(left) !== isDirectoryLike(right)) {\n return isDirectoryLike(left) ? -1 : 1;\n }\n let result: number;\n if (resolved.field === \"modified\") {\n result = left.metadata.times.modifiedAt.localeCompare(right.metadata.times.modifiedAt);\n } else if (resolved.field === \"size\") {\n result =\n (left.kind === \"directory\" ? 0 : left.metadata.size) -\n (right.kind === \"directory\" ? 0 : right.metadata.size);\n } else {\n result = compareNames(left.name, right.name, resolved.nameMode);\n }\n if (result === 0) result = compareNames(left.name, right.name, resolved.nameMode);\n return resolved.direction === \"asc\" ? result : -result;\n}\n\nfunction rawLinkFilename(entry: FileSystemEntry): string {\n return `${createHash(\"sha256\")\n .update(entry.relativePath)\n .update(\"\\0\")\n .update(entry.symlink?.target ?? \"\")\n .digest(\"hex\")\n .slice(0, 16)}.txt`;\n}\n\nexport async function generateExplorer(options: GenerateOptions): Promise<void> {\n return generateExplorerSkippingPaths(options, []);\n}\n\n/** Internal entry point for hosts that stage previews outside their published output. */\nexport async function generateExplorerSkippingPaths(\n options: GenerateOptions,\n ignoredPaths: readonly string[],\n): Promise<void> {\n const sourceDir = path.resolve(options.sourceDir);\n const outputDir = path.resolve(options.outputDir);\n const ignoredSourcePaths = ignoredPaths.map((value) => path.resolve(value));\n const rootRealPath = await realpath(sourceDir);\n const outputName = options.outputName ?? defaultOutputName;\n const resolveOutputName: OutputNameResolver =\n typeof outputName === \"string\" ? () => outputName : outputName;\n const theme: ExplorerTheme = options.theme ?? defaultTheme;\n const mode = options.mode ?? \"ssg\";\n const urlStrategy = options.urlStrategy ?? \"relative\";\n const base = normalizeBase(options.base ?? \"/\");\n const followSymlinks = options.symlinks?.follow ?? false;\n const boundary = options.symlinks?.boundary ?? \"root\";\n const onCycle = options.symlinks?.onCycle ?? \"skip\";\n const filtersActive =\n options.include !== undefined || options.exclude !== undefined || ignoredSourcePaths.length > 0;\n const plans: Array<{\n readonly directory: DirectoryData;\n readonly logicalDir: string;\n readonly outputName: string | null;\n }> = [];\n if (isInsideRoot(outputDir, sourceDir)) {\n throw new Error(\"outputDir must not contain the sourceDir\");\n }\n try {\n await lstat(path.join(sourceDir, \"__dirwell\"));\n throw new Error('Dirwell reserves the source-root path \"__dirwell\"');\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n // The reserved asset path is available.\n } else {\n throw error;\n }\n }\n const outputIsWithinSource = isInsideRoot(sourceDir, outputDir);\n const selection = await selectSourcePaths(\n sourceDir,\n outputDir,\n options.include,\n options.exclude,\n ignoredSourcePaths,\n );\n const stageParent = outputIsWithinSource ? path.dirname(sourceDir) : path.dirname(outputDir);\n await mkdir(stageParent, { recursive: true });\n const stagedOutputDir = await mkdtemp(\n path.join(stageParent, `.${path.basename(outputDir)}-dirwell-`),\n );\n const buildOutputDir = stagedOutputDir;\n\n try {\n if (options.mirror ?? true) {\n await rm(buildOutputDir, { recursive: true, force: true });\n await mkdir(buildOutputDir, { recursive: true });\n await cp(sourceDir, buildOutputDir, {\n recursive: true,\n dereference: false,\n preserveTimestamps: true,\n filter: (sourcePath) => {\n const relativePath = path.relative(sourceDir, sourcePath).split(path.sep).join(\"/\");\n return (\n selection.selected.has(relativePath) &&\n (!selection.symlinks.has(relativePath) || selection.mirroredSymlinks.has(relativePath))\n );\n },\n });\n }\n } catch (error) {\n await rm(stagedOutputDir, { recursive: true, force: true });\n throw error;\n }\n\n async function visit(\n logicalDir: string,\n physicalDir: string,\n ancestors: ReadonlySet<string>,\n ): Promise<void> {\n const physicalRealPath = await realpath(physicalDir);\n if (ancestors.has(physicalRealPath)) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${logicalDir}`);\n return;\n }\n\n const nextAncestors = new Set(ancestors).add(physicalRealPath);\n const names = (await readdir(physicalDir)).filter((name) => {\n if (outputIsWithinSource && isInsideRoot(outputDir, path.join(physicalDir, name)))\n return false;\n if (ignoredSourcePaths.some((value) => isInsideRoot(value, path.join(physicalDir, name))))\n return false;\n if (!filtersActive) return true;\n const relativePath = path.relative(rootRealPath, path.join(physicalRealPath, name));\n return selection.selected.has(relativePath.split(path.sep).join(\"/\"));\n });\n const entries = await Promise.all(\n names.map((name) =>\n describeEntry({\n absolutePath: path.join(physicalDir, name),\n relativePath: path.posix.join(logicalDir, name),\n rootRealPath,\n ancestors: nextAncestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n }),\n ),\n );\n entries.sort((left, right) => compareEntries(left, right, options.sort));\n\n const describedCurrent = await describeEntry({\n absolutePath: physicalDir,\n relativePath: logicalDir,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n if (describedCurrent.kind !== \"directory\") {\n throw new Error(`${physicalDir} is not a directory`);\n }\n const current: DirectoryData[\"current\"] = {\n ...describedCurrent,\n kind: \"directory\",\n };\n\n const root = await describeEntry({\n absolutePath: sourceDir,\n relativePath: \"\",\n rootRealPath,\n ancestors: new Set(),\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const parent =\n logicalDir === \"\"\n ? null\n : await describeEntry({\n absolutePath: path.dirname(physicalDir),\n relativePath:\n path.posix.dirname(logicalDir) === \".\" ? \"\" : path.posix.dirname(logicalDir),\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const directory: DirectoryData = {\n root,\n current,\n parent,\n depth: logicalDir === \"\" ? 0 : logicalDir.split(\"/\").length,\n entries,\n };\n\n const name = await resolveOutputName(directory);\n if (name !== null) assertSafeOutputName(name);\n plans.push({ directory, logicalDir, outputName: name });\n\n for (const entry of entries) {\n if (entry.kind === \"directory\") {\n await visit(path.posix.join(logicalDir, entry.name), entry.absolutePath, nextAncestors);\n continue;\n }\n if (!followSymlinks || entry.symlink?.targetKind !== \"directory\") continue;\n const physicalLinkPath = path\n .relative(rootRealPath, path.join(physicalRealPath, entry.name))\n .split(path.sep)\n .join(\"/\");\n if ((options.mirror ?? true) && !selection.mirroredSymlinks.has(physicalLinkPath)) continue;\n if (entry.symlink.isCycle) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${entry.relativePath}`);\n continue;\n }\n if (entry.symlink.resolvedPath === null) continue;\n if (boundary === \"root\" && entry.symlink.isOutsideRoot) continue;\n if (\n filtersActive &&\n (entry.symlink.targetRelativePath === null ||\n !selection.selected.has(entry.symlink.targetRelativePath))\n )\n continue;\n await visit(\n path.posix.join(logicalDir, entry.name),\n entry.symlink.resolvedPath,\n nextAncestors,\n );\n }\n }\n\n try {\n await visit(\"\", sourceDir, new Set());\n\n const generatedPages = new Map(\n plans\n .filter(\n (plan): plan is typeof plan & { readonly outputName: string } => plan.outputName !== null,\n )\n .map((plan) => [plan.logicalDir, plan.outputName]),\n );\n const generatedDirectories = new Set(generatedPages.keys());\n const pagePathForDirectory = (logicalPath: string): string => {\n const pageName = generatedPages.get(logicalPath);\n return pageName === undefined || pageName === \"index.html\"\n ? logicalPath\n : path.posix.join(logicalPath, pageName);\n };\n const sharedAssets = new Map<string, string | Uint8Array>();\n const rawLinkFiles = new Map<string, string>();\n const searchEntries = new Map<\n string,\n {\n href: string | null;\n exitsExplorer: boolean;\n isLink: boolean;\n kind: EntryKind;\n modifiedAt: string;\n name: string;\n path: string;\n size: number;\n target: string | null;\n targetKind: Exclude<EntryKind, \"symlink\"> | null;\n targetSize: number | null;\n isTargetUnavailable: boolean;\n isCycle: boolean;\n }\n >();\n\n for (const { directory, logicalDir } of theme.searchIndex === false ? [] : plans) {\n for (const entry of directory.entries) {\n if (searchEntries.has(entry.relativePath)) continue;\n const targetLogicalPath = isUnavailableSymlink(entry)\n ? null\n : entry.symlink?.targetRelativePath !== null && entry.symlink !== null\n ? entry.symlink.targetRelativePath\n : path.posix.join(logicalDir, entry.name);\n const directoryLike = isDirectoryLike(entry);\n const linkedPath =\n directoryLike && targetLogicalPath !== null\n ? pagePathForDirectory(targetLogicalPath)\n : targetLogicalPath;\n let href: string | null = null;\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n href = `raw-links/${filename}`;\n } else if (linkedPath !== null) {\n href =\n linkedPath === \"\"\n ? \"../\"\n : `../${encodeLogicalPath(linkedPath)}${directoryLike && linkedPath === targetLogicalPath ? \"/\" : \"\"}`;\n }\n searchEntries.set(entry.relativePath, {\n exitsExplorer:\n isUnavailableSymlink(entry) ||\n (targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))),\n href,\n isLink: entry.kind === \"symlink\",\n kind: entry.kind,\n modifiedAt: entry.metadata.times.modifiedAt,\n name: entry.name,\n path: entry.relativePath,\n size: entry.metadata.size,\n target: entry.symlink?.target ?? null,\n targetKind: entry.symlink?.targetKind ?? null,\n targetSize: entry.symlink?.targetSize ?? null,\n isTargetUnavailable: isUnavailableSymlink(entry),\n isCycle: entry.symlink?.isCycle ?? false,\n });\n }\n }\n\n for (const plan of plans) {\n const { directory, logicalDir, outputName: name } = plan;\n if (name === null) continue;\n\n const targetLogicalPathFor = (entry: FileSystemEntry): string | null => {\n if (isUnavailableSymlink(entry)) return null;\n if (entry.symlink?.targetRelativePath !== null && entry.symlink !== null) {\n return entry.symlink.targetRelativePath;\n }\n return path.posix.join(logicalDir, entry.name);\n };\n const hrefForLogicalPath = (targetPath: string, directoryLike: boolean): string => {\n const linkedPath = directoryLike ? pagePathForDirectory(targetPath) : targetPath;\n const linkToDirectory = directoryLike && linkedPath === targetPath;\n if (urlStrategy === \"relative\") {\n const relativeTarget = path.posix.relative(\n logicalDir === \"\" ? \".\" : logicalDir,\n linkedPath === \"\" ? \".\" : linkedPath,\n );\n const encodedTarget = relativeTarget\n .split(\"/\")\n .map((segment) =>\n segment === \".\" || segment === \"..\" ? segment : encodeURIComponent(segment),\n )\n .join(\"/\");\n return `${encodedTarget || \".\"}${linkToDirectory ? \"/\" : \"\"}`;\n }\n const encodedTarget = encodeLogicalPath(linkedPath);\n if (encodedTarget === \"\") {\n return urlStrategy === \"base\" ? base : \"./\";\n }\n const suffix = `${encodedTarget}${linkToDirectory ? \"/\" : \"\"}`;\n return urlStrategy === \"base\" ? `${base}${suffix}` : suffix;\n };\n const hrefFor = (entry: FileSystemEntry): string | null => {\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n return hrefForLogicalPath(path.posix.join(\"__dirwell\", \"raw-links\", filename), false);\n }\n const targetLogicalPath = targetLogicalPathFor(entry);\n if (targetLogicalPath === null) return null;\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n return hrefForLogicalPath(targetLogicalPath, directoryLike);\n };\n const page = await theme.render({\n directory,\n documentBaseHref: urlStrategy === \"html-base\" ? base : null,\n outputName: name,\n mode,\n searchIndexHref: hrefForLogicalPath(\n path.posix.join(\"__dirwell\", \"search-index.json\"),\n false,\n ),\n sort: { ...defaultSort, ...options.sort },\n assetHref: (assetName) => {\n assertSafeOutputName(assetName);\n return hrefForLogicalPath(\n mode === \"ssg\"\n ? path.posix.join(logicalDir, assetName)\n : path.posix.join(\"__dirwell\", assetName),\n false,\n );\n },\n hrefFor,\n hrefForDirectory: (relativePath) => hrefForLogicalPath(relativePath, true),\n exitsExplorerFor: (entry) => {\n if (isUnavailableSymlink(entry)) return true;\n const targetLogicalPath = targetLogicalPathFor(entry);\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n return (\n targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))\n );\n },\n });\n const targetDir = path.join(buildOutputDir, logicalDir);\n await mkdir(targetDir, { recursive: true });\n await writeFile(path.join(targetDir, name), page.html);\n for (const [assetName, contents] of Object.entries(page.assets ?? {})) {\n assertSafeOutputName(assetName);\n if (mode === \"ssg\") {\n await writeFile(path.join(targetDir, assetName), contents);\n } else {\n const bytes = Buffer.from(contents);\n const existing = sharedAssets.get(assetName);\n if (existing !== undefined && !Buffer.from(existing).equals(bytes)) {\n throw new Error(`Theme emitted conflicting shared asset: ${assetName}`);\n }\n sharedAssets.set(assetName, bytes);\n }\n }\n }\n\n if (mode === \"mpa\" && sharedAssets.size > 0) {\n const assetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(assetDirectory, { recursive: true });\n for (const [assetName, contents] of sharedAssets) {\n await writeFile(path.join(assetDirectory, assetName), contents);\n }\n }\n\n if (rawLinkFiles.size > 0) {\n const rawLinkDirectory = path.join(buildOutputDir, \"__dirwell\", \"raw-links\");\n await mkdir(rawLinkDirectory, { recursive: true });\n for (const [filename, target] of rawLinkFiles) {\n await writeFile(path.join(rawLinkDirectory, filename), target);\n }\n }\n if (theme.searchIndex !== false) {\n const generatedAssetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(generatedAssetDirectory, { recursive: true });\n const indexedEntries = [...searchEntries.values()];\n const shards: string[] = [];\n for (let offset = 0; offset < indexedEntries.length; offset += 512) {\n const filename = `search-${String(shards.length).padStart(5, \"0\")}.json`;\n shards.push(filename);\n await writeFile(\n path.join(generatedAssetDirectory, filename),\n JSON.stringify({ entries: indexedEntries.slice(offset, offset + 512) }),\n );\n }\n await writeFile(\n path.join(generatedAssetDirectory, \"search-index.json\"),\n JSON.stringify({ count: indexedEntries.length, shards, version: 3 }),\n );\n }\n\n await rm(outputDir, { recursive: true, force: true });\n await mkdir(path.dirname(outputDir), { recursive: true });\n await rename(stagedOutputDir, outputDir);\n } finally {\n await rm(stagedOutputDir, { recursive: true, force: true });\n }\n}\n\nexport async function readGeneratedPage(filePath: string): Promise<string> {\n return readFile(filePath, \"utf8\");\n}\n"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { a as FileSystemEntry, c as NameSortMode, d as SortDirection, f as SortField, h as ThemeContext, i as FileMetadata, l as OutputNameResolver, m as SymlinkMetadata, n as EntryKind, o as FileTimes, p as SortOptions, r as ExplorerTheme, s as GenerateOptions, t as DirectoryData, u as RenderedPage } from "./model-CWjYM17j.mjs";
2
+ import { a as loadDirwellConfig, i as defineConfig, n as DirwellConfigContext, o as resolveGenerateOptions, r as DirwellConfigInput, t as DirwellConfig } from "./config-BJG2Zc3Q.mjs";
3
+ import { _ as resolveThemeComponents, a as DirwellThemeComponents, b as ThemeProjectOptions, c as EntryListProps, d as FooterProps, f as IconName, g as ToolbarProps, i as DirwellThemeComponentOverrides, l as EntryNavigation, m as PageShellProps, n as BreadcrumbsProps, o as EmptyStateProps, p as IconProps, r as DefaultThemeRuntimeConfig, s as EntryListItem, t as BreadcrumbItem, u as EntryRowProps, v as DefaultThemeIconSet, y as DefaultThemeIconVariant } from "./theme-components-DW0fv9_C.mjs";
4
+ //#region src/dev-server.d.ts
5
+ export declare function createExplorerDevServer(options: GenerateOptions & {
6
+ readonly host?: string;
7
+ readonly port?: number;
8
+ }): Promise<{
9
+ url: string;
10
+ close(): Promise<void>;
11
+ }>;
12
+ //#endregion
13
+ //#region src/generator.d.ts
14
+ export declare const defaultOutputName: OutputNameResolver;
15
+ export declare function compareEntries(left: FileSystemEntry, right: FileSystemEntry, options?: SortOptions): number;
16
+ export declare function generateExplorer(options: GenerateOptions): Promise<void>;
17
+ export declare function readGeneratedPage(filePath: string): Promise<string>;
18
+ //#endregion
19
+ //#region src/theme-default/components.d.ts
20
+ export declare function escapeHtml(value: string): string;
21
+ export declare const defaultThemeComponents: DirwellThemeComponents;
22
+ //#endregion
23
+ //#region src/theme-default.d.ts
24
+ interface DefaultThemeOptions {
25
+ readonly colorScheme?: boolean;
26
+ readonly components?: DirwellThemeComponentOverrides | readonly DirwellThemeComponentOverrides[];
27
+ readonly fuzzySearch?: boolean;
28
+ readonly globalSearch?: boolean;
29
+ readonly keyboardNavigation?: boolean;
30
+ readonly icons?: DefaultThemeIconSet;
31
+ readonly project?: ThemeProjectOptions;
32
+ readonly sorting?: boolean;
33
+ /** MPA directories above this size load rows from an asset and render a measured window. */
34
+ readonly virtualizeAfter?: number;
35
+ }
36
+ export declare function createDefaultTheme(options?: DefaultThemeOptions): ExplorerTheme;
37
+ export declare const defaultTheme: ExplorerTheme;
38
+ //#endregion
39
+ //#region src/theme-plain.d.ts
40
+ interface PlainThemeOptions {
41
+ readonly project?: ThemeProjectOptions;
42
+ }
43
+ /** A no-icon, no-script theme that leaves navigation and controls to the browser. */
44
+ export declare function createPlainTheme(options?: PlainThemeOptions): ExplorerTheme;
45
+ //#endregion
46
+ export { type BreadcrumbItem, type BreadcrumbsProps, type DefaultThemeIconSet, type DefaultThemeIconVariant, type DefaultThemeRuntimeConfig, type DirectoryData, type DirwellConfig, type DirwellConfigContext, type DirwellConfigInput, type DirwellThemeComponentOverrides, type DirwellThemeComponents, type EmptyStateProps, type EntryKind, type EntryListItem, type EntryListProps, type EntryNavigation, type EntryRowProps, type ExplorerTheme, type FileMetadata, type FileSystemEntry, type FileTimes, type FooterProps, type GenerateOptions, type IconName, type IconProps, type NameSortMode, type OutputNameResolver, type PageShellProps, type PlainThemeOptions, type RenderedPage, type SortDirection, type SortField, type SortOptions, type SymlinkMetadata, type ThemeContext, type ToolbarProps, defineConfig, loadDirwellConfig, resolveGenerateOptions, resolveThemeComponents };
47
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,74 @@
1
+ import { a as readGeneratedPage, c as resolveThemeProject, d as utcTimestamp, f as defineConfig, l as defaultThemeComponents, m as resolveGenerateOptions, n as defaultOutputName, o as createDefaultTheme, p as loadDirwellConfig, r as generateExplorer, s as defaultTheme, t as compareEntries, u as escapeHtml } from "./generator-CtX3iHhK.mjs";
2
+ import { t as resolveThemeComponents } from "./theme-components-CXzvdQY-.mjs";
3
+ import { t as createExplorerDevServer } from "./dev-server-Q7NC1wiB.mjs";
4
+ //#region src/theme-plain.ts
5
+ function escapeHtml$1(value) {
6
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
7
+ }
8
+ function externalHref(value) {
9
+ if (value === void 0) return null;
10
+ try {
11
+ const url = new URL(value);
12
+ return url.protocol === "https:" || url.protocol === "http:" ? url.href : null;
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+ function externalLink(label, href) {
18
+ return href === null ? escapeHtml$1(label) : `<a href="${escapeHtml$1(href)}" target="_blank" rel="noopener">${escapeHtml$1(label)}</a>`;
19
+ }
20
+ function status(entry) {
21
+ if (entry.symlink?.isBroken) return "broken link";
22
+ if (entry.symlink?.isOutsideRoot) return "unavailable link";
23
+ if (entry.symlink?.isCycle) return "cycle link";
24
+ if (entry.kind === "symlink") return "link";
25
+ if (entry.kind === "directory") return "folder";
26
+ return "file";
27
+ }
28
+ function renderBreadcrumbs(context) {
29
+ const segments = context.directory.current.relativePath.split("/").filter(Boolean);
30
+ if (segments.length === 0) return "";
31
+ const ancestors = segments.slice(0, -1).map((segment, index) => {
32
+ const relativePath = segments.slice(0, index + 1).join("/");
33
+ return `<a href="${escapeHtml$1(context.hrefForDirectory(relativePath))}">${escapeHtml$1(segment)}</a>`;
34
+ });
35
+ return `<nav aria-label="Breadcrumb"><a href="${escapeHtml$1(context.hrefForDirectory(""))}">Home</a> / ${ancestors.length === 0 ? "" : `${ancestors.join(" / ")} / `}<span aria-current="page">${escapeHtml$1(segments.at(-1) ?? "")}</span></nav>`;
36
+ }
37
+ function renderEntry(entry, context) {
38
+ const directoryLike = entry.kind === "directory" || entry.symlink?.targetKind === "directory";
39
+ const name = `${escapeHtml$1(entry.name)}${directoryLike ? "/" : ""}`;
40
+ const href = context.hrefFor(entry);
41
+ const exitsExplorer = context.exitsExplorerFor(entry);
42
+ const link = href === null ? `<span>${name}</span>` : `<a href="${escapeHtml$1(href)}"${exitsExplorer ? " target=\"_blank\" rel=\"noopener\"" : ""}>${name}</a>`;
43
+ const details = [status(entry)];
44
+ if (!directoryLike) details.push(`${entry.metadata.size} B`);
45
+ if (entry.symlink !== null) details.push(`Target: ${entry.symlink.target}`);
46
+ if (exitsExplorer) details.push("opens in a new tab");
47
+ const modified = utcTimestamp(entry.metadata.times.modifiedAt);
48
+ return `<li>${link}<small>${escapeHtml$1(details.join(" · "))} · ${modified === null ? "Unknown" : `<time datetime="${modified.datetime}">${modified.label}</time>`}</small></li>`;
49
+ }
50
+ /** A no-icon, no-script theme that leaves navigation and controls to the browser. */
51
+ function createPlainTheme(options = {}) {
52
+ const project = resolveThemeProject(options.project);
53
+ const repositoryHref = externalHref(project.repositoryUrl);
54
+ const licenseHref = externalHref(options.project?.licenseUrl ?? (options.project?.license === void 0 ? "https://opensource.org/license/mit" : void 0));
55
+ return {
56
+ name: "plain",
57
+ searchIndex: false,
58
+ render(context) {
59
+ const visiblePath = context.directory.current.relativePath === "" ? "/" : `/${context.directory.current.relativePath}/`;
60
+ const parentHref = context.directory.parent === null ? null : context.hrefForDirectory(context.directory.parent.relativePath);
61
+ const parentRow = parentHref === null ? "" : `<li><a href="${escapeHtml$1(parentHref)}">../</a></li>`;
62
+ const rows = context.directory.entries.map((entry) => renderEntry(entry, context)).join("");
63
+ const count = context.directory.entries.length;
64
+ const footer = `<footer><hr><p>Repository: ${externalLink(project.name, repositoryHref)} by ${escapeHtml$1(project.author)} · ${externalLink(project.license, licenseHref)}</p></footer>`;
65
+ return { html: `<!doctype html>
66
+ <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light">${context.documentBaseHref === null ? "" : `<base href="${escapeHtml$1(context.documentBaseHref)}">`}<title>Index of ${escapeHtml$1(visiblePath)}</title><style>body{max-width:72ch;margin:2rem auto;padding:0 1rem}h1,li,nav{overflow-wrap:anywhere}li{margin:.6rem 0}small{display:block}</style></head>
67
+ <body><main>${renderBreadcrumbs(context)}<h1>Index of ${escapeHtml$1(visiblePath)}</h1><p>${count} ${count === 1 ? "entry" : "entries"}</p>${count === 0 ? "<p>This directory is empty.</p>" : ""}<ul>${parentRow}${rows}</ul></main>${footer}</body></html>` };
68
+ }
69
+ };
70
+ }
71
+ //#endregion
72
+ export { compareEntries, createDefaultTheme, createExplorerDevServer, createPlainTheme, defaultOutputName, defaultTheme, defaultThemeComponents, defineConfig, escapeHtml, generateExplorer, loadDirwellConfig, readGeneratedPage, resolveGenerateOptions, resolveThemeComponents };
73
+
74
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["escapeHtml"],"sources":["../src/theme-plain.ts"],"sourcesContent":["import type { ExplorerTheme, FileSystemEntry, ThemeContext } from \"./model.ts\";\nimport { resolveThemeProject, type ThemeProjectOptions } from \"./theme-project.ts\";\nimport { utcTimestamp } from \"./timestamp.ts\";\n\nexport interface PlainThemeOptions {\n readonly project?: ThemeProjectOptions;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\");\n}\n\nfunction externalHref(value: string | undefined): string | null {\n if (value === undefined) return null;\n try {\n const url = new URL(value);\n return url.protocol === \"https:\" || url.protocol === \"http:\" ? url.href : null;\n } catch {\n return null;\n }\n}\n\nfunction externalLink(label: string, href: string | null): string {\n return href === null\n ? escapeHtml(label)\n : `<a href=\"${escapeHtml(href)}\" target=\"_blank\" rel=\"noopener\">${escapeHtml(label)}</a>`;\n}\n\nfunction status(entry: FileSystemEntry): string {\n if (entry.symlink?.isBroken) return \"broken link\";\n if (entry.symlink?.isOutsideRoot) return \"unavailable link\";\n if (entry.symlink?.isCycle) return \"cycle link\";\n if (entry.kind === \"symlink\") return \"link\";\n if (entry.kind === \"directory\") return \"folder\";\n return \"file\";\n}\n\nfunction renderBreadcrumbs(context: ThemeContext): string {\n const segments = context.directory.current.relativePath.split(\"/\").filter(Boolean);\n if (segments.length === 0) return \"\";\n const ancestors = segments.slice(0, -1).map((segment, index) => {\n const relativePath = segments.slice(0, index + 1).join(\"/\");\n return `<a href=\"${escapeHtml(context.hrefForDirectory(relativePath))}\">${escapeHtml(segment)}</a>`;\n });\n return `<nav aria-label=\"Breadcrumb\"><a href=\"${escapeHtml(context.hrefForDirectory(\"\"))}\">Home</a> / ${ancestors.length === 0 ? \"\" : `${ancestors.join(\" / \")} / `}<span aria-current=\"page\">${escapeHtml(segments.at(-1) ?? \"\")}</span></nav>`;\n}\n\nfunction renderEntry(entry: FileSystemEntry, context: ThemeContext): string {\n const directoryLike = entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n const name = `${escapeHtml(entry.name)}${directoryLike ? \"/\" : \"\"}`;\n const href = context.hrefFor(entry);\n const exitsExplorer = context.exitsExplorerFor(entry);\n const link =\n href === null\n ? `<span>${name}</span>`\n : `<a href=\"${escapeHtml(href)}\"${exitsExplorer ? ' target=\"_blank\" rel=\"noopener\"' : \"\"}>${name}</a>`;\n const details = [status(entry)];\n if (!directoryLike) details.push(`${entry.metadata.size} B`);\n if (entry.symlink !== null) details.push(`Target: ${entry.symlink.target}`);\n if (exitsExplorer) details.push(\"opens in a new tab\");\n const modified = utcTimestamp(entry.metadata.times.modifiedAt);\n return `<li>${link}<small>${escapeHtml(details.join(\" · \"))} · ${modified === null ? \"Unknown\" : `<time datetime=\"${modified.datetime}\">${modified.label}</time>`}</small></li>`;\n}\n\n/** A no-icon, no-script theme that leaves navigation and controls to the browser. */\nexport function createPlainTheme(options: PlainThemeOptions = {}): ExplorerTheme {\n const project = resolveThemeProject(options.project);\n const repositoryHref = externalHref(project.repositoryUrl);\n const licenseHref = externalHref(\n options.project?.licenseUrl ??\n (options.project?.license === undefined ? \"https://opensource.org/license/mit\" : undefined),\n );\n return {\n name: \"plain\",\n searchIndex: false,\n render(context) {\n const visiblePath =\n context.directory.current.relativePath === \"\"\n ? \"/\"\n : `/${context.directory.current.relativePath}/`;\n const parentHref =\n context.directory.parent === null\n ? null\n : context.hrefForDirectory(context.directory.parent.relativePath);\n const parentRow =\n parentHref === null ? \"\" : `<li><a href=\"${escapeHtml(parentHref)}\">../</a></li>`;\n const rows = context.directory.entries.map((entry) => renderEntry(entry, context)).join(\"\");\n const count = context.directory.entries.length;\n const footer = `<footer><hr><p>Repository: ${externalLink(project.name, repositoryHref)} by ${escapeHtml(project.author)} · ${externalLink(project.license, licenseHref)}</p></footer>`;\n const html = `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><meta name=\"color-scheme\" content=\"light\">${context.documentBaseHref === null ? \"\" : `<base href=\"${escapeHtml(context.documentBaseHref)}\">`}<title>Index of ${escapeHtml(visiblePath)}</title><style>body{max-width:72ch;margin:2rem auto;padding:0 1rem}h1,li,nav{overflow-wrap:anywhere}li{margin:.6rem 0}small{display:block}</style></head>\n<body><main>${renderBreadcrumbs(context)}<h1>Index of ${escapeHtml(visiblePath)}</h1><p>${count} ${count === 1 ? \"entry\" : \"entries\"}</p>${count === 0 ? \"<p>This directory is empty.</p>\" : \"\"}<ul>${parentRow}${rows}</ul></main>${footer}</body></html>`;\n return { html };\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ //#region src/model.d.ts
2
+ type EntryKind = "directory" | "file" | "symlink" | "other";
3
+ interface FileTimes {
4
+ readonly accessedAt: string;
5
+ readonly changedAt: string;
6
+ readonly createdAt: string;
7
+ readonly modifiedAt: string;
8
+ }
9
+ interface FileMetadata {
10
+ readonly device: number;
11
+ readonly groupId: number;
12
+ readonly inode: number;
13
+ readonly mode: number;
14
+ readonly hardLinkCount: number;
15
+ readonly size: number;
16
+ readonly ownerId: number;
17
+ readonly times: FileTimes;
18
+ }
19
+ interface SymlinkMetadata {
20
+ readonly target: string;
21
+ readonly resolvedPath: string | null;
22
+ readonly targetRelativePath: string | null;
23
+ readonly targetKind: Exclude<EntryKind, "symlink"> | null;
24
+ readonly targetSize?: number | null;
25
+ readonly isBroken: boolean;
26
+ readonly isCycle: boolean;
27
+ readonly isOutsideRoot: boolean;
28
+ readonly isTargetExcluded?: boolean;
29
+ readonly wasFollowed: boolean;
30
+ }
31
+ interface FileSystemEntry {
32
+ readonly name: string;
33
+ readonly absolutePath: string;
34
+ readonly relativePath: string;
35
+ readonly kind: EntryKind;
36
+ readonly metadata: FileMetadata;
37
+ readonly symlink: SymlinkMetadata | null;
38
+ }
39
+ interface DirectoryData {
40
+ readonly root: FileSystemEntry;
41
+ readonly current: FileSystemEntry & {
42
+ readonly kind: "directory";
43
+ };
44
+ readonly parent: FileSystemEntry | null;
45
+ readonly depth: number;
46
+ readonly entries: readonly FileSystemEntry[];
47
+ }
48
+ type OutputNameResolver = (directory: DirectoryData) => string | null | Promise<string | null>;
49
+ interface RenderedPage {
50
+ readonly html: string;
51
+ readonly assets?: Readonly<Record<string, string | Uint8Array>>;
52
+ }
53
+ type SortField = "modified" | "name" | "size";
54
+ type NameSortMode = "locale" | "natural" | "unicode";
55
+ type SortDirection = "asc" | "desc";
56
+ interface SortOptions {
57
+ readonly direction?: SortDirection;
58
+ readonly directoriesFirst?: boolean;
59
+ readonly field?: SortField;
60
+ readonly nameMode?: NameSortMode;
61
+ }
62
+ interface ThemeContext {
63
+ readonly documentBaseHref: string | null;
64
+ readonly directory: DirectoryData;
65
+ readonly outputName: string;
66
+ readonly mode: "mpa" | "ssg";
67
+ readonly searchIndexHref: string;
68
+ readonly sort: Required<SortOptions>;
69
+ readonly assetHref: (assetName: string) => string;
70
+ readonly hrefForDirectory: (relativePath: string) => string;
71
+ readonly hrefFor: (entry: FileSystemEntry) => string | null;
72
+ readonly exitsExplorerFor: (entry: FileSystemEntry) => boolean;
73
+ }
74
+ interface ExplorerTheme {
75
+ readonly name: string;
76
+ /** Set to false when the theme does not offer global search. */
77
+ readonly searchIndex?: boolean;
78
+ readonly render: (context: ThemeContext) => RenderedPage | Promise<RenderedPage>;
79
+ }
80
+ interface GenerateOptions {
81
+ readonly base?: string;
82
+ readonly include?: string | readonly string[];
83
+ readonly exclude?: string | readonly string[];
84
+ readonly sourceDir: string;
85
+ readonly outputDir: string;
86
+ readonly mode?: "mpa" | "ssg";
87
+ readonly mirror?: boolean;
88
+ readonly outputName?: OutputNameResolver | string;
89
+ readonly theme?: ExplorerTheme;
90
+ readonly urlStrategy?: "base" | "html-base" | "relative";
91
+ readonly symlinks?: {
92
+ readonly follow?: boolean;
93
+ readonly boundary?: "anywhere" | "root";
94
+ readonly onCycle?: "error" | "skip";
95
+ };
96
+ readonly sort?: SortOptions;
97
+ }
98
+ //#endregion
99
+ export { FileSystemEntry as a, NameSortMode as c, SortDirection as d, SortField as f, ThemeContext as h, FileMetadata as i, OutputNameResolver as l, SymlinkMetadata as m, EntryKind as n, FileTimes as o, SortOptions as p, ExplorerTheme as r, GenerateOptions as s, DirectoryData as t, RenderedPage as u };
100
+ //# sourceMappingURL=model-CWjYM17j.d.mts.map
@@ -0,0 +1,7 @@
1
+ import { n as DirwellPluginOptions, t as DirwellPluginInput } from "./unplugin-CKRUCTgW.mjs";
2
+ import { UnpluginInstance } from "unplugin";
3
+ //#region src/rolldown.d.ts
4
+ declare const plugin: UnpluginInstance<DirwellPluginInput, true>["rolldown"];
5
+ //#endregion
6
+ export { type DirwellPluginOptions, plugin as default };
7
+ //# sourceMappingURL=rolldown.d.mts.map
@@ -0,0 +1,7 @@
1
+ import { t as unplugin } from "./unplugin-p6AXhL4F.mjs";
2
+ //#region src/rolldown.ts
3
+ const plugin = unplugin.rolldown;
4
+ //#endregion
5
+ export { plugin as default };
6
+
7
+ //# sourceMappingURL=rolldown.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rolldown.mjs","names":[],"sources":["../src/rolldown.ts"],"sourcesContent":["import type { UnpluginInstance } from \"unplugin\";\nimport unplugin, { type DirwellPluginInput } from \"./unplugin.ts\";\nexport type { DirwellPluginOptions } from \"./unplugin.ts\";\nconst plugin: UnpluginInstance<DirwellPluginInput, true>[\"rolldown\"] = unplugin.rolldown;\nexport default plugin;\n"],"mappings":";;AAGA,MAAM,SAAiE,SAAS"}
@@ -0,0 +1,7 @@
1
+ import { n as DirwellPluginOptions, t as DirwellPluginInput } from "./unplugin-CKRUCTgW.mjs";
2
+ import { UnpluginInstance } from "unplugin";
3
+ //#region src/rollup.d.ts
4
+ declare const plugin: UnpluginInstance<DirwellPluginInput, true>["rollup"];
5
+ //#endregion
6
+ export { type DirwellPluginOptions, plugin as default };
7
+ //# sourceMappingURL=rollup.d.mts.map
@@ -0,0 +1,7 @@
1
+ import { t as unplugin } from "./unplugin-p6AXhL4F.mjs";
2
+ //#region src/rollup.ts
3
+ const plugin = unplugin.rollup;
4
+ //#endregion
5
+ export { plugin as default };
6
+
7
+ //# sourceMappingURL=rollup.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollup.mjs","names":[],"sources":["../src/rollup.ts"],"sourcesContent":["import type { UnpluginInstance } from \"unplugin\";\nimport unplugin, { type DirwellPluginInput } from \"./unplugin.ts\";\nexport type { DirwellPluginOptions } from \"./unplugin.ts\";\nconst plugin: UnpluginInstance<DirwellPluginInput, true>[\"rollup\"] = unplugin.rollup;\nexport default plugin;\n"],"mappings":";;AAGA,MAAM,SAA+D,SAAS"}
@@ -0,0 +1,7 @@
1
+ import { n as DirwellPluginOptions, t as DirwellPluginInput } from "./unplugin-CKRUCTgW.mjs";
2
+ import { UnpluginInstance } from "unplugin";
3
+ //#region src/rsbuild.d.ts
4
+ declare const plugin: UnpluginInstance<DirwellPluginInput, true>["rsbuild"];
5
+ //#endregion
6
+ export { type DirwellPluginOptions, plugin as default };
7
+ //# sourceMappingURL=rsbuild.d.mts.map
@@ -0,0 +1,7 @@
1
+ import { t as unplugin } from "./unplugin-p6AXhL4F.mjs";
2
+ //#region src/rsbuild.ts
3
+ const plugin = unplugin.rsbuild;
4
+ //#endregion
5
+ export { plugin as default };
6
+
7
+ //# sourceMappingURL=rsbuild.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rsbuild.mjs","names":[],"sources":["../src/rsbuild.ts"],"sourcesContent":["import type { UnpluginInstance } from \"unplugin\";\nimport unplugin, { type DirwellPluginInput } from \"./unplugin.ts\";\nexport type { DirwellPluginOptions } from \"./unplugin.ts\";\nconst plugin: UnpluginInstance<DirwellPluginInput, true>[\"rsbuild\"] = unplugin.rsbuild;\nexport default plugin;\n"],"mappings":";;AAGA,MAAM,SAAgE,SAAS"}
@@ -0,0 +1,7 @@
1
+ import { n as DirwellPluginOptions, t as DirwellPluginInput } from "./unplugin-CKRUCTgW.mjs";
2
+ import { UnpluginInstance } from "unplugin";
3
+ //#region src/rspack.d.ts
4
+ declare const plugin: UnpluginInstance<DirwellPluginInput, true>["rspack"];
5
+ //#endregion
6
+ export { type DirwellPluginOptions, plugin as default };
7
+ //# sourceMappingURL=rspack.d.mts.map