nebula-cms 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +42 -0
- package/.github/workflows/ci.yml +31 -0
- package/.mcp.json +12 -0
- package/.prettierignore +5 -0
- package/.prettierrc.cjs +22 -0
- package/AGENTS.md +183 -0
- package/LICENSE +201 -0
- package/README.md +128 -0
- package/package.json +74 -0
- package/playground/.claude/settings.local.json +5 -0
- package/playground/astro.config.mjs +7 -0
- package/playground/node_modules/.bin/astro +21 -0
- package/playground/node_modules/.bin/rollup +21 -0
- package/playground/node_modules/.bin/tsc +21 -0
- package/playground/node_modules/.bin/tsserver +21 -0
- package/playground/node_modules/.bin/vite +21 -0
- package/playground/node_modules/.vite/_svelte_metadata.json +1 -0
- package/playground/node_modules/.vite/deps/@astrojs_svelte_client__js.js +80 -0
- package/playground/node_modules/.vite/deps/@astrojs_svelte_client__js.js.map +7 -0
- package/playground/node_modules/.vite/deps/_metadata.json +184 -0
- package/playground/node_modules/.vite/deps/astro___aria-query.js +6776 -0
- package/playground/node_modules/.vite/deps/astro___aria-query.js.map +7 -0
- package/playground/node_modules/.vite/deps/astro___axobject-query.js +3754 -0
- package/playground/node_modules/.vite/deps/astro___axobject-query.js.map +7 -0
- package/playground/node_modules/.vite/deps/astro___html-escaper.js +34 -0
- package/playground/node_modules/.vite/deps/astro___html-escaper.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-AJXJMYAF.js +0 -0
- package/playground/node_modules/.vite/deps/chunk-AJXJMYAF.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-ALJIOON6.js +1005 -0
- package/playground/node_modules/.vite/deps/chunk-ALJIOON6.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-BUSYA2B4.js +8 -0
- package/playground/node_modules/.vite/deps/chunk-BUSYA2B4.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-CNYJBM5F.js +21 -0
- package/playground/node_modules/.vite/deps/chunk-CNYJBM5F.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-DBPNBGEI.js +223 -0
- package/playground/node_modules/.vite/deps/chunk-DBPNBGEI.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-G3C2FXJT.js +204 -0
- package/playground/node_modules/.vite/deps/chunk-G3C2FXJT.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-GKDKFWC5.js +27 -0
- package/playground/node_modules/.vite/deps/chunk-GKDKFWC5.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-HNCLEOC5.js +4376 -0
- package/playground/node_modules/.vite/deps/chunk-HNCLEOC5.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-JICYXBFU.js +688 -0
- package/playground/node_modules/.vite/deps/chunk-JICYXBFU.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-KCUTL6DD.js +5099 -0
- package/playground/node_modules/.vite/deps/chunk-KCUTL6DD.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-ZP4UNCSN.js +23 -0
- package/playground/node_modules/.vite/deps/chunk-ZP4UNCSN.js.map +7 -0
- package/playground/node_modules/.vite/deps/chunk-ZREFNRZZ.js +148 -0
- package/playground/node_modules/.vite/deps/chunk-ZREFNRZZ.js.map +7 -0
- package/playground/node_modules/.vite/deps/package.json +3 -0
- package/playground/node_modules/.vite/deps/smol-toml.js +843 -0
- package/playground/node_modules/.vite/deps/smol-toml.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte.js +55 -0
- package/playground/node_modules/.vite/deps/svelte.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte___clsx.js +9 -0
- package/playground/node_modules/.vite/deps/svelte___clsx.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_animate.js +57 -0
- package/playground/node_modules/.vite/deps/svelte_animate.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_attachments.js +15 -0
- package/playground/node_modules/.vite/deps/svelte_attachments.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_easing.js +67 -0
- package/playground/node_modules/.vite/deps/svelte_easing.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_events.js +11 -0
- package/playground/node_modules/.vite/deps/svelte_events.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_internal.js +5 -0
- package/playground/node_modules/.vite/deps/svelte_internal.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_internal_client.js +402 -0
- package/playground/node_modules/.vite/deps/svelte_internal_client.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_internal_disclose-version.js +10 -0
- package/playground/node_modules/.vite/deps/svelte_internal_disclose-version.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_internal_flags_async.js +8 -0
- package/playground/node_modules/.vite/deps/svelte_internal_flags_async.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_internal_flags_legacy.js +8 -0
- package/playground/node_modules/.vite/deps/svelte_internal_flags_legacy.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_internal_flags_tracing.js +8 -0
- package/playground/node_modules/.vite/deps/svelte_internal_flags_tracing.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_legacy.js +35 -0
- package/playground/node_modules/.vite/deps/svelte_legacy.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_motion.js +545 -0
- package/playground/node_modules/.vite/deps/svelte_motion.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_reactivity.js +29 -0
- package/playground/node_modules/.vite/deps/svelte_reactivity.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_reactivity_window.js +127 -0
- package/playground/node_modules/.vite/deps/svelte_reactivity_window.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_store.js +103 -0
- package/playground/node_modules/.vite/deps/svelte_store.js.map +7 -0
- package/playground/node_modules/.vite/deps/svelte_transition.js +208 -0
- package/playground/node_modules/.vite/deps/svelte_transition.js.map +7 -0
- package/playground/package.json +16 -0
- package/playground/pnpm-lock.yaml +3167 -0
- package/playground/src/content/authors/jane-doe.json +8 -0
- package/playground/src/content/config/build.toml +2 -0
- package/playground/src/content/courses/web-fundamentals.json +29 -0
- package/playground/src/content/docs/advanced.mdx +6 -0
- package/playground/src/content/docs/intro.md +6 -0
- package/playground/src/content/guides/getting-started.mdx +6 -0
- package/playground/src/content/posts/hello-world.md +7 -0
- package/playground/src/content/products/t-shirt.json +16 -0
- package/playground/src/content/recipes/pancakes.mdoc +8 -0
- package/playground/src/content/settings/site.yml +2 -0
- package/playground/src/content.config.ts +198 -0
- package/playground/src/env.d.ts +1 -0
- package/playground/src/pages/index.astro +11 -0
- package/playground/src/pages/nebula.astro +14 -0
- package/pnpm-workspace.yaml +2 -0
- package/scripts/subset-icons.mjs +178 -0
- package/src/astro/index.ts +295 -0
- package/src/client/Admin.svelte +283 -0
- package/src/client/components/BackendPicker.svelte +291 -0
- package/src/client/components/DraftChip.svelte +46 -0
- package/src/client/components/MetadataForm.svelte +56 -0
- package/src/client/components/ThemeToggle.svelte +18 -0
- package/src/client/components/dialogs/DeleteDraftDialog.svelte +51 -0
- package/src/client/components/dialogs/FilenameDialog.svelte +129 -0
- package/src/client/components/editor/EditorPane.svelte +227 -0
- package/src/client/components/editor/EditorTabs.svelte +81 -0
- package/src/client/components/editor/EditorToolbar.svelte +131 -0
- package/src/client/components/editor/FormatSelector.svelte +66 -0
- package/src/client/components/editor/Toolbar.svelte +17 -0
- package/src/client/components/fields/ArrayField.svelte +339 -0
- package/src/client/components/fields/ArrayItem.svelte +325 -0
- package/src/client/components/fields/BooleanField.svelte +114 -0
- package/src/client/components/fields/DateField.svelte +82 -0
- package/src/client/components/fields/EnumField.svelte +74 -0
- package/src/client/components/fields/FieldWrapper.svelte +96 -0
- package/src/client/components/fields/NumberField.svelte +99 -0
- package/src/client/components/fields/ObjectField.svelte +121 -0
- package/src/client/components/fields/SchemaField.svelte +107 -0
- package/src/client/components/fields/StringField.svelte +104 -0
- package/src/client/components/sidebar/AdminSidebar.svelte +339 -0
- package/src/client/components/sidebar/AdminSidebarSort.svelte +123 -0
- package/src/client/css/a11y.css +14 -0
- package/src/client/css/btn.css +113 -0
- package/src/client/css/dialog.css +29 -0
- package/src/client/css/field-input.css +39 -0
- package/src/client/css/reset.css +59 -0
- package/src/client/css/theme.css +77 -0
- package/src/client/index.ts +1 -0
- package/src/client/js/drafts/merge.svelte.ts +121 -0
- package/src/client/js/drafts/ops.svelte.ts +227 -0
- package/src/client/js/drafts/storage.ts +108 -0
- package/src/client/js/drafts/workers/diff.ts +40 -0
- package/src/client/js/editor/editor.svelte.ts +343 -0
- package/src/client/js/editor/languages.ts +98 -0
- package/src/client/js/editor/link-wrap.ts +45 -0
- package/src/client/js/editor/markdown-shortcuts.ts +261 -0
- package/src/client/js/handlers/admin.ts +246 -0
- package/src/client/js/state/dialogs.svelte.ts +35 -0
- package/src/client/js/state/router.svelte.ts +156 -0
- package/src/client/js/state/schema.svelte.ts +140 -0
- package/src/client/js/state/state.svelte.ts +334 -0
- package/src/client/js/state/theme.svelte.ts +173 -0
- package/src/client/js/storage/adapter.ts +102 -0
- package/src/client/js/storage/client.ts +150 -0
- package/src/client/js/storage/db.ts +36 -0
- package/src/client/js/storage/fsa.ts +110 -0
- package/src/client/js/storage/github.ts +297 -0
- package/src/client/js/storage/storage.ts +83 -0
- package/src/client/js/storage/workers/frontmatter.ts +320 -0
- package/src/client/js/storage/workers/storage.ts +177 -0
- package/src/client/js/storage/workers/toml-parser.ts +106 -0
- package/src/client/js/storage/workers/yaml-parser.ts +132 -0
- package/src/client/js/utils/file-types.ts +192 -0
- package/src/client/js/utils/format.ts +16 -0
- package/src/client/js/utils/frontmatter.ts +38 -0
- package/src/client/js/utils/schema-utils.ts +295 -0
- package/src/client/js/utils/slug.ts +18 -0
- package/src/client/js/utils/sort.ts +84 -0
- package/src/client/js/utils/stable-stringify.ts +27 -0
- package/src/client/js/utils/url-utils.ts +38 -0
- package/src/types.ts +25 -0
- package/src/virtual.d.ts +22 -0
- package/svelte.config.js +4 -0
- package/tests/astro/build.test.ts +63 -0
- package/tests/astro/index.test.ts +689 -0
- package/tests/client/components/Admin.test.ts +446 -0
- package/tests/client/components/BackendPicker.test.ts +239 -0
- package/tests/client/components/DraftChip.test.ts +53 -0
- package/tests/client/components/MetadataForm.test.ts +164 -0
- package/tests/client/components/dialogs/DeleteDraftDialog.test.ts +91 -0
- package/tests/client/components/dialogs/FilenameDialog.test.ts +209 -0
- package/tests/client/components/dialogs/dialog-stubs.ts +19 -0
- package/tests/client/components/editor/EditorPane.test.ts +100 -0
- package/tests/client/components/editor/EditorTabs.test.ts +253 -0
- package/tests/client/components/editor/EditorToolbar.test.ts +252 -0
- package/tests/client/components/editor/fixtures.ts +31 -0
- package/tests/client/components/fields/ArrayField.test.ts +197 -0
- package/tests/client/components/fields/BooleanField.test.ts +206 -0
- package/tests/client/components/fields/DateField.test.ts +210 -0
- package/tests/client/components/fields/EnumField.test.ts +246 -0
- package/tests/client/components/fields/NumberField.test.ts +240 -0
- package/tests/client/components/fields/ObjectField.test.ts +157 -0
- package/tests/client/components/fields/SchemaField.test.ts +190 -0
- package/tests/client/components/fields/StringField.test.ts +223 -0
- package/tests/client/components/sidebar/AdminSidebar.test.ts +285 -0
- package/tests/client/components/sidebar/AdminSidebarSort.test.ts +135 -0
- package/tests/client/components/sidebar/sort-mock.ts +23 -0
- package/tests/client/js/drafts/fixtures.ts +22 -0
- package/tests/client/js/drafts/merge.test.ts +282 -0
- package/tests/client/js/drafts/ops.test.ts +658 -0
- package/tests/client/js/drafts/storage.test.ts +200 -0
- package/tests/client/js/drafts/workers/diff.test.ts +165 -0
- package/tests/client/js/editor/editor.test.ts +616 -0
- package/tests/client/js/editor/link-wrap.test.ts +225 -0
- package/tests/client/js/editor/markdown-shortcuts.test.ts +370 -0
- package/tests/client/js/handlers/admin.test.ts +467 -0
- package/tests/client/js/state/router.test.ts +619 -0
- package/tests/client/js/state/schema.test.ts +266 -0
- package/tests/client/js/state/state.test.ts +328 -0
- package/tests/client/js/storage/adapter.test.ts +115 -0
- package/tests/client/js/storage/client.test.ts +250 -0
- package/tests/client/js/storage/db.test.ts +59 -0
- package/tests/client/js/storage/fsa.test.ts +284 -0
- package/tests/client/js/storage/github.test.ts +349 -0
- package/tests/client/js/storage/mock-port.ts +95 -0
- package/tests/client/js/storage/storage.test.ts +77 -0
- package/tests/client/js/storage/workers/frontmatter.test.ts +479 -0
- package/tests/client/js/storage/workers/storage.test.ts +299 -0
- package/tests/client/js/storage/workers/toml-parser.test.ts +169 -0
- package/tests/client/js/storage/workers/yaml-parser.test.ts +168 -0
- package/tests/client/js/utils/file-types.test.ts +268 -0
- package/tests/client/js/utils/frontmatter.test.ts +87 -0
- package/tests/client/js/utils/schema-utils.test.ts +318 -0
- package/tests/client/js/utils/slug.test.ts +58 -0
- package/tests/client/js/utils/sort.test.ts +276 -0
- package/tests/client/js/utils/stable-stringify.test.ts +68 -0
- package/tests/client/js/utils/url-utils.test.ts +70 -0
- package/tests/e2e/backend-connection.test.ts +301 -0
- package/tests/e2e/draft-lifecycle.test.ts +388 -0
- package/tests/e2e/editing.test.ts +355 -0
- package/tests/e2e/github-adapter.test.ts +330 -0
- package/tests/e2e/helpers/mock-adapter.ts +166 -0
- package/tests/e2e/helpers/test-app.ts +155 -0
- package/tests/e2e/navigation.test.ts +358 -0
- package/tests/e2e/publishing.test.ts +345 -0
- package/tests/e2e/unsaved-changes.test.ts +317 -0
- package/tests/setup.ts +2 -0
- package/tests/stubs/codemirror.ts +197 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +178 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"mcp__plugin_context7_context7__resolve-library-id",
|
|
5
|
+
"mcp__plugin_context7_context7__query-docs",
|
|
6
|
+
"Bash(pnpm fix:*)",
|
|
7
|
+
"Bash(pnpm lint:*)",
|
|
8
|
+
"Bash(git add:*)",
|
|
9
|
+
"Bash(git commit:*)",
|
|
10
|
+
"mcp__plugin_playwright_playwright__browser_navigate",
|
|
11
|
+
"mcp__plugin_playwright_playwright__browser_close",
|
|
12
|
+
"Bash(git worktree:*)",
|
|
13
|
+
"Bash(pnpm test:*)",
|
|
14
|
+
"Bash(pnpm sync:*)",
|
|
15
|
+
"Bash(pnpm build:*)",
|
|
16
|
+
"Bash(ag:*)",
|
|
17
|
+
"Bash(git ls-tree:*)",
|
|
18
|
+
"Bash(git stash:*)",
|
|
19
|
+
"Bash(pnpm vitest:*)",
|
|
20
|
+
"mcp__plugin_playwright_playwright__browser_console_messages",
|
|
21
|
+
"mcp__plugin_playwright_playwright__browser_click",
|
|
22
|
+
"mcp__plugin_playwright_playwright__browser_take_screenshot",
|
|
23
|
+
"mcp__plugin_playwright_playwright__browser_snapshot",
|
|
24
|
+
"mcp__plugin_playwright_playwright__browser_evaluate",
|
|
25
|
+
"WebSearch",
|
|
26
|
+
"mcp__playwright__browser_navigate",
|
|
27
|
+
"mcp__playwright__browser_take_screenshot",
|
|
28
|
+
"mcp__playwright__browser_snapshot",
|
|
29
|
+
"mcp__playwright__browser_click",
|
|
30
|
+
"mcp__playwright__browser_console_messages",
|
|
31
|
+
"mcp__playwright__browser_network_requests",
|
|
32
|
+
"Bash(/Users/avalon/.claude/plugins/cache/claude-plugins-official/superpowers/5.0.7/skills/brainstorming/scripts/start-server.sh --project-dir /Users/avalon/Development/nebula-cms)",
|
|
33
|
+
"WebFetch(domain:discuss.codemirror.net)",
|
|
34
|
+
"Bash(/Users/avalon/.claude/plugins/cache/claude-plugins-official/superpowers/5.0.7/skills/brainstorming/scripts/stop-server.sh /Users/avalon/Development/nebula-cms/.superpowers/brainstorm/53523-1775161916)",
|
|
35
|
+
"mcp__playwright__browser_tabs",
|
|
36
|
+
"mcp__playwright__browser_select_option",
|
|
37
|
+
"Bash(git check-ignore:*)"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"enableAllProjectMcpServers": true,
|
|
41
|
+
"enabledMcpjsonServers": ["playwright"]
|
|
42
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: pnpm/action-setup@v4
|
|
15
|
+
|
|
16
|
+
- uses: actions/setup-node@v4
|
|
17
|
+
with:
|
|
18
|
+
node-version: 22
|
|
19
|
+
cache: pnpm
|
|
20
|
+
|
|
21
|
+
- name: Install dependencies
|
|
22
|
+
run: pnpm install
|
|
23
|
+
|
|
24
|
+
- name: Install Playwright browsers
|
|
25
|
+
run: pnpm exec playwright install --with-deps chromium
|
|
26
|
+
|
|
27
|
+
- name: Lint
|
|
28
|
+
run: pnpm lint
|
|
29
|
+
|
|
30
|
+
- name: Test
|
|
31
|
+
run: pnpm test
|
package/.mcp.json
ADDED
package/.prettierignore
ADDED
package/.prettierrc.cjs
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
singleQuote: true,
|
|
3
|
+
trailingComma: 'all',
|
|
4
|
+
plugins: [
|
|
5
|
+
require.resolve('prettier-plugin-astro'),
|
|
6
|
+
require.resolve('prettier-plugin-svelte'),
|
|
7
|
+
],
|
|
8
|
+
overrides: [
|
|
9
|
+
{
|
|
10
|
+
files: '*.astro',
|
|
11
|
+
options: {
|
|
12
|
+
parser: 'astro',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
files: '*.svelte',
|
|
17
|
+
options: {
|
|
18
|
+
parser: 'svelte',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
## Git Commits
|
|
2
|
+
|
|
3
|
+
You are STRICTLY FORBIDDEN from co-authoring commits.
|
|
4
|
+
|
|
5
|
+
**STRICTLY FORBIDDEN: Committing gitignored files.** You MUST NEVER use `git add -f` or any other mechanism to commit files that are matched by `.gitignore`. If a file is gitignored, it is gitignored — no skill, plugin, or workflow instruction overrides this. If a skill tells you to commit a file and that file is gitignored, skip the commit step for that file. This rule has no exceptions.
|
|
6
|
+
|
|
7
|
+
## Personality
|
|
8
|
+
|
|
9
|
+
You are a senior-level, high-standards technical peer. You operate as a rigorous sounding board and code auditor. Your goal is technical precision and architectural integrity, not social validation.
|
|
10
|
+
|
|
11
|
+
- **Eliminate Fluff:** Remove all conversational filler, preambles, and post-task pleasantries. Never use: "I understand," "That's a great question," "I'm happy to help," or "I've updated the code for you."
|
|
12
|
+
- **Zero Praise:** Do not compliment the user or their code. In a peer-to-peer professional environment, praise is often perceived as condescending or belittling.
|
|
13
|
+
- **Directness without Rudeness:** Be blunt but objective. Focus on the code, the logic, and the constraints. Avoid emotive language; rely on technical evidence.
|
|
14
|
+
- **Immediate Execution:** If a request is clear, provide the solution or critique immediately without acknowledging the instruction.
|
|
15
|
+
- **Collaborative Dissent:** Do not assume you are more experienced than the user. If the user’s approach seems flawed, frame it as a technical trade-off or a potential risk rather than a "mistake."
|
|
16
|
+
- **Contextual Deference:** Acknowledge implicitly that the user possesses domain-specific knowledge and project context you lack. Challenge assumptions with "How does this handle X?" rather than "You should do X."
|
|
17
|
+
- **Constructive Alternatives:** Suggest alternatives only if they provide tangible improvements in performance, maintainability, or security. Do not suggest "standard" alternatives that are clearly inferior to the user's current direction.
|
|
18
|
+
- **Assumption Checking:** If the user's prompt is ambiguous, state your assumption before providing the solution: "Assuming this must scale to X concurrent users, the implementation is as follows..."
|
|
19
|
+
- **Requirement Adherence:** Do not suggest patterns or libraries that deviate from the tech stack or constraints already established in the conversation.
|
|
20
|
+
|
|
21
|
+
## Commands
|
|
22
|
+
|
|
23
|
+
**CRITICAL: ALWAYS USE `pnpm`, AND ONLY USE THE EXISTING `package.json` SCRIPTS! Never use `npm`, `npx`, or `pnpx`!** If a Node.js based CLI is not already installed and configured to be run through a `package.json` script, it should not be run.
|
|
24
|
+
|
|
25
|
+
**STRICTLY FORBIDDEN: Editing `package.json` scripts.** You and your subagents MUST NOT add, modify, or remove entries in the `"scripts"` block of ANY `package.json` file. This has been a recurring violation where agents add wrapper scripts (e.g., `"sync": "astro sync"`) to circumvent the compound command prohibition. The correct approach is simple: `cd` into the directory (as its own Bash tool call), then run the command directly (as a separate Bash tool call). Existing scripts may be _used_ but never _edited_.
|
|
26
|
+
|
|
27
|
+
**STRICTLY FORBIDDEN: Directory-changing flags.** Do NOT use `--dir`, `--cwd`, `--prefix`, `-C`, `--root`, `--filter`, `bash -c`, `sh -c`, or any other flag/mechanism that changes the working directory or wraps commands. The ONLY way to run a command in a different directory is to `cd` there first (its own Bash call), then run the command (separate Bash call).
|
|
28
|
+
|
|
29
|
+
**ALWAYS RUN `pnpm lint` and `pnpm fix` before committing!** You are FORBIDDEN from finalizing your code until you have no more warnings or errors from either script.
|
|
30
|
+
|
|
31
|
+
**IMPORTANT!** Before asking to run the dev server, check to see if it already is (it is often running). Only ask to run the dev server if you've already checked and it's not running, or if you specifically need access to the dev server's output.
|
|
32
|
+
|
|
33
|
+
## Git Worktrees
|
|
34
|
+
|
|
35
|
+
Worktree directory: `.worktrees/` (project-local). All feature work must be done in an isolated git worktree, never directly on `main`.
|
|
36
|
+
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
### File Size and Component Decomposition
|
|
40
|
+
|
|
41
|
+
**CRITICAL REQUIREMENT!** FILES MUST NOT BE LARGER THAN 350 LINES OF CODE! IF YOUR CHANGES WOULD VIOLATE THIS, YOU MUST REFACTOR YOUR WORK SO THAT IT DOES NOT. We do this to ensure each individual file is easy to read and maintain (docs, planning files like `.feature` files, tests because they have a lot of boilerplate, and markdown files excluded).
|
|
42
|
+
|
|
43
|
+
Files usually balloon larger than this because they're trying to do too much at one. Aim for components and library files to do a SINGLE THING. Compose multiple smaller components together into larger ones **instead of** trying to put everything into a single file.
|
|
44
|
+
|
|
45
|
+
### Semantic HTML
|
|
46
|
+
|
|
47
|
+
**CRITICAL REQUIREMENTS!** YOU ARE STRICTLY FORBIDDEN FROM ATTACHING CLICK HANDLERS TO ANYTHING THAT IS NOT A `button` OR `a` ELEMENT! YOU MUST USE THOSE ELEMENTS CORRECTLY, `a` IS FOR LINKING TO RESOURCES (URLs, files with paths, etc…), `button` IS FOR IN-PAGE INTERACTION. FAILURE TO ADHERE TO THIS IS CONSIDERED A CRITICAL FAILURE!
|
|
48
|
+
|
|
49
|
+
### State Management
|
|
50
|
+
|
|
51
|
+
**CRITICAL:** Prop drilling architecture patterns for state are STRICTLY FORBIDDEN! They add too much boilerplate and complexity. Use small, reactive state instead.
|
|
52
|
+
|
|
53
|
+
**CRITICAL:** Function and callback drilling architecture patterns are STRICTLY FORBIDDEN! Functions and callbacks must ONLY be passed into components if their functionality changes per-instance (like a button). It MUST NOT be used for coordination or managing state! You MUST use reactive state instead.
|
|
54
|
+
|
|
55
|
+
### CSS Rules
|
|
56
|
+
|
|
57
|
+
Font sizes MUST follow this scale:
|
|
58
|
+
|
|
59
|
+
- **Default** text: `1rem`
|
|
60
|
+
- **Smallest non-caption** text: `0.875rem` (for compact UI elements, labels, buttons)
|
|
61
|
+
- **Smallest allowed** text: `0.75rem` — ONLY for captions, secondary information (timestamps, placeholders, empty states). Using `0.75rem` for primary or interactive content requires explicit permission.
|
|
62
|
+
|
|
63
|
+
Non-standard sizes like `0.8rem`, `0.85rem`, `0.9rem`, `0.95rem` are NOT allowed. Round to the nearest size on this scale. Font sizes can increment above `1rem` in steps of `.25rem`
|
|
64
|
+
|
|
65
|
+
All other CSS sizing MUST be in `rem` units, and MUST be written in `.25rem` increments, pixels are FORBIDDEN. The ONLY exceptions are:
|
|
66
|
+
|
|
67
|
+
- Border radius, border width, outline, outline-offset, text shadow, or drop shadow <= `5px`
|
|
68
|
+
- The visually-hidden/sr-only accessibility pattern (`width: 1px; height: 1px; clip: rect(0,0,0,0)`) — this exception applies ONLY to this specific pattern and MUST NOT be used to justify pixel values in any other context
|
|
69
|
+
- The `.chip` class in `DraftChip.svelte` is exempt from the font size scale and the `.25rem` increment rule for `padding-block` — it uses `0.6rem` font size and `0.15rem` block padding to achieve the correct visual weight relative to sidebar item labels
|
|
70
|
+
|
|
71
|
+
Other relative units, where applicable, are OK (like `vh`, `vw`, `cqi`, `cqb`, `fr`).
|
|
72
|
+
|
|
73
|
+
Prefer CSS Grid to Flexbox unless you need the specific characteristics of flexbox.
|
|
74
|
+
|
|
75
|
+
### `:global` Usage Policy
|
|
76
|
+
|
|
77
|
+
`:global` escapes Svelte's scoped CSS. Most uses indicate styles that should be in a global CSS file instead. Only use `:global` when scoped CSS physically cannot reach the target element.
|
|
78
|
+
|
|
79
|
+
- **Top-layer rendering** — Elements using the Popover API or `<dialog>` render in the browser's top layer, outside the component DOM where scoped CSS cannot reach
|
|
80
|
+
- **Scoped parent + global child** — Combining a scoped parent selector with a `:global` child when the child is library-generated (e.g. `.lexical-editor--readonly :global([contenteditable='false'])`)
|
|
81
|
+
|
|
82
|
+
**Not allowed:**
|
|
83
|
+
|
|
84
|
+
- **Convenience** — If a style could be a global partial or scoped class, don't use `:global`
|
|
85
|
+
- **Shared/reusable styles** — Move to `src/client/css` (e.g. `input.css`, `utilities.css`)
|
|
86
|
+
- **Utility classes** — Add to `src/client/css/utilities.css`
|
|
87
|
+
- **Portal-rendered content** — Refactor to Svelte-rendered markup with scoped styles instead of imperative DOM + `:global`
|
|
88
|
+
|
|
89
|
+
### Code Comments
|
|
90
|
+
|
|
91
|
+
You are REQUIRED to professionally comment your code. Comments should be short and helpful, explaining what something does, but MUST NOT include your dialog or thinking.
|
|
92
|
+
|
|
93
|
+
If supported by the language, single line comments MUST ALWAYS use `//`, even when describing types, interfaces, or classes. NEVER use single-line JSDoc (`/** foo */`). If unsuppored, use standard, single asterix comments.
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
// Whether the dialog should be shown
|
|
97
|
+
let showDialog = $state(false);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```css
|
|
101
|
+
/* Reset dialog box-sizing */
|
|
102
|
+
dialog {
|
|
103
|
+
box-sizing: border-box;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Functions MUST have multi-line JSDoc comments (`/** ... */` with newlines). They MUST include a description of why they've been written, plus `@param` and `@return` with proper TypeScript typing, EVEN IF ITS ALREADY DOCUMENTED WITH TYPESCRIPT TYPES AT THE METHOD LEVEL.
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
/**
|
|
111
|
+
* Display the dialog
|
|
112
|
+
* @param {string} text - The text to show in the dialog
|
|
113
|
+
* @return {void}
|
|
114
|
+
*/
|
|
115
|
+
function showDialog(text: string) {
|
|
116
|
+
dialog.textContent = text;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
File-level description comments MUST come BEFORE any imports and MUST use standard JavaScript multi-line comment syntax (`/* ... */`). They describe what the file is for and why it exists. Multi-line comments that are not covered by JSDoc comments MUST use this style of comment block, too.
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
/*
|
|
124
|
+
* State management for dialog
|
|
125
|
+
*/
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Comment Blocks that are meant to draw the eye and describe a section of code be written as follows, with each line of the description starting with `//`:
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
/*
|
|
132
|
+
//////////////////////////////
|
|
133
|
+
// Description
|
|
134
|
+
//////////////////////////////
|
|
135
|
+
*/
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Comments MUST NOT have arbitrary line breaks to conform to an invisible max character count, just write normally and have line wrapping handle comment wrapping.
|
|
139
|
+
|
|
140
|
+
It is CRITICAL that you write comments explaining specific items that we've gone back and forth on a number of times to ensure that the reason why it exists the way it does (which likely went against your normal thinking) so that future developers and agents can learn from it and improve.
|
|
141
|
+
|
|
142
|
+
### Naming Conventions
|
|
143
|
+
|
|
144
|
+
When writing CamelCase variable, function, type, or class names, abbreviations (like CSS, URL, HTML, API, ID, UUID, IDB, FSA, DOM, BOM, CRLF, SHA, TOML, YAML, JSON, MDX) MUST ALWAYS be all-caps. For example: `parseURL`, `getCSS`, `buildHTML`, `tomlStringifyURL`, `fetchAPIData`. Never `parseUrl`, `getCss`, `buildHtml`.
|
|
145
|
+
|
|
146
|
+
### Component Reuse (CRITICAL)
|
|
147
|
+
|
|
148
|
+
Before creating ANY new UI component, pattern, or styling, you MUST search the existing codebase for similar functionality. If a component, pattern, or style already exists, you MUST reuse or extend it — even if it requires refactoring to accept props for configurability. Creating duplicates of existing functionality is FORBIDDEN. Specifically:
|
|
149
|
+
|
|
150
|
+
- **Search `src/client/components/`** for existing components that do what you need. If one exists but is hardcoded to one page's state, refactor it to accept optional props (controlled mode) while preserving the original behavior (uncontrolled mode).
|
|
151
|
+
- **Search `src/client/css/`** for existing styles before writing new CSS.
|
|
152
|
+
- **Match existing layout patterns** — reuse the same components and follow the same structure, not recreate it from scratch.
|
|
153
|
+
|
|
154
|
+
### DOM Manipulation Rules
|
|
155
|
+
|
|
156
|
+
Svelte's declarative rendering MUST be used for all UI construction. Direct DOM manipulation (`document.createElement`, `appendChild`, `innerHTML`, `querySelector`, etc.) is FORBIDDEN except in these cases:
|
|
157
|
+
|
|
158
|
+
- **Focus and scroll** — `.focus()` and `.scrollIntoView()` are imperative by nature, but the element reference MUST come from `bind:this` (in components) or reactive state signals (in state files). Using `document.getElementById`/`querySelector` to obtain element references is FORBIDDEN.
|
|
159
|
+
- **Popover API** — `.showPopover()` / `.hidePopover()` require imperative calls, but the element MUST be obtained via `bind:this`, never DOM queries.
|
|
160
|
+
- **Cross-component coordination** — State files MUST NOT query the DOM. Use reactive signals (counter increment pattern) so components react via `$effect` and control their own elements.
|
|
161
|
+
- **Positioning** — Use CSS Anchor Positioning (`anchor-name`, `position-anchor`, `position-area`) instead of computing pixel positions with `getBoundingClientRect()` and `style.top`/`style.left`.
|
|
162
|
+
|
|
163
|
+
## Rule Compliance
|
|
164
|
+
|
|
165
|
+
The rules in this file are literal requirements, not guidelines. Do not invent exceptions, even if industry convention differs. If a rule doesn't list an exception, there is no exception.
|
|
166
|
+
|
|
167
|
+
Before writing or modifying code, re-read this entire file. Do not work from memory of the rules — memory introduces drift and invented exceptions. Do not decide which sections are "relevant" and skip the rest; rules interact and a section you think doesn't apply often does.
|
|
168
|
+
|
|
169
|
+
## Subagent Delegation
|
|
170
|
+
|
|
171
|
+
When delegating tasks to subagents, you MUST copy the relevant rules from BOTH this project's CLAUDE.md AND the global CLAUDE.md verbatim into the subagent prompt. Do NOT paraphrase, summarize, or add your own interpretations of the rules. If you need to add task-specific context, keep it clearly separate from the rules themselves. Subagents do not have access to CLAUDE.md files, so they will only follow what you put in their prompt — if you reword, omit, or "helpfully" add exceptions, the subagent will produce work that violates the actual rules.
|
|
172
|
+
|
|
173
|
+
## Mandatory Code Review Before Completion
|
|
174
|
+
|
|
175
|
+
After any agent or subagent finishes writing code, you MUST NOT mark the work as done until a compliance review has been performed. This review MUST:
|
|
176
|
+
|
|
177
|
+
1. Load the FULL text of BOTH this project's CLAUDE.md AND the global CLAUDE.md — not just sections you think are relevant, the entire files
|
|
178
|
+
2. Check every line of changed code against those rules verbatim — not from memory, not paraphrased, the actual text of the rules
|
|
179
|
+
3. Flag ANY violation, no matter how minor or how "standard" the alternative practice might be
|
|
180
|
+
4. The reviewer MUST NOT rationalize a violation as acceptable. If the code doesn't match what the rule literally says, it's a violation and must be fixed
|
|
181
|
+
5. All flagged violations must be fixed and re-reviewed before the work can be marked complete
|
|
182
|
+
|
|
183
|
+
This review applies to your own direct work as well as work produced by subagents. "It looks right" is not a substitute for checking against the rules.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Nebula CMS
|
|
2
|
+
|
|
3
|
+
A streamlined, Git-based Content Management System built specifically for [Astro](https://astro.build/). Nebula CMS provides a beautiful, unified editing interface for your Markdown, MDX, JSON, YAML, TOML, and Markdoc files, driven directly by your existing Astro [Content Collections](https://docs.astro.build/en/guides/content-collections/).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Painless Integration**: Plugs perfectly into Astro as a standard integration.
|
|
8
|
+
- **Git-Backed**: Modifications are made directly to the files in your repository. No external databases required.
|
|
9
|
+
- **Zero-Config Schemas**: Reads directly from your Astro Content Collections schemas via Zod.
|
|
10
|
+
- **Modern UI**: Svelte-powered dashboard to seamlessly manage entries, relational fields, and deeply nested object structures.
|
|
11
|
+
|
|
12
|
+
## Requirements, Installation, Setup
|
|
13
|
+
|
|
14
|
+
Nebula CMS requires the following peer dependencies:
|
|
15
|
+
|
|
16
|
+
- `astro` 6.1.0 or higher
|
|
17
|
+
- `@astrojs/svelte` 8.0.0 or higher
|
|
18
|
+
- `svelte` 5.0.0 or higher
|
|
19
|
+
|
|
20
|
+
Install the package via your preferred package manager:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install nebula-cms
|
|
24
|
+
# or
|
|
25
|
+
pnpm add nebula-cms
|
|
26
|
+
# or
|
|
27
|
+
yarn add nebula-cms
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Once installed, make sure you include both Svelte and Nebula in your Astro config:
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
// astro.config.mjs
|
|
34
|
+
import { defineConfig } from 'astro/config';
|
|
35
|
+
import svelte from '@astrojs/svelte';
|
|
36
|
+
import nebulaCMS from 'nebula-cms';
|
|
37
|
+
|
|
38
|
+
export default defineConfig({
|
|
39
|
+
integrations: [svelte(), nebulaCMS()],
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Then import the Nebula component into the path you want to use for the CMS:
|
|
44
|
+
|
|
45
|
+
```astro
|
|
46
|
+
---
|
|
47
|
+
import NebulaCMS from 'nebula-cms/client';
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
<html lang="en">
|
|
51
|
+
<head>
|
|
52
|
+
<meta charset="utf-8" />
|
|
53
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
54
|
+
<title>Nebula CMS</title>
|
|
55
|
+
</head>
|
|
56
|
+
<body>
|
|
57
|
+
<NebulaCMS client:only="svelte" />
|
|
58
|
+
</body>
|
|
59
|
+
</html>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Nebula assumes that your path is `/admin`. If you want to change it, in your Astro config, pass the `basePath` option to the integration:
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
export default defineConfig({
|
|
66
|
+
integrations: [svelte(), nebulaCMS({ basePath: '/cms' })],
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Defining Content Models
|
|
71
|
+
|
|
72
|
+
Unlike an external CMS where you have to duplicate your schema configuration, Nebula reads the exact same schemas you're already building in your [Astro Content Collections](https://docs.astro.build/en/guides/content-collections/).
|
|
73
|
+
|
|
74
|
+
For even more control, new in Astro 6, you can make use of Zod's `meta()` method to configure how collections and fields are displayed inside Nebula.
|
|
75
|
+
|
|
76
|
+
### Field Meta
|
|
77
|
+
|
|
78
|
+
Adding `.meta()` to individual fields lets you provide UI-specific hints:
|
|
79
|
+
|
|
80
|
+
- **`title`** _(string)_: A human-readable display name for the field
|
|
81
|
+
- **`description`** _(string)_: A short description explaining what the field is for.
|
|
82
|
+
|
|
83
|
+
### Content Collection Meta
|
|
84
|
+
|
|
85
|
+
Adding `.meta()` to your base object schema lets you provide UI-specific hints to the CMS:
|
|
86
|
+
|
|
87
|
+
- **`title`** _(string)_: A human-readable display name for the collection (e.g., `'Blog Posts'`).
|
|
88
|
+
- **`description`** _(string)_: A short description explaining what the collection is for.
|
|
89
|
+
- **`files`** _(array of strings)_: The file extensions supported by this collection (e.g., `['md']`, `['json']`, `['md', 'mdx']`). This ensures Nebula CMS reads and writes the correct formats. Including `md`, `mdx`, or `markdoc` in this array will enable the rich text editor for those collections.
|
|
90
|
+
|
|
91
|
+
### Example Schema
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// src/content.config.ts
|
|
95
|
+
import { defineCollection, reference } from 'astro:content';
|
|
96
|
+
import { glob } from 'astro/loaders';
|
|
97
|
+
import { z } from 'astro/zod';
|
|
98
|
+
|
|
99
|
+
const posts = defineCollection({
|
|
100
|
+
loader: glob({ base: './src/content/posts', pattern: '**/*.md' }),
|
|
101
|
+
schema: z
|
|
102
|
+
.object({
|
|
103
|
+
title: z.string(),
|
|
104
|
+
date: z.date().meta({
|
|
105
|
+
description: 'Published date for the post',
|
|
106
|
+
}),
|
|
107
|
+
draft: z.boolean().optional(),
|
|
108
|
+
author: reference('authors'),
|
|
109
|
+
})
|
|
110
|
+
.meta({
|
|
111
|
+
title: 'Posts',
|
|
112
|
+
description: 'Blog posts',
|
|
113
|
+
files: ['md'],
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
export const collections = { posts };
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Accessing the CMS
|
|
121
|
+
|
|
122
|
+
Once your integration is configured and your collections are defined, start your Astro development server and navigate to the page you integrated Nebula to. You'll be presented with two options: either using the File System Access API to work with your files locally, or connecting to a GitHub repository with a Personal Access Token to manage your content remotely.
|
|
123
|
+
|
|
124
|
+
While working locally, Nebula will automatically manage soft (SPA) navigations and includes middleware to ensure that all relevant pages are captured and redirected to the main URL. The path you configured will work for static or dynamic configurations, but you may need to configure your hosting provider to provide the same functionality if you export as a static site.
|
|
125
|
+
|
|
126
|
+
## Drafts
|
|
127
|
+
|
|
128
|
+
Nebula will let you create drafts of new pieces of content or changes to existing content. It stores these in IndexedDB in your browser and not included in your source files.
|