nebula-cms 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/astro/index.d.ts +43 -0
- package/dist/astro/index.d.ts.map +1 -0
- package/dist/astro/index.js +223 -0
- package/{src → dist}/client/Admin.svelte +20 -11
- package/dist/client/Admin.svelte.d.ts +11 -0
- package/dist/client/Admin.svelte.d.ts.map +1 -0
- package/dist/client/components/BackendPicker.svelte.d.ts +4 -0
- package/dist/client/components/BackendPicker.svelte.d.ts.map +1 -0
- package/dist/client/components/DraftChip.svelte.d.ts +10 -0
- package/dist/client/components/DraftChip.svelte.d.ts.map +1 -0
- package/dist/client/components/MetadataForm.svelte.d.ts +12 -0
- package/dist/client/components/MetadataForm.svelte.d.ts.map +1 -0
- package/dist/client/components/ThemeToggle.svelte.d.ts +19 -0
- package/dist/client/components/ThemeToggle.svelte.d.ts.map +1 -0
- package/dist/client/components/dialogs/DeleteDraftDialog.svelte.d.ts +11 -0
- package/dist/client/components/dialogs/DeleteDraftDialog.svelte.d.ts.map +1 -0
- package/{src → dist}/client/components/dialogs/FilenameDialog.svelte +1 -2
- package/dist/client/components/dialogs/FilenameDialog.svelte.d.ts +13 -0
- package/dist/client/components/dialogs/FilenameDialog.svelte.d.ts.map +1 -0
- package/dist/client/components/editor/EditorPane.svelte.d.ts +4 -0
- package/dist/client/components/editor/EditorPane.svelte.d.ts.map +1 -0
- package/dist/client/components/editor/EditorTabs.svelte.d.ts +8 -0
- package/dist/client/components/editor/EditorTabs.svelte.d.ts.map +1 -0
- package/dist/client/components/editor/EditorToolbar.svelte.d.ts +4 -0
- package/dist/client/components/editor/EditorToolbar.svelte.d.ts.map +1 -0
- package/dist/client/components/editor/FormatSelector.svelte.d.ts +4 -0
- package/dist/client/components/editor/FormatSelector.svelte.d.ts.map +1 -0
- package/dist/client/components/editor/Toolbar.svelte.d.ts +19 -0
- package/dist/client/components/editor/Toolbar.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/ArrayField.svelte.d.ts +15 -0
- package/dist/client/components/fields/ArrayField.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/ArrayItem.svelte.d.ts +28 -0
- package/dist/client/components/fields/ArrayItem.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/BooleanField.svelte.d.ts +16 -0
- package/dist/client/components/fields/BooleanField.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/DateField.svelte.d.ts +16 -0
- package/dist/client/components/fields/DateField.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/EnumField.svelte.d.ts +17 -0
- package/dist/client/components/fields/EnumField.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/FieldWrapper.svelte.d.ts +18 -0
- package/dist/client/components/fields/FieldWrapper.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/NumberField.svelte.d.ts +16 -0
- package/dist/client/components/fields/NumberField.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/ObjectField.svelte.d.ts +16 -0
- package/dist/client/components/fields/ObjectField.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/SchemaField.svelte.d.ts +16 -0
- package/dist/client/components/fields/SchemaField.svelte.d.ts.map +1 -0
- package/dist/client/components/fields/StringField.svelte.d.ts +16 -0
- package/dist/client/components/fields/StringField.svelte.d.ts.map +1 -0
- package/{src → dist}/client/components/sidebar/AdminSidebar.svelte +2 -4
- package/dist/client/components/sidebar/AdminSidebar.svelte.d.ts +19 -0
- package/dist/client/components/sidebar/AdminSidebar.svelte.d.ts.map +1 -0
- package/dist/client/components/sidebar/AdminSidebarSort.svelte.d.ts +12 -0
- package/dist/client/components/sidebar/AdminSidebarSort.svelte.d.ts.map +1 -0
- package/dist/client/css/icons.css +29 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/js/drafts/merge.svelte.d.ts +24 -0
- package/dist/client/js/drafts/merge.svelte.d.ts.map +1 -0
- package/dist/client/js/drafts/merge.svelte.js +106 -0
- package/dist/client/js/drafts/ops.svelte.d.ts +31 -0
- package/dist/client/js/drafts/ops.svelte.d.ts.map +1 -0
- package/dist/client/js/drafts/ops.svelte.js +182 -0
- package/dist/client/js/drafts/storage.d.ts +45 -0
- package/dist/client/js/drafts/storage.d.ts.map +1 -0
- package/dist/client/js/drafts/storage.js +76 -0
- package/dist/client/js/drafts/workers/diff.d.ts +2 -0
- package/dist/client/js/drafts/workers/diff.d.ts.map +1 -0
- package/dist/client/js/drafts/workers/diff.js +20 -0
- package/dist/client/js/editor/editor.svelte.d.ts +124 -0
- package/dist/client/js/editor/editor.svelte.d.ts.map +1 -0
- package/dist/client/js/editor/editor.svelte.js +294 -0
- package/dist/client/js/editor/languages.d.ts +11 -0
- package/dist/client/js/editor/languages.d.ts.map +1 -0
- package/dist/client/js/editor/languages.js +93 -0
- package/dist/client/js/editor/link-wrap.d.ts +6 -0
- package/dist/client/js/editor/link-wrap.d.ts.map +1 -0
- package/{src/client/js/editor/link-wrap.ts → dist/client/js/editor/link-wrap.js} +17 -24
- package/dist/client/js/editor/markdown-shortcuts.d.ts +4 -0
- package/dist/client/js/editor/markdown-shortcuts.d.ts.map +1 -0
- package/dist/client/js/editor/markdown-shortcuts.js +219 -0
- package/dist/client/js/handlers/admin.d.ts +64 -0
- package/dist/client/js/handlers/admin.d.ts.map +1 -0
- package/dist/client/js/handlers/admin.js +186 -0
- package/dist/client/js/state/dialogs.svelte.d.ts +16 -0
- package/dist/client/js/state/dialogs.svelte.d.ts.map +1 -0
- package/dist/client/js/state/dialogs.svelte.js +28 -0
- package/dist/client/js/state/router.svelte.d.ts +44 -0
- package/dist/client/js/state/router.svelte.d.ts.map +1 -0
- package/dist/client/js/state/router.svelte.js +141 -0
- package/dist/client/js/state/schema.svelte.d.ts +51 -0
- package/dist/client/js/state/schema.svelte.d.ts.map +1 -0
- package/{src/client/js/state/schema.svelte.ts → dist/client/js/state/schema.svelte.js} +55 -70
- package/dist/client/js/state/state.svelte.d.ts +68 -0
- package/dist/client/js/state/state.svelte.d.ts.map +1 -0
- package/dist/client/js/state/state.svelte.js +300 -0
- package/dist/client/js/state/theme.svelte.d.ts +24 -0
- package/dist/client/js/state/theme.svelte.d.ts.map +1 -0
- package/{src/client/js/state/theme.svelte.ts → dist/client/js/state/theme.svelte.js} +54 -91
- package/dist/client/js/storage/adapter.d.ts +130 -0
- package/dist/client/js/storage/adapter.d.ts.map +1 -0
- package/dist/client/js/storage/adapter.js +5 -0
- package/dist/client/js/storage/client.d.ts +72 -0
- package/dist/client/js/storage/client.d.ts.map +1 -0
- package/dist/client/js/storage/client.js +121 -0
- package/dist/client/js/storage/db.d.ts +8 -0
- package/dist/client/js/storage/db.d.ts.map +1 -0
- package/dist/client/js/storage/db.js +35 -0
- package/dist/client/js/storage/fsa.d.ts +51 -0
- package/dist/client/js/storage/fsa.d.ts.map +1 -0
- package/dist/client/js/storage/fsa.js +91 -0
- package/dist/client/js/storage/github.d.ts +62 -0
- package/dist/client/js/storage/github.d.ts.map +1 -0
- package/dist/client/js/storage/github.js +216 -0
- package/dist/client/js/storage/storage.d.ts +32 -0
- package/dist/client/js/storage/storage.d.ts.map +1 -0
- package/dist/client/js/storage/storage.js +68 -0
- package/dist/client/js/storage/workers/frontmatter.d.ts +2 -0
- package/dist/client/js/storage/workers/frontmatter.d.ts.map +1 -0
- package/dist/client/js/storage/workers/frontmatter.js +253 -0
- package/dist/client/js/storage/workers/storage.d.ts +2 -0
- package/dist/client/js/storage/workers/storage.d.ts.map +1 -0
- package/dist/client/js/storage/workers/storage.js +167 -0
- package/dist/client/js/storage/workers/toml-parser.d.ts +2 -0
- package/dist/client/js/storage/workers/toml-parser.d.ts.map +1 -0
- package/dist/client/js/storage/workers/toml-parser.js +75 -0
- package/dist/client/js/storage/workers/yaml-parser.d.ts +2 -0
- package/dist/client/js/storage/workers/yaml-parser.d.ts.map +1 -0
- package/dist/client/js/storage/workers/yaml-parser.js +100 -0
- package/dist/client/js/utils/file-types.d.ts +58 -0
- package/dist/client/js/utils/file-types.d.ts.map +1 -0
- package/{src/client/js/utils/file-types.ts → dist/client/js/utils/file-types.js} +75 -107
- package/dist/client/js/utils/format.d.ts +8 -0
- package/dist/client/js/utils/format.d.ts.map +1 -0
- package/{src/client/js/utils/format.ts → dist/client/js/utils/format.js} +5 -6
- package/dist/client/js/utils/frontmatter.d.ts +12 -0
- package/dist/client/js/utils/frontmatter.d.ts.map +1 -0
- package/dist/client/js/utils/frontmatter.js +29 -0
- package/dist/client/js/utils/schema-utils.d.ts +110 -0
- package/dist/client/js/utils/schema-utils.d.ts.map +1 -0
- package/dist/client/js/utils/schema-utils.js +242 -0
- package/dist/client/js/utils/slug.d.ts +8 -0
- package/dist/client/js/utils/slug.d.ts.map +1 -0
- package/{src/client/js/utils/slug.ts → dist/client/js/utils/slug.js} +6 -7
- package/dist/client/js/utils/sort.d.ts +41 -0
- package/dist/client/js/utils/sort.d.ts.map +1 -0
- package/dist/client/js/utils/sort.js +65 -0
- package/dist/client/js/utils/stable-stringify.d.ts +8 -0
- package/dist/client/js/utils/stable-stringify.d.ts.map +1 -0
- package/dist/client/js/utils/stable-stringify.js +23 -0
- package/dist/client/js/utils/url-utils.d.ts +11 -0
- package/dist/client/js/utils/url-utils.d.ts.map +1 -0
- package/{src/client/js/utils/url-utils.ts → dist/client/js/utils/url-utils.js} +22 -23
- package/dist/client/types/browser-apis.d.ts +39 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +13 -3
- package/.github/workflows/ci.yml +0 -27
- package/.github/workflows/publish.yml +0 -34
- package/.mcp.json +0 -12
- package/.prettierignore +0 -5
- package/.prettierrc.cjs +0 -22
- package/AGENTS.md +0 -183
- package/playground/astro.config.mjs +0 -7
- package/playground/node_modules/.bin/astro +0 -21
- package/playground/node_modules/.vite/deps/@astrojs_svelte_client__js.js +0 -85
- package/playground/node_modules/.vite/deps/@astrojs_svelte_client__js.js.map +0 -7
- package/playground/node_modules/.vite/deps/_metadata.json +0 -184
- package/playground/node_modules/.vite/deps/astro___aria-query.js +0 -6776
- package/playground/node_modules/.vite/deps/astro___aria-query.js.map +0 -7
- package/playground/node_modules/.vite/deps/astro___axobject-query.js +0 -3754
- package/playground/node_modules/.vite/deps/astro___axobject-query.js.map +0 -7
- package/playground/node_modules/.vite/deps/astro___html-escaper.js +0 -34
- package/playground/node_modules/.vite/deps/astro___html-escaper.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-AJXJMYAF.js +0 -0
- package/playground/node_modules/.vite/deps/chunk-AJXJMYAF.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-BUSYA2B4.js +0 -8
- package/playground/node_modules/.vite/deps/chunk-BUSYA2B4.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-CNYJBM5F.js +0 -21
- package/playground/node_modules/.vite/deps/chunk-CNYJBM5F.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-DBPNBGEI.js +0 -223
- package/playground/node_modules/.vite/deps/chunk-DBPNBGEI.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-FPEUJ7DG.js +0 -27
- package/playground/node_modules/.vite/deps/chunk-FPEUJ7DG.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-MHDZ3SK7.js +0 -1005
- package/playground/node_modules/.vite/deps/chunk-MHDZ3SK7.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-RBDTDTPY.js +0 -204
- package/playground/node_modules/.vite/deps/chunk-RBDTDTPY.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-RJGEXL5C.js +0 -688
- package/playground/node_modules/.vite/deps/chunk-RJGEXL5C.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-YL4MIWGJ.js +0 -5099
- package/playground/node_modules/.vite/deps/chunk-YL4MIWGJ.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-ZOV3DWEJ.js +0 -4376
- package/playground/node_modules/.vite/deps/chunk-ZOV3DWEJ.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-ZP4UNCSN.js +0 -23
- package/playground/node_modules/.vite/deps/chunk-ZP4UNCSN.js.map +0 -7
- package/playground/node_modules/.vite/deps/chunk-ZREFNRZZ.js +0 -148
- package/playground/node_modules/.vite/deps/chunk-ZREFNRZZ.js.map +0 -7
- package/playground/node_modules/.vite/deps/package.json +0 -3
- package/playground/node_modules/.vite/deps/smol-toml.js +0 -843
- package/playground/node_modules/.vite/deps/smol-toml.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte.js +0 -55
- package/playground/node_modules/.vite/deps/svelte.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte___clsx.js +0 -9
- package/playground/node_modules/.vite/deps/svelte___clsx.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_animate.js +0 -57
- package/playground/node_modules/.vite/deps/svelte_animate.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_attachments.js +0 -15
- package/playground/node_modules/.vite/deps/svelte_attachments.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_easing.js +0 -67
- package/playground/node_modules/.vite/deps/svelte_easing.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_events.js +0 -11
- package/playground/node_modules/.vite/deps/svelte_events.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_internal.js +0 -5
- package/playground/node_modules/.vite/deps/svelte_internal.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_internal_client.js +0 -402
- package/playground/node_modules/.vite/deps/svelte_internal_client.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_internal_disclose-version.js +0 -10
- package/playground/node_modules/.vite/deps/svelte_internal_disclose-version.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_internal_flags_async.js +0 -8
- package/playground/node_modules/.vite/deps/svelte_internal_flags_async.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_internal_flags_legacy.js +0 -8
- package/playground/node_modules/.vite/deps/svelte_internal_flags_legacy.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_internal_flags_tracing.js +0 -8
- package/playground/node_modules/.vite/deps/svelte_internal_flags_tracing.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_legacy.js +0 -35
- package/playground/node_modules/.vite/deps/svelte_legacy.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_motion.js +0 -545
- package/playground/node_modules/.vite/deps/svelte_motion.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_reactivity.js +0 -29
- package/playground/node_modules/.vite/deps/svelte_reactivity.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_reactivity_window.js +0 -127
- package/playground/node_modules/.vite/deps/svelte_reactivity_window.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_store.js +0 -103
- package/playground/node_modules/.vite/deps/svelte_store.js.map +0 -7
- package/playground/node_modules/.vite/deps/svelte_transition.js +0 -208
- package/playground/node_modules/.vite/deps/svelte_transition.js.map +0 -7
- package/playground/package.json +0 -16
- package/playground/pnpm-lock.yaml +0 -3167
- package/playground/src/content/authors/jane-doe.json +0 -8
- package/playground/src/content/config/build.toml +0 -2
- package/playground/src/content/courses/web-fundamentals.json +0 -29
- package/playground/src/content/docs/advanced.mdx +0 -6
- package/playground/src/content/docs/intro.md +0 -6
- package/playground/src/content/guides/getting-started.mdx +0 -6
- package/playground/src/content/posts/hello-world.md +0 -7
- package/playground/src/content/products/t-shirt.json +0 -16
- package/playground/src/content/recipes/pancakes.mdoc +0 -8
- package/playground/src/content/settings/site.yml +0 -2
- package/playground/src/content.config.ts +0 -198
- package/playground/src/env.d.ts +0 -1
- package/playground/src/pages/index.astro +0 -11
- package/playground/src/pages/nebula.astro +0 -14
- package/pnpm-workspace.yaml +0 -2
- package/scripts/subset-icons.mjs +0 -178
- package/src/astro/index.ts +0 -295
- package/src/client/js/drafts/merge.svelte.ts +0 -121
- package/src/client/js/drafts/ops.svelte.ts +0 -227
- package/src/client/js/drafts/storage.ts +0 -108
- package/src/client/js/drafts/workers/diff.ts +0 -40
- package/src/client/js/editor/editor.svelte.ts +0 -343
- package/src/client/js/editor/languages.ts +0 -98
- package/src/client/js/editor/markdown-shortcuts.ts +0 -261
- package/src/client/js/handlers/admin.ts +0 -246
- package/src/client/js/state/dialogs.svelte.ts +0 -35
- package/src/client/js/state/router.svelte.ts +0 -156
- package/src/client/js/state/state.svelte.ts +0 -334
- package/src/client/js/storage/adapter.ts +0 -102
- package/src/client/js/storage/client.ts +0 -150
- package/src/client/js/storage/db.ts +0 -36
- package/src/client/js/storage/fsa.ts +0 -110
- package/src/client/js/storage/github.ts +0 -297
- package/src/client/js/storage/storage.ts +0 -83
- package/src/client/js/storage/workers/frontmatter.ts +0 -320
- package/src/client/js/storage/workers/storage.ts +0 -177
- package/src/client/js/storage/workers/toml-parser.ts +0 -106
- package/src/client/js/storage/workers/yaml-parser.ts +0 -132
- package/src/client/js/utils/frontmatter.ts +0 -38
- package/src/client/js/utils/schema-utils.ts +0 -295
- package/src/client/js/utils/sort.ts +0 -84
- package/src/client/js/utils/stable-stringify.ts +0 -27
- package/src/types.ts +0 -25
- package/svelte.config.js +0 -4
- package/tests/astro/build.test.ts +0 -63
- package/tests/astro/index.test.ts +0 -689
- package/tests/client/components/Admin.test.ts +0 -446
- package/tests/client/components/BackendPicker.test.ts +0 -239
- package/tests/client/components/DraftChip.test.ts +0 -53
- package/tests/client/components/MetadataForm.test.ts +0 -164
- package/tests/client/components/dialogs/DeleteDraftDialog.test.ts +0 -91
- package/tests/client/components/dialogs/FilenameDialog.test.ts +0 -209
- package/tests/client/components/dialogs/dialog-stubs.ts +0 -19
- package/tests/client/components/editor/EditorPane.test.ts +0 -100
- package/tests/client/components/editor/EditorTabs.test.ts +0 -253
- package/tests/client/components/editor/EditorToolbar.test.ts +0 -252
- package/tests/client/components/editor/fixtures.ts +0 -31
- package/tests/client/components/fields/ArrayField.test.ts +0 -197
- package/tests/client/components/fields/BooleanField.test.ts +0 -206
- package/tests/client/components/fields/DateField.test.ts +0 -210
- package/tests/client/components/fields/EnumField.test.ts +0 -246
- package/tests/client/components/fields/NumberField.test.ts +0 -240
- package/tests/client/components/fields/ObjectField.test.ts +0 -157
- package/tests/client/components/fields/SchemaField.test.ts +0 -190
- package/tests/client/components/fields/StringField.test.ts +0 -223
- package/tests/client/components/sidebar/AdminSidebar.test.ts +0 -285
- package/tests/client/components/sidebar/AdminSidebarSort.test.ts +0 -135
- package/tests/client/components/sidebar/sort-mock.ts +0 -23
- package/tests/client/js/drafts/fixtures.ts +0 -22
- package/tests/client/js/drafts/merge.test.ts +0 -282
- package/tests/client/js/drafts/ops.test.ts +0 -658
- package/tests/client/js/drafts/storage.test.ts +0 -200
- package/tests/client/js/drafts/workers/diff.test.ts +0 -165
- package/tests/client/js/editor/editor.test.ts +0 -616
- package/tests/client/js/editor/link-wrap.test.ts +0 -225
- package/tests/client/js/editor/markdown-shortcuts.test.ts +0 -370
- package/tests/client/js/handlers/admin.test.ts +0 -467
- package/tests/client/js/state/router.test.ts +0 -619
- package/tests/client/js/state/schema.test.ts +0 -266
- package/tests/client/js/state/state.test.ts +0 -328
- package/tests/client/js/storage/adapter.test.ts +0 -115
- package/tests/client/js/storage/client.test.ts +0 -250
- package/tests/client/js/storage/db.test.ts +0 -59
- package/tests/client/js/storage/fsa.test.ts +0 -284
- package/tests/client/js/storage/github.test.ts +0 -349
- package/tests/client/js/storage/mock-port.ts +0 -95
- package/tests/client/js/storage/storage.test.ts +0 -77
- package/tests/client/js/storage/workers/frontmatter.test.ts +0 -479
- package/tests/client/js/storage/workers/storage.test.ts +0 -299
- package/tests/client/js/storage/workers/toml-parser.test.ts +0 -169
- package/tests/client/js/storage/workers/yaml-parser.test.ts +0 -168
- package/tests/client/js/utils/file-types.test.ts +0 -268
- package/tests/client/js/utils/frontmatter.test.ts +0 -87
- package/tests/client/js/utils/schema-utils.test.ts +0 -318
- package/tests/client/js/utils/slug.test.ts +0 -58
- package/tests/client/js/utils/sort.test.ts +0 -276
- package/tests/client/js/utils/stable-stringify.test.ts +0 -68
- package/tests/client/js/utils/url-utils.test.ts +0 -70
- package/tests/e2e/backend-connection.test.ts +0 -301
- package/tests/e2e/draft-lifecycle.test.ts +0 -388
- package/tests/e2e/editing.test.ts +0 -355
- package/tests/e2e/github-adapter.test.ts +0 -330
- package/tests/e2e/helpers/mock-adapter.ts +0 -166
- package/tests/e2e/helpers/test-app.ts +0 -155
- package/tests/e2e/navigation.test.ts +0 -358
- package/tests/e2e/publishing.test.ts +0 -345
- package/tests/e2e/unsaved-changes.test.ts +0 -317
- package/tests/setup.ts +0 -2
- package/tests/stubs/codemirror.ts +0 -197
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -178
- /package/{src → dist}/client/components/BackendPicker.svelte +0 -0
- /package/{src → dist}/client/components/DraftChip.svelte +0 -0
- /package/{src → dist}/client/components/MetadataForm.svelte +0 -0
- /package/{src → dist}/client/components/ThemeToggle.svelte +0 -0
- /package/{src → dist}/client/components/dialogs/DeleteDraftDialog.svelte +0 -0
- /package/{src → dist}/client/components/editor/EditorPane.svelte +0 -0
- /package/{src → dist}/client/components/editor/EditorTabs.svelte +0 -0
- /package/{src → dist}/client/components/editor/EditorToolbar.svelte +0 -0
- /package/{src → dist}/client/components/editor/FormatSelector.svelte +0 -0
- /package/{src → dist}/client/components/editor/Toolbar.svelte +0 -0
- /package/{src → dist}/client/components/fields/ArrayField.svelte +0 -0
- /package/{src → dist}/client/components/fields/ArrayItem.svelte +0 -0
- /package/{src → dist}/client/components/fields/BooleanField.svelte +0 -0
- /package/{src → dist}/client/components/fields/DateField.svelte +0 -0
- /package/{src → dist}/client/components/fields/EnumField.svelte +0 -0
- /package/{src → dist}/client/components/fields/FieldWrapper.svelte +0 -0
- /package/{src → dist}/client/components/fields/NumberField.svelte +0 -0
- /package/{src → dist}/client/components/fields/ObjectField.svelte +0 -0
- /package/{src → dist}/client/components/fields/SchemaField.svelte +0 -0
- /package/{src → dist}/client/components/fields/StringField.svelte +0 -0
- /package/{src → dist}/client/components/sidebar/AdminSidebarSort.svelte +0 -0
- /package/{src → dist}/client/css/a11y.css +0 -0
- /package/{src → dist}/client/css/btn.css +0 -0
- /package/{src → dist}/client/css/dialog.css +0 -0
- /package/{src → dist}/client/css/field-input.css +0 -0
- /package/{src → dist}/client/css/reset.css +0 -0
- /package/{src → dist}/client/css/theme.css +0 -0
- /package/{src/client/index.ts → dist/client/index.js} +0 -0
- /package/{src → dist}/virtual.d.ts +0 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Global application state for the admin SPA.
|
|
3
|
+
* Manages backend connection, schema loading, collections, and navigation state.
|
|
4
|
+
*/
|
|
5
|
+
import schemas from 'virtual:nebula/collections';
|
|
6
|
+
import { loadBackend, saveBackend, clearBackend, } from '../storage/storage';
|
|
7
|
+
import { StorageClient } from '../storage/client';
|
|
8
|
+
import { nav, navigate, adminPath } from './router.svelte';
|
|
9
|
+
import { drafts, mergeDrafts, refreshDrafts, resetDraftMerge, } from '../drafts/merge.svelte';
|
|
10
|
+
import { getSchemaExtensions } from './schema.svelte';
|
|
11
|
+
export { drafts, refreshDrafts };
|
|
12
|
+
// Sorted collection names derived from virtual:nebula/collections.
|
|
13
|
+
export const collections = Object.keys(schemas).sort();
|
|
14
|
+
/*
|
|
15
|
+
* Uses .js extension because svelte-package does not rewrite URL string literals;
|
|
16
|
+
* the dist output must reference the compiled .js file, not the source .ts file.
|
|
17
|
+
*
|
|
18
|
+
* Guarded for SSR: SharedWorker only exists in browsers. All code paths
|
|
19
|
+
* that use sharedWorker/storageClient run exclusively on the client
|
|
20
|
+
* (inside onMount, event handlers, or user-initiated actions).
|
|
21
|
+
*/
|
|
22
|
+
const sharedWorker = typeof SharedWorker !== 'undefined'
|
|
23
|
+
? new SharedWorker(new URL('../storage/workers/storage.js', import.meta.url), { type: 'module', name: 'cms-storage' })
|
|
24
|
+
: null;
|
|
25
|
+
/*
|
|
26
|
+
* Main-thread StorageClient for editor and draft-merge I/O.
|
|
27
|
+
* Null during SSR but typed as non-null because every caller is client-only.
|
|
28
|
+
*/
|
|
29
|
+
export const storageClient = (sharedWorker ? new StorageClient(sharedWorker.port) : null);
|
|
30
|
+
let backendType = $state(null);
|
|
31
|
+
let backendReady = $state(false);
|
|
32
|
+
let permissionState = $state('denied');
|
|
33
|
+
let contentList = $state([]);
|
|
34
|
+
let error = $state(null);
|
|
35
|
+
let loading = $state(false);
|
|
36
|
+
export const backend = {
|
|
37
|
+
// Active backend type, or null if not connected.
|
|
38
|
+
get type() {
|
|
39
|
+
return backendType;
|
|
40
|
+
},
|
|
41
|
+
// True if a backend is initialized and ready.
|
|
42
|
+
get ready() {
|
|
43
|
+
return backendReady;
|
|
44
|
+
},
|
|
45
|
+
// FSA permission state for the re-auth flow in BackendPicker.
|
|
46
|
+
get permission() {
|
|
47
|
+
return permissionState;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
export const content = {
|
|
51
|
+
// Parsed content items for the selected collection.
|
|
52
|
+
get list() {
|
|
53
|
+
return contentList;
|
|
54
|
+
},
|
|
55
|
+
// True if the frontmatter worker is actively parsing.
|
|
56
|
+
get loading() {
|
|
57
|
+
return loading;
|
|
58
|
+
},
|
|
59
|
+
// Error message for display in the sidebar.
|
|
60
|
+
get error() {
|
|
61
|
+
return error;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
let worker = null;
|
|
65
|
+
let loadedCollection = '';
|
|
66
|
+
let initPromise = null;
|
|
67
|
+
const contentCache = new Map();
|
|
68
|
+
/**
|
|
69
|
+
* Initializes the frontmatter worker and bridges a port to the SharedWorker.
|
|
70
|
+
* @return {Worker}
|
|
71
|
+
*/
|
|
72
|
+
function ensureWorker() {
|
|
73
|
+
if (worker)
|
|
74
|
+
return worker;
|
|
75
|
+
// Uses .js extension because svelte-package does not rewrite URL string literals
|
|
76
|
+
worker = new Worker(new URL('../storage/workers/frontmatter.js', import.meta.url), { type: 'module' });
|
|
77
|
+
worker.addEventListener('message', (event) => {
|
|
78
|
+
const data = event.data;
|
|
79
|
+
if (data.type === 'result') {
|
|
80
|
+
const forCollection = data.collection;
|
|
81
|
+
// Always cache under the correct collection
|
|
82
|
+
contentCache.set(forCollection, data.items);
|
|
83
|
+
// Only update the visible list if this result is for the current collection
|
|
84
|
+
if (forCollection === loadedCollection) {
|
|
85
|
+
contentList = data.items;
|
|
86
|
+
loading = false;
|
|
87
|
+
error = null;
|
|
88
|
+
if (backendReady)
|
|
89
|
+
mergeDrafts(forCollection);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (data.type === 'error') {
|
|
93
|
+
error = data.message;
|
|
94
|
+
loading = false;
|
|
95
|
+
contentList = [];
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
// Bridge a port so the frontmatter worker can talk to the storage SharedWorker
|
|
99
|
+
const channel = new MessageChannel();
|
|
100
|
+
worker.postMessage({ type: 'port' }, [channel.port1]);
|
|
101
|
+
sharedWorker.port.postMessage({ type: 'connect-port' }, [channel.port2]);
|
|
102
|
+
return worker;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Sends a parse request to the frontmatter worker. Refresh mode keeps current sidebar visible.
|
|
106
|
+
* @param {string} collection - The collection name to parse
|
|
107
|
+
* @param {boolean} refresh - If true, keep current contentList and skip loading state
|
|
108
|
+
* @return {Promise<void>}
|
|
109
|
+
*/
|
|
110
|
+
async function dispatchWorker(collection, refresh = false) {
|
|
111
|
+
if (!backendReady)
|
|
112
|
+
return;
|
|
113
|
+
if (!refresh) {
|
|
114
|
+
loading = true;
|
|
115
|
+
contentList = [];
|
|
116
|
+
}
|
|
117
|
+
error = null;
|
|
118
|
+
// Wait for the SharedWorker adapter to be ready before dispatching
|
|
119
|
+
if (initPromise)
|
|
120
|
+
await initPromise;
|
|
121
|
+
const w = ensureWorker();
|
|
122
|
+
const extensions = getSchemaExtensions(collection);
|
|
123
|
+
w.postMessage({ type: 'parse', collection, extensions });
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Restores a stored backend config from IndexedDB and initializes the SharedWorker.
|
|
127
|
+
* @return {Promise<void>}
|
|
128
|
+
*/
|
|
129
|
+
export async function restoreBackend() {
|
|
130
|
+
try {
|
|
131
|
+
const config = await loadBackend();
|
|
132
|
+
if (!config) {
|
|
133
|
+
backendType = null;
|
|
134
|
+
backendReady = false;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (config.type === 'fsa') {
|
|
138
|
+
// Check FSA permission state
|
|
139
|
+
const perm = await config.handle.queryPermission({ mode: 'readwrite' });
|
|
140
|
+
permissionState = perm;
|
|
141
|
+
backendType = 'fsa';
|
|
142
|
+
if (perm === 'granted') {
|
|
143
|
+
await storageClient.init({ type: 'init', backend: config });
|
|
144
|
+
backendReady = true;
|
|
145
|
+
navigateToFirstCollectionIfHome();
|
|
146
|
+
}
|
|
147
|
+
// If perm is 'prompt', BackendPicker shows re-auth button
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// GitHub — show UI optimistically, validate in background
|
|
151
|
+
backendType = 'github';
|
|
152
|
+
backendReady = true;
|
|
153
|
+
navigateToFirstCollectionIfHome();
|
|
154
|
+
initPromise = storageClient
|
|
155
|
+
.init({ type: 'init', backend: config })
|
|
156
|
+
.catch(async () => {
|
|
157
|
+
await clearBackend();
|
|
158
|
+
backendType = null;
|
|
159
|
+
backendReady = false;
|
|
160
|
+
contentList = [];
|
|
161
|
+
contentCache.clear();
|
|
162
|
+
loadedCollection = '';
|
|
163
|
+
navigate(adminPath());
|
|
164
|
+
})
|
|
165
|
+
.finally(() => {
|
|
166
|
+
initPromise = null;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
backendType = null;
|
|
172
|
+
backendReady = false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Re-requests FSA permission. Must be called from a user gesture.
|
|
177
|
+
* @return {Promise<void>}
|
|
178
|
+
*/
|
|
179
|
+
export async function requestPermission() {
|
|
180
|
+
const config = await loadBackend();
|
|
181
|
+
if (!config || config.type !== 'fsa')
|
|
182
|
+
return;
|
|
183
|
+
try {
|
|
184
|
+
const perm = await config.handle.requestPermission({ mode: 'readwrite' });
|
|
185
|
+
permissionState = perm;
|
|
186
|
+
if (perm === 'granted') {
|
|
187
|
+
await storageClient.init({ type: 'init', backend: config });
|
|
188
|
+
backendReady = true;
|
|
189
|
+
navigateToFirstCollectionIfHome();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
permissionState = 'denied';
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Opens the directory picker and initializes the FSA backend. Must be called from a user gesture.
|
|
198
|
+
* @return {Promise<void>}
|
|
199
|
+
*/
|
|
200
|
+
export async function pickDirectory() {
|
|
201
|
+
try {
|
|
202
|
+
const handle = await window.showDirectoryPicker({ mode: 'readwrite' });
|
|
203
|
+
const config = { type: 'fsa', handle };
|
|
204
|
+
await storageClient.init({ type: 'init', backend: config });
|
|
205
|
+
await saveBackend(config);
|
|
206
|
+
backendType = 'fsa';
|
|
207
|
+
permissionState = 'granted';
|
|
208
|
+
backendReady = true;
|
|
209
|
+
navigateToFirstCollectionIfHome();
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
if (err instanceof DOMException && err.name === 'AbortError')
|
|
213
|
+
return;
|
|
214
|
+
error = err instanceof Error ? err.message : String(err);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Connects to a GitHub repository via PAT and persists the config.
|
|
219
|
+
* @param {string} token - GitHub Personal Access Token
|
|
220
|
+
* @param {string} repo - Repository in "owner/repo" format
|
|
221
|
+
* @return {Promise<void>}
|
|
222
|
+
*/
|
|
223
|
+
export async function connectGitHub(token, repo) {
|
|
224
|
+
const config = { type: 'github', token, repo };
|
|
225
|
+
await storageClient.init({ type: 'init', backend: config });
|
|
226
|
+
await saveBackend(config);
|
|
227
|
+
backendType = 'github';
|
|
228
|
+
backendReady = true;
|
|
229
|
+
navigateToFirstCollectionIfHome();
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Disconnects the backend, clears credentials, and resets all state.
|
|
233
|
+
* @return {Promise<void>}
|
|
234
|
+
*/
|
|
235
|
+
export async function disconnect() {
|
|
236
|
+
worker?.terminate();
|
|
237
|
+
worker = null;
|
|
238
|
+
resetDraftMerge();
|
|
239
|
+
await storageClient.teardown();
|
|
240
|
+
await clearBackend();
|
|
241
|
+
backendType = null;
|
|
242
|
+
backendReady = false;
|
|
243
|
+
permissionState = 'denied';
|
|
244
|
+
contentList = [];
|
|
245
|
+
contentCache.clear();
|
|
246
|
+
loadedCollection = '';
|
|
247
|
+
error = null;
|
|
248
|
+
loading = false;
|
|
249
|
+
navigate(adminPath());
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Navigates to the first collection if currently on the home view.
|
|
253
|
+
* @return {void}
|
|
254
|
+
*/
|
|
255
|
+
function navigateToFirstCollectionIfHome() {
|
|
256
|
+
if (nav.route.view === 'home' && collections.length > 0) {
|
|
257
|
+
navigate(adminPath(collections[0]));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Loads a collection. Serves from cache instantly if available, then background refreshes.
|
|
262
|
+
* @param {string} collection - The collection name to load
|
|
263
|
+
* @return {void}
|
|
264
|
+
*/
|
|
265
|
+
export function loadCollection(collection) {
|
|
266
|
+
if (collection === loadedCollection)
|
|
267
|
+
return;
|
|
268
|
+
loadedCollection = collection;
|
|
269
|
+
const cached = contentCache.get(collection);
|
|
270
|
+
if (cached) {
|
|
271
|
+
// Serve cached items instantly, then refresh in background
|
|
272
|
+
contentList = cached;
|
|
273
|
+
refreshDrafts(collection);
|
|
274
|
+
dispatchWorker(collection, true);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
dispatchWorker(collection);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Forces a background reload, keeping the sidebar visible.
|
|
282
|
+
* @param {string} collection - The collection to reload
|
|
283
|
+
* @return {void}
|
|
284
|
+
*/
|
|
285
|
+
export function reloadCollection(collection) {
|
|
286
|
+
loadedCollection = collection;
|
|
287
|
+
dispatchWorker(collection, true);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Optimistically updates a single item's frontmatter in the content list and cache.
|
|
291
|
+
* @param {string} filename - The filename to update
|
|
292
|
+
* @param {Record<string, unknown>} data - The new frontmatter data
|
|
293
|
+
* @return {void}
|
|
294
|
+
*/
|
|
295
|
+
export function updateContentItem(filename, data) {
|
|
296
|
+
const updated = contentList.map((item) => item.filename === filename ? { ...item, data } : item);
|
|
297
|
+
contentList = updated;
|
|
298
|
+
if (loadedCollection)
|
|
299
|
+
contentCache.set(loadedCollection, updated);
|
|
300
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type ResolvedTheme = 'light' | 'dark';
|
|
2
|
+
type ThemeIcon = 'light_mode' | 'dark_mode' | 'brightness_auto';
|
|
3
|
+
type ThemeLabel = 'Light' | 'Dark' | 'Auto';
|
|
4
|
+
export declare const theme: {
|
|
5
|
+
readonly resolved: ResolvedTheme;
|
|
6
|
+
readonly icon: ThemeIcon;
|
|
7
|
+
readonly label: ThemeLabel;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Starts listening to OS color scheme changes via matchMedia.
|
|
11
|
+
* Preference and initial system state are already read at module init,
|
|
12
|
+
* so this only needs to register the change listener. Call once on mount.
|
|
13
|
+
* Safe to call multiple times — registers the listener only once.
|
|
14
|
+
* @return {() => void} Cleanup function that removes the listener
|
|
15
|
+
*/
|
|
16
|
+
export declare function initTheme(): () => void;
|
|
17
|
+
/**
|
|
18
|
+
* Cycles the preference through auto -> light -> dark -> auto.
|
|
19
|
+
* Persists the new value to localStorage.
|
|
20
|
+
* @return {void}
|
|
21
|
+
*/
|
|
22
|
+
export declare function cycleTheme(): void;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=theme.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/js/state/theme.svelte.ts"],"names":[],"mappings":"AAUA,KAAK,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAGtC,KAAK,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,iBAAiB,CAAC;AAGhE,KAAK,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAmF5C,eAAO,MAAM,KAAK;uBACA,aAAa;mBAGjB,SAAS;oBAGR,UAAU;CAGxB,CAAC;AAWF;;;;;;GAMG;AACH,wBAAgB,SAAS,IAAI,MAAM,IAAI,CAmBtC;AAQD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAajC"}
|
|
@@ -3,121 +3,88 @@
|
|
|
3
3
|
* Manages a three-way preference (light / dark / auto) and resolves the effective
|
|
4
4
|
* theme by combining user preference with the OS-level color scheme.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
// Tri-state preference: 'light', 'dark', or 'auto' (follow system)
|
|
8
|
-
type ThemePreference = 'light' | 'dark' | 'auto';
|
|
9
|
-
|
|
10
|
-
// Resolved theme applied to the DOM — always 'light' or 'dark'
|
|
11
|
-
type ResolvedTheme = 'light' | 'dark';
|
|
12
|
-
|
|
13
|
-
// Material Symbols icon name for each preference
|
|
14
|
-
type ThemeIcon = 'light_mode' | 'dark_mode' | 'brightness_auto';
|
|
15
|
-
|
|
16
|
-
// Human-readable label for each preference
|
|
17
|
-
type ThemeLabel = 'Light' | 'Dark' | 'Auto';
|
|
18
|
-
|
|
19
6
|
// localStorage key for persisting the user's preference
|
|
20
7
|
const STORAGE_KEY = 'nebula-theme';
|
|
21
|
-
|
|
22
8
|
/*
|
|
23
9
|
//////////////////////////////
|
|
24
10
|
// Preference → UI mapping
|
|
25
11
|
//////////////////////////////
|
|
26
12
|
*/
|
|
27
|
-
|
|
28
13
|
/*
|
|
29
14
|
* Single source of truth for all preference-derived UI values.
|
|
30
15
|
* Adding a new preference requires a new entry here — TypeScript
|
|
31
16
|
* enforces exhaustiveness via the Record<ThemePreference, ...> type.
|
|
32
17
|
*/
|
|
33
|
-
const THEME_MAP
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
light: { icon: 'light_mode', label: 'Light' },
|
|
38
|
-
dark: { icon: 'dark_mode', label: 'Dark' },
|
|
39
|
-
auto: { icon: 'brightness_auto', label: 'Auto' },
|
|
18
|
+
const THEME_MAP = {
|
|
19
|
+
light: { icon: 'light_mode', label: 'Light' },
|
|
20
|
+
dark: { icon: 'dark_mode', label: 'Dark' },
|
|
21
|
+
auto: { icon: 'brightness_auto', label: 'Auto' },
|
|
40
22
|
};
|
|
41
|
-
|
|
42
23
|
/*
|
|
43
24
|
//////////////////////////////
|
|
44
25
|
// Module initialization
|
|
45
26
|
//////////////////////////////
|
|
46
27
|
*/
|
|
47
|
-
|
|
48
28
|
/*
|
|
49
29
|
* Read preference from localStorage at module init to avoid a flash of wrong theme.
|
|
50
30
|
* Safe because this module is only loaded client-side (client:only="svelte").
|
|
51
31
|
*/
|
|
52
|
-
let stored
|
|
32
|
+
let stored = null;
|
|
53
33
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
34
|
+
if (typeof localStorage !== 'undefined') {
|
|
35
|
+
stored = localStorage.getItem(STORAGE_KEY);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Storage access blocked (SecurityError, private browsing, etc.)
|
|
59
40
|
}
|
|
60
|
-
|
|
61
41
|
/*
|
|
62
42
|
* Read system preference at module init so the first render has the correct
|
|
63
43
|
* resolved theme — deferring this to onMount would cause a flash for auto+dark users.
|
|
64
44
|
*/
|
|
65
|
-
const mq =
|
|
66
|
-
typeof window !== 'undefined'
|
|
45
|
+
const mq = typeof window !== 'undefined'
|
|
67
46
|
? window.matchMedia('(prefers-color-scheme: dark)')
|
|
68
47
|
: null;
|
|
69
|
-
|
|
70
48
|
// The user's explicit preference
|
|
71
|
-
let preference = $state
|
|
72
|
-
stored === 'light' || stored === 'dark' || stored === 'auto'
|
|
49
|
+
let preference = $state(stored === 'light' || stored === 'dark' || stored === 'auto'
|
|
73
50
|
? stored
|
|
74
|
-
: 'auto'
|
|
75
|
-
);
|
|
76
|
-
|
|
51
|
+
: 'auto');
|
|
77
52
|
// Whether the OS prefers dark mode — updated via matchMedia listener
|
|
78
53
|
let systemPrefersDark = $state(mq?.matches ?? false);
|
|
79
|
-
|
|
80
54
|
/*
|
|
81
55
|
//////////////////////////////
|
|
82
56
|
// Derived state
|
|
83
57
|
//////////////////////////////
|
|
84
58
|
*/
|
|
85
|
-
|
|
86
59
|
/*
|
|
87
60
|
* $derived can only be a variable declaration initializer, not an object
|
|
88
61
|
* property — Svelte compiler restriction. These private derivations feed
|
|
89
62
|
* the exported theme object via getters.
|
|
90
63
|
*/
|
|
91
|
-
const resolved
|
|
92
|
-
preference === 'auto' ? (systemPrefersDark ? 'dark' : 'light') : preference,
|
|
93
|
-
);
|
|
64
|
+
const resolved = $derived(preference === 'auto' ? (systemPrefersDark ? 'dark' : 'light') : preference);
|
|
94
65
|
const ui = $derived(THEME_MAP[preference]);
|
|
95
|
-
|
|
96
66
|
/*
|
|
97
67
|
* Reactive theme state. Consumers read properties directly: theme.resolved,
|
|
98
68
|
* theme.icon, theme.label. The getters forward Svelte's reactive tracking.
|
|
99
69
|
*/
|
|
100
70
|
export const theme = {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
71
|
+
get resolved() {
|
|
72
|
+
return resolved;
|
|
73
|
+
},
|
|
74
|
+
get icon() {
|
|
75
|
+
return ui.icon;
|
|
76
|
+
},
|
|
77
|
+
get label() {
|
|
78
|
+
return ui.label;
|
|
79
|
+
},
|
|
110
80
|
};
|
|
111
|
-
|
|
112
81
|
/*
|
|
113
82
|
//////////////////////////////
|
|
114
83
|
// System preference tracking
|
|
115
84
|
//////////////////////////////
|
|
116
85
|
*/
|
|
117
|
-
|
|
118
86
|
// Guard against duplicate listener registration (e.g. HMR remount)
|
|
119
87
|
let initialized = false;
|
|
120
|
-
|
|
121
88
|
/**
|
|
122
89
|
* Starts listening to OS color scheme changes via matchMedia.
|
|
123
90
|
* Preference and initial system state are already read at module init,
|
|
@@ -125,49 +92,45 @@ let initialized = false;
|
|
|
125
92
|
* Safe to call multiple times — registers the listener only once.
|
|
126
93
|
* @return {() => void} Cleanup function that removes the listener
|
|
127
94
|
*/
|
|
128
|
-
export function initTheme()
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
initialized = false;
|
|
146
|
-
};
|
|
95
|
+
export function initTheme() {
|
|
96
|
+
if (initialized)
|
|
97
|
+
return () => { };
|
|
98
|
+
initialized = true;
|
|
99
|
+
/**
|
|
100
|
+
* Updates the systemPrefersDark flag when the OS color scheme changes.
|
|
101
|
+
* @param {MediaQueryListEvent} e - The change event from matchMedia
|
|
102
|
+
* @return {void}
|
|
103
|
+
*/
|
|
104
|
+
const handler = (e) => {
|
|
105
|
+
systemPrefersDark = e.matches;
|
|
106
|
+
};
|
|
107
|
+
mq?.addEventListener('change', handler);
|
|
108
|
+
return () => {
|
|
109
|
+
mq?.removeEventListener('change', handler);
|
|
110
|
+
initialized = false;
|
|
111
|
+
};
|
|
147
112
|
}
|
|
148
|
-
|
|
149
113
|
/*
|
|
150
114
|
//////////////////////////////
|
|
151
115
|
// Actions
|
|
152
116
|
//////////////////////////////
|
|
153
117
|
*/
|
|
154
|
-
|
|
155
118
|
/**
|
|
156
119
|
* Cycles the preference through auto -> light -> dark -> auto.
|
|
157
120
|
* Persists the new value to localStorage.
|
|
158
121
|
* @return {void}
|
|
159
122
|
*/
|
|
160
|
-
export function cycleTheme()
|
|
161
|
-
|
|
162
|
-
preference
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
123
|
+
export function cycleTheme() {
|
|
124
|
+
const next = preference === 'auto' ? 'light' : preference === 'light' ? 'dark' : 'auto';
|
|
125
|
+
preference = next;
|
|
126
|
+
try {
|
|
127
|
+
localStorage.setItem(STORAGE_KEY, next);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
/*
|
|
131
|
+
* Persistence failed (quota exceeded, storage disabled, etc.).
|
|
132
|
+
* The in-memory preference is already updated, so the current
|
|
133
|
+
* session works correctly — it just won't survive a page reload.
|
|
134
|
+
*/
|
|
135
|
+
}
|
|
173
136
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export type FileEntry = {
|
|
2
|
+
filename: string;
|
|
3
|
+
content: string;
|
|
4
|
+
};
|
|
5
|
+
export type FileWrite = {
|
|
6
|
+
collection: string;
|
|
7
|
+
filename: string;
|
|
8
|
+
content: string;
|
|
9
|
+
};
|
|
10
|
+
export interface StorageAdapter {
|
|
11
|
+
/**
|
|
12
|
+
* Lists files in a collection matching the given extensions, returning their names and content.
|
|
13
|
+
* @param {string} collection - The collection name
|
|
14
|
+
* @param {string[]} extensions - File extensions to include (e.g. ['.md', '.mdx', '.yaml'])
|
|
15
|
+
* @return {Promise<FileEntry[]>} Array of filename + content pairs
|
|
16
|
+
*/
|
|
17
|
+
listFiles(collection: string, extensions: string[]): Promise<FileEntry[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Deletes a single file from the collection. Used during file type conversion to remove the old file after the new one is written.
|
|
20
|
+
* @param {string} collection - The collection name
|
|
21
|
+
* @param {string} filename - The filename to delete
|
|
22
|
+
* @return {Promise<void>}
|
|
23
|
+
*/
|
|
24
|
+
deleteFile(collection: string, filename: string): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Reads a single file's content.
|
|
27
|
+
* @param {string} collection - The collection name
|
|
28
|
+
* @param {string} filename - The filename within the collection
|
|
29
|
+
* @return {Promise<string>} The file content as a string
|
|
30
|
+
*/
|
|
31
|
+
readFile(collection: string, filename: string): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Writes content to a single file, creating it if it doesn't exist.
|
|
34
|
+
* @param {string} collection - The collection name
|
|
35
|
+
* @param {string} filename - The filename within the collection
|
|
36
|
+
* @param {string} content - The content to write
|
|
37
|
+
* @return {Promise<void>}
|
|
38
|
+
*/
|
|
39
|
+
writeFile(collection: string, filename: string, content: string): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Writes multiple files atomically (single commit for GitHub, sequential for FSA).
|
|
42
|
+
* @param {FileWrite[]} files - Array of files to write
|
|
43
|
+
* @return {Promise<void>}
|
|
44
|
+
*/
|
|
45
|
+
writeFiles(files: FileWrite[]): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
export type StorageRequest = {
|
|
48
|
+
type: 'init';
|
|
49
|
+
backend: {
|
|
50
|
+
type: 'fsa';
|
|
51
|
+
handle: FileSystemDirectoryHandle;
|
|
52
|
+
} | {
|
|
53
|
+
type: 'github';
|
|
54
|
+
token: string;
|
|
55
|
+
repo: string;
|
|
56
|
+
};
|
|
57
|
+
} | {
|
|
58
|
+
type: 'listFiles';
|
|
59
|
+
collection: string;
|
|
60
|
+
extensions: string[];
|
|
61
|
+
} | {
|
|
62
|
+
type: 'readFile';
|
|
63
|
+
collection: string;
|
|
64
|
+
filename: string;
|
|
65
|
+
} | {
|
|
66
|
+
type: 'writeFile';
|
|
67
|
+
collection: string;
|
|
68
|
+
filename: string;
|
|
69
|
+
content: string;
|
|
70
|
+
} | {
|
|
71
|
+
type: 'writeFiles';
|
|
72
|
+
files: FileWrite[];
|
|
73
|
+
} | {
|
|
74
|
+
type: 'deleteFile';
|
|
75
|
+
collection: string;
|
|
76
|
+
filename: string;
|
|
77
|
+
} | {
|
|
78
|
+
type: 'teardown';
|
|
79
|
+
};
|
|
80
|
+
export type StorageResponse = {
|
|
81
|
+
type: 'init';
|
|
82
|
+
ok: true;
|
|
83
|
+
} | {
|
|
84
|
+
type: 'init';
|
|
85
|
+
ok: false;
|
|
86
|
+
error: string;
|
|
87
|
+
} | {
|
|
88
|
+
type: 'listFiles';
|
|
89
|
+
ok: true;
|
|
90
|
+
files: FileEntry[];
|
|
91
|
+
} | {
|
|
92
|
+
type: 'listFiles';
|
|
93
|
+
ok: false;
|
|
94
|
+
error: string;
|
|
95
|
+
} | {
|
|
96
|
+
type: 'readFile';
|
|
97
|
+
ok: true;
|
|
98
|
+
content: string;
|
|
99
|
+
} | {
|
|
100
|
+
type: 'readFile';
|
|
101
|
+
ok: false;
|
|
102
|
+
error: string;
|
|
103
|
+
} | {
|
|
104
|
+
type: 'writeFile';
|
|
105
|
+
ok: true;
|
|
106
|
+
} | {
|
|
107
|
+
type: 'writeFile';
|
|
108
|
+
ok: false;
|
|
109
|
+
error: string;
|
|
110
|
+
} | {
|
|
111
|
+
type: 'writeFiles';
|
|
112
|
+
ok: true;
|
|
113
|
+
} | {
|
|
114
|
+
type: 'writeFiles';
|
|
115
|
+
ok: false;
|
|
116
|
+
error: string;
|
|
117
|
+
} | {
|
|
118
|
+
type: 'deleteFile';
|
|
119
|
+
ok: true;
|
|
120
|
+
} | {
|
|
121
|
+
type: 'deleteFile';
|
|
122
|
+
ok: false;
|
|
123
|
+
error: string;
|
|
124
|
+
} | {
|
|
125
|
+
type: 'teardown';
|
|
126
|
+
ok: true;
|
|
127
|
+
} | {
|
|
128
|
+
type: 'port-connected';
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=adapter.d.ts.map
|