livemark 0.25.0 → 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
|
@@ -28,7 +28,7 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
|
|
|
28
28
|
|
|
29
29
|
return (
|
|
30
30
|
<figure
|
|
31
|
-
className="shiki not-prose my-4 relative rounded-
|
|
31
|
+
className="shiki not-prose my-4 relative rounded-card border shadow-sm overflow-hidden text-sm bg-sidebar dark:bg-sidebar"
|
|
32
32
|
style={{ ...style, backgroundColor: undefined }}
|
|
33
33
|
>
|
|
34
34
|
{title ? (
|
|
@@ -44,7 +44,7 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
|
|
|
44
44
|
<TooltipTrigger
|
|
45
45
|
onClick={handleWrapToggle}
|
|
46
46
|
aria-label={wrap ? "Disable wrap" : "Enable wrap"}
|
|
47
|
-
className={`-me-2 p-1.5 rounded-
|
|
47
|
+
className={`-me-2 p-1.5 rounded-control hover:text-foreground transition-colors ${wrap ? "text-foreground" : ""}`}
|
|
48
48
|
>
|
|
49
49
|
<WrapText className="size-3.5" />
|
|
50
50
|
</TooltipTrigger>
|
|
@@ -54,7 +54,7 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
|
|
|
54
54
|
<TooltipTrigger
|
|
55
55
|
onClick={handleCopy}
|
|
56
56
|
aria-label={copied ? "Copied" : "Copy code"}
|
|
57
|
-
className="-me-2 p-1.5 rounded-
|
|
57
|
+
className="-me-2 p-1.5 rounded-control hover:text-foreground transition-colors"
|
|
58
58
|
>
|
|
59
59
|
{copied ? (
|
|
60
60
|
<Check className="size-3.5" />
|
|
@@ -66,12 +66,12 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
|
|
|
66
66
|
</Tooltip>
|
|
67
67
|
</div>
|
|
68
68
|
) : (
|
|
69
|
-
<div className="empty:hidden absolute top-2 right-2 z-10 backdrop-blur-lg rounded-
|
|
69
|
+
<div className="empty:hidden absolute top-2 right-2 z-10 backdrop-blur-lg rounded-control text-muted-foreground">
|
|
70
70
|
<Tooltip>
|
|
71
71
|
<TooltipTrigger
|
|
72
72
|
onClick={handleWrapToggle}
|
|
73
73
|
aria-label={wrap ? "Disable wrap" : "Enable wrap"}
|
|
74
|
-
className={`p-1.5 rounded-
|
|
74
|
+
className={`p-1.5 rounded-control hover:text-foreground transition-colors ${wrap ? "text-foreground" : ""}`}
|
|
75
75
|
>
|
|
76
76
|
<WrapText className="size-3.5" />
|
|
77
77
|
</TooltipTrigger>
|
|
@@ -81,7 +81,7 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
|
|
|
81
81
|
<TooltipTrigger
|
|
82
82
|
onClick={handleCopy}
|
|
83
83
|
aria-label={copied ? "Copied" : "Copy code"}
|
|
84
|
-
className="p-1.5 rounded-
|
|
84
|
+
className="p-1.5 rounded-control hover:text-foreground transition-colors"
|
|
85
85
|
>
|
|
86
86
|
{copied ? (
|
|
87
87
|
<Check className="size-3.5" />
|
|
@@ -47,7 +47,7 @@ export function CodeTabs(props: {
|
|
|
47
47
|
}, [props.sync, names])
|
|
48
48
|
|
|
49
49
|
return (
|
|
50
|
-
<div className="not-prose my-4 rounded-
|
|
50
|
+
<div className="not-prose my-4 rounded-card border shadow-sm overflow-hidden text-sm bg-sidebar dark:bg-sidebar">
|
|
51
51
|
<div className="flex border-b">
|
|
52
52
|
{names.map((name, i) => (
|
|
53
53
|
<button
|
|
@@ -45,7 +45,7 @@ export function ContentTabs(props: { sync?: string; children: React.ReactNode })
|
|
|
45
45
|
}, [props.sync, titles])
|
|
46
46
|
|
|
47
47
|
return (
|
|
48
|
-
<div className="not-prose my-4 rounded-
|
|
48
|
+
<div className="not-prose my-4 rounded-card border bg-card">
|
|
49
49
|
<div className="flex border-b">
|
|
50
50
|
{titles.map((title, i) => (
|
|
51
51
|
<button
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
useMatch,
|
|
7
7
|
useRouter,
|
|
8
8
|
} from "@tanstack/react-router"
|
|
9
|
+
import { buttonVariants } from "../elements/button.tsx"
|
|
9
10
|
|
|
10
11
|
export function DefaultCatchBoundary({ error }: ErrorComponentProps) {
|
|
11
12
|
const router = useRouter()
|
|
@@ -25,21 +26,18 @@ export function DefaultCatchBoundary({ error }: ErrorComponentProps) {
|
|
|
25
26
|
onClick={() => {
|
|
26
27
|
router.invalidate()
|
|
27
28
|
}}
|
|
28
|
-
className=
|
|
29
|
+
className={buttonVariants({ size: "lg" })}
|
|
29
30
|
>
|
|
30
31
|
Try Again
|
|
31
32
|
</button>
|
|
32
33
|
{isRoot ? (
|
|
33
|
-
<Link
|
|
34
|
-
to="/"
|
|
35
|
-
className="border border-border px-4 py-2 text-sm font-medium hover:bg-card transition-colors"
|
|
36
|
-
>
|
|
34
|
+
<Link to="/" className={buttonVariants({ variant: "outline", size: "lg" })}>
|
|
37
35
|
Home
|
|
38
36
|
</Link>
|
|
39
37
|
) : (
|
|
40
38
|
<Link
|
|
41
39
|
to="/"
|
|
42
|
-
className=
|
|
40
|
+
className={buttonVariants({ variant: "outline", size: "lg" })}
|
|
43
41
|
onClick={(e: any) => {
|
|
44
42
|
e.preventDefault()
|
|
45
43
|
window.history.back()
|
|
@@ -14,7 +14,7 @@ export function Details(props: { summary: string; children: React.ReactNode }) {
|
|
|
14
14
|
<Collapsible
|
|
15
15
|
open={open}
|
|
16
16
|
onOpenChange={setOpen}
|
|
17
|
-
className="not-prose my-4 rounded-
|
|
17
|
+
className="not-prose my-4 rounded-card border border-border bg-card px-4 py-3"
|
|
18
18
|
>
|
|
19
19
|
<CollapsibleTrigger className="flex w-full cursor-pointer items-center gap-2 text-sm font-semibold select-none">
|
|
20
20
|
<ChevronRight
|
|
@@ -11,7 +11,7 @@ export function FileTree(props: { tree: string }) {
|
|
|
11
11
|
const items: TreeItem[] = JSON.parse(props.tree)
|
|
12
12
|
|
|
13
13
|
return (
|
|
14
|
-
<div className="not-prose my-4 rounded-
|
|
14
|
+
<div className="not-prose my-4 rounded-card border border-border bg-card p-4 font-mono text-sm">
|
|
15
15
|
<TreeItems items={items} depth={0} />
|
|
16
16
|
</div>
|
|
17
17
|
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { config } from "livemark:virtual"
|
|
2
|
+
import { useLocation, useMatch } from "@tanstack/react-router"
|
|
3
|
+
import { useState } from "react"
|
|
4
|
+
import { cn } from "cn"
|
|
5
|
+
import { currentSection } from "../content/article.ts"
|
|
6
|
+
import { activeSiteLink } from "../helpers/section.ts"
|
|
7
|
+
import { HeaderMenu } from "./HeaderMenu.tsx"
|
|
8
|
+
import { HeaderNav } from "./HeaderNav.tsx"
|
|
9
|
+
import { Search } from "./Search.tsx"
|
|
10
|
+
import { SiteLink } from "./SiteLink.tsx"
|
|
11
|
+
import { SiteTitle } from "./SiteTitle.tsx"
|
|
12
|
+
import { Theme } from "./Theme.tsx"
|
|
13
|
+
|
|
14
|
+
/** Sticky site header: title, header sections and links, search and theme. `toggle`
|
|
15
|
+
* sits before the title from `lg`; `menu` opens the phone navigation */
|
|
16
|
+
export function Header(props: { toggle?: React.ReactNode; menu?: React.ReactNode }) {
|
|
17
|
+
const pathname = useLocation({ select: l => l.pathname })
|
|
18
|
+
const articleRoute = useMatch({ from: "/$", shouldThrow: false })
|
|
19
|
+
const activeSection = articleRoute
|
|
20
|
+
? currentSection(`/${pathname.replace(/^\/|\/$/g, "")}/`)
|
|
21
|
+
: undefined
|
|
22
|
+
const siteLinkTarget = activeSiteLink(pathname, config.sections ?? [])
|
|
23
|
+
const [compactSearch, setCompactSearch] = useState(false)
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<header className="sticky top-0 z-20 flex has-[[data-header-search]]:z-40 h-16 shrink-0 items-center border-b bg-background">
|
|
27
|
+
<div
|
|
28
|
+
className={cn(
|
|
29
|
+
"flex min-w-0 items-center self-stretch pl-4 lg:shrink-0",
|
|
30
|
+
props.toggle ? "pr-4" : "lg:w-[calc(var(--sidebar-width,16rem)+4rem)]",
|
|
31
|
+
)}
|
|
32
|
+
>
|
|
33
|
+
{props.toggle && <div className="hidden lg:flex">{props.toggle}</div>}
|
|
34
|
+
<SiteLink
|
|
35
|
+
to={siteLinkTarget}
|
|
36
|
+
className={cn("flex min-w-0 items-center gap-2", props.toggle && "lg:hidden")}
|
|
37
|
+
>
|
|
38
|
+
<SiteTitle />
|
|
39
|
+
</SiteLink>
|
|
40
|
+
</div>
|
|
41
|
+
<HeaderNav
|
|
42
|
+
activePrefix={activeSection?.prefix}
|
|
43
|
+
onCompactChange={setCompactSearch}
|
|
44
|
+
/>
|
|
45
|
+
<div className="ml-auto flex shrink-0 items-center gap-1 pr-2 lg:pr-1">
|
|
46
|
+
<Search compact={compactSearch} />
|
|
47
|
+
<Theme />
|
|
48
|
+
<div className="lg:hidden">{props.menu ?? <HeaderMenu />}</div>
|
|
49
|
+
</div>
|
|
50
|
+
</header>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { config } from "livemark:virtual"
|
|
2
|
+
import { useNavigate } from "@tanstack/react-router"
|
|
3
|
+
import { Menu } from "lucide-react"
|
|
4
|
+
import { Button } from "../elements/button.tsx"
|
|
5
|
+
import { DynamicIcon } from "../helpers/dynamic-icon.tsx"
|
|
6
|
+
import { useNavItems } from "../helpers/nav-items.tsx"
|
|
7
|
+
import { prefixUrl } from "../helpers/prefix-url.ts"
|
|
8
|
+
import { MenuSheet } from "./MenuSheet.tsx"
|
|
9
|
+
|
|
10
|
+
/** Phone navigation for a `Header` without a sidebar: the header sections and links */
|
|
11
|
+
export function HeaderMenu() {
|
|
12
|
+
const items = useNavItems()
|
|
13
|
+
const navigate = useNavigate()
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<MenuSheet
|
|
17
|
+
title="Navigation"
|
|
18
|
+
items={items.map(item => ({
|
|
19
|
+
id: item.key,
|
|
20
|
+
label: item.suffix ? `${item.title} (${item.suffix})` : item.title,
|
|
21
|
+
icon: item.icon && <DynamicIcon name={item.icon} className="size-4 shrink-0" />,
|
|
22
|
+
active: item.active,
|
|
23
|
+
onSelect: () => {
|
|
24
|
+
if (item.href) window.location.assign(prefixUrl(item.href, config.base))
|
|
25
|
+
else if (item.target) navigate({ to: item.target })
|
|
26
|
+
},
|
|
27
|
+
}))}
|
|
28
|
+
trigger={
|
|
29
|
+
<Button
|
|
30
|
+
variant="ghost"
|
|
31
|
+
size="icon-sm"
|
|
32
|
+
title="Navigation"
|
|
33
|
+
aria-label="Navigation"
|
|
34
|
+
className="cursor-pointer"
|
|
35
|
+
/>
|
|
36
|
+
}
|
|
37
|
+
>
|
|
38
|
+
<Menu />
|
|
39
|
+
</MenuSheet>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { ChevronDown } from "lucide-react"
|
|
2
|
+
import { useLayoutEffect, useRef, useState } from "react"
|
|
3
|
+
import { cn } from "cn"
|
|
4
|
+
import { type NavItem, renderNavAnchor, useNavItems } from "../helpers/nav-items.tsx"
|
|
5
|
+
import {
|
|
6
|
+
DropdownMenu,
|
|
7
|
+
DropdownMenuContent,
|
|
8
|
+
DropdownMenuItem,
|
|
9
|
+
DropdownMenuTrigger,
|
|
10
|
+
} from "../elements/dropdown-menu.tsx"
|
|
11
|
+
|
|
12
|
+
// The `lg:w-56` Search field minus its 36px icon-only form
|
|
13
|
+
const SEARCH_COMPACT_SAVING = 188
|
|
14
|
+
|
|
15
|
+
/** Header sections and links from `lg`: once they outgrow the bar, Search turns
|
|
16
|
+
* compact and the rest fold into a "More" menu */
|
|
17
|
+
export function HeaderNav(props: {
|
|
18
|
+
activePrefix?: string
|
|
19
|
+
onCompactChange: (compact: boolean) => void
|
|
20
|
+
}) {
|
|
21
|
+
const items = useNavItems(props.activePrefix)
|
|
22
|
+
const strip = useRef<HTMLElement>(null)
|
|
23
|
+
const measure = useRef<HTMLDivElement>(null)
|
|
24
|
+
const [visibleCount, setVisibleCount] = useState(items.length)
|
|
25
|
+
const onCompactChange = useRef(props.onCompactChange)
|
|
26
|
+
onCompactChange.current = props.onCompactChange
|
|
27
|
+
|
|
28
|
+
useLayoutEffect(() => {
|
|
29
|
+
let compact = false
|
|
30
|
+
const fit = () => {
|
|
31
|
+
if (!strip.current || !measure.current) return
|
|
32
|
+
const style = getComputedStyle(strip.current)
|
|
33
|
+
const width =
|
|
34
|
+
strip.current.clientWidth -
|
|
35
|
+
parseFloat(style.paddingLeft) -
|
|
36
|
+
parseFloat(style.paddingRight)
|
|
37
|
+
if (width <= 0) return
|
|
38
|
+
// Measured as if Search were full, so toggling it never feeds back into the fit
|
|
39
|
+
const room = width - (compact ? SEARCH_COMPACT_SAVING : 0)
|
|
40
|
+
const gap = parseFloat(getComputedStyle(measure.current).columnGap) || 0
|
|
41
|
+
const widths = [...measure.current.children].map(
|
|
42
|
+
child => child.getBoundingClientRect().width,
|
|
43
|
+
)
|
|
44
|
+
const more = widths.pop() ?? 0
|
|
45
|
+
const total = widths.reduce((sum, w) => sum + w, 0) + gap * (widths.length - 1)
|
|
46
|
+
|
|
47
|
+
compact = total > room
|
|
48
|
+
let count = widths.length
|
|
49
|
+
if (total > room + SEARCH_COMPACT_SAVING) {
|
|
50
|
+
let used = more
|
|
51
|
+
count = 0
|
|
52
|
+
for (const w of widths) {
|
|
53
|
+
if (used + gap + w > room + SEARCH_COMPACT_SAVING) break
|
|
54
|
+
used += gap + w
|
|
55
|
+
count++
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
onCompactChange.current(compact)
|
|
59
|
+
setVisibleCount(count)
|
|
60
|
+
}
|
|
61
|
+
fit()
|
|
62
|
+
const observer = new ResizeObserver(fit)
|
|
63
|
+
if (strip.current) observer.observe(strip.current)
|
|
64
|
+
if (measure.current) observer.observe(measure.current)
|
|
65
|
+
return () => observer.disconnect()
|
|
66
|
+
}, [])
|
|
67
|
+
|
|
68
|
+
const shown = items.slice(0, visibleCount)
|
|
69
|
+
const folded = items.slice(visibleCount)
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<nav
|
|
73
|
+
ref={strip}
|
|
74
|
+
className="relative hidden w-0 min-w-0 flex-1 items-center gap-6 self-stretch overflow-hidden px-6 text-sm lg:flex xl:gap-8"
|
|
75
|
+
>
|
|
76
|
+
{shown.map(item => (
|
|
77
|
+
<HeaderNavLink key={item.key} item={item} />
|
|
78
|
+
))}
|
|
79
|
+
{folded.length > 0 && <HeaderNavMore items={folded} />}
|
|
80
|
+
<div
|
|
81
|
+
ref={measure}
|
|
82
|
+
aria-hidden
|
|
83
|
+
inert
|
|
84
|
+
className="invisible absolute left-0 flex gap-6 whitespace-nowrap xl:gap-8"
|
|
85
|
+
>
|
|
86
|
+
{items.map(item => (
|
|
87
|
+
<HeaderNavLink key={item.key} item={item} />
|
|
88
|
+
))}
|
|
89
|
+
<HeaderNavMoreTrigger active={false} />
|
|
90
|
+
</div>
|
|
91
|
+
</nav>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function HeaderNavLink(props: { item: NavItem }) {
|
|
96
|
+
return renderNavAnchor(
|
|
97
|
+
props.item,
|
|
98
|
+
cn(
|
|
99
|
+
"inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap text-foreground",
|
|
100
|
+
props.item.active ? ACTIVE : IDLE,
|
|
101
|
+
),
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function HeaderNavMore(props: { items: NavItem[] }) {
|
|
106
|
+
return (
|
|
107
|
+
<DropdownMenu>
|
|
108
|
+
<DropdownMenuTrigger
|
|
109
|
+
render={<HeaderNavMoreTrigger active={props.items.some(item => item.active)} />}
|
|
110
|
+
/>
|
|
111
|
+
<DropdownMenuContent align="end" className="w-auto">
|
|
112
|
+
{props.items.map(item => (
|
|
113
|
+
<DropdownMenuItem
|
|
114
|
+
key={item.key}
|
|
115
|
+
className={cn("cursor-pointer", item.active && "font-medium")}
|
|
116
|
+
render={renderNavAnchor(item)}
|
|
117
|
+
/>
|
|
118
|
+
))}
|
|
119
|
+
</DropdownMenuContent>
|
|
120
|
+
</DropdownMenu>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function HeaderNavMoreTrigger(
|
|
125
|
+
props: React.ComponentProps<"button"> & { active: boolean },
|
|
126
|
+
) {
|
|
127
|
+
const { active, className, ...rest } = props
|
|
128
|
+
return (
|
|
129
|
+
<button
|
|
130
|
+
type="button"
|
|
131
|
+
{...rest}
|
|
132
|
+
className={cn(
|
|
133
|
+
"inline-flex shrink-0 cursor-pointer items-center gap-1 whitespace-nowrap text-foreground",
|
|
134
|
+
active ? ACTIVE : IDLE,
|
|
135
|
+
className,
|
|
136
|
+
)}
|
|
137
|
+
>
|
|
138
|
+
More
|
|
139
|
+
<ChevronDown className="size-3.5" />
|
|
140
|
+
</button>
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const ACTIVE = "font-medium border-b-2 border-foreground pb-0.5 -mb-0.5"
|
|
145
|
+
const IDLE = "opacity-80 hover:opacity-100 transition-opacity"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef, useState } from "react"
|
|
2
|
+
import { X } from "lucide-react"
|
|
3
|
+
import { SearchResultGroups, useArticleSearch } from "../helpers/article-search.tsx"
|
|
4
|
+
import { Command, CommandEmpty, CommandInput, CommandList } from "../elements/command.tsx"
|
|
5
|
+
|
|
6
|
+
/** Search field that takes over the header below `lg`, with results dropping under it */
|
|
7
|
+
export function HeaderSearch(props: { onClose: () => void }) {
|
|
8
|
+
const search = useArticleSearch()
|
|
9
|
+
const bar = useRef<HTMLDivElement>(null)
|
|
10
|
+
const [panelTop, setPanelTop] = useState<number>()
|
|
11
|
+
|
|
12
|
+
// Measured, not `top-16`: while the Banner is in view it pushes the header down.
|
|
13
|
+
useLayoutEffect(() => {
|
|
14
|
+
const measure = () => setPanelTop(bar.current?.getBoundingClientRect().bottom)
|
|
15
|
+
measure()
|
|
16
|
+
window.addEventListener("scroll", measure, { passive: true })
|
|
17
|
+
window.addEventListener("resize", measure)
|
|
18
|
+
return () => {
|
|
19
|
+
window.removeEventListener("scroll", measure)
|
|
20
|
+
window.removeEventListener("resize", measure)
|
|
21
|
+
}
|
|
22
|
+
}, [])
|
|
23
|
+
|
|
24
|
+
// `data-header-search` lifts the header over the Toc bar and BackToTop (Layout).
|
|
25
|
+
return (
|
|
26
|
+
<Command
|
|
27
|
+
ref={bar}
|
|
28
|
+
data-header-search
|
|
29
|
+
shouldFilter={false}
|
|
30
|
+
loop
|
|
31
|
+
onKeyDown={event => {
|
|
32
|
+
if (event.key === "Escape") props.onClose()
|
|
33
|
+
}}
|
|
34
|
+
className="absolute inset-0 z-10 overflow-visible rounded-none! bg-background p-0 lg:hidden"
|
|
35
|
+
>
|
|
36
|
+
<div className="flex h-full items-center gap-1 pl-1 pr-2">
|
|
37
|
+
<div className="flex-1 [&_[data-slot=command-input-wrapper]]:p-0 [&_[data-slot=input-group]]:border-transparent! [&_[data-slot=input-group]]:bg-transparent! [&_[data-slot=input-group]]:ring-0!">
|
|
38
|
+
<CommandInput
|
|
39
|
+
autoFocus
|
|
40
|
+
placeholder="Search docs..."
|
|
41
|
+
value={search.query}
|
|
42
|
+
onValueChange={search.searchArticles}
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
onClick={props.onClose}
|
|
48
|
+
aria-label="Close search"
|
|
49
|
+
title="Close search"
|
|
50
|
+
className="flex size-9 shrink-0 items-center justify-center rounded-control text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer"
|
|
51
|
+
>
|
|
52
|
+
<X className="size-5" />
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
55
|
+
<div
|
|
56
|
+
style={{ top: panelTop }}
|
|
57
|
+
className="fixed inset-x-0 bottom-0 flex flex-col border-t bg-background p-1"
|
|
58
|
+
>
|
|
59
|
+
<CommandList className="max-h-none flex-1 overscroll-contain">
|
|
60
|
+
<CommandEmpty>
|
|
61
|
+
{search.query.trim()
|
|
62
|
+
? "No results found."
|
|
63
|
+
: "Type to search across all contents."}
|
|
64
|
+
</CommandEmpty>
|
|
65
|
+
<SearchResultGroups
|
|
66
|
+
query={search.query}
|
|
67
|
+
grouped={search.grouped}
|
|
68
|
+
onSelect={path => {
|
|
69
|
+
props.onClose()
|
|
70
|
+
search.selectArticle(path)
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
</CommandList>
|
|
74
|
+
</div>
|
|
75
|
+
</Command>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
@@ -3,7 +3,7 @@ import { Badge } from "../elements/badge.tsx"
|
|
|
3
3
|
/** Inline badge rendered from :badge text directives */
|
|
4
4
|
export function InlineBadge(props: {
|
|
5
5
|
label: string
|
|
6
|
-
variant?: "default" | "secondary" | "destructive" | "outline"
|
|
6
|
+
variant?: "default" | "secondary" | "positive" | "warning" | "destructive" | "outline"
|
|
7
7
|
}) {
|
|
8
8
|
return <Badge variant={props.variant}>{props.label}</Badge>
|
|
9
9
|
}
|
|
@@ -9,7 +9,7 @@ export function InlineToc(props: { maxLevel?: string }) {
|
|
|
9
9
|
if (items.length === 0) return null
|
|
10
10
|
|
|
11
11
|
return (
|
|
12
|
-
<nav className="not-prose my-8 rounded-
|
|
12
|
+
<nav className="not-prose my-8 rounded-card border border-border bg-card p-6">
|
|
13
13
|
<p className="text-base font-semibold mb-4">Table of Contents</p>
|
|
14
14
|
<ul className="text-base space-y-2.5">
|
|
15
15
|
{items.map(item => (
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
import { config } from "livemark:virtual"
|
|
2
|
-
import { Link, useLocation, useMatch } from "@tanstack/react-router"
|
|
3
|
-
import { useHotkey } from "@tanstack/react-hotkeys"
|
|
4
|
-
import {
|
|
5
|
-
currentSection,
|
|
6
|
-
sectionFirstArticle,
|
|
7
|
-
sectionFlatArticles,
|
|
8
|
-
sortedArticles,
|
|
9
|
-
} from "../content/article.ts"
|
|
10
|
-
import { DynamicIcon } from "../helpers/dynamic-icon.tsx"
|
|
11
|
-
import { prefixUrl } from "../helpers/prefix-url.ts"
|
|
12
|
-
import { activeSiteLink, customSectionActive } from "../helpers/section.ts"
|
|
13
1
|
import {
|
|
14
2
|
SidebarInset,
|
|
15
3
|
SidebarProvider,
|
|
@@ -18,160 +6,25 @@ import {
|
|
|
18
6
|
} from "../elements/sidebar.tsx"
|
|
19
7
|
import { BackToTop } from "./BackToTop.tsx"
|
|
20
8
|
import { Banner } from "./Banner.tsx"
|
|
9
|
+
import { Header } from "./Header.tsx"
|
|
21
10
|
import { Sidebar } from "./Sidebar.tsx"
|
|
22
|
-
import { SiteLink } from "./SiteLink.tsx"
|
|
23
|
-
import { SiteTitle } from "./SiteTitle.tsx"
|
|
24
|
-
|
|
25
|
-
function splatFor(pathname: string) {
|
|
26
|
-
return { _splat: pathname.replace(/^\/|\/$/g, "") }
|
|
27
|
-
}
|
|
28
11
|
|
|
12
|
+
/** Site chrome around a page: banner, header, sidebar and back-to-top */
|
|
29
13
|
export function Layout(props: { withSidebar?: boolean; children?: React.ReactNode }) {
|
|
30
|
-
const pathname = useLocation({ select: l => l.pathname })
|
|
31
|
-
const articleRoute = useMatch({ from: "/$", shouldThrow: false })
|
|
32
|
-
const activeSection = articleRoute
|
|
33
|
-
? currentSection(`/${pathname.replace(/^\/|\/$/g, "")}/`)
|
|
34
|
-
: undefined
|
|
35
|
-
const siteLinkTarget = activeSiteLink(pathname, config.sections ?? [])
|
|
36
|
-
|
|
37
|
-
useHotkey("J", () =>
|
|
38
|
-
window.scrollBy({ top: window.innerHeight * 0.8, behavior: "smooth" }),
|
|
39
|
-
)
|
|
40
|
-
useHotkey("K", () =>
|
|
41
|
-
window.scrollBy({ top: -window.innerHeight * 0.8, behavior: "smooth" }),
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
const sections = config.sections
|
|
45
|
-
|
|
46
|
-
const header = (
|
|
47
|
-
<header className="sticky top-0 z-20 flex h-16 shrink-0 items-center border-b bg-background">
|
|
48
|
-
<div
|
|
49
|
-
className={`flex items-center self-stretch pl-4 ${props.withSidebar ? "pr-4" : "lg:pr-20"}`}
|
|
50
|
-
>
|
|
51
|
-
{props.withSidebar ? (
|
|
52
|
-
<>
|
|
53
|
-
<div className="hidden lg:flex">
|
|
54
|
-
<SidebarTrigger />
|
|
55
|
-
</div>
|
|
56
|
-
<SiteLink to={siteLinkTarget} className="lg:hidden flex items-center gap-2">
|
|
57
|
-
<SiteTitle />
|
|
58
|
-
</SiteLink>
|
|
59
|
-
</>
|
|
60
|
-
) : (
|
|
61
|
-
<SiteLink to={siteLinkTarget} className="flex items-center gap-2">
|
|
62
|
-
<SiteTitle />
|
|
63
|
-
</SiteLink>
|
|
64
|
-
)}
|
|
65
|
-
</div>
|
|
66
|
-
<div className="hidden lg:flex flex-1 items-center gap-8 self-stretch px-6 text-sm">
|
|
67
|
-
{sections?.length ? (
|
|
68
|
-
sections
|
|
69
|
-
.filter(section => section.position === "header")
|
|
70
|
-
.map(section => {
|
|
71
|
-
const icon = section.icon
|
|
72
|
-
if (section.type === "custom") {
|
|
73
|
-
const isActive = customSectionActive(section.url, pathname)
|
|
74
|
-
return (
|
|
75
|
-
<a
|
|
76
|
-
key={section.url}
|
|
77
|
-
href={prefixUrl(section.url, config.base)}
|
|
78
|
-
className={`inline-flex items-center gap-1.5 text-foreground ${
|
|
79
|
-
isActive
|
|
80
|
-
? "font-medium border-b-2 border-foreground pb-0.5 -mb-0.5"
|
|
81
|
-
: "opacity-80 hover:opacity-100 transition-opacity"
|
|
82
|
-
}`}
|
|
83
|
-
>
|
|
84
|
-
{icon && <DynamicIcon name={icon} className="size-3.5" />}
|
|
85
|
-
<span>{section.title}</span>
|
|
86
|
-
</a>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
const isActive = activeSection?.prefix === section.prefix
|
|
90
|
-
const target =
|
|
91
|
-
section.type === "blog" || section.type === "changelog"
|
|
92
|
-
? section.prefix
|
|
93
|
-
: sectionFirstArticle.get(section.prefix)
|
|
94
|
-
const latestVersion =
|
|
95
|
-
section.type === "changelog" && section.version
|
|
96
|
-
? sortedArticles.find(
|
|
97
|
-
a => a.path === sectionFlatArticles.get(section.prefix)?.[0],
|
|
98
|
-
)?.title
|
|
99
|
-
: undefined
|
|
100
|
-
return (
|
|
101
|
-
<Link
|
|
102
|
-
key={section.prefix}
|
|
103
|
-
to={target === "/" ? "/" : "/$"}
|
|
104
|
-
params={target && target !== "/" ? splatFor(target) : {}}
|
|
105
|
-
className={`inline-flex items-center gap-1.5 text-foreground ${
|
|
106
|
-
isActive
|
|
107
|
-
? "font-medium border-b-2 border-foreground pb-0.5 -mb-0.5"
|
|
108
|
-
: "opacity-80 hover:opacity-100 transition-opacity"
|
|
109
|
-
}`}
|
|
110
|
-
>
|
|
111
|
-
{icon && <DynamicIcon name={icon} className="size-3.5" />}
|
|
112
|
-
<span>
|
|
113
|
-
{section.title}
|
|
114
|
-
{latestVersion && (
|
|
115
|
-
<span className="opacity-80"> ({latestVersion})</span>
|
|
116
|
-
)}
|
|
117
|
-
</span>
|
|
118
|
-
</Link>
|
|
119
|
-
)
|
|
120
|
-
})
|
|
121
|
-
) : (
|
|
122
|
-
<Link
|
|
123
|
-
to="/"
|
|
124
|
-
className="text-foreground font-medium underline underline-offset-4"
|
|
125
|
-
>
|
|
126
|
-
Docs
|
|
127
|
-
</Link>
|
|
128
|
-
)}
|
|
129
|
-
{config.links
|
|
130
|
-
?.filter(
|
|
131
|
-
link =>
|
|
132
|
-
link.position === "header" &&
|
|
133
|
-
(!link.prefix || link.prefix === activeSection?.prefix),
|
|
134
|
-
)
|
|
135
|
-
.map(link => (
|
|
136
|
-
<a
|
|
137
|
-
key={link.url}
|
|
138
|
-
href={prefixUrl(link.url, config.base)}
|
|
139
|
-
className="text-foreground opacity-80 hover:opacity-100 transition-opacity"
|
|
140
|
-
>
|
|
141
|
-
{link.icon && (
|
|
142
|
-
<DynamicIcon
|
|
143
|
-
name={link.icon}
|
|
144
|
-
className="inline size-3.5 align-[-0.125em]"
|
|
145
|
-
/>
|
|
146
|
-
)}{" "}
|
|
147
|
-
{link.title}
|
|
148
|
-
</a>
|
|
149
|
-
))}
|
|
150
|
-
<Banner />
|
|
151
|
-
</div>
|
|
152
|
-
<div className="lg:hidden ml-auto pr-2">
|
|
153
|
-
<SidebarTrigger />
|
|
154
|
-
</div>
|
|
155
|
-
</header>
|
|
156
|
-
)
|
|
157
|
-
|
|
158
14
|
return (
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
15
|
+
<>
|
|
16
|
+
<Banner />
|
|
17
|
+
<SidebarProvider
|
|
18
|
+
key={props.withSidebar ? "sidebar" : "mini"}
|
|
19
|
+
defaultOpen={!!props.withSidebar}
|
|
20
|
+
>
|
|
21
|
+
<SidebarShell withSidebar={props.withSidebar}>{props.children}</SidebarShell>
|
|
22
|
+
</SidebarProvider>
|
|
23
|
+
</>
|
|
167
24
|
)
|
|
168
25
|
}
|
|
169
26
|
|
|
170
|
-
function SidebarShell(props: {
|
|
171
|
-
withSidebar?: boolean
|
|
172
|
-
header: React.ReactNode
|
|
173
|
-
children?: React.ReactNode
|
|
174
|
-
}) {
|
|
27
|
+
function SidebarShell(props: { withSidebar?: boolean; children?: React.ReactNode }) {
|
|
175
28
|
const { isMobile, setOpenMobile } = useSidebar()
|
|
176
29
|
const onClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
177
30
|
if (!isMobile) return
|
|
@@ -181,7 +34,10 @@ function SidebarShell(props: {
|
|
|
181
34
|
<div style={{ display: "contents" }} onClick={onClick}>
|
|
182
35
|
<Sidebar withSidebar={props.withSidebar} />
|
|
183
36
|
<SidebarInset>
|
|
184
|
-
|
|
37
|
+
<Header
|
|
38
|
+
toggle={props.withSidebar && <SidebarTrigger />}
|
|
39
|
+
menu={<SidebarTrigger />}
|
|
40
|
+
/>
|
|
185
41
|
<main className="flex-1">{props.children}</main>
|
|
186
42
|
<BackToTop />
|
|
187
43
|
</SidebarInset>
|