feat(templates): editor snippet insert + save-as-template (B11.10 surface #2)#85
Merged
Merged
Conversation
…face #2) Completes B11.10 — the editor-side templates surface (surface #1, the Database create-flow picker + object save-as-template, landed in #48). Every editor- bearing app inherits these once wired. Foundation (reusable keystones): - @brainstorm/editor `insertSnippet(editor, json)` — inserts a serialized-blocks snippet (the ClipboardPayload shape serializeBlocksAsJson emits) at the caret via the SAME paste path, so a snippet's transclusion/mention/object-link nodes carry their entityId verbatim (OQ-TPL-2 — a snippet is a reusable view of the graph, not a text macro). Replaces the empty slash paragraph so it lands in place. Returns false on a malformed/empty payload. - @brainstorm/sdk `blockSnippetToTemplateProperties`/`snippetFromTemplate`/ `TEMPLATE_SNIPPET_KEY` — a block-snippet stores its fragment as serialized- blocks JSON on `prototype.snippet` (per the user's storage decision: reuse the paste wire format, no headless @lexical/yjs binding). Object templates keep their Yjs-root body unchanged. Notes wiring (the 3 shared surfaces, mirroring Database): - `/template` slash command — queries block-snippet templates, opens the shared anchored-menu picker (caret-anchored; captures the point before the async query), inserts on select; quiet no-op when none exist. - "Save selection as template" block-selection action — serializeBlocksAsJson of the selected blocks → a new Template/v1{block-snippet}, name derived from the first block's text (truncated) or a default. - "Save as template" object-⋯ item — Note → object template via objectToTemplateProperties + copyEntityBody (Database's path). +53 tests (insertSnippet round-trip/fail-closed; snippet codec produce/read/ round-trip; templatesToSnippetOptions filter + deriveSnippetName). Workspace + apps/notes tsc + lint (incl. i18n + css-token checkers) clean. Real-shell dogfood of the picker + save round-trip is the remaining B11.10 gate (unit-unverifiable). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Completes B11.10 Templates — the editor-side surface. Surface #1 (Database create-flow picker + object save-as-template) landed in #48; this is surface #2, inherited by every editor-bearing app.
Foundation (reusable keystones)
@brainstorm/editorinsertSnippet(editor, json)— inserts a serialized-blocks snippet at the caret via the same paste path, so a snippet's transclusion / mention / object-link nodes carry theirentityIdverbatim (OQ-TPL-2: a snippet is a reusable view of the graph, not a text macro). Replaces the empty slash paragraph so it lands in place; fail-closed on malformed/empty.@brainstorm/sdkblockSnippetToTemplateProperties/snippetFromTemplate— a block-snippet stores its fragment as serialized-blocks JSON onprototype.snippet. Storage decision (per @razor): reuse the paste wire format — no headless@lexical/yjsbinding (the intricate alternative). Object templates keep their Yjs-root body unchanged.Notes wiring (the 3 shared surfaces, mirroring Database)
/templateslash command — queries block-snippet templates, opens the shared anchored-menu picker (caret-anchored; captures the point before the async query), inserts on select; quiet no-op when none exist.serializeBlocksAsJsonof the selected blocks → a newTemplate/v1{block-snippet}, name derived from the first block's text.objectToTemplateProperties+copyEntityBody(Database's path).Verified
+53 tests (insertSnippet round-trip/fail-closed; snippet codec produce/read/round-trip;
templatesToSnippetOptionsfilter +deriveSnippetName). Workspace + apps/notestsc+bun run lint(incl. the i18n + phantom-CSS-token checkers) clean; full suite 0 test-case failures (the 10 failed files are the known worktree Electron-collection artifact). Real-shell dogfood of the picker + save round-trip is the remaining B11.10 gate (unit-unverifiable).🤖 Generated with Claude Code