@glw907/cairn-cms 0.52.1 → 0.54.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/CHANGELOG.md +46 -0
- package/dist/components/AdminLayout.svelte +58 -23
- package/dist/components/EditPage.svelte +456 -124
- package/dist/components/EditPage.svelte.d.ts +4 -2
- package/dist/components/EditorToolbar.svelte +29 -53
- package/dist/components/EditorToolbar.svelte.d.ts +3 -11
- package/dist/components/MarkdownEditor.svelte +163 -24
- package/dist/components/MarkdownEditor.svelte.d.ts +3 -0
- package/dist/components/MarkdownHelpDialog.svelte +5 -0
- package/dist/components/ShortcutsDialog.svelte +37 -0
- package/dist/components/ShortcutsDialog.svelte.d.ts +13 -0
- package/dist/components/ShortcutsGrid.svelte +18 -0
- package/dist/components/ShortcutsGrid.svelte.d.ts +23 -0
- package/dist/components/cairn-admin.css +199 -99
- package/dist/components/editor-folding.d.ts +7 -0
- package/dist/components/editor-folding.js +331 -0
- package/dist/components/editor-highlight.js +55 -6
- package/dist/components/editor-shortcuts.d.ts +16 -0
- package/dist/components/editor-shortcuts.js +36 -0
- package/dist/components/fonts/{Figtree-OFL.txt → IBMPlexSans-OFL.txt} +2 -2
- package/dist/components/fonts/ibm-plex-sans.woff2 +0 -0
- package/dist/components/markdown-directives.d.ts +17 -0
- package/dist/components/markdown-directives.js +41 -0
- package/dist/components/topbar-context.d.ts +13 -0
- package/dist/components/topbar-context.js +17 -0
- package/dist/sveltekit/static-admin-page.js +2 -2
- package/package.json +1 -1
- package/src/lib/components/AdminLayout.svelte +58 -23
- package/src/lib/components/EditPage.svelte +456 -124
- package/src/lib/components/EditorToolbar.svelte +29 -53
- package/src/lib/components/MarkdownEditor.svelte +163 -24
- package/src/lib/components/MarkdownHelpDialog.svelte +5 -0
- package/src/lib/components/ShortcutsDialog.svelte +37 -0
- package/src/lib/components/ShortcutsGrid.svelte +18 -0
- package/src/lib/components/cairn-admin.css +51 -14
- package/src/lib/components/editor-folding.ts +356 -0
- package/src/lib/components/editor-highlight.ts +54 -4
- package/src/lib/components/editor-shortcuts.ts +42 -0
- package/src/lib/components/fonts/{Figtree-OFL.txt → IBMPlexSans-OFL.txt} +2 -2
- package/src/lib/components/fonts/ibm-plex-sans.woff2 +0 -0
- package/src/lib/components/markdown-directives.ts +42 -0
- package/src/lib/components/topbar-context.ts +30 -0
- package/src/lib/sveltekit/static-admin-page.ts +2 -2
- package/dist/components/fonts/figtree.woff2 +0 -0
- package/src/lib/components/fonts/figtree.woff2 +0 -0
|
@@ -124,6 +124,32 @@ export function caretContainerRange(scan: FenceScan, caretLine: number): Contain
|
|
|
124
124
|
return { fromLine, toLine, depth };
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Every paired directive container in the document, as inclusive line ranges. Walks the scan's
|
|
129
|
+
* roles with a stack: an opener pushes its line, a closer pops the nearest open one and emits the
|
|
130
|
+
* pair at the opener's depth. The ranges come back in close order, so an inner container precedes
|
|
131
|
+
* the outer that holds it, which is exactly the order a fold consumer wants (folding the innermost
|
|
132
|
+
* first). An unbalanced opener is left on the stack and never emitted (a half-typed fence earns no
|
|
133
|
+
* fold range, the safety invariant), and a stray closer with nothing open is dropped. The scan
|
|
134
|
+
* already disowns a fence-shaped line inside a code block (its role is null), so a documented
|
|
135
|
+
* example can neither open nor close a range. This is the sole source of fold ranges.
|
|
136
|
+
*/
|
|
137
|
+
export function containerRanges(scan: FenceScan): ContainerRange[] {
|
|
138
|
+
const { depths, roles } = scan;
|
|
139
|
+
const out: ContainerRange[] = [];
|
|
140
|
+
const stack: number[] = [];
|
|
141
|
+
for (let i = 0; i < roles.length; i++) {
|
|
142
|
+
if (roles[i] === 'opener') {
|
|
143
|
+
stack.push(i);
|
|
144
|
+
} else if (roles[i] === 'closer') {
|
|
145
|
+
const fromLine = stack.pop();
|
|
146
|
+
if (fromLine === undefined) continue;
|
|
147
|
+
out.push({ fromLine, toLine: i, depth: depths[fromLine] ?? 1 });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
|
|
127
153
|
/** One span of a fence line, in line-local offsets: machinery (`mark`) or meaning (`label`). */
|
|
128
154
|
export interface FenceToken {
|
|
129
155
|
from: number;
|
|
@@ -163,6 +189,22 @@ export function fenceTokens(line: string): FenceToken[] {
|
|
|
163
189
|
return out;
|
|
164
190
|
}
|
|
165
191
|
|
|
192
|
+
// The marker prefix of a quote or list line: leading indentation, the marker itself, and the one
|
|
193
|
+
// space after it. A task checkbox (`[ ]`/`[x]`) extends a bullet's marker. Ordered markers vary in
|
|
194
|
+
// width (a two-digit number is wider than a bullet), so the width is read from the match, never
|
|
195
|
+
// assumed. The anchored alternatives mirror the markers the highlight pass styles.
|
|
196
|
+
const MARKER = /^(\s*)(?:[-*+](?: \[[ xX]\])?|\d+[.)]|>) /;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* The marker prefix of a line (indentation plus marker plus its trailing space), or null when the
|
|
200
|
+
* line carries no quote or list marker. The hanging-indent decoration uses the prefix length, in
|
|
201
|
+
* fixed-pitch chars, to wrap continuation lines under the content rather than under the marker.
|
|
202
|
+
*/
|
|
203
|
+
export function markerPrefix(line: string): string | null {
|
|
204
|
+
const m = MARKER.exec(line);
|
|
205
|
+
return m ? m[0] : null;
|
|
206
|
+
}
|
|
207
|
+
|
|
166
208
|
/** Inline directive ranges (`:name[...]{...}`) within a line of text. */
|
|
167
209
|
export function findInlineDirectives(text: string): { from: number; to: number }[] {
|
|
168
210
|
const out: { from: number; to: number }[] = [];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getContext, setContext, type Snippet } from 'svelte';
|
|
2
|
+
|
|
3
|
+
// The topbar context portal. On an edit route the document owns the band's live state (status,
|
|
4
|
+
// save-state, the lifecycle actions), so the desk's controls have to render up in AdminLayout's
|
|
5
|
+
// one topbar rather than in a second header of their own. AdminLayout owns a holder and provides
|
|
6
|
+
// it; EditPage, a descendant through the children snippet, registers its desk snippet into the
|
|
7
|
+
// holder and clears it on teardown. CairnAdmin's view switch unmounts EditPage, which nulls the
|
|
8
|
+
// holder, so the band reverts to the office layout with no route plumbing.
|
|
9
|
+
|
|
10
|
+
const TOPBAR_CONTEXT_KEY = Symbol('cairn-topbar');
|
|
11
|
+
|
|
12
|
+
/** The shared holder: the desk snippet a document registers, or null on the office routes. */
|
|
13
|
+
export interface TopbarHolder {
|
|
14
|
+
desk: Snippet | null;
|
|
15
|
+
/** True while the document is in zen: AdminLayout drops the whole topbar element so the band
|
|
16
|
+
* slides away (the desk's three clusters include AdminLayout-owned chrome, the drawer toggle and
|
|
17
|
+
* breadcrumb, that must vanish with it). EditPage sets this; the office routes leave it false. */
|
|
18
|
+
zen: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Called by AdminLayout once: creates the holder, provides it on context, returns it to render. */
|
|
22
|
+
export function provideTopbar(holder: TopbarHolder): TopbarHolder {
|
|
23
|
+
setContext(TOPBAR_CONTEXT_KEY, holder);
|
|
24
|
+
return holder;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Called by a descendant document (EditPage) to reach the holder it registers its desk into. */
|
|
28
|
+
export function useTopbar(): TopbarHolder | undefined {
|
|
29
|
+
return getContext<TopbarHolder | undefined>(TOPBAR_CONTEXT_KEY);
|
|
30
|
+
}
|
|
@@ -32,7 +32,7 @@ const SHARED_STYLE = `:root {
|
|
|
32
32
|
--shadow: 0 1px 2px oklch(28% 0.02 75 / 0.05), 0 18px 40px -12px oklch(28% 0.02 75 / 0.16);
|
|
33
33
|
--radius-box: 1rem;
|
|
34
34
|
--radius-field: 0.625rem;
|
|
35
|
-
--font: '
|
|
35
|
+
--font: 'IBM Plex Sans Variable', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
36
36
|
}
|
|
37
37
|
@media (prefers-color-scheme: dark) {
|
|
38
38
|
:root {
|
|
@@ -107,7 +107,7 @@ main {
|
|
|
107
107
|
h1 {
|
|
108
108
|
margin: 0 0 0.75rem;
|
|
109
109
|
font-size: 1.6rem;
|
|
110
|
-
font-weight:
|
|
110
|
+
font-weight: 700;
|
|
111
111
|
letter-spacing: -0.02em;
|
|
112
112
|
line-height: 1.15;
|
|
113
113
|
}
|
|
Binary file
|
|
Binary file
|