@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.
Files changed (45) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/components/AdminLayout.svelte +58 -23
  3. package/dist/components/EditPage.svelte +456 -124
  4. package/dist/components/EditPage.svelte.d.ts +4 -2
  5. package/dist/components/EditorToolbar.svelte +29 -53
  6. package/dist/components/EditorToolbar.svelte.d.ts +3 -11
  7. package/dist/components/MarkdownEditor.svelte +163 -24
  8. package/dist/components/MarkdownEditor.svelte.d.ts +3 -0
  9. package/dist/components/MarkdownHelpDialog.svelte +5 -0
  10. package/dist/components/ShortcutsDialog.svelte +37 -0
  11. package/dist/components/ShortcutsDialog.svelte.d.ts +13 -0
  12. package/dist/components/ShortcutsGrid.svelte +18 -0
  13. package/dist/components/ShortcutsGrid.svelte.d.ts +23 -0
  14. package/dist/components/cairn-admin.css +199 -99
  15. package/dist/components/editor-folding.d.ts +7 -0
  16. package/dist/components/editor-folding.js +331 -0
  17. package/dist/components/editor-highlight.js +55 -6
  18. package/dist/components/editor-shortcuts.d.ts +16 -0
  19. package/dist/components/editor-shortcuts.js +36 -0
  20. package/dist/components/fonts/{Figtree-OFL.txt → IBMPlexSans-OFL.txt} +2 -2
  21. package/dist/components/fonts/ibm-plex-sans.woff2 +0 -0
  22. package/dist/components/markdown-directives.d.ts +17 -0
  23. package/dist/components/markdown-directives.js +41 -0
  24. package/dist/components/topbar-context.d.ts +13 -0
  25. package/dist/components/topbar-context.js +17 -0
  26. package/dist/sveltekit/static-admin-page.js +2 -2
  27. package/package.json +1 -1
  28. package/src/lib/components/AdminLayout.svelte +58 -23
  29. package/src/lib/components/EditPage.svelte +456 -124
  30. package/src/lib/components/EditorToolbar.svelte +29 -53
  31. package/src/lib/components/MarkdownEditor.svelte +163 -24
  32. package/src/lib/components/MarkdownHelpDialog.svelte +5 -0
  33. package/src/lib/components/ShortcutsDialog.svelte +37 -0
  34. package/src/lib/components/ShortcutsGrid.svelte +18 -0
  35. package/src/lib/components/cairn-admin.css +51 -14
  36. package/src/lib/components/editor-folding.ts +356 -0
  37. package/src/lib/components/editor-highlight.ts +54 -4
  38. package/src/lib/components/editor-shortcuts.ts +42 -0
  39. package/src/lib/components/fonts/{Figtree-OFL.txt → IBMPlexSans-OFL.txt} +2 -2
  40. package/src/lib/components/fonts/ibm-plex-sans.woff2 +0 -0
  41. package/src/lib/components/markdown-directives.ts +42 -0
  42. package/src/lib/components/topbar-context.ts +30 -0
  43. package/src/lib/sveltekit/static-admin-page.ts +2 -2
  44. package/dist/components/fonts/figtree.woff2 +0 -0
  45. package/src/lib/components/fonts/figtree.woff2 +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,52 @@
2
2
 
3
3
  All notable changes to this project are recorded here, most recent first.
4
4
 
5
+ ## 0.54.0
6
+
7
+ The editor takes the shell. On an edit route the page is now one context, the desk: the edit page's
8
+ sticky header dissolves into the single topbar (one band in three clusters, the way back and the
9
+ status and the lifecycle actions), the nav drawer opens closed and the breadcrumb is the way out,
10
+ the frontmatter fields move behind a right slide-over panel, and a zen toggle (and `Ctrl+Shift+.`)
11
+ fades the remaining chrome to leave the manuscript alone, with a floating chip carrying the save
12
+ state and the way out. List and settings pages keep the office chrome unchanged.
13
+
14
+ The editor ergonomics round out alongside it: the directive rail pitch widens to 8px and the
15
+ caret-active rail reads by strength alone (no width step), wrapped quote and list lines hang under
16
+ their content, directive containers fold from the rail band (a chevron on the opener row, a folded
17
+ row with an `N lines` pill, the safety invariant that an edit or selection never hides text), the
18
+ format keymap completes (inline code, quote, both lists, the heading pair) and the page-level
19
+ actions get keys, a `Ctrl+/` sheet lists every shortcut, and `####` gains a real heading size step.
20
+ The everyday formats (inline code, strikethrough, table) promote onto the strip, and the footer
21
+ controls dress as what they are: a segmented posture control, check-and-tint mode toggles, and a
22
+ plain Markdown-help link. The whole admin picks up the same grade of polish, including a scoped
23
+ reset so every bare admin button sheds its native chrome.
24
+
25
+ Consumers may: nothing is required, the new chrome and the editor behaviors apply in place. A site
26
+ that embeds `MarkdownEditor` directly gets the rail, hang, fold, and keymap changes automatically;
27
+ the editor's public props are unchanged.
28
+
29
+ ## 0.53.0
30
+
31
+ An iterative design session on the editor-as-home direction, shipped as one window.
32
+
33
+ The admin's UI face is now IBM Plex Sans (self-hosted, SIL OFL), replacing Figtree: the editor
34
+ writes in iA Writer Mono, which descends from IBM Plex Mono, so the chrome and the manuscript
35
+ share one type skeleton. The brand display face (Bricolage Grotesque) is unchanged.
36
+
37
+ The editor gains two surface postures, persisted and toggled from the card footer: Prose (the
38
+ default) is the writing instrument, a 72ch centered measure at a larger type step; Markup is the
39
+ working surface, a wide dense fill for tables, attributed directives, and long URLs. The footer
40
+ is now the writing-environment strip (word count, postures, focus mode, typewriter, help), the
41
+ insert actions joined the toolbar as icons, and the document title sits on the manuscript's left
42
+ edge. Focus mode now also eases the directive rails and the title back with the dimmed field.
43
+
44
+ The chrome cedes the stage: a narrower nav sidebar and details column, a wider gutter around the
45
+ editor, a quieter details card, rebalanced surface margins, and the topbar pinned to the brand
46
+ band's height so the header hairline meets across the seam.
47
+
48
+ Consumers may: pass the new optional `surface` prop ('prose' | 'markup') when embedding
49
+ `MarkdownEditor` directly. No action required; the release is additive.
50
+
5
51
  ## 0.52.1
6
52
 
7
53
  Two field reports from the first 0.52.0 session, both in-editor polish with no consumer action.
@@ -11,6 +11,7 @@ identical on every host regardless of the site's own theme.
11
11
  import type { LayoutData } from '../sveltekit/content-routes.js';
12
12
  import CsrfField from './CsrfField.svelte';
13
13
  import { CSRF_CONTEXT_KEY } from './csrf-context.js';
14
+ import { provideTopbar, type TopbarHolder } from './topbar-context.js';
14
15
  import { MenuIcon, LogOutIcon, SunIcon, MoonIcon, ChevronRightIcon, SearchIcon } from './admin-icons.js';
15
16
  import CairnLogo from './CairnLogo.svelte';
16
17
  import { cairnFaviconHref } from './cairn-favicon.js';
@@ -225,6 +226,16 @@ identical on every host regardless of the site's own theme.
225
226
 
226
227
  // The browser-tab title: the deepest breadcrumb (the active concept or entry), then the brand.
227
228
  const pageTitle = $derived(crumbs.length ? crumbs[crumbs.length - 1].label : 'Admin');
229
+
230
+ // A desk route is an open document (/admin/<concept>/<id>): the third path segment is the entry.
231
+ // The band has one job there, so the topbar drops the palette trigger and the site-wide Publish
232
+ // button and renders the document's own desk controls instead.
233
+ const isDeskRoute = $derived(data.pathname.split('/').filter(Boolean).length > 2);
234
+
235
+ // The topbar context portal: a reactive holder a descendant document fills with its desk snippet.
236
+ // EditPage registers on mount and nulls it on teardown; the office routes leave it null.
237
+ let topbar = $state<TopbarHolder>({ desk: null, zen: false });
238
+ provideTopbar(topbar);
228
239
  </script>
229
240
 
230
241
  <svelte:head>
@@ -239,14 +250,30 @@ identical on every host regardless of the site's own theme.
239
250
  itself never matches. Keeping the drawer and its base/utility classes one level in lets the
240
251
  scoped sheet style them. -->
241
252
  <div data-theme={theme} bind:this={rootEl}>
242
- <div class="drawer lg:drawer-open min-h-screen bg-base-200 text-base-content">
253
+ <!-- The persistent desktop sidebar (lg:drawer-open) recedes inside an open document: a desk route
254
+ renders the drawer shell without it, so the nav starts closed at desktop width and the
255
+ manuscript takes the shell. This resolves at SSR from data.pathname (isDeskRoute), never in an
256
+ effect, so the chrome-free state does not flash. The checkbox still governs the overlay, so the
257
+ toggle (and Cmd/Ctrl+B) reopens the nav over the document on demand. -->
258
+ <div class="drawer min-h-screen bg-base-200 text-base-content" class:lg:drawer-open={!isDeskRoute}>
243
259
  <input id="cairn-drawer" type="checkbox" class="drawer-toggle" bind:checked={drawerOpen} />
244
260
 
245
261
  <div class="drawer-content flex flex-col">
262
+ <!-- Zen (rung 4) drops the whole topbar element, not just its contents: a desk document
263
+ registers zen through the topbar holder and the band slides away entirely. The desk's
264
+ three clusters include AdminLayout-owned chrome (the drawer toggle, the breadcrumb), so
265
+ emptying the band would leave that chrome behind; the band must be GONE. The manuscript
266
+ and EditPage's own floating zen chip carry on below. -->
267
+ {#if !topbar.zen}
246
268
  <!-- The topbar is a flat, opaque continuation of the sidebar's brand band: same surface and the
247
- same hairline, no shadow, so the two form one clean header strip across the sidebar seam. -->
248
- <div class="navbar bg-base-100 border-b border-[var(--cairn-card-border)] sticky top-0 z-30 gap-2 px-4 lg:px-8">
249
- <div class="flex-none lg:hidden">
269
+ same hairline, no shadow, so the two form one clean header strip across the sidebar seam.
270
+ The height is pinned to the brand band's h-16 (a content-driven navbar drifts with font
271
+ metrics, and the two border-bottoms stop meeting at the seam). -->
272
+ <div class="navbar bg-base-100 border-b border-[var(--cairn-card-border)] sticky top-0 z-30 h-16 min-h-16 gap-2 px-4 py-0 lg:px-8">
273
+ <!-- The drawer toggle is hidden at desktop width on the office routes (the persistent sidebar
274
+ stands in for it); on a desk route the sidebar is closed, so the toggle stays visible and
275
+ reopens the nav as an overlay. -->
276
+ <div class="flex-none" class:lg:hidden={!isDeskRoute}>
250
277
  <label for="cairn-drawer" aria-label="Open menu" class="btn btn-square btn-ghost">
251
278
  <MenuIcon class="h-5 w-5" />
252
279
  </label>
@@ -266,25 +293,32 @@ identical on every host regardless of the site's own theme.
266
293
  <span class="font-semibold tracking-tight">{data.siteName}</span>
267
294
  {/if}
268
295
  </div>
269
- <!-- The command-palette trigger fills the center: a quick jump-to over the admin, opened here
270
- or with Cmd/Ctrl+K. -->
271
- <div class="flex min-w-0 flex-1 justify-center">
272
- <button
273
- type="button"
274
- onclick={openPalette}
275
- class="flex w-full max-w-md items-center gap-2 rounded-field border border-[var(--cairn-card-border)] bg-base-200/70 px-3 py-1.5 text-sm text-[var(--color-muted)] transition-colors hover:bg-base-200 hover:text-base-content"
276
- >
277
- <SearchIcon class="h-4 w-4 shrink-0" aria-hidden="true" />
278
- <span class="truncate">Search or jump to&hellip;</span>
279
- <kbd class="ml-auto hidden rounded border border-[var(--cairn-card-border)] px-1.5 text-[0.6875rem] font-medium sm:inline">&#8984;K</kbd>
280
- </button>
281
- </div>
282
- {#if pendingCount > 0}
283
- <div class="flex-none">
284
- <button type="button" class="btn btn-primary btn-sm" aria-haspopup="dialog" onclick={() => publishAllDialog?.showModal()}>
285
- Publish site ({pendingCount})
296
+ {#if isDeskRoute}
297
+ <!-- An open document takes the band: the registered desk snippet (the status and action
298
+ clusters) fills the row to the right of the breadcrumb. The palette trigger and the
299
+ site-wide Publish button stand down so the band has one job here. -->
300
+ {@render topbar.desk?.()}
301
+ {:else}
302
+ <!-- The command-palette trigger fills the center: a quick jump-to over the admin, opened
303
+ here or with Cmd/Ctrl+K. -->
304
+ <div class="flex min-w-0 flex-1 justify-center">
305
+ <button
306
+ type="button"
307
+ onclick={openPalette}
308
+ class="flex w-full max-w-md items-center gap-2 rounded-field border border-[var(--cairn-card-border)] bg-base-200/70 px-3 py-1.5 text-sm text-[var(--color-muted)] transition-colors hover:bg-base-200 hover:text-base-content"
309
+ >
310
+ <SearchIcon class="h-4 w-4 shrink-0" aria-hidden="true" />
311
+ <span class="truncate">Search or jump to&hellip;</span>
312
+ <kbd class="ml-auto hidden rounded border border-[var(--cairn-card-border)] px-1.5 text-[0.6875rem] font-medium sm:inline">&#8984;K</kbd>
286
313
  </button>
287
314
  </div>
315
+ {#if pendingCount > 0}
316
+ <div class="flex-none">
317
+ <button type="button" class="btn btn-primary btn-sm" aria-haspopup="dialog" onclick={() => publishAllDialog?.showModal()}>
318
+ Publish site ({pendingCount})
319
+ </button>
320
+ </div>
321
+ {/if}
288
322
  {/if}
289
323
  <div class="flex-none">
290
324
  <button type="button" class="btn btn-square btn-ghost" aria-label="Toggle theme" onclick={toggleTheme}>
@@ -292,8 +326,9 @@ identical on every host regardless of the site's own theme.
292
326
  </button>
293
327
  </div>
294
328
  </div>
329
+ {/if}
295
330
 
296
- <main class="flex-1 p-4 lg:p-8">
331
+ <main class="flex-1 p-4 lg:px-10 lg:py-8">
297
332
  {@render children()}
298
333
  </main>
299
334
 
@@ -380,7 +415,7 @@ identical on every host regardless of the site's own theme.
380
415
 
381
416
  <div class="drawer-side">
382
417
  <label for="cairn-drawer" aria-label="Close menu" class="drawer-overlay"></label>
383
- <nav class="bg-base-100 flex min-h-full w-64 flex-col border-r border-[var(--cairn-card-border)]" aria-label="Site content">
418
+ <nav class="bg-base-100 flex min-h-full w-56 flex-col border-r border-[var(--cairn-card-border)]" aria-label="Site content">
384
419
  <!-- Brand band, the same height as the topbar. The mark sits in a filled "app-icon" tile, which
385
420
  anchors the corner as a deliberate brand object rather than a washed box. The logo and
386
421
  wordmark link to the admin home. -->