livemark 0.24.1 → 0.26.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/README.md +3 -2
- package/build/actions/config/define.d.ts +6 -0
- package/build/actions/config/define.unit.js +8 -1
- package/build/actions/escape/copy.d.ts +11 -0
- package/build/actions/escape/copy.js +29 -0
- package/build/actions/escape/copy.unit.d.ts +1 -0
- package/build/actions/escape/copy.unit.js +37 -0
- package/build/actions/escape/list.d.ts +12 -0
- package/build/actions/escape/list.js +27 -0
- package/build/actions/escape/list.unit.d.ts +1 -0
- package/build/actions/escape/list.unit.js +36 -0
- package/build/actions/target/build.d.ts +9 -26
- package/build/actions/target/build.js +50 -71
- package/build/actions/target/build.unit.d.ts +1 -0
- package/build/actions/target/build.unit.js +76 -0
- package/build/actions/target/clear.d.ts +4 -0
- package/build/actions/target/clear.js +14 -0
- package/build/actions/target/clear.unit.d.ts +1 -0
- package/build/actions/target/clear.unit.js +23 -0
- package/build/commands/build.js +1 -2
- package/build/commands/clear.d.ts +5 -0
- package/build/commands/clear.js +15 -0
- package/build/commands/escape.d.ts +4 -3
- package/build/commands/escape.js +45 -48
- package/build/commands/preview.js +1 -2
- package/build/commands/start.js +1 -2
- package/build/components/Abbr.d.ts +1 -1
- package/build/components/Abbr.js +2 -4
- package/build/components/AnsiCode.d.ts +1 -1
- package/build/components/AnsiCode.js +2 -2
- package/build/components/Article.d.ts +2 -1
- package/build/components/Article.js +7 -14
- package/build/components/BackToTop.d.ts +1 -1
- package/build/components/Banner.d.ts +2 -2
- package/build/components/Banner.js +7 -3
- package/build/components/BlogIndex.d.ts +1 -1
- package/build/components/BlogIndex.js +2 -11
- package/build/components/Breadcrumbs.d.ts +1 -1
- package/build/components/Breadcrumbs.js +2 -3
- package/build/components/Callout.d.ts +1 -1
- package/build/components/Callout.js +5 -9
- package/build/components/Card.d.ts +1 -1
- package/build/components/Card.js +2 -3
- package/build/components/Cards.d.ts +1 -1
- package/build/components/ChangelogIndex.d.ts +1 -1
- package/build/components/ChangelogIndex.js +2 -11
- package/build/components/ChoiceList.d.ts +15 -0
- package/build/components/ChoiceList.js +13 -0
- package/build/components/CodeBlock.d.ts +1 -1
- package/build/components/CodeBlock.js +3 -16
- package/build/components/CodeTabs.d.ts +1 -1
- package/build/components/CodeTabs.js +2 -3
- package/build/components/Column.d.ts +1 -1
- package/build/components/Columns.d.ts +1 -1
- package/build/components/Content.d.ts +1 -1
- package/build/components/ContentTab.d.ts +1 -1
- package/build/components/ContentTabs.d.ts +1 -1
- package/build/components/ContentTabs.js +2 -3
- package/build/components/DefaultCatchBoundary.d.ts +1 -1
- package/build/components/DefaultCatchBoundary.js +5 -7
- package/build/components/DefinitionList.d.ts +3 -3
- package/build/components/Details.d.ts +1 -1
- package/build/components/Details.js +2 -5
- package/build/components/FileTree.d.ts +1 -1
- package/build/components/FileTree.js +3 -5
- package/build/components/Footer.d.ts +1 -1
- package/build/components/Footer.js +2 -5
- package/build/components/FootnoteRef.d.ts +1 -1
- package/build/components/FootnoteRef.js +2 -4
- package/build/components/Header.d.ts +6 -0
- package/build/components/Header.js +26 -0
- package/build/components/HeaderMenu.d.ts +2 -0
- package/build/components/HeaderMenu.js +27 -0
- package/build/components/HeaderNav.d.ts +6 -0
- package/build/components/HeaderNav.js +74 -0
- package/build/components/HeaderSearch.d.ts +4 -0
- package/build/components/HeaderSearch.js +33 -0
- package/build/components/Heading.d.ts +6 -6
- package/build/components/InlineBadge.d.ts +2 -2
- package/build/components/InlineBadge.js +1 -1
- package/build/components/InlineIcon.d.ts +1 -1
- package/build/components/InlineToc.d.ts +1 -1
- package/build/components/InlineToc.js +2 -4
- package/build/components/Layout.d.ts +2 -1
- package/build/components/Layout.js +5 -58
- package/build/components/LinkButton.d.ts +2 -2
- package/build/components/LinkButton.js +1 -1
- package/build/components/MenuSheet.d.ts +22 -0
- package/build/components/MenuSheet.js +27 -0
- package/build/components/Mermaid.d.ts +1 -1
- package/build/components/MermaidRenderer.d.ts +1 -1
- package/build/components/MermaidRenderer.js +20 -8
- package/build/components/NotFound.d.ts +1 -1
- package/build/components/NotFound.js +3 -6
- package/build/components/PackageTabs.d.ts +1 -1
- package/build/components/PackageTabs.js +3 -7
- package/build/components/PageToolbar.d.ts +1 -1
- package/build/components/PageToolbar.js +2 -10
- package/build/components/PrevNext.d.ts +1 -1
- package/build/components/PrevNext.js +2 -10
- package/build/components/Root.d.ts +4 -0
- package/build/components/Root.js +8 -0
- package/build/components/Search.d.ts +5 -2
- package/build/components/Search.js +11 -9
- package/build/components/SearchDialog.d.ts +1 -1
- package/build/components/SearchDialog.js +10 -133
- package/build/components/Section.d.ts +1 -1
- package/build/components/SectionHeader.d.ts +1 -1
- package/build/components/SheetPanel.d.ts +12 -0
- package/build/components/SheetPanel.js +19 -0
- package/build/components/Sidebar.d.ts +1 -1
- package/build/components/Sidebar.js +12 -14
- package/build/components/SidebarArticles.d.ts +4 -1
- package/build/components/SidebarArticles.js +5 -9
- package/build/components/SidebarLinks.d.ts +4 -1
- package/build/components/SidebarLinks.js +6 -9
- package/build/components/SidebarPosts.d.ts +4 -1
- package/build/components/SidebarPosts.js +7 -23
- package/build/components/SidebarReleases.d.ts +4 -1
- package/build/components/SidebarReleases.js +5 -15
- package/build/components/SidebarSectionPicker.d.ts +8 -0
- package/build/components/SidebarSectionPicker.js +31 -0
- package/build/components/SidebarSections.d.ts +1 -1
- package/build/components/SidebarSections.js +5 -9
- package/build/components/SiteLink.d.ts +1 -1
- package/build/components/SiteTitle.d.ts +1 -1
- package/build/components/SiteTitle.js +2 -6
- package/build/components/SortableTable.d.ts +1 -1
- package/build/components/SoundCloud.d.ts +1 -1
- package/build/components/SoundCloud.js +2 -2
- package/build/components/TagIndex.d.ts +1 -1
- package/build/components/TagIndex.js +2 -11
- package/build/components/Theme.d.ts +2 -1
- package/build/components/Theme.js +35 -15
- package/build/components/Toc.d.ts +5 -4
- package/build/components/Toc.js +35 -35
- package/build/components/YouTube.d.ts +1 -1
- package/build/components/YouTube.js +2 -2
- package/build/components/ZoomImage.d.ts +1 -1
- package/build/content-collections.js +5 -1
- package/build/elements/accordion.d.ts +4 -4
- package/build/elements/accordion.js +2 -3
- package/build/elements/alert-dialog.d.ts +12 -12
- package/build/elements/alert-dialog.js +2 -4
- package/build/elements/alert.d.ts +4 -4
- package/build/elements/alert.js +2 -2
- package/build/elements/aspect-ratio.d.ts +1 -1
- package/build/elements/avatar.d.ts +6 -6
- package/build/elements/badge.d.ts +1 -1
- package/build/elements/badge.js +3 -1
- package/build/elements/breadcrumb.d.ts +6 -6
- package/build/elements/breadcrumb.js +2 -4
- package/build/elements/button-group.d.ts +2 -2
- package/build/elements/button-group.js +5 -5
- package/build/elements/button.d.ts +2 -2
- package/build/elements/button.js +9 -7
- package/build/elements/calendar.d.ts +2 -2
- package/build/elements/calendar.js +2 -2
- package/build/elements/card.d.ts +7 -7
- package/build/elements/card.js +4 -4
- package/build/elements/carousel.d.ts +5 -5
- package/build/elements/carousel.js +3 -7
- package/build/elements/chart.d.ts +6 -6
- package/build/elements/chart.js +5 -11
- package/build/elements/checkbox.d.ts +1 -1
- package/build/elements/collapsible.d.ts +3 -3
- package/build/elements/command.d.ts +9 -9
- package/build/elements/command.js +5 -11
- package/build/elements/context-menu.d.ts +15 -15
- package/build/elements/context-menu.js +6 -9
- package/build/elements/dialog.d.ts +10 -10
- package/build/elements/dialog.js +2 -6
- package/build/elements/drawer.d.ts +14 -12
- package/build/elements/drawer.js +14 -15
- package/build/elements/dropdown-menu.d.ts +15 -15
- package/build/elements/dropdown-menu.js +7 -10
- package/build/elements/empty.d.ts +6 -6
- package/build/elements/empty.js +2 -2
- package/build/elements/field.d.ts +10 -10
- package/build/elements/field.js +3 -4
- package/build/elements/hover-card.d.ts +3 -3
- package/build/elements/hover-card.js +2 -2
- package/build/elements/input-group.d.ts +7 -7
- package/build/elements/input-group.js +5 -5
- package/build/elements/input-otp.d.ts +4 -4
- package/build/elements/input.d.ts +1 -1
- package/build/elements/input.js +2 -2
- package/build/elements/item.d.ts +9 -9
- package/build/elements/item.js +2 -2
- package/build/elements/kbd.d.ts +2 -2
- package/build/elements/label.d.ts +1 -1
- package/build/elements/menubar.d.ts +16 -16
- package/build/elements/menubar.js +9 -11
- package/build/elements/native-select.d.ts +3 -3
- package/build/elements/native-select.js +2 -4
- package/build/elements/navigation-menu.d.ts +8 -8
- package/build/elements/navigation-menu.js +3 -5
- package/build/elements/pagination.d.ts +7 -7
- package/build/elements/pagination.js +4 -10
- package/build/elements/popover.d.ts +6 -6
- package/build/elements/popover.js +2 -2
- package/build/elements/progress.d.ts +5 -5
- package/build/elements/progress.js +2 -3
- package/build/elements/radio-group.d.ts +2 -2
- package/build/elements/resizable.d.ts +3 -3
- package/build/elements/scroll-area.d.ts +2 -2
- package/build/elements/scroll-area.js +2 -4
- package/build/elements/select.d.ts +9 -9
- package/build/elements/select.js +4 -9
- package/build/elements/separator.d.ts +1 -1
- package/build/elements/sheet.d.ts +8 -8
- package/build/elements/sheet.js +2 -6
- package/build/elements/sidebar.d.ts +19 -19
- package/build/elements/sidebar.js +15 -37
- package/build/elements/skeleton.d.ts +1 -1
- package/build/elements/slider.d.ts +2 -1
- package/build/elements/slider.js +2 -3
- package/build/elements/sonner.d.ts +1 -1
- package/build/elements/spinner.d.ts +1 -1
- package/build/elements/switch.d.ts +1 -1
- package/build/elements/table.d.ts +8 -8
- package/build/elements/tabs.d.ts +4 -4
- package/build/elements/tabs.js +3 -3
- package/build/elements/textarea.d.ts +1 -1
- package/build/elements/textarea.js +2 -2
- package/build/elements/toggle-group.d.ts +3 -2
- package/build/elements/toggle-group.js +3 -3
- package/build/elements/toggle.d.ts +1 -1
- package/build/elements/toggle.js +2 -2
- package/build/elements/tooltip.d.ts +4 -4
- package/build/elements/tooltip.js +2 -3
- package/build/head.d.ts +4 -0
- package/build/head.js +6 -0
- package/build/helpers/article-search.d.ts +19 -0
- package/build/helpers/article-search.js +134 -0
- package/build/helpers/dependency-dir.d.ts +5 -0
- package/build/helpers/dependency-dir.js +20 -0
- package/build/helpers/dependency-dir.unit.d.ts +1 -0
- package/build/helpers/dependency-dir.unit.js +25 -0
- package/build/helpers/dynamic-icon-resolver.d.ts +1 -1
- package/build/helpers/dynamic-icon.d.ts +1 -1
- package/build/helpers/head.d.ts +53 -0
- package/build/helpers/head.js +69 -0
- package/build/helpers/head.unit.d.ts +1 -0
- package/build/helpers/head.unit.js +108 -0
- package/build/helpers/nav-items.d.ts +11 -0
- package/build/helpers/nav-items.js +65 -0
- package/build/helpers/render-inline-markdown.d.ts +1 -0
- package/build/helpers/render-inline-markdown.js +34 -0
- package/build/helpers/render-inline-markdown.unit.d.ts +1 -0
- package/build/helpers/render-inline-markdown.unit.js +20 -0
- package/build/helpers/search-highlight.d.ts +8 -0
- package/build/helpers/search-highlight.js +59 -0
- package/build/helpers/search-highlight.unit.d.ts +1 -0
- package/build/helpers/search-highlight.unit.js +36 -0
- package/build/helpers/target-export.d.ts +9 -0
- package/build/helpers/target-export.js +24 -0
- package/build/helpers/target-export.unit.d.ts +1 -0
- package/build/helpers/target-export.unit.js +25 -0
- package/build/helpers/theme.d.ts +6 -2
- package/build/helpers/theme.js +40 -7
- package/build/helpers/theme.unit.d.ts +1 -0
- package/build/helpers/theme.unit.js +30 -0
- package/build/hooks/hydrated.d.ts +2 -0
- package/build/hooks/hydrated.js +15 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -1
- package/build/models/config.d.ts +32 -6
- package/build/models/config.js +10 -1
- package/build/models/section.d.ts +4 -2
- package/build/models/section.js +1 -1
- package/build/plugins/vite-livemark.d.ts +4 -5
- package/build/plugins/vite-livemark.js +56 -90
- package/build/program.js +4 -2
- package/build/routes/$.d.ts +4 -1
- package/build/routes/$.js +20 -9
- package/build/routes/__root.js +29 -63
- package/build/settings.js +2 -1
- package/package.json +68 -66
- package/{.agents/skills → skills}/livemark-authoring/SKILL.md +2 -2
- package/{.agents/skills → skills}/livemark-configuration/SKILL.md +12 -5
- package/skills/livemark-customization/SKILL.md +145 -0
- package/source/actions/config/define.unit.ts +9 -0
- package/source/actions/escape/copy.ts +35 -0
- package/source/actions/escape/copy.unit.ts +51 -0
- package/source/actions/escape/list.ts +30 -0
- package/source/actions/escape/list.unit.ts +42 -0
- package/source/actions/target/build.ts +49 -69
- package/source/actions/target/build.unit.ts +95 -0
- package/source/actions/target/clear.ts +14 -0
- package/source/actions/target/clear.unit.ts +25 -0
- package/source/commands/build.ts +0 -1
- package/source/commands/clear.ts +15 -0
- package/source/commands/escape.ts +42 -59
- package/source/commands/preview.ts +0 -1
- package/source/commands/start.ts +0 -1
- package/source/components/AnsiCode.tsx +1 -1
- package/source/components/Article.tsx +8 -4
- package/source/components/Banner.tsx +12 -2
- package/source/components/BlogIndex.tsx +1 -1
- package/source/components/Callout.tsx +4 -6
- package/source/components/ChangelogIndex.tsx +1 -1
- package/source/components/ChoiceList.tsx +69 -0
- package/source/components/CodeBlock.tsx +6 -6
- package/source/components/CodeTabs.tsx +1 -1
- package/source/components/ContentTabs.tsx +1 -1
- package/source/components/DefaultCatchBoundary.tsx +4 -6
- package/source/components/Details.tsx +1 -1
- package/source/components/FileTree.tsx +1 -1
- package/source/components/Header.tsx +52 -0
- package/source/components/HeaderMenu.tsx +41 -0
- package/source/components/HeaderNav.tsx +145 -0
- package/source/components/HeaderSearch.tsx +77 -0
- package/source/components/InlineBadge.tsx +1 -1
- package/source/components/InlineToc.tsx +1 -1
- package/source/components/Layout.tsx +16 -160
- package/source/components/LinkButton.tsx +9 -1
- package/source/components/MenuSheet.tsx +92 -0
- package/source/components/MermaidRenderer.tsx +19 -8
- package/source/components/NotFound.tsx +3 -5
- package/source/components/PackageTabs.tsx +2 -2
- package/source/components/PageToolbar.tsx +11 -3
- package/source/components/PrevNext.tsx +2 -2
- package/source/components/Root.tsx +13 -0
- package/source/components/Search.tsx +28 -8
- package/source/components/SearchDialog.tsx +15 -189
- package/source/components/SheetPanel.tsx +69 -0
- package/source/components/Sidebar.tsx +27 -14
- package/source/components/SidebarArticles.tsx +4 -3
- package/source/components/SidebarLinks.tsx +3 -2
- package/source/components/SidebarPosts.tsx +3 -2
- package/source/components/SidebarReleases.tsx +3 -2
- package/source/components/SidebarSectionPicker.tsx +70 -0
- package/source/components/SiteTitle.tsx +5 -5
- package/source/components/SoundCloud.tsx +1 -1
- package/source/components/TagIndex.tsx +1 -1
- package/source/components/Theme.tsx +55 -29
- package/source/components/Toc.tsx +76 -55
- package/source/components/YouTube.tsx +1 -1
- package/source/content-collections.ts +4 -0
- package/source/elements/alert-dialog.tsx +1 -1
- package/source/elements/alert.tsx +1 -1
- package/source/elements/badge.tsx +4 -0
- package/source/elements/button-group.tsx +4 -4
- package/source/elements/button.tsx +10 -6
- package/source/elements/calendar.tsx +1 -1
- package/source/elements/card.tsx +3 -3
- package/source/elements/command.tsx +7 -4
- package/source/elements/context-menu.tsx +5 -5
- package/source/elements/dialog.tsx +1 -1
- package/source/elements/drawer.tsx +59 -43
- package/source/elements/dropdown-menu.tsx +6 -6
- package/source/elements/empty.tsx +1 -1
- package/source/elements/field.tsx +1 -1
- package/source/elements/hover-card.tsx +1 -1
- package/source/elements/input-group.tsx +4 -4
- package/source/elements/input.tsx +1 -1
- package/source/elements/item.tsx +1 -1
- package/source/elements/menubar.tsx +8 -8
- package/source/elements/native-select.tsx +1 -1
- package/source/elements/popover.tsx +1 -1
- package/source/elements/select.tsx +3 -3
- package/source/elements/sidebar.tsx +8 -21
- package/source/elements/tabs.tsx +2 -2
- package/source/elements/textarea.tsx +1 -1
- package/source/elements/toggle-group.tsx +2 -2
- package/source/elements/toggle.tsx +1 -1
- package/source/env.d.ts +1 -0
- package/source/head.ts +7 -0
- package/source/helpers/article-search.tsx +192 -0
- package/source/helpers/dependency-dir.ts +20 -0
- package/source/helpers/dependency-dir.unit.ts +39 -0
- package/source/helpers/head.ts +94 -0
- package/source/helpers/head.unit.ts +116 -0
- package/source/helpers/nav-items.tsx +102 -0
- package/source/helpers/render-inline-markdown.ts +44 -0
- package/source/helpers/render-inline-markdown.unit.ts +30 -0
- package/source/helpers/search-highlight.ts +73 -0
- package/source/helpers/search-highlight.unit.ts +42 -0
- package/source/helpers/target-export.ts +28 -0
- package/source/helpers/target-export.unit.ts +37 -0
- package/source/helpers/theme.ts +40 -6
- package/source/helpers/theme.unit.ts +32 -0
- package/source/hooks/hydrated.ts +18 -0
- package/source/index.ts +1 -0
- package/source/models/config.ts +13 -0
- package/source/models/section.ts +3 -0
- package/source/plugins/vite-livemark.ts +54 -95
- package/source/program.ts +2 -0
- package/source/routes/$.tsx +27 -9
- package/source/routes/__root.tsx +51 -71
- package/source/settings.ts +1 -0
- package/source/styles/general.css +59 -11
- package/source/styles/markdown.css +13 -7
- package/source/styles/shape.css +14 -0
- package/.agents/skills/change-review/SKILL.md +0 -47
- package/.agents/skills/livemark-customization/SKILL.md +0 -118
package/build/settings.js
CHANGED
|
@@ -13,6 +13,7 @@ export const ESCAPABLE_FILES = [
|
|
|
13
13
|
"client.tsx",
|
|
14
14
|
"server.ts",
|
|
15
15
|
"router.tsx",
|
|
16
|
+
"head.ts",
|
|
16
17
|
];
|
|
17
18
|
/** Glob patterns auto-excluded from content scanning when the consumer's
|
|
18
19
|
* project doesn't ship a `.gitignore` to declare its own exclusions. */
|
|
@@ -22,4 +23,4 @@ export const DEFAULT_EXCLUDES = [
|
|
|
22
23
|
"**/build/**",
|
|
23
24
|
"**/dist/**",
|
|
24
25
|
];
|
|
25
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
26
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dGluZ3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zb3VyY2Uvc2V0dGluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O2dCQUVnQjtBQUNoQixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBc0I7SUFDbEQsWUFBWTtJQUNaLFVBQVU7SUFDVixRQUFRO0lBQ1IsUUFBUTtJQUNSLFFBQVE7Q0FDVCxDQUFBO0FBRUQsNkVBQTZFO0FBQzdFLE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBc0I7SUFDaEQsWUFBWTtJQUNaLFdBQVc7SUFDWCxZQUFZO0lBQ1osU0FBUztDQUNWLENBQUE7QUFFRDt5RUFDeUU7QUFDekUsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQXNCO0lBQ2pELG9CQUFvQjtJQUNwQixZQUFZO0lBQ1osYUFBYTtJQUNiLFlBQVk7Q0FDYixDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLyoqIFN1YmRpcnMgb2Ygc291cmNlLyB3aGVyZSBjb25zdW1lciBmaWxlcyBpbiBgLmxpdmVtYXJrLzxmb2xkZXI+L2AgYXJlXG4gKiAgbWVyZ2VkIHBlci1maWxlIGludG8gdGhlIHJ1bnRpbWUgbW91bnQsIHdpdGggYC5saXZlbWFya2Agd2lubmluZyBvblxuICogIGNvbmZsaWN0LiAqL1xuZXhwb3J0IGNvbnN0IEVTQ0FQQUJMRV9GT0xERVJTOiByZWFkb25seSBzdHJpbmdbXSA9IFtcbiAgXCJjb21wb25lbnRzXCIsXG4gIFwiZWxlbWVudHNcIixcbiAgXCJzdHlsZXNcIixcbiAgXCJyb3V0ZXNcIixcbiAgXCJwdWJsaWNcIixcbl1cblxuLyoqIFRvcC1sZXZlbCBzb3VyY2UgZmlsZXMgdGhhdCBgLmxpdmVtYXJrLzxmaWxlPmAgY2FuIHJlcGxhY2UgYXRvbWljYWxseS4gKi9cbmV4cG9ydCBjb25zdCBFU0NBUEFCTEVfRklMRVM6IHJlYWRvbmx5IHN0cmluZ1tdID0gW1xuICBcImNsaWVudC50c3hcIixcbiAgXCJzZXJ2ZXIudHNcIixcbiAgXCJyb3V0ZXIudHN4XCIsXG4gIFwiaGVhZC50c1wiLFxuXVxuXG4vKiogR2xvYiBwYXR0ZXJucyBhdXRvLWV4Y2x1ZGVkIGZyb20gY29udGVudCBzY2FubmluZyB3aGVuIHRoZSBjb25zdW1lcidzXG4gKiAgcHJvamVjdCBkb2Vzbid0IHNoaXAgYSBgLmdpdGlnbm9yZWAgdG8gZGVjbGFyZSBpdHMgb3duIGV4Y2x1c2lvbnMuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9FWENMVURFUzogcmVhZG9ubHkgc3RyaW5nW10gPSBbXG4gIFwiKiovbm9kZV9tb2R1bGVzLyoqXCIsXG4gIFwiKiovLmdpdC8qKlwiLFxuICBcIioqL2J1aWxkLyoqXCIsXG4gIFwiKiovZGlzdC8qKlwiLFxuXVxuIl19
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livemark",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Livemark description",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Evgeny Karev",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"files": [
|
|
15
15
|
"build",
|
|
16
16
|
"source",
|
|
17
|
-
"
|
|
17
|
+
"skills"
|
|
18
18
|
],
|
|
19
19
|
"type": "module",
|
|
20
20
|
"sideEffects": false,
|
|
@@ -26,86 +26,87 @@
|
|
|
26
26
|
"./styles/*": "./source/styles/*.css"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@base-ui/react": "1.
|
|
30
|
-
"@
|
|
29
|
+
"@base-ui/react": "1.9.0",
|
|
30
|
+
"@clack/prompts": "1.8.1",
|
|
31
|
+
"@content-collections/core": "0.15.3",
|
|
31
32
|
"@content-collections/mdx": "0.2.2",
|
|
32
|
-
"@content-collections/vite": "0.3.
|
|
33
|
+
"@content-collections/vite": "0.3.1",
|
|
33
34
|
"@orama/orama": "^3.1.18",
|
|
34
|
-
"@shikijs/rehype": "4.0
|
|
35
|
-
"@shikijs/twoslash": "^4.0
|
|
36
|
-
"@sindresorhus/slugify": "^3.0.
|
|
37
|
-
"@tailwindcss/typography": "^0.5.
|
|
38
|
-
"@tailwindcss/vite": "4.3.
|
|
39
|
-
"@tanstack/devtools-vite": "0.
|
|
40
|
-
"@tanstack/react-devtools": "0.10.
|
|
41
|
-
"@tanstack/react-hotkeys": "^0.
|
|
42
|
-
"@tanstack/react-query": "5.
|
|
43
|
-
"@tanstack/react-query-devtools": "5.
|
|
44
|
-
"@tanstack/react-router": "1.
|
|
45
|
-
"@tanstack/react-router-devtools": "1.
|
|
46
|
-
"@tanstack/react-router-ssr-query": "1.
|
|
47
|
-
"@tanstack/react-start": "1.
|
|
48
|
-
"@tanstack/virtual-file-routes": "^1.
|
|
35
|
+
"@shikijs/rehype": "4.5.0",
|
|
36
|
+
"@shikijs/twoslash": "^4.5.0",
|
|
37
|
+
"@sindresorhus/slugify": "^3.0.1",
|
|
38
|
+
"@tailwindcss/typography": "^0.5.20",
|
|
39
|
+
"@tailwindcss/vite": "4.3.3",
|
|
40
|
+
"@tanstack/devtools-vite": "0.8.5",
|
|
41
|
+
"@tanstack/react-devtools": "0.10.13",
|
|
42
|
+
"@tanstack/react-hotkeys": "^0.13.0",
|
|
43
|
+
"@tanstack/react-query": "5.104.2",
|
|
44
|
+
"@tanstack/react-query-devtools": "5.104.2",
|
|
45
|
+
"@tanstack/react-router": "1.170.42",
|
|
46
|
+
"@tanstack/react-router-devtools": "1.167.2",
|
|
47
|
+
"@tanstack/react-router-ssr-query": "1.167.3",
|
|
48
|
+
"@tanstack/react-start": "1.168.61",
|
|
49
|
+
"@tanstack/virtual-file-routes": "^1.162.0",
|
|
49
50
|
"@types/mdast": "^4.0.4",
|
|
50
|
-
"@types/react": "19.
|
|
51
|
-
"@types/react-dom": "19.
|
|
52
|
-
"@vitejs/plugin-react": "6.
|
|
53
|
-
"chokidar": "^5.0.0",
|
|
51
|
+
"@types/react": "19.3.0",
|
|
52
|
+
"@types/react-dom": "19.3.0",
|
|
53
|
+
"@vitejs/plugin-react": "6.1.2",
|
|
54
54
|
"class-variance-authority": "0.7.1",
|
|
55
55
|
"cmdk": "1.1.1",
|
|
56
|
-
"cn": "0.
|
|
57
|
-
"commander": "
|
|
56
|
+
"cn": "0.4.0",
|
|
57
|
+
"commander": "15.0.0",
|
|
58
58
|
"embla-carousel-react": "8.6.0",
|
|
59
|
-
"es-toolkit": "1.
|
|
59
|
+
"es-toolkit": "1.52.0",
|
|
60
60
|
"github-slugger": "^2.0.0",
|
|
61
|
-
"input-otp": "1.
|
|
62
|
-
"katex": "0.
|
|
61
|
+
"input-otp": "1.5.0",
|
|
62
|
+
"katex": "0.19.0",
|
|
63
63
|
"lucide-react": "0.577.0",
|
|
64
|
-
"mdast-util-directive": "^3.1.
|
|
64
|
+
"mdast-util-directive": "^3.1.1",
|
|
65
65
|
"mdast-util-to-string": "^4.0.0",
|
|
66
|
-
"mermaid": "^
|
|
67
|
-
"npm-to-yarn": "^3.0
|
|
66
|
+
"mermaid": "^12.1.0",
|
|
67
|
+
"npm-to-yarn": "^3.2.0",
|
|
68
68
|
"picocolors": "1.1.1",
|
|
69
|
-
"react-day-picker": "
|
|
70
|
-
"react-medium-image-zoom": "^5.4.
|
|
71
|
-
"react-resizable-panels": "4.
|
|
72
|
-
"recharts": "3.
|
|
69
|
+
"react-day-picker": "10.0.2",
|
|
70
|
+
"react-medium-image-zoom": "^5.4.9",
|
|
71
|
+
"react-resizable-panels": "4.14.4",
|
|
72
|
+
"recharts": "3.10.1",
|
|
73
73
|
"rehype-katex": "7.0.1",
|
|
74
74
|
"rehype-sanitize": "6.0.0",
|
|
75
75
|
"rehype-slug": "^6.0.0",
|
|
76
|
-
"
|
|
76
|
+
"rehype-stringify": "^10.0.1",
|
|
77
|
+
"remark-definition-list": "^2.0.1",
|
|
77
78
|
"remark-directive": "^4.0.0",
|
|
78
79
|
"remark-gemoji": "^8.0.0",
|
|
79
80
|
"remark-gfm": "4.0.1",
|
|
80
81
|
"remark-math": "6.0.0",
|
|
81
82
|
"remark-parse": "^11.0.0",
|
|
83
|
+
"remark-rehype": "^11.1.2",
|
|
82
84
|
"remark-stringify": "^11.0.0",
|
|
83
|
-
"shadcn": "
|
|
84
|
-
"shiki": "4.0
|
|
85
|
-
"sonner": "2.0.
|
|
86
|
-
"tailwindcss": "4.
|
|
85
|
+
"shadcn": "4.21.4",
|
|
86
|
+
"shiki": "4.5.0",
|
|
87
|
+
"sonner": "2.0.8",
|
|
88
|
+
"tailwindcss": "4.3.3",
|
|
87
89
|
"tw-animate-css": "1.4.0",
|
|
88
90
|
"unified": "^11.0.5",
|
|
89
91
|
"unist-util-visit": "^5.1.0",
|
|
90
|
-
"
|
|
91
|
-
"vite": "8.3.1",
|
|
92
|
+
"vite": "8.3.4",
|
|
92
93
|
"vite-plugin-svgr": "5.2.0",
|
|
93
|
-
"zod": "4.
|
|
94
|
+
"zod": "4.6.6"
|
|
94
95
|
},
|
|
95
96
|
"devDependencies": {
|
|
96
|
-
"@plausible-analytics/tracker": "^0.4.
|
|
97
|
-
"@types/node": "24.2
|
|
98
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
99
|
-
"@vitest/coverage-v8": "5.0.
|
|
100
|
-
"lefthook": "2.
|
|
97
|
+
"@plausible-analytics/tracker": "^0.4.6",
|
|
98
|
+
"@types/node": "24.19.2",
|
|
99
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
100
|
+
"@vitest/coverage-v8": "5.0.3",
|
|
101
|
+
"lefthook": "2.2.1",
|
|
101
102
|
"livemark": "link:.",
|
|
102
|
-
"npm-check-updates": "23.1.
|
|
103
|
-
"react": "19.
|
|
104
|
-
"react-dom": "19.
|
|
103
|
+
"npm-check-updates": "23.1.1",
|
|
104
|
+
"react": "19.3.0",
|
|
105
|
+
"react-dom": "19.3.0",
|
|
105
106
|
"tempy": "3.2.0",
|
|
106
|
-
"vite-plus": "1.
|
|
107
|
-
"vitest": "5.0.
|
|
108
|
-
"wrangler": "4.
|
|
107
|
+
"vite-plus": "1.1.0",
|
|
108
|
+
"vitest": "5.0.3",
|
|
109
|
+
"wrangler": "4.149.0"
|
|
109
110
|
},
|
|
110
111
|
"peerDependencies": {
|
|
111
112
|
"react": "^19.0.0",
|
|
@@ -117,18 +118,19 @@
|
|
|
117
118
|
},
|
|
118
119
|
"scripts": {
|
|
119
120
|
"build": "tsgo --project tsconfig.build.json",
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
121
|
+
"build:docs": "node source/entrypoints/main.ts build",
|
|
122
|
+
"check": "pnpm check:lint && pnpm check:types",
|
|
123
|
+
"check:lint": "vp fmt --check && vp lint",
|
|
124
|
+
"check:types": "tsgo --noEmit",
|
|
123
125
|
"format": "vp fmt --no-error-on-unmatched-pattern",
|
|
124
|
-
"leaks": "gitleaks git --config=.gitleaks.toml --verbose --redact",
|
|
125
|
-
"lint": "vp fmt --check && vp lint",
|
|
126
126
|
"release": "pnpm publish --access public --ignore-scripts --no-git-checks",
|
|
127
|
-
"scan": "pnpm leaks && pnpm vulns",
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
127
|
+
"scan": "pnpm scan:leaks && pnpm scan:vulns",
|
|
128
|
+
"scan:leaks": "gitleaks git --config=.gitleaks.toml --verbose --redact",
|
|
129
|
+
"scan:vulns": "semgrep --config=p/typescript --config=p/nodejs --config=p/owasp-top-ten --config=p/secrets --exclude=\"**/fixtures/**\" --metrics=off",
|
|
130
|
+
"squash": "node .scripts/squash-branch.ts",
|
|
131
|
+
"start": "node source/entrypoints/main.ts start",
|
|
132
|
+
"test": "pnpm check && pnpm test:unit",
|
|
133
|
+
"test:unit": "vp test",
|
|
134
|
+
"update:deps": "ncu -u --cooldown 7d"
|
|
133
135
|
}
|
|
134
136
|
}
|
|
@@ -36,7 +36,7 @@ group: Docs # sidebar section label
|
|
|
36
36
|
path: /getting-started/ # default: slugified filename + leading/trailing slashes
|
|
37
37
|
sidebar: true # false hides from nav but keeps URL reachable
|
|
38
38
|
toc: true # false suppresses right-hand TOC
|
|
39
|
-
image: ./cover.png #
|
|
39
|
+
image: ./cover.png # og:image (needs `site`); relative resolves against the file
|
|
40
40
|
author: Ada Lovelace # or [Ada Lovelace, Grace Hopper]
|
|
41
41
|
date: 2026-04-20 # ISO — drives blog section sort order
|
|
42
42
|
tags: [release, announcement] # blog-section tag pages /prefix/tags/<tag>/
|
|
@@ -87,7 +87,7 @@ description: What's new in 0.3, in 400 words.
|
|
|
87
87
|
|
|
88
88
|
After authoring, run:
|
|
89
89
|
|
|
90
|
-
- `
|
|
90
|
+
- `npx livemark build` — confirms the file prerenders without error.
|
|
91
91
|
- Grep built HTML (`.livemark/build/client/<path>/index.html`) to confirm title and metadata land as intended.
|
|
92
92
|
|
|
93
93
|
## References
|
|
@@ -11,7 +11,7 @@ Guidance for editing `livemark.config.ts` at the project root.
|
|
|
11
11
|
|
|
12
12
|
Invoke when the user asks to:
|
|
13
13
|
|
|
14
|
-
- Set the site title, description, canonical URL, logo, favicon.
|
|
14
|
+
- Set the site title, description, canonical URL, logo, favicon, announcement banner.
|
|
15
15
|
- Change which files are included or excluded.
|
|
16
16
|
- Switch code-block syntax highlighting themes.
|
|
17
17
|
- Add, reorder, or retype a section (docs/blog/changelog).
|
|
@@ -34,6 +34,13 @@ export default defineConfig({
|
|
|
34
34
|
description: "Short blurb.", // <meta description>, og:description
|
|
35
35
|
logo: "/logo.svg", // header mark; also default favicon
|
|
36
36
|
favicon: "/favicon.ico", // browser tab icon
|
|
37
|
+
banner: "v2 is out · [Notes](/blog/v2/)", // inline Markdown strip above the header; raw HTML dropped
|
|
38
|
+
head: {
|
|
39
|
+
// extra <head> tags after the defaults; a meta sharing name/property replaces one
|
|
40
|
+
meta: [{ name: "twitter:site", content: "@me" }],
|
|
41
|
+
links: [{ rel: "me", href: "https://mastodon.social/@me" }],
|
|
42
|
+
scripts: [{ src: "https://example.com/analytics.js", defer: "" }],
|
|
43
|
+
},
|
|
37
44
|
|
|
38
45
|
// Optional: content selection
|
|
39
46
|
exclude: "docs/drafts/**", // string | string[]
|
|
@@ -71,7 +78,7 @@ export default defineConfig({
|
|
|
71
78
|
- **Blog** (`type: "blog"`): auto-generated index at `prefix`, sorts by `date`, exposes `/prefix/tags/<tag>/` pages.
|
|
72
79
|
- **Changelog** (`type: "changelog"`): reads `source` file; with `version: true`, splits on semver headings into per-version articles. Several changelog sections may coexist as long as their prefixes differ — each is cached in its own `cache/changelog/<slug-of-prefix>-<hash-of-prefix>/` directory (the hash keeps prefixes that slugify alike, like `/python/changelog/` and `/python-changelog/`, apart), so a version shared by two changelogs never collides. The `(version)` suffix only renders for `position: "header"` sections.
|
|
73
80
|
|
|
74
|
-
Shared fields on every section: `title`, `prefix` (keep trailing-slashed), `type`, `icon` (lucide), `position` (`"header"` default, `"sidebar"` also available).
|
|
81
|
+
Shared fields on every section: `title`, `prefix` (keep trailing-slashed), `type`, `icon` (lucide), `position` (`"header"` default, `"sidebar"` also available). Header sections and links never overflow: past the bar's width Search turns icon-only, then the rest fold into a "More" menu.
|
|
75
82
|
|
|
76
83
|
Article-to-section matching is longest-prefix-wins on the article's URL `path`.
|
|
77
84
|
|
|
@@ -102,12 +109,12 @@ Any [Shiki theme](https://shiki.style/themes) name works. Defaults keep the catp
|
|
|
102
109
|
|
|
103
110
|
## Autoreload
|
|
104
111
|
|
|
105
|
-
The dev server watches `livemark.config.ts` and restarts on edit. No need to kill `
|
|
112
|
+
The dev server watches `livemark.config.ts` and restarts on edit. No need to kill `npx livemark start` after tweaking the config.
|
|
106
113
|
|
|
107
114
|
## Verification
|
|
108
115
|
|
|
109
|
-
-
|
|
110
|
-
- `
|
|
116
|
+
- The project's type check (e.g. `npx tsc --noEmit`) — catches schema mismatches.
|
|
117
|
+
- `npx livemark build` — prerenders with the new config; the output listing shows whether section routes resolved.
|
|
111
118
|
|
|
112
119
|
## References
|
|
113
120
|
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: livemark-customization
|
|
3
|
+
description: Use when overriding Livemark's built-in UI or adding custom routes — shadow defaults with same-named files under .livemark/{components,elements,styles}, add .livemark/routes/*.tsx pages, or copy defaults with `livemark escape`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Livemark Customization
|
|
7
|
+
|
|
8
|
+
Guidance for customizing the UI layer of a Livemark project beyond what `livemark.config.ts` exposes.
|
|
9
|
+
|
|
10
|
+
## When to use this skill
|
|
11
|
+
|
|
12
|
+
Invoke when the user asks to:
|
|
13
|
+
|
|
14
|
+
- Change a built-in component's layout or markup (Footer, Sidebar, Banner, …).
|
|
15
|
+
- Restyle a shared primitive (buttons, inputs, cards, sheet, …).
|
|
16
|
+
- Rebrand via CSS tokens (colors, radii, typography).
|
|
17
|
+
- Add a brand-new page that isn't a Markdown article (landing hero, pricing page, about page).
|
|
18
|
+
- Replace Livemark's default landing page with a custom React component.
|
|
19
|
+
- Serve a custom `favicon.svg`, `robots.txt`, `og-image.png`, or other static asset.
|
|
20
|
+
|
|
21
|
+
## Three overlapping mechanisms
|
|
22
|
+
|
|
23
|
+
| Goal | Mechanism |
|
|
24
|
+
| --------------------------------- | ----------------------------------------------------- |
|
|
25
|
+
| Replace a default component/style | Drop a file at `.livemark/components/<Name>.tsx` etc. |
|
|
26
|
+
| Add a new page at an exact URL | Create `.livemark/routes/<path>.tsx` |
|
|
27
|
+
| Serve a static asset at `/<path>` | Put the file in `.livemark/public/<path>` |
|
|
28
|
+
| Rewrite site-wide `<head>` tags | `.livemark/head.ts` exporting `customizeHead(head)` |
|
|
29
|
+
|
|
30
|
+
None require config changes. The Vite plugin (`source/plugins/vite-livemark.ts`) watches `.livemark/**` and hot-reloads.
|
|
31
|
+
|
|
32
|
+
## Discovering what's overridable
|
|
33
|
+
|
|
34
|
+
Run the `escape` command with `--list` to print every overridable file:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
livemark escape --list
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Output is a flat `<subdir>/<file>` list across `components/`, `elements/`, and `styles/`. Without arguments in a terminal the command opens an interactive picker instead — agents should pass `--list` or explicit paths. With paths, it copies each default into `.livemark/`:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
livemark escape components/Footer.tsx # → .livemark/components/Footer.tsx
|
|
44
|
+
livemark escape elements/button.tsx styles/general.css # several at once
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The command refuses to overwrite an existing override (and exits 1 after copying the rest). Delete the override first if you want a fresh start.
|
|
48
|
+
|
|
49
|
+
## Typical workflow: override a component
|
|
50
|
+
|
|
51
|
+
1. `livemark escape components/Footer.tsx` — copy the default.
|
|
52
|
+
2. Edit `.livemark/components/Footer.tsx`. All the site's Footer renders shift to the new file on save.
|
|
53
|
+
3. Inside the override, import other Livemark modules from the `livemark/<subdir>/*` subpath exports:
|
|
54
|
+
```tsx
|
|
55
|
+
import { cn } from "cn"
|
|
56
|
+
import { Button } from "livemark/elements/button"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Typical workflow: announcement banner
|
|
60
|
+
|
|
61
|
+
Prefer the `banner` config option — an inline Markdown string, rendered to HTML at build time and exposed as `bannerHtml` from `livemark:virtual`. Escape `components/Banner.tsx` only for icons or custom markup. The strip spans the full page width above both the sidebar and the sticky header — it scrolls away while the sidebar and header pin to the top (the sidebar container is `sticky`, not `fixed`, for this). Let it wrap (`flex-wrap`, `text-balance`, `min-w-0`) rather than `truncate`, so phones neither clip it nor scroll sideways. Style the injected HTML from the wrapper (`[&_a]:underline`): Tailwind never sees classes inside a config string. Search and the theme toggle sit at the right of the header, not in the sidebar. The header's section strip is `components/HeaderNav.tsx`; it tells `Header` when to render `<Search compact />` and folds what still doesn't fit into a "More" menu. Below `lg`, `Search` opens `components/HeaderSearch.tsx` instead of the dialog: a field that covers the whole header bar, with results dropping full-width beneath it — positioned `absolute` against the sticky header, so an override must stay inside `<header>`.
|
|
62
|
+
|
|
63
|
+
## Sidebar escapes
|
|
64
|
+
|
|
65
|
+
`Sidebar` picks the body slot (`SidebarArticles`, `SidebarPosts`, `SidebarReleases`) and passes each, plus `SidebarLinks`, the section to show as an optional `section` prop. On mobile inside a section it swaps the Sections list for `SidebarSectionPicker`, which changes that prop without navigating — an escaped body slot must read `props.section` before falling back to the route's section, or the picker stops working.
|
|
66
|
+
|
|
67
|
+
## Typical workflow: rebrand
|
|
68
|
+
|
|
69
|
+
1. `livemark escape styles/general.css`.
|
|
70
|
+
2. Edit the `:root` and `.dark` blocks in `.livemark/styles/general.css`:
|
|
71
|
+
- `--primary` — brand accent (Tailwind-flavoured oklch values work).
|
|
72
|
+
- `--positive`, `--warning`, `--destructive` — status tones, each with a `-foreground` for text on the fill and a `-tint` / `-tint-foreground` pair for soft surfaces (callouts, diff lines, badge and button variants).
|
|
73
|
+
- `--radius` — the `rounded-sm`…`rounded-xl` scale only. Element corners are named tokens in `styles/shape.css` (`rounded-control` pills, `rounded-card`/`rounded-row`/`rounded-menu` 1rem, `rounded-panel` 1.5rem); escape that file to change them, and use those names rather than raw `rounded-md` in new elements.
|
|
74
|
+
- Sidebar / chart tokens if you want deeper tweaks.
|
|
75
|
+
3. Save — the dev server applies immediately.
|
|
76
|
+
|
|
77
|
+
Whole-site contrast is audited: light mode targets blue-600, dark mode targets blue-500. Keep new token values AA-compliant on both backgrounds (≥4.5:1 for text).
|
|
78
|
+
|
|
79
|
+
## Typical workflow: add a page
|
|
80
|
+
|
|
81
|
+
Custom routes use [TanStack Router](https://tanstack.com/router). Minimal example:
|
|
82
|
+
|
|
83
|
+
```tsx title=".livemark/routes/about.tsx"
|
|
84
|
+
import { createFileRoute } from "@tanstack/react-router"
|
|
85
|
+
import { Layout } from "livemark/components/Layout"
|
|
86
|
+
|
|
87
|
+
export const Route = createFileRoute("/about")({
|
|
88
|
+
component: () => (
|
|
89
|
+
<Layout>
|
|
90
|
+
<div className="mx-auto max-w-3xl px-6 py-16 prose">
|
|
91
|
+
<h1>About</h1>
|
|
92
|
+
<p>Hello.</p>
|
|
93
|
+
</div>
|
|
94
|
+
</Layout>
|
|
95
|
+
),
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
A custom route renders **bare**: the root wraps every route in the headless `components/Root.tsx`, and only the Markdown route, 404 and error pages add chrome. Pick it per route:
|
|
100
|
+
|
|
101
|
+
- `<Layout>` — banner, header, sidebar sheet and back-to-top, as articles get (`withSidebar` adds the article sidebar)
|
|
102
|
+
- `<Banner />` + `<Header />` — a landing page's chrome without the sidebar; on phones `Header` opens `HeaderMenu`, a flat list of the header sections and links
|
|
103
|
+
- nothing — a fully custom page
|
|
104
|
+
|
|
105
|
+
`Header` never reads sidebar context: `Layout` passes its `SidebarTrigger`s in as the `toggle` and `menu` slots. A `Header` without `toggle` keeps its title block at sidebar width so the nav lines up with article pages.
|
|
106
|
+
|
|
107
|
+
Filename maps to URL path: `.livemark/routes/pricing.tsx` → `/pricing/`. Nested paths work via nested folders.
|
|
108
|
+
|
|
109
|
+
An `index.tsx` in `.livemark/routes/` **replaces** Livemark's default landing at `/`.
|
|
110
|
+
|
|
111
|
+
Custom routes win over the Markdown catch-all at exact URLs. Don't create a route that collides with an article URL unless you intend to hide the article.
|
|
112
|
+
|
|
113
|
+
## Rules of thumb
|
|
114
|
+
|
|
115
|
+
1. **Don't fork the repo** for routine customization. Use `.livemark/` first — it reliably survives Livemark upgrades.
|
|
116
|
+
2. **Same filename, same path under `.livemark/`.** The override plugin is case-sensitive and mirrors the subdirectory structure exactly.
|
|
117
|
+
3. **Override files are full replacements**, not diffs. Copy the default first (via `escape`), then edit.
|
|
118
|
+
4. **Import Livemark internals via `livemark/*`**, not via relative paths — the plugin resolves those to the project's copy, so chained overrides (e.g., your Layout using your Header) compose correctly.
|
|
119
|
+
5. **Static files belong in `.livemark/public/`**, which Vite exposes at the site root.
|
|
120
|
+
6. **Never edit `.livemark/.target/`** — it is the generated mount Vite runs (Livemark's source with your overrides copied in), rebuilt on every run, so stack traces point there but edits are lost. Gitignore it alongside `.livemark/build/`.
|
|
121
|
+
7. **Keyboard shortcuts live in the component they drive** — bare keys through `@tanstack/react-hotkeys`, ignored while typing: `L` sidebar (`Sidebar`), `S` search (`Search`), `T` theme (`Theme`), `J`/`K` scroll (`Root`), `B` back to top (`BackToTop`). Overriding one of these drops its key unless the copy keeps the `useHotkey` call; register a key in a component that mounts once, or one press fires twice.
|
|
122
|
+
8. **Search highlights live in `Article`** — picking a result opens the page with `?highlight=<query>`, and `Article` passes it to `useSearchHighlight` with a ref on its `.prose` wrapper. An overridden `components/Article.tsx` must keep that call and ref, or matches stop being marked. Theme the mark through the `--highlight` and `--highlight-foreground` tokens; code blocks are never marked.
|
|
123
|
+
|
|
124
|
+
## Head tags
|
|
125
|
+
|
|
126
|
+
Add tags with the config `head` field (`livemark-configuration`); escape `head.ts` only to drop or rewrite defaults. `customizeHead` receives the finished `RootHead` (`meta`, `links`, `scripts`, typed from `livemark`) and returns it — mutate or filter, never rebuild, or later Livemark defaults are lost. Per-page `title`, `description`, `og:*` and canonical come from the article route and win over root meta with the same `name`/`property`.
|
|
127
|
+
|
|
128
|
+
## What's NOT overridable
|
|
129
|
+
|
|
130
|
+
- `actions/`, `commands/`, `program.ts` — server/CLI code. Fork upstream if you need to change these.
|
|
131
|
+
- `livemark.config.ts` schema — fixed.
|
|
132
|
+
- Content-collections transform pipeline. Customize markdown via remark/rehype plugins in a fork (or PR upstream).
|
|
133
|
+
|
|
134
|
+
## Verification
|
|
135
|
+
|
|
136
|
+
- The project's type check (e.g. `npx tsc --noEmit`) — confirms overrides typecheck.
|
|
137
|
+
- `npx livemark build` — smoke-test the override lands in the bundle.
|
|
138
|
+
- Browser: load an article page with the dev server; custom Footer/Sidebar/etc. should render without a full reload.
|
|
139
|
+
|
|
140
|
+
## References
|
|
141
|
+
|
|
142
|
+
- Narrative docs: `docs/customization/file-overrides.md`, `docs/customization/custom-routes.md`.
|
|
143
|
+
- Plugin implementation: `source/plugins/vite-livemark.ts`.
|
|
144
|
+
- Escape command: `commands/escape.ts`; list and copy logic in `actions/escape/`.
|
|
145
|
+
- Subpath exports: `package.json` `exports` block.
|
|
@@ -31,4 +31,13 @@ describe("defineConfig", () => {
|
|
|
31
31
|
const config = defineConfig({})
|
|
32
32
|
expect(config.include).toBe("**/*.md")
|
|
33
33
|
})
|
|
34
|
+
|
|
35
|
+
it("should accept an inline Markdown banner", () => {
|
|
36
|
+
const config = defineConfig({ banner: "Hi · [x](/y/)" })
|
|
37
|
+
expect(config.banner).toBe("Hi · [x](/y/)")
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it("should leave banner unset by default", () => {
|
|
41
|
+
expect(defineConfig({}).banner).toBeUndefined()
|
|
42
|
+
})
|
|
34
43
|
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { dirname, join } from "node:path"
|
|
3
|
+
import { ESCAPABLE_FILES, ESCAPABLE_FOLDERS } from "../../settings.ts"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Copy a livemark default into `<root>/.livemark/<path>`.
|
|
7
|
+
*
|
|
8
|
+
* Throws when the path is not escapable, is not a livemark file, or the
|
|
9
|
+
* destination already exists. Returns the destination path.
|
|
10
|
+
*/
|
|
11
|
+
export function copyEscape(props: { root: string; sourceRoot: string; path: string }) {
|
|
12
|
+
const isTopLevelFile = !props.path.includes("/") && ESCAPABLE_FILES.includes(props.path)
|
|
13
|
+
const [first] = props.path.split("/")
|
|
14
|
+
const isFolderPath =
|
|
15
|
+
!!first && ESCAPABLE_FOLDERS.includes(first) && !props.path.includes("..")
|
|
16
|
+
if (!isTopLevelFile && !isFolderPath) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`'${props.path}' is not escapable (folders: ${ESCAPABLE_FOLDERS.join(", ")}; files: ${ESCAPABLE_FILES.join(", ")})`,
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const src = join(props.sourceRoot, props.path)
|
|
23
|
+
if (!existsSync(src) || !statSync(src).isFile()) {
|
|
24
|
+
throw new Error(`'${props.path}' is not a livemark file`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const dest = join(props.root, ".livemark", props.path)
|
|
28
|
+
if (existsSync(dest)) {
|
|
29
|
+
throw new Error(`.livemark/${props.path} already exists`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
mkdirSync(dirname(dest), { recursive: true })
|
|
33
|
+
writeFileSync(dest, readFileSync(src))
|
|
34
|
+
return dest
|
|
35
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { temporaryDirectoryTask } from "tempy"
|
|
4
|
+
import { describe, expect, it } from "vite-plus/test"
|
|
5
|
+
import { copyEscape } from "./copy.ts"
|
|
6
|
+
|
|
7
|
+
describe("copyEscape", () => {
|
|
8
|
+
it("should copy a default into .livemark/", () =>
|
|
9
|
+
temporaryDirectoryTask(async tmpDir => {
|
|
10
|
+
const sourceRoot = createSource(tmpDir)
|
|
11
|
+
const dest = copyEscape({ root: tmpDir, sourceRoot, path: "components/Footer.tsx" })
|
|
12
|
+
expect(dest).toBe(join(tmpDir, ".livemark", "components", "Footer.tsx"))
|
|
13
|
+
expect(fs.readFileSync(dest, "utf8")).toBe("default\n")
|
|
14
|
+
}))
|
|
15
|
+
|
|
16
|
+
it("should refuse to overwrite an existing override", () =>
|
|
17
|
+
temporaryDirectoryTask(async tmpDir => {
|
|
18
|
+
const sourceRoot = createSource(tmpDir)
|
|
19
|
+
copyEscape({ root: tmpDir, sourceRoot, path: "client.tsx" })
|
|
20
|
+
expect(() => copyEscape({ root: tmpDir, sourceRoot, path: "client.tsx" })).toThrow(
|
|
21
|
+
/already exists/,
|
|
22
|
+
)
|
|
23
|
+
}))
|
|
24
|
+
|
|
25
|
+
it("should reject paths outside the escape contract", () =>
|
|
26
|
+
temporaryDirectoryTask(async tmpDir => {
|
|
27
|
+
const sourceRoot = createSource(tmpDir)
|
|
28
|
+
for (const path of ["index.ts", "components/../index.ts", "helpers/toc.ts"]) {
|
|
29
|
+
expect(() => copyEscape({ root: tmpDir, sourceRoot, path })).toThrow(
|
|
30
|
+
/not escapable/,
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
}))
|
|
34
|
+
|
|
35
|
+
it("should reject an escapable path with no livemark file", () =>
|
|
36
|
+
temporaryDirectoryTask(async tmpDir => {
|
|
37
|
+
const sourceRoot = createSource(tmpDir)
|
|
38
|
+
expect(() =>
|
|
39
|
+
copyEscape({ root: tmpDir, sourceRoot, path: "components/Missing.tsx" }),
|
|
40
|
+
).toThrow(/not a livemark file/)
|
|
41
|
+
}))
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
function createSource(tmpDir: string) {
|
|
45
|
+
const sourceRoot = join(tmpDir, "source")
|
|
46
|
+
fs.mkdirSync(join(sourceRoot, "components"), { recursive: true })
|
|
47
|
+
fs.writeFileSync(join(sourceRoot, "components", "Footer.tsx"), "default\n")
|
|
48
|
+
fs.writeFileSync(join(sourceRoot, "client.tsx"), "default\n")
|
|
49
|
+
fs.writeFileSync(join(sourceRoot, "index.ts"), "default\n")
|
|
50
|
+
return sourceRoot
|
|
51
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { existsSync, readdirSync, statSync } from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { ESCAPABLE_FILES, ESCAPABLE_FOLDERS } from "../../settings.ts"
|
|
4
|
+
|
|
5
|
+
/** An escapable livemark file and whether the project already shadows it. */
|
|
6
|
+
export interface Escape {
|
|
7
|
+
path: string
|
|
8
|
+
escaped: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* List every file a project can shadow under `.livemark/`, sorted by path.
|
|
13
|
+
*/
|
|
14
|
+
export function listEscapes(props: { root: string; sourceRoot: string }) {
|
|
15
|
+
const paths: string[] = []
|
|
16
|
+
for (const folder of ESCAPABLE_FOLDERS) {
|
|
17
|
+
const dir = join(props.sourceRoot, folder)
|
|
18
|
+
if (!existsSync(dir)) continue
|
|
19
|
+
for (const entry of readdirSync(dir)) {
|
|
20
|
+
if (statSync(join(dir, entry)).isFile()) paths.push(`${folder}/${entry}`)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
for (const file of ESCAPABLE_FILES) {
|
|
24
|
+
if (existsSync(join(props.sourceRoot, file))) paths.push(file)
|
|
25
|
+
}
|
|
26
|
+
return paths.sort().map((path): Escape => ({
|
|
27
|
+
path,
|
|
28
|
+
escaped: existsSync(join(props.root, ".livemark", path)),
|
|
29
|
+
}))
|
|
30
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { temporaryDirectoryTask } from "tempy"
|
|
4
|
+
import { describe, expect, it } from "vite-plus/test"
|
|
5
|
+
import { listEscapes } from "./list.ts"
|
|
6
|
+
|
|
7
|
+
describe("listEscapes", () => {
|
|
8
|
+
it("should list folder files and top-level files, sorted", () =>
|
|
9
|
+
temporaryDirectoryTask(async tmpDir => {
|
|
10
|
+
const sourceRoot = join(tmpDir, "source")
|
|
11
|
+
writeFile(join(sourceRoot, "components", "Footer.tsx"))
|
|
12
|
+
writeFile(join(sourceRoot, "styles", "general.css"))
|
|
13
|
+
writeFile(join(sourceRoot, "client.tsx"))
|
|
14
|
+
writeFile(join(sourceRoot, "index.ts"))
|
|
15
|
+
fs.mkdirSync(join(sourceRoot, "elements", "nested"), { recursive: true })
|
|
16
|
+
|
|
17
|
+
const escapes = listEscapes({ root: tmpDir, sourceRoot })
|
|
18
|
+
expect(escapes.map(escape => escape.path)).toEqual([
|
|
19
|
+
"client.tsx",
|
|
20
|
+
"components/Footer.tsx",
|
|
21
|
+
"styles/general.css",
|
|
22
|
+
])
|
|
23
|
+
}))
|
|
24
|
+
|
|
25
|
+
it("should mark files the project already shadows", () =>
|
|
26
|
+
temporaryDirectoryTask(async tmpDir => {
|
|
27
|
+
const sourceRoot = join(tmpDir, "source")
|
|
28
|
+
writeFile(join(sourceRoot, "components", "Footer.tsx"))
|
|
29
|
+
writeFile(join(sourceRoot, "components", "Header.tsx"))
|
|
30
|
+
writeFile(join(tmpDir, ".livemark", "components", "Footer.tsx"))
|
|
31
|
+
|
|
32
|
+
expect(listEscapes({ root: tmpDir, sourceRoot })).toEqual([
|
|
33
|
+
{ path: "components/Footer.tsx", escaped: true },
|
|
34
|
+
{ path: "components/Header.tsx", escaped: false },
|
|
35
|
+
])
|
|
36
|
+
}))
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
function writeFile(path: string) {
|
|
40
|
+
fs.mkdirSync(join(path, ".."), { recursive: true })
|
|
41
|
+
fs.writeFileSync(path, "default\n")
|
|
42
|
+
}
|