create-obsidian-arrow 0.5.0 → 0.5.2
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 +7 -7
- package/cli/create.mjs +65 -0
- package/cli/detect-pm.mjs +20 -0
- package/cli/lib.mjs +117 -0
- package/cli/refresh.mjs +65 -0
- package/index.mjs +47 -204
- package/package.json +11 -2
- package/template/.husky/pre-commit +3 -2
- package/template/AGENTS.md +58 -12
- package/template/README.md +67 -31
- package/template/_gitignore +4 -1
- package/template/biome.json +7 -1
- package/template/docs/prompts/agent-setup.md +24 -20
- package/template/docs/prompts/update-existing.md +3 -3
- package/template/docs/workflow.md +11 -7
- package/template/package.json +15 -14
- package/template/src/components/DiffViewer/DiffViewer.css +41 -0
- package/template/src/components/DiffViewer/DiffViewer.ts +55 -0
- package/template/src/components/EmptyState/EmptyState.css +5 -5
- package/template/src/components/EmptyState/EmptyState.ts +5 -9
- package/template/src/utilities.css +259 -1
- package/template/src/views/DiffViewer/DiffViewerView.css +42 -0
- package/template/src/views/DiffViewer/DiffViewerView.ts +53 -0
- package/template/src/views/ExampleView/ExampleView.ts +92 -0
- package/template/stories/components/ComponentShell.stories.ts +28 -0
- package/template/stories/components/EmptyState.stories.ts +1 -0
- package/template/stories/components/LoadingState.stories.ts +1 -0
- package/template/stories/components/Toggle.stories.ts +50 -0
- package/template/stories/views/DiffViewer/DiffViewer.stories.ts +94 -0
- package/template/stories/views/EditorView.stories.ts +55 -0
- package/template/stories/views/ExampleView/ExampleView.stories.ts +15 -0
- package/template/stories/views/PanelView.stories.ts +61 -0
- package/template/stories/views/SettingsPanel/SettingsPanel.stories.ts +14 -0
- package/template/test/css-structure.test.mjs +112 -0
- package/template/test/template-footguns.test.mjs +85 -6
- package/template/test/viewer-stories.test.mjs +12 -0
- package/template/tools/router/client.ts +26 -4
- package/template/tools/router/routeToPage.ts +29 -13
- package/template/tools/sandbox/frame.ts +7 -27
- package/template/tools/sandbox/home.ts +6 -11
- package/template/tools/sandbox/layout.ts +24 -2
- package/template/tools/sandbox/sandbox.css +188 -226
- package/template/tools/sandbox/shell.ts +2 -2
- package/template/tools/sandbox/toolbar.ts +20 -9
- package/template/tools/viewer/ClassesPage.ts +7 -7
- package/template/tools/viewer/ComponentsIndex.ts +3 -3
- package/template/tools/viewer/StoryPage.ts +53 -40
- package/template/tools/viewer/TokensPage.ts +10 -10
- package/template/tools/viewer/ViewsIndex.ts +66 -0
- package/template/tools/viewer/discovery.ts +2 -0
- package/template/tools/viewer/obsidian-classes.ts +1 -1
- package/template/tools/viewer/sidebar.ts +27 -38
- package/template/tools/viewer/stories.ts +16 -2
- package/template/.github/workflows/ci.yml +0 -36
- package/template/pnpm-lock.yaml +0 -1608
- package/template/scripts/create-component.mjs +0 -101
- package/template/scripts/create-view.mjs +0 -75
- package/template/src/components/DiffViewer.ts +0 -42
- package/template/stories/DiffViewer.stories.ts +0 -75
- package/template/stories/SettingsPanel.stories.ts +0 -11
- package/template/stories/Toggle.stories.ts +0 -28
package/template/AGENTS.md
CHANGED
|
@@ -11,6 +11,7 @@ This file is the hub — everything else is linked from here:
|
|
|
11
11
|
- [`docs/workflow.md`](docs/workflow.md) — fresh-machine → running workflow.
|
|
12
12
|
- [`skills/`](skills/) — installable domain skills (`pnpm skills:install`):
|
|
13
13
|
- `obsidian-arrow-sandbox` — running the sandbox, CSS scoping, porting basics.
|
|
14
|
+
- `obsidian-arrow-composition` — **run before designing any view area**: surveys codebase, shows file trees for confirmation, asks questions, checks DRY/primitive use, produces a locked hierarchy doc.
|
|
14
15
|
- `obsidian-arrow-stories` — **component + story authoring workflow**: `defineStories` API, variants, children, status flag, DRY patterns, utilities.
|
|
15
16
|
- `obsidian-arrow-css` — **CSS decision hierarchy**: Obsidian classes → oas-* utilities → custom CSS; token reference; specificity scoping; overrides via variables; auditing for excess CSS.
|
|
16
17
|
- `arrow-js-obsidian-templates` — Arrow v1.0.6 template syntax + footguns.
|
|
@@ -19,6 +20,9 @@ This file is the hub — everything else is linked from here:
|
|
|
19
20
|
- `obsidian-arrow-maintenance` — updating an existing project.
|
|
20
21
|
- [`docs/prompts/`](docs/prompts/) — copy-paste agent prompts: `agent-setup.md`
|
|
21
22
|
(scaffold + orient) and `update-existing.md` (update tooling + skills, keep src).
|
|
23
|
+
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — source-repo and tool development (monorepo layout,
|
|
24
|
+
`oasbox`/`create-obsidian-arrow` package dev, `pnpm create:sync`). **Project-level work
|
|
25
|
+
does not require reading this.**
|
|
22
26
|
|
|
23
27
|
Design rationale (why `core`+`framework`, no SSR, how `app.css` is sourced) is
|
|
24
28
|
summarized in "What this is (and isn't)" below and in the README.
|
|
@@ -37,23 +41,64 @@ summarized in "What this is (and isn't)" below and in the README.
|
|
|
37
41
|
## Run it
|
|
38
42
|
|
|
39
43
|
```sh
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
<pm> install
|
|
45
|
+
<pm> run pull-css # macOS-only auto-detect; else --path <asar|css> / OBSIDIAN_ASAR=<path>
|
|
46
|
+
<pm> run dev # Vite + HMR
|
|
43
47
|
```
|
|
44
48
|
|
|
49
|
+
(`<pm>` = `pnpm` / `npm` / `bun` — any package manager works.)
|
|
50
|
+
|
|
45
51
|
`public/app.css` is **git-ignored** (Obsidian's proprietary CSS — not
|
|
46
|
-
redistributed); run `
|
|
52
|
+
redistributed); run `pull-css` once before `dev`.
|
|
47
53
|
|
|
48
54
|
Install the skills (pulled from the published repo, not vendored):
|
|
49
|
-
|
|
50
|
-
(TUI); update with
|
|
55
|
+
`<pm> run skills:install --yes` (non-interactive, all skills) or `<pm> run skills:install`
|
|
56
|
+
(TUI); update with `<pm> run skills:update`. Scope
|
|
51
57
|
flags: `--agent <name>`, `--project-dir=<path>`, `--global`. **Nested inside
|
|
52
58
|
another repo?** Skills install cwd-relative — use `--project-dir=<outer-repo>` so
|
|
53
59
|
they land where an agent at the outer repo looks. To refresh an existing
|
|
54
|
-
project's tooling, run `npx create-obsidian-arrow
|
|
60
|
+
project's tooling, run `npx create-obsidian-arrow refresh` (see the
|
|
55
61
|
obsidian-arrow-maintenance skill).
|
|
56
62
|
|
|
63
|
+
## oasbox — in-project CLI
|
|
64
|
+
|
|
65
|
+
`oasbox` is installed as a local devDependency by the scaffold. Run it via
|
|
66
|
+
`npx oasbox …`, `pnpm oasbox …`, or `bunx oasbox …` — works under any package manager.
|
|
67
|
+
|
|
68
|
+
### generate
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
oasbox generate component <Name> [--css] # flat or Parent/Child (view-scoped)
|
|
72
|
+
oasbox generate view <Name> [--editor] # --editor → surface:"editor", readable line width
|
|
73
|
+
oasbox generate story <Name> [--kind view|component]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`pnpm create:view <Name>` and `pnpm create:component <Name>` are convenience aliases
|
|
77
|
+
that delegate to `oasbox generate` — use whichever you prefer.
|
|
78
|
+
|
|
79
|
+
### validate & test
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
oasbox validate # check:css + check:scope + check:imports + typecheck
|
|
83
|
+
oasbox validate --json # machine-readable output
|
|
84
|
+
oasbox test # pass-through to project test runner
|
|
85
|
+
oasbox dev # pass-through to project dev server
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## create-obsidian-arrow lifecycle
|
|
89
|
+
|
|
90
|
+
`create-obsidian-arrow` is the **project lifecycle** CLI — run it ephemerally (no
|
|
91
|
+
local install needed):
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
npx create-obsidian-arrow create <dir> # scaffold a new project
|
|
95
|
+
npx create-obsidian-arrow refresh [dir] # refresh managed tooling files from the current template
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`refresh` (formerly `update`) pulls fresh managed files; `--dry-run` shows what
|
|
99
|
+
would change without writing. Genuine version bumps (skills, dependencies) are
|
|
100
|
+
handled separately. Works with any PM: `npx` / `pnpm dlx` / `bunx`.
|
|
101
|
+
|
|
57
102
|
## Arrow v1.0.6 footguns — READ BEFORE WRITING TEMPLATES
|
|
58
103
|
|
|
59
104
|
These are hard runtime errors, not style nits. They are encoded in CI
|
|
@@ -106,8 +151,9 @@ in `boundary()`.
|
|
|
106
151
|
- `stories/components/` — stories for primitives (`kind: "component"`)
|
|
107
152
|
- Mirror the `src/` structure. `kind` auto-detected from path; set explicitly to override.
|
|
108
153
|
- `kind` — specifies story type (`"view"` or `"component"`).
|
|
154
|
+
- `surface?: "panel" | "editor"` — which Obsidian surface a view replicates (orthogonal to `kind`). `"panel"` (default) is full-bleed (workspace leaf); `"editor"` is readable line width for note/document views. Scaffold with `pnpm create:view <Name> --editor` — it wraps the body in the portable `oas-readable-width` utility (ports 1:1) and sets the flag; the flag only widens the sandbox pane so the centering shows. Use that utility — don't write your own `max-width: var(--file-line-width)` container.
|
|
109
155
|
- `decorator?: (content: ArrowExpression) => ArrowExpression` — wraps the rendered variant in ancestor context when a component requires a parent class to render correctly.
|
|
110
|
-
- Scaffold: `pnpm create:view <Name>` / `pnpm create:component <Name>`
|
|
156
|
+
- Scaffold: `pnpm create:view <Name>` (add `--editor` for readable-width) / `pnpm create:component <Name>`
|
|
111
157
|
|
|
112
158
|
### Composition analysis (extracting shared primitives)
|
|
113
159
|
|
|
@@ -131,10 +177,10 @@ When multiple views share a pattern, extract a primitive — but do it in this o
|
|
|
131
177
|
## Verify before claiming done
|
|
132
178
|
|
|
133
179
|
```sh
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
180
|
+
<pm> run typecheck # tsc --noEmit
|
|
181
|
+
<pm> run test # node:test
|
|
182
|
+
<pm> run lint # biome
|
|
183
|
+
<pm> run check # all of the above + CSS orphan + import boundary + scope checks
|
|
138
184
|
```
|
|
139
185
|
|
|
140
186
|
Then confirm the actual render:
|
package/template/README.md
CHANGED
|
@@ -7,31 +7,33 @@ styled entirely by Obsidian's real `app.css`, so what you see here is what you
|
|
|
7
7
|
get inside a plugin view.
|
|
8
8
|
|
|
9
9
|
New machine? See [`docs/workflow.md`](docs/workflow.md) for the full
|
|
10
|
-
fresh-checkout-to-running workflow.
|
|
10
|
+
fresh-checkout-to-running workflow. **Working on the tooling itself?** See
|
|
11
|
+
[`CONTRIBUTING.md`](CONTRIBUTING.md) for the monorepo dev workflow.
|
|
11
12
|
|
|
12
13
|
## Scaffold a new project
|
|
13
14
|
|
|
14
|
-
Scaffold a fresh sandbox with the published initializer
|
|
15
|
-
([`create-obsidian-arrow`](create-obsidian-arrow/)):
|
|
15
|
+
Scaffold a fresh sandbox with the published initializer:
|
|
16
16
|
|
|
17
17
|
```sh
|
|
18
18
|
npm create obsidian-arrow@latest my-app
|
|
19
|
-
# or:
|
|
20
|
-
# or:
|
|
19
|
+
# or: npx create-obsidian-arrow create my-app
|
|
20
|
+
# or: pnpm dlx create-obsidian-arrow create my-app
|
|
21
|
+
# or: bunx create-obsidian-arrow create my-app
|
|
21
22
|
```
|
|
22
23
|
|
|
23
|
-
Then `cd my-app &&
|
|
24
|
-
scaffolded project passes
|
|
25
|
-
template is generated from this repo (`pnpm create:sync`), so it never drifts.
|
|
24
|
+
Then `cd my-app && <pm> install && <pm> run pull-css && <pm> run dev`. A freshly
|
|
25
|
+
scaffolded project passes the full `check` suite out of the box.
|
|
26
26
|
|
|
27
|
-
**
|
|
27
|
+
**Refresh an existing project's tooling** (pulls fresh managed files — scripts,
|
|
28
28
|
docs, CI, `biome.json`, agent guides, and the viewer/router/sandbox
|
|
29
29
|
infrastructure in `src/` — merges new `package.json` scripts/deps; never
|
|
30
30
|
touches `src/components/`, `stories/`, `public/`, `index.html`, or build configs):
|
|
31
31
|
|
|
32
32
|
```sh
|
|
33
|
-
npx create-obsidian-arrow
|
|
34
|
-
npx create-obsidian-arrow
|
|
33
|
+
npx create-obsidian-arrow refresh # in the project (or: refresh <dir>)
|
|
34
|
+
npx create-obsidian-arrow refresh --dry-run # preview first
|
|
35
|
+
# also: pnpm dlx create-obsidian-arrow refresh
|
|
36
|
+
# also: bunx create-obsidian-arrow refresh
|
|
35
37
|
```
|
|
36
38
|
|
|
37
39
|
> **Nested in another repo?** If you scaffold inside an existing repo, skills
|
|
@@ -43,55 +45,84 @@ npx create-obsidian-arrow update --dry-run # preview first
|
|
|
43
45
|
> the session**. The scaffolder prints this hint when it detects nesting.
|
|
44
46
|
|
|
45
47
|
> This repo (the full sandbox) is **not** published to npm — only the
|
|
46
|
-
> `create-obsidian-arrow
|
|
48
|
+
> `create-obsidian-arrow` initializer is. Copy-paste agent prompts live in
|
|
47
49
|
> [`docs/prompts/`](docs/prompts/): `agent-setup.md` (scaffold + orient) and
|
|
48
|
-
> `update-existing.md` (
|
|
50
|
+
> `update-existing.md` (refresh tooling + skills, keeping `src/` intact).
|
|
49
51
|
|
|
50
52
|
## Quick start
|
|
51
53
|
|
|
52
54
|
```sh
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
<pm> install
|
|
56
|
+
<pm> run pull-css # extract Obsidian's app.css from your local install (required)
|
|
57
|
+
<pm> run dev # Vite dev server with HMR
|
|
56
58
|
```
|
|
57
59
|
|
|
60
|
+
(`<pm>` = `npm`, `pnpm`, `bun`, or `yarn` — whichever you prefer.)
|
|
61
|
+
|
|
58
62
|
`pull-css` reads `app.css` out of `Obsidian.app/.../obsidian.asar` (macOS) and
|
|
59
63
|
writes `public/app.css`. Override the location with `--path <obsidian.asar|app.css>`
|
|
60
|
-
or `OBSIDIAN_ASAR=<path>`. **Run it once before `
|
|
64
|
+
or `OBSIDIAN_ASAR=<path>`. **Run it once before `dev`** — it needs a local
|
|
61
65
|
Obsidian install.
|
|
62
66
|
|
|
63
67
|
> **Why it isn't committed:** `public/app.css` is **git-ignored**. It's
|
|
64
68
|
> Obsidian's proprietary stylesheet, so we don't redistribute it — each developer
|
|
65
|
-
> extracts it from their own licensed Obsidian install via `
|
|
69
|
+
> extracts it from their own licensed Obsidian install via `pull-css`.
|
|
66
70
|
|
|
67
71
|
> **Platform note:** automatic Obsidian discovery is currently **macOS-only** —
|
|
68
72
|
> `pull-css` knows where `Obsidian.app` lives on macOS. Windows and WSL paths are
|
|
69
73
|
> not auto-detected yet (planned). On those platforms, point the script at the
|
|
70
74
|
> file explicitly via `--path <obsidian.asar|app.css>` or `OBSIDIAN_ASAR=<path>`.
|
|
71
75
|
|
|
76
|
+
## Daily driver: `oasbox`
|
|
77
|
+
|
|
78
|
+
`oasbox` is the in-project CLI — installed as a local devDependency by the scaffold.
|
|
79
|
+
Run it via your package manager or `npx`:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
# Generate scaffolding
|
|
83
|
+
oasbox generate view ChatView # new view (full-pane)
|
|
84
|
+
oasbox generate view ChatView --editor # readable line-width (surface: "editor")
|
|
85
|
+
oasbox generate component Composer # primitive → src/components/Composer/
|
|
86
|
+
oasbox generate component ChatView/Widget # view-scoped → src/views/ChatView/Widget.ts
|
|
87
|
+
oasbox generate story MyWidget --kind component
|
|
88
|
+
|
|
89
|
+
# Validate (runs CSS orphan/scope/import checks + typecheck)
|
|
90
|
+
oasbox validate
|
|
91
|
+
oasbox validate --json # machine-readable output
|
|
92
|
+
|
|
93
|
+
# Pass-throughs
|
|
94
|
+
oasbox test
|
|
95
|
+
oasbox dev
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Invoke via your PM if `oasbox` isn't on your PATH: `pnpm oasbox …` / `npx oasbox …` / `bunx oasbox …`.
|
|
99
|
+
|
|
100
|
+
The `create:view` / `create:component` scripts delegate to `oasbox generate` — both forms work.
|
|
101
|
+
|
|
72
102
|
## Scripts
|
|
73
103
|
|
|
74
104
|
| Script | What it does |
|
|
75
105
|
|---|---|
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
106
|
+
| `dev` | Vite dev server (client-only, HMR) |
|
|
107
|
+
| `build` / `preview` | Production build / preview |
|
|
108
|
+
| `typecheck` | `tsc --noEmit` |
|
|
109
|
+
| `test` | Node built-in test runner (`test/*.test.mjs`) |
|
|
110
|
+
| `lint` / `format` | Biome check / check-and-write |
|
|
111
|
+
| `check` | Biome + typecheck + test + CSS-orphan/scope/import checks (local pre-flight) |
|
|
112
|
+
| `ci` | Biome CI + typecheck + test + CSS-orphan/scope/import checks + build (what CI runs) |
|
|
113
|
+
| `pull-css` | refresh `public/app.css` from the local Obsidian install |
|
|
84
114
|
|
|
85
115
|
A husky `pre-commit` hook runs `lint-staged` (Biome on staged files) + a full
|
|
86
116
|
typecheck. CI (`.github/workflows/ci.yml`) runs the `ci` script on push/PR.
|
|
87
117
|
|
|
88
118
|
## Agent skills
|
|
89
119
|
|
|
90
|
-
This repo is the source of truth for
|
|
120
|
+
This repo is the source of truth for eight [`skills`](https://github.com/vercel-labs/skills)-compatible
|
|
91
121
|
skills under [`skills/`](skills/) — it's a skill marketplace. Scaffolds **don't
|
|
92
122
|
vendor copies**; they pull from this published repo, so installs are always
|
|
93
123
|
current.
|
|
94
124
|
|
|
125
|
+
- `obsidian-arrow-composition` — **run before designing any view area**: surveys codebase, shows proposed file trees, asks targeted questions, checks DRY and primitive use, produces a locked hierarchy doc for the migration agent to execute.
|
|
95
126
|
- `obsidian-arrow-sandbox` — running and using this sandbox, CSS scoping, porting basics.
|
|
96
127
|
- `obsidian-arrow-stories` — **component + story authoring workflow**: the complete `defineStories` API (variants, children, status flag, notes), DRY patterns, utility classes, story viewing, and how to structure sub-components.
|
|
97
128
|
- `obsidian-arrow-css` — **CSS decision hierarchy**: Obsidian classes first, `oas-*` utilities second, custom CSS last; the live token reference (`/reference`), class catalog (`/reference/classes`), specificity scoping, overrides via CSS variables, and auditing components to minimize hand-written CSS.
|
|
@@ -101,8 +132,8 @@ current.
|
|
|
101
132
|
- `arrow-js-obsidian-porting` — content-addressed porting parity: the
|
|
102
133
|
`component-hash` tool + a husky/CI check that the plugin copy hasn't drifted
|
|
103
134
|
from the sandbox source.
|
|
104
|
-
- `obsidian-arrow-maintenance` —
|
|
105
|
-
|
|
135
|
+
- `obsidian-arrow-maintenance` — refreshing an existing project: `create-obsidian-arrow
|
|
136
|
+
refresh`, `skills:update`, nesting/`--project-dir`, re-pull styling.
|
|
106
137
|
|
|
107
138
|
Install them into your agent (pulls from the published repo; the sandbox repo
|
|
108
139
|
itself uses its local `skills/`):
|
|
@@ -118,7 +149,7 @@ pnpm skills:update # update an existing setup t
|
|
|
118
149
|
Anywhere, with no project at all:
|
|
119
150
|
`npx skills add kylebrodeur/obsidian-arrow-sandbox --all --yes`.
|
|
120
151
|
|
|
121
|
-
`postinstall` offers the picker automatically after
|
|
152
|
+
`postinstall` offers the picker automatically after `<pm> install`, but only in
|
|
122
153
|
an interactive terminal — in CI / non-TTY it just prints how to install (never
|
|
123
154
|
hangs). For agents/CI, use `--yes`.
|
|
124
155
|
Scope flags: `--agent <name>` (one agent), `--project-dir=<path>` (install into a
|
|
@@ -146,6 +177,7 @@ with live previews.
|
|
|
146
177
|
|
|
147
178
|
```sh
|
|
148
179
|
pnpm create:view ChatView
|
|
180
|
+
# or: oasbox generate view ChatView
|
|
149
181
|
```
|
|
150
182
|
|
|
151
183
|
Creates `src/views/ChatView/` (ts + css + state.ts) and `stories/views/ChatView.stories.ts`.
|
|
@@ -155,9 +187,13 @@ Creates `src/views/ChatView/` (ts + css + state.ts) and `stories/views/ChatView.
|
|
|
155
187
|
```sh
|
|
156
188
|
pnpm create:component Composer # primitive → src/components/Composer/
|
|
157
189
|
pnpm create:component ChatView/Widget # view-specific → src/views/ChatView/Widget.ts
|
|
190
|
+
# or: oasbox generate component Composer
|
|
158
191
|
```
|
|
159
192
|
|
|
160
|
-
View stories use `kind: "view"` — full pane frame
|
|
193
|
+
View stories use `kind: "view"` — full pane frame with `surface: "panel"` (default) for
|
|
194
|
+
full-bleed or `surface: "editor"` for readable line width. Component stories use
|
|
195
|
+
`kind: "component"` — centered canvas. Both auto-detected from the `stories/views/` vs
|
|
196
|
+
`stories/components/` path.
|
|
161
197
|
|
|
162
198
|
## Porting a component into the plugin
|
|
163
199
|
|
package/template/_gitignore
CHANGED
|
@@ -9,7 +9,10 @@ dist
|
|
|
9
9
|
|
|
10
10
|
# Obsidian's app.css is proprietary — extract it locally with `pnpm pull-css`,
|
|
11
11
|
# don't commit/redistribute it.
|
|
12
|
-
public/app.css
|
|
12
|
+
**/public/app.css
|
|
13
|
+
|
|
14
|
+
# CodeGraph index (per-machine, regenerated by `codegraph index`).
|
|
15
|
+
.codegraph/
|
|
13
16
|
|
|
14
17
|
# subagent-driven-development scratch (briefs, reports, ledger)
|
|
15
18
|
.superpowers/
|
package/template/biome.json
CHANGED
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"files": {
|
|
28
|
-
"ignore": [
|
|
28
|
+
"ignore": [
|
|
29
|
+
"dist",
|
|
30
|
+
"node_modules",
|
|
31
|
+
"public",
|
|
32
|
+
"pnpm-lock.yaml",
|
|
33
|
+
"packages/create-obsidian-arrow/template"
|
|
34
|
+
]
|
|
29
35
|
}
|
|
30
36
|
}
|
|
@@ -24,26 +24,29 @@ SCAFFOLD IT (use the published tool — pick one)
|
|
|
24
24
|
|
|
25
25
|
Then:
|
|
26
26
|
cd my-app
|
|
27
|
-
pnpm install
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
27
|
+
<pm> install # npm install, pnpm install, or bun install
|
|
28
|
+
<pm> run pull-css # REQUIRED before dev — extracts Obsidian's app.css from your
|
|
29
|
+
# LOCAL install into public/app.css (git-ignored, never
|
|
30
|
+
# committed; it's Obsidian's proprietary CSS). Auto-detect is
|
|
31
|
+
# macOS-only; on Windows/WSL pass --path <obsidian.asar|app.css>
|
|
32
|
+
# or set OBSIDIAN_ASAR=<path>.
|
|
33
|
+
<pm> run dev # open the printed URL: / is home, /components the story viewer,
|
|
34
|
+
# /reference the Obsidian token/class index.
|
|
35
|
+
# The toolbar slider/presets + edge drag handle resize the panel.
|
|
36
|
+
oasbox generate view MyView # scaffold a new view (or component/story)
|
|
37
|
+
pnpm skills:install --yes # install all agent skills non-interactively, pulled
|
|
38
|
+
# from the published repo (not vendored) — this loads
|
|
39
|
+
# the domain knowledge. Drop --yes for an interactive picker.
|
|
40
|
+
# NESTED inside another repo? Skills install cwd-relative,
|
|
41
|
+
# so add --project-dir=<outer-repo> (or --global) to put them
|
|
42
|
+
# where an agent at the outer repo will find them.
|
|
42
43
|
|
|
43
44
|
READ FIRST
|
|
44
45
|
- AGENTS.md (root) — operating guide + docs map (links everything below).
|
|
45
46
|
- docs/workflow.md — fresh-machine → running workflow.
|
|
46
|
-
- skills/*/SKILL.md —
|
|
47
|
+
- skills/*/SKILL.md — eight installable skills:
|
|
48
|
+
obsidian-arrow-composition design component hierarchy: surveys codebase, shows file trees,
|
|
49
|
+
asks questions, checks DRY/primitives, produces locked plan
|
|
47
50
|
obsidian-arrow-sandbox running the sandbox, CSS scoping, porting basics
|
|
48
51
|
obsidian-arrow-stories component + story authoring: defineStories API,
|
|
49
52
|
variants, children, status, DRY patterns, utilities
|
|
@@ -75,9 +78,10 @@ CONVENTIONS
|
|
|
75
78
|
only when Obsidian has no class, scoped under a container class + element type
|
|
76
79
|
(e.g. `.my-panel button.my-action`) so it beats Obsidian's global button rule.
|
|
77
80
|
- Sandbox-only chrome lives in tools/sandbox/* — it does NOT port to a plugin.
|
|
78
|
-
- Add a story by creating `stories/MyThing.stories.ts` (
|
|
79
|
-
|
|
80
|
-
`
|
|
81
|
+
- Add a story by creating `stories/components/MyThing.stories.ts` (or
|
|
82
|
+
`stories/views/MyView/MyView.stories.ts` for a view) — under `stories/`, NOT in
|
|
83
|
+
`src/`. Import (depth follows nesting): `"../../tools/viewer/stories"` and
|
|
84
|
+
`"../../src/components/MyThing"`. It appears at `/components/<slug>` automatically.
|
|
81
85
|
Browse tokens at `/reference`, curated classes at `/reference/classes`.
|
|
82
86
|
|
|
83
87
|
VERIFY BEFORE CLAIMING DONE
|
|
@@ -97,7 +101,7 @@ Leave tools/sandbox/* behind. Guard against drift with the porting-parity check
|
|
|
97
101
|
(see the arrow-js-obsidian-porting skill).
|
|
98
102
|
|
|
99
103
|
MAINTENANCE (existing project)
|
|
100
|
-
Refresh tooling with `npx create-obsidian-arrow
|
|
104
|
+
Refresh tooling with `npx create-obsidian-arrow refresh` (preserves src/components/
|
|
101
105
|
and stories/ — updates viewer, router, sandbox, utilities, and tooling files),
|
|
102
106
|
update skills with `pnpm skills:update`. See the obsidian-arrow-maintenance skill.
|
|
103
107
|
|
|
@@ -32,8 +32,8 @@ STEPS (in order)
|
|
|
32
32
|
so the session's skill:// registry (repo-root + global only) can find them.
|
|
33
33
|
|
|
34
34
|
2. Refresh tooling — preserves src/components/ only
|
|
35
|
-
- Preview: npx create-obsidian-arrow
|
|
36
|
-
- Apply: npx create-obsidian-arrow
|
|
35
|
+
- Preview: npx create-obsidian-arrow refresh --dry-run
|
|
36
|
+
- Apply: npx create-obsidian-arrow refresh
|
|
37
37
|
- Then: pnpm install
|
|
38
38
|
Refreshes scripts/, docs/, .github/, .husky/, biome.json, AGENTS.md, CLAUDE.md,
|
|
39
39
|
tools/, src/main.ts, src/utilities.css, test/,
|
|
@@ -77,6 +77,6 @@ REPORT
|
|
|
77
77
|
- Skills are pulled from the published repo, so step 3 is location-independent for
|
|
78
78
|
the *source* — only the *install location* matters (run it at the repo root the
|
|
79
79
|
agent uses; reload after).
|
|
80
|
-
- `npx create-obsidian-arrow
|
|
80
|
+
- `npx create-obsidian-arrow refresh` refreshes managed files and merges
|
|
81
81
|
`package.json`, but never overwrites `src/components/`, `stories/`, `public/`,
|
|
82
82
|
`index.html`, or build configs. See the `obsidian-arrow-maintenance` skill.
|
|
@@ -51,25 +51,29 @@ Then point the agent at [`AGENTS.md`](../AGENTS.md), or brief a fresh agent with
|
|
|
51
51
|
|
|
52
52
|
**Refresh an existing project's tooling** (scripts, docs, CI, viewer/router/sandbox
|
|
53
53
|
in `src/` — never `src/components/` or `stories/`):
|
|
54
|
-
`npx create-obsidian-arrow
|
|
54
|
+
`npx create-obsidian-arrow refresh` (add `--dry-run` to preview).
|
|
55
55
|
|
|
56
56
|
## Build → verify → port loop
|
|
57
57
|
|
|
58
58
|
```sh
|
|
59
59
|
# 1. Check /reference/classes in the running sandbox — does Obsidian have a class
|
|
60
60
|
# for your pattern? Use it before writing custom CSS.
|
|
61
|
-
# 2.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
# 2. Generate components, views, and stories (using oasbox or the npm scripts):
|
|
62
|
+
oasbox generate view ChatView # full-pane view → src/views/ChatView/ + stories/views/
|
|
63
|
+
oasbox generate component Composer # reusable primitive → src/components/Composer/ + stories/components/
|
|
64
|
+
oasbox generate component ChatView/Widget # view-specific sub-component (not promoted yet)
|
|
65
|
+
# Alternatively, the npm scripts delegate to oasbox:
|
|
66
|
+
<pm> run create:view ChatView
|
|
67
|
+
<pm> run create:component Composer
|
|
65
68
|
# 3. Iterate with HMR
|
|
66
|
-
|
|
69
|
+
<pm> run dev
|
|
67
70
|
# /components → index of all discovered stories
|
|
68
71
|
# /components/my-thing → story for MyThing (kind: "component" → centered canvas)
|
|
69
72
|
# /components/chat-view → story for ChatView (kind: "view" → full pane)
|
|
70
73
|
# /reference → live Obsidian token reference
|
|
71
74
|
# /reference/classes → curated class catalog with live previews
|
|
72
|
-
|
|
75
|
+
oasbox validate # CSS check + scope + imports + typecheck
|
|
76
|
+
<pm> run ci # biome + typecheck + tests + build before trusting it
|
|
73
77
|
```
|
|
74
78
|
|
|
75
79
|
Always confirm the actual render in the browser — Arrow's footguns and CSS scoping bugs
|
package/template/package.json
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"name": "obsidian-arrow-sandbox",
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
|
+
"version": "0.1.0",
|
|
5
6
|
"description": "Client-only sandbox for prototyping Obsidian plugin UI with Arrow.js against Obsidian's real styling.",
|
|
6
7
|
"license": "MIT",
|
|
7
|
-
"packageManager": "pnpm@10.14.0",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"dev": "vite",
|
|
10
10
|
"build": "vite build",
|
|
@@ -12,21 +12,20 @@
|
|
|
12
12
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
13
13
|
"pull-css": "node scripts/pull-app-css.mjs",
|
|
14
14
|
"port:css": "node scripts/port-css.mjs",
|
|
15
|
-
"create:
|
|
16
|
-
"create:
|
|
17
|
-
"create:view": "node scripts/create-view.mjs",
|
|
15
|
+
"create:component": "oasbox generate component",
|
|
16
|
+
"create:view": "oasbox generate view",
|
|
18
17
|
"lint": "biome check .",
|
|
19
18
|
"format": "biome check --write .",
|
|
20
19
|
"test": "node --experimental-strip-types --test test/*.test.mjs",
|
|
21
20
|
"check:css": "node scripts/check-orphaned-css.mjs",
|
|
22
21
|
"check:scope": "node scripts/check-scope-classes.mjs",
|
|
23
22
|
"check:imports": "node scripts/check-view-imports.mjs",
|
|
24
|
-
"check": "biome check . &&
|
|
25
|
-
"ci": "biome ci . &&
|
|
23
|
+
"check": "biome check . && tsc -p tsconfig.json --noEmit && node --experimental-strip-types --test test/*.test.mjs && node scripts/check-orphaned-css.mjs && node scripts/check-scope-classes.mjs && node scripts/check-view-imports.mjs",
|
|
24
|
+
"ci": "biome ci . && tsc -p tsconfig.json --noEmit && node --experimental-strip-types --test test/*.test.mjs && node scripts/check-orphaned-css.mjs && node scripts/check-scope-classes.mjs && node scripts/check-view-imports.mjs && vite build",
|
|
25
|
+
"prepare": "husky",
|
|
26
26
|
"skills:install": "node scripts/install-skills.mjs --force",
|
|
27
27
|
"skills:update": "node scripts/install-skills.mjs --update",
|
|
28
|
-
"postinstall": "node scripts/install-skills.mjs"
|
|
29
|
-
"prepare": "husky"
|
|
28
|
+
"postinstall": "node scripts/install-skills.mjs"
|
|
30
29
|
},
|
|
31
30
|
"lint-staged": {
|
|
32
31
|
"*.{ts,mjs,js,json,jsonc}": "biome check --write --no-errors-on-unmatched"
|
|
@@ -42,14 +41,16 @@
|
|
|
42
41
|
"devDependencies": {
|
|
43
42
|
"@biomejs/biome": "^1.9.4",
|
|
44
43
|
"@types/node": "^22.16.5",
|
|
45
|
-
"
|
|
46
|
-
"lint-staged": "^15.2.10",
|
|
44
|
+
"oasbox": "^0.1.0",
|
|
47
45
|
"postcss": "^8.5.16",
|
|
48
46
|
"typescript": "^5.9.3",
|
|
49
|
-
"vite": "^8.0.0"
|
|
47
|
+
"vite": "^8.0.0",
|
|
48
|
+
"husky": "^9.1.6",
|
|
49
|
+
"lint-staged": "^15.2.10"
|
|
50
50
|
},
|
|
51
51
|
"pnpm": {
|
|
52
|
-
"onlyBuiltDependencies": [
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
"onlyBuiltDependencies": [
|
|
53
|
+
"@biomejs/biome"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
55
56
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/* DiffViewer — CodeMirror 6 MergeView container. Portable. */
|
|
2
|
+
.oas-diff-viewer {
|
|
3
|
+
height: 480px;
|
|
4
|
+
overflow: hidden;
|
|
5
|
+
border: 1px solid var(--background-modifier-border);
|
|
6
|
+
border-radius: var(--radius-m);
|
|
7
|
+
font-family: var(--font-monospace);
|
|
8
|
+
font-size: var(--font-ui-small);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.oas-diff-viewer .cm-mergeView {
|
|
12
|
+
height: 100%;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.oas-diff-viewer .cm-editor {
|
|
16
|
+
height: 100%;
|
|
17
|
+
background: var(--background-primary);
|
|
18
|
+
color: var(--text-normal);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.oas-diff-viewer .cm-scroller {
|
|
22
|
+
overflow: auto;
|
|
23
|
+
font-family: var(--font-monospace);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.oas-diff-viewer .cm-mergeViewEditor {
|
|
27
|
+
border-right: 1px solid var(--background-modifier-border);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.oas-diff-viewer .cm-mergeViewEditor:last-child {
|
|
31
|
+
border-right: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.oas-diff-viewer .cm-deletedChunk {
|
|
35
|
+
background: color-mix(in srgb, var(--color-red) 15%, transparent);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.oas-diff-viewer .cm-insertedChunk,
|
|
39
|
+
.oas-diff-viewer .cm-changedLine {
|
|
40
|
+
background: color-mix(in srgb, var(--color-green) 12%, transparent);
|
|
41
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { html } from "@arrow-js/core";
|
|
2
|
+
import type { ArrowTemplate } from "@arrow-js/core";
|
|
3
|
+
import { markdown } from "@codemirror/lang-markdown";
|
|
4
|
+
import { MergeView } from "@codemirror/merge";
|
|
5
|
+
import { EditorState } from "@codemirror/state";
|
|
6
|
+
import "./DiffViewer.css";
|
|
7
|
+
|
|
8
|
+
export interface DiffViewerOptions {
|
|
9
|
+
original: string;
|
|
10
|
+
modified: string;
|
|
11
|
+
/** Which side shows original (a) and which shows modified (b). Default: a-b */
|
|
12
|
+
orientation?: "a-b" | "b-a";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* CodeMirror 6 MergeView — side-by-side diff using the same CM6 engine as
|
|
17
|
+
* Obsidian's editor. Obsidian's app.css styles .cm-* classes automatically,
|
|
18
|
+
* so this looks native without additional theming.
|
|
19
|
+
*
|
|
20
|
+
* Arrow.js 1.x only handles ArrowTemplate/component/array in expressions —
|
|
21
|
+
* raw Node insertion isn't supported. We render a placeholder via html`` and
|
|
22
|
+
* mount the CM6 MergeView into it after Arrow commits the DOM.
|
|
23
|
+
*
|
|
24
|
+
* requestAnimationFrame (not queueMicrotask) is required here: CSS flex layout
|
|
25
|
+
* is calculated by the rendering engine, not during microtask execution. CM6
|
|
26
|
+
* reads the container's offsetHeight at mount time — if flex hasn't painted yet
|
|
27
|
+
* it gets 0, and the editor renders at a fixed fallback height instead of
|
|
28
|
+
* filling its container.
|
|
29
|
+
*/
|
|
30
|
+
export function DiffViewer(options: DiffViewerOptions): ArrowTemplate {
|
|
31
|
+
// Unique attribute so we can locate the container after Arrow mounts it.
|
|
32
|
+
const key = Math.random().toString(36).slice(2, 10);
|
|
33
|
+
|
|
34
|
+
requestAnimationFrame(() => {
|
|
35
|
+
const container = document.querySelector(`[data-diff="${key}"]`);
|
|
36
|
+
if (!container) return;
|
|
37
|
+
container.removeAttribute("data-diff");
|
|
38
|
+
new MergeView({
|
|
39
|
+
a: {
|
|
40
|
+
doc: options.original,
|
|
41
|
+
extensions: [markdown(), EditorState.readOnly.of(true)],
|
|
42
|
+
},
|
|
43
|
+
b: {
|
|
44
|
+
doc: options.modified,
|
|
45
|
+
extensions: [markdown(), EditorState.readOnly.of(true)],
|
|
46
|
+
},
|
|
47
|
+
parent: container,
|
|
48
|
+
orientation: options.orientation ?? "a-b",
|
|
49
|
+
highlightChanges: true,
|
|
50
|
+
collapseUnchanged: { margin: 3, minSize: 4 },
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return html`<div class="oas-diff-viewer" data-diff="${key}"></div>`;
|
|
55
|
+
}
|