svelte-docsmith 0.10.0 → 0.11.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/bin/svelte-docsmith.mjs +13 -158
- package/dist/buildtime/archives.d.ts +18 -0
- package/dist/buildtime/archives.js +43 -0
- package/dist/buildtime/cli/archive-version.d.ts +18 -0
- package/dist/buildtime/cli/archive-version.js +104 -0
- package/dist/buildtime/cli/error.d.ts +9 -0
- package/dist/buildtime/cli/error.js +9 -0
- package/dist/buildtime/cli/run.d.ts +13 -0
- package/dist/buildtime/cli/run.js +62 -0
- package/dist/buildtime/{vite/git.d.ts → git.d.ts} +1 -1
- package/dist/buildtime/{vite/git.js → git.js} +15 -3
- package/dist/buildtime/paths.d.ts +7 -0
- package/dist/buildtime/paths.js +15 -0
- package/dist/buildtime/vite/collect.js +1 -1
- package/dist/buildtime/vite/index.js +9 -4
- package/dist/buildtime/vite/releases.js +1 -1
- package/dist/components/changelog/changelog-entry.svelte +6 -1
- package/dist/components/chrome/search.svelte +8 -5
- package/dist/components/chrome/version-banner.svelte +5 -20
- package/dist/components/chrome/version-banner.svelte.d.ts +3 -3
- package/dist/components/chrome/version-switcher.svelte +39 -49
- package/dist/components/chrome/version-switcher.svelte.d.ts +3 -9
- package/dist/components/docs-page-context.d.ts +20 -0
- package/dist/components/docs-page-context.js +41 -0
- package/dist/components/layouts/docs-header.svelte +9 -23
- package/dist/components/layouts/docs-header.svelte.d.ts +1 -9
- package/dist/components/layouts/docs-mobile-header.svelte +6 -21
- package/dist/components/layouts/docs-mobile-header.svelte.d.ts +1 -9
- package/dist/components/layouts/docs-shell.svelte +29 -28
- package/dist/core/changelog.d.ts +4 -1
- package/dist/core/content.d.ts +6 -1
- package/dist/core/docs-page.d.ts +15 -0
- package/dist/core/docs-page.js +20 -3
- package/dist/core/index.d.ts +1 -1
- package/dist/core/version.d.ts +36 -0
- package/dist/core/version.js +101 -0
- package/dist/search/context.svelte.d.ts +0 -2
- package/dist/search/context.svelte.js +0 -2
- package/package.json +1 -1
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import TriangleAlert from '@lucide/svelte/icons/triangle-alert';
|
|
3
3
|
import ArrowRight from '@lucide/svelte/icons/arrow-right';
|
|
4
|
-
import {
|
|
5
|
-
mapPathToVersion,
|
|
6
|
-
scopeContent,
|
|
7
|
-
type ResolvedVersion,
|
|
8
|
-
type DocsContentItem
|
|
9
|
-
} from '../../core/index.js';
|
|
4
|
+
import type { ResolvedVersion } from '../../core/index.js';
|
|
10
5
|
|
|
11
6
|
// Rendered by DocsShell only on an archived version, to warn a reader who
|
|
12
7
|
// landed there (usually from a search engine) and give them a one-click path
|
|
@@ -15,23 +10,13 @@
|
|
|
15
10
|
const {
|
|
16
11
|
active,
|
|
17
12
|
current,
|
|
18
|
-
|
|
19
|
-
content
|
|
13
|
+
href
|
|
20
14
|
}: {
|
|
21
15
|
active: ResolvedVersion;
|
|
22
16
|
current: ResolvedVersion;
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
/** This page under the current version, from the resolved page view. */
|
|
18
|
+
href: string;
|
|
25
19
|
} = $props();
|
|
26
|
-
|
|
27
|
-
const currentHref = $derived(
|
|
28
|
-
mapPathToVersion(
|
|
29
|
-
pathname,
|
|
30
|
-
active,
|
|
31
|
-
current,
|
|
32
|
-
scopeContent(content, current.id).map((c) => c.path)
|
|
33
|
-
)
|
|
34
|
-
);
|
|
35
20
|
</script>
|
|
36
21
|
|
|
37
22
|
<div class="docsmith-version-banner" role="note">
|
|
@@ -39,7 +24,7 @@
|
|
|
39
24
|
<p>
|
|
40
25
|
You're reading the <strong>{active.label}</strong> docs. The current version is
|
|
41
26
|
<strong>{current.label}</strong>.
|
|
42
|
-
<a href
|
|
27
|
+
<a {href}>View this page in {current.label} <ArrowRight size={14} /></a>
|
|
43
28
|
</p>
|
|
44
29
|
</div>
|
|
45
30
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ResolvedVersion } from '../../core/index.js';
|
|
2
2
|
type $$ComponentProps = {
|
|
3
3
|
active: ResolvedVersion;
|
|
4
4
|
current: ResolvedVersion;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/** This page under the current version, from the resolved page view. */
|
|
6
|
+
href: string;
|
|
7
7
|
};
|
|
8
8
|
declare const VersionBanner: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
9
|
type VersionBanner = ReturnType<typeof VersionBanner>;
|
|
@@ -4,60 +4,50 @@
|
|
|
4
4
|
import * as DropdownMenu from '../shadcn/dropdown-menu/index.js';
|
|
5
5
|
import Check from '@lucide/svelte/icons/check';
|
|
6
6
|
import ChevronsUpDown from '@lucide/svelte/icons/chevrons-up-down';
|
|
7
|
-
import {
|
|
8
|
-
mapPathToVersion,
|
|
9
|
-
scopeContent,
|
|
10
|
-
type ResolvedVersion,
|
|
11
|
-
type DocsContentItem
|
|
12
|
-
} from '../../core/index.js';
|
|
7
|
+
import type { VersionLink } from '../../core/index.js';
|
|
13
8
|
|
|
9
|
+
// Purely presentational: where each version leads is resolved once, with the
|
|
10
|
+
// rest of the page view, in `core/docs-page.ts`.
|
|
14
11
|
const {
|
|
15
|
-
|
|
16
|
-
active,
|
|
17
|
-
pathname,
|
|
18
|
-
content
|
|
12
|
+
links
|
|
19
13
|
}: {
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
/** The version the current page belongs to. */
|
|
23
|
-
active: ResolvedVersion;
|
|
24
|
-
/** The current normalized pathname, e.g. `/docs/v2/intro`. */
|
|
25
|
-
pathname: string;
|
|
26
|
-
/** Full content index, to map the current page into the chosen version. */
|
|
27
|
-
content: DocsContentItem[];
|
|
14
|
+
/** Every declared version and its destination, in switcher order. */
|
|
15
|
+
links: VersionLink[];
|
|
28
16
|
} = $props();
|
|
29
17
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
const active = $derived(links.find((link) => link.active));
|
|
19
|
+
|
|
20
|
+
function select(link: VersionLink) {
|
|
21
|
+
if (link.active) return;
|
|
22
|
+
goto(link.href);
|
|
34
23
|
}
|
|
35
24
|
</script>
|
|
36
25
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
</DropdownMenu.Root>
|
|
26
|
+
<!-- Nothing to switch from without an active version, which only happens on an
|
|
27
|
+
unversioned site, where the header doesn't render this at all. -->
|
|
28
|
+
{#if active}
|
|
29
|
+
<DropdownMenu.Root>
|
|
30
|
+
<DropdownMenu.Trigger>
|
|
31
|
+
{#snippet child({ props })}
|
|
32
|
+
<Button
|
|
33
|
+
variant="outline"
|
|
34
|
+
size="sm"
|
|
35
|
+
class="h-8 gap-1.5 px-2.5 font-medium"
|
|
36
|
+
aria-label={`Documentation version: ${active.label}. Change version`}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
<span class="truncate">{active.label}</span>
|
|
40
|
+
<ChevronsUpDown class="size-3.5 shrink-0 opacity-60" aria-hidden="true" />
|
|
41
|
+
</Button>
|
|
42
|
+
{/snippet}
|
|
43
|
+
</DropdownMenu.Trigger>
|
|
44
|
+
<DropdownMenu.Content align="start" class="w-44">
|
|
45
|
+
{#each links as link (link.id)}
|
|
46
|
+
<DropdownMenu.Item onSelect={() => select(link)} class="gap-2">
|
|
47
|
+
<Check class="size-4 {link.active ? 'opacity-100' : 'opacity-0'}" aria-hidden="true" />
|
|
48
|
+
<span class="flex-1 truncate">{link.label}</span>
|
|
49
|
+
</DropdownMenu.Item>
|
|
50
|
+
{/each}
|
|
51
|
+
</DropdownMenu.Content>
|
|
52
|
+
</DropdownMenu.Root>
|
|
53
|
+
{/if}
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { VersionLink } from '../../core/index.js';
|
|
2
2
|
type $$ComponentProps = {
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
/** The version the current page belongs to. */
|
|
6
|
-
active: ResolvedVersion;
|
|
7
|
-
/** The current normalized pathname, e.g. `/docs/v2/intro`. */
|
|
8
|
-
pathname: string;
|
|
9
|
-
/** Full content index, to map the current page into the chosen version. */
|
|
10
|
-
content: DocsContentItem[];
|
|
3
|
+
/** Every declared version and its destination, in switcher order. */
|
|
4
|
+
links: VersionLink[];
|
|
11
5
|
};
|
|
12
6
|
declare const VersionSwitcher: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
13
7
|
type VersionSwitcher = ReturnType<typeof VersionSwitcher>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DocsPageView } from '../core/index.js';
|
|
2
|
+
/** A live read of the page view: `view` re-reads the shell's `$derived`. */
|
|
3
|
+
export type DocsPageContext = {
|
|
4
|
+
readonly view: DocsPageView;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Publish the page view. `DocsShell` calls this once, with a getter rather than
|
|
8
|
+
* a value, so readers see the current `$derived` rather than the one that
|
|
9
|
+
* existed at init.
|
|
10
|
+
*/
|
|
11
|
+
export declare function setDocsPage(view: () => DocsPageView): void;
|
|
12
|
+
/**
|
|
13
|
+
* Read the page view. `getContext` only works during init, so this hands back
|
|
14
|
+
* an accessor rather than a snapshot: hold it at init, read `.view` where the
|
|
15
|
+
* value is used, and the read stays reactive.
|
|
16
|
+
*
|
|
17
|
+
* Throws outside `DocsShell`. Every caller is internal chrome the shell renders
|
|
18
|
+
* itself, so an absent context is a wiring bug, not a supported mode.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useDocsPage(): DocsPageContext;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The resolved page view, on context.
|
|
3
|
+
*
|
|
4
|
+
* `core/docs-page.ts` decides what the page is; this is the single route that
|
|
5
|
+
* decision travels to the chrome. Publishing it once is what keeps the headers
|
|
6
|
+
* from taking props described in terms of their grandchildren, and the search
|
|
7
|
+
* scope from being pushed into shared mutable state by an effect.
|
|
8
|
+
*
|
|
9
|
+
* Sits at the root of `components/` rather than in a concern folder of its own:
|
|
10
|
+
* `core/` stays free of any Svelte import, and both `layouts/` and `chrome/`
|
|
11
|
+
* read this, so it can't live in either without one importing the other.
|
|
12
|
+
*/
|
|
13
|
+
import { getContext, setContext } from 'svelte';
|
|
14
|
+
const KEY = Symbol('docsmith-page');
|
|
15
|
+
/**
|
|
16
|
+
* Publish the page view. `DocsShell` calls this once, with a getter rather than
|
|
17
|
+
* a value, so readers see the current `$derived` rather than the one that
|
|
18
|
+
* existed at init.
|
|
19
|
+
*/
|
|
20
|
+
export function setDocsPage(view) {
|
|
21
|
+
setContext(KEY, view);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read the page view. `getContext` only works during init, so this hands back
|
|
25
|
+
* an accessor rather than a snapshot: hold it at init, read `.view` where the
|
|
26
|
+
* value is used, and the read stays reactive.
|
|
27
|
+
*
|
|
28
|
+
* Throws outside `DocsShell`. Every caller is internal chrome the shell renders
|
|
29
|
+
* itself, so an absent context is a wiring bug, not a supported mode.
|
|
30
|
+
*/
|
|
31
|
+
export function useDocsPage() {
|
|
32
|
+
const get = getContext(KEY);
|
|
33
|
+
if (!get) {
|
|
34
|
+
throw new Error('[svelte-docsmith] this component must be rendered inside <DocsShell>.');
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
get view() {
|
|
38
|
+
return get();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -7,46 +7,32 @@
|
|
|
7
7
|
import { useSearch } from '../../search/context.svelte.js';
|
|
8
8
|
import ThemeToggle from '../chrome/theme-toggle.svelte';
|
|
9
9
|
import VersionSwitcher from '../chrome/version-switcher.svelte';
|
|
10
|
-
import type {
|
|
11
|
-
DocsmithConfig,
|
|
12
|
-
DocsmithLink,
|
|
13
|
-
DocsContentItem,
|
|
14
|
-
ResolvedVersion
|
|
15
|
-
} from '../../core/index.js';
|
|
10
|
+
import type { DocsmithConfig, DocsmithLink } from '../../core/index.js';
|
|
16
11
|
import BookOpenText from '@lucide/svelte/icons/book-open-text';
|
|
17
12
|
import type { Snippet } from 'svelte';
|
|
18
|
-
import { page } from '$app/state';
|
|
19
13
|
import { cn } from '../../utils/cn.js';
|
|
20
14
|
import { normalizePath } from '../../utils/normalize-path.js';
|
|
15
|
+
import { useDocsPage } from '../docs-page-context.js';
|
|
21
16
|
|
|
22
17
|
const {
|
|
23
18
|
config,
|
|
24
19
|
logo,
|
|
25
|
-
actions
|
|
26
|
-
versions = [],
|
|
27
|
-
active,
|
|
28
|
-
content = [],
|
|
29
|
-
pathname = ''
|
|
20
|
+
actions
|
|
30
21
|
}: {
|
|
31
22
|
config: DocsmithConfig;
|
|
32
23
|
/** Custom logo mark; defaults to a book icon in a primary-tinted chip. */
|
|
33
24
|
logo?: Snippet;
|
|
34
25
|
/** Extra header controls, rendered before the theme toggle. */
|
|
35
26
|
actions?: Snippet;
|
|
36
|
-
/** Declared versions; renders the switcher once there's more than one. */
|
|
37
|
-
versions?: ResolvedVersion[];
|
|
38
|
-
/** The active version, for the switcher's current selection. */
|
|
39
|
-
active?: ResolvedVersion;
|
|
40
|
-
/** Content index, so the switcher can map the current page across versions. */
|
|
41
|
-
content?: DocsContentItem[];
|
|
42
|
-
/** Current normalized pathname, for the switcher's page mapping. */
|
|
43
|
-
pathname?: string;
|
|
44
27
|
} = $props();
|
|
45
28
|
|
|
46
29
|
// Present only when the consumer passed a `search` loader to DocsShell.
|
|
47
30
|
const search = useSearch();
|
|
48
31
|
|
|
49
|
-
|
|
32
|
+
// Everything about the page being read comes off the shell's one resolved
|
|
33
|
+
// view, including the normalized path the nav highlights against.
|
|
34
|
+
const docsPage = useDocsPage();
|
|
35
|
+
const current = $derived(docsPage.view.pathname);
|
|
50
36
|
|
|
51
37
|
/**
|
|
52
38
|
* A header link is usually the entry point to a whole section rather than a
|
|
@@ -109,9 +95,9 @@
|
|
|
109
95
|
</nav>
|
|
110
96
|
{/if}
|
|
111
97
|
|
|
112
|
-
{#if
|
|
98
|
+
{#if docsPage.view.versionLinks.length > 1}
|
|
113
99
|
<div class="px-1">
|
|
114
|
-
<VersionSwitcher {
|
|
100
|
+
<VersionSwitcher links={docsPage.view.versionLinks} />
|
|
115
101
|
</div>
|
|
116
102
|
{:else if config.version}
|
|
117
103
|
<div class="px-2">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DocsmithConfig
|
|
1
|
+
import type { DocsmithConfig } from '../../core/index.js';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
type $$ComponentProps = {
|
|
4
4
|
config: DocsmithConfig;
|
|
@@ -6,14 +6,6 @@ type $$ComponentProps = {
|
|
|
6
6
|
logo?: Snippet;
|
|
7
7
|
/** Extra header controls, rendered before the theme toggle. */
|
|
8
8
|
actions?: Snippet;
|
|
9
|
-
/** Declared versions; renders the switcher once there's more than one. */
|
|
10
|
-
versions?: ResolvedVersion[];
|
|
11
|
-
/** The active version, for the switcher's current selection. */
|
|
12
|
-
active?: ResolvedVersion;
|
|
13
|
-
/** Content index, so the switcher can map the current page across versions. */
|
|
14
|
-
content?: DocsContentItem[];
|
|
15
|
-
/** Current normalized pathname, for the switcher's page mapping. */
|
|
16
|
-
pathname?: string;
|
|
17
9
|
};
|
|
18
10
|
declare const DocsHeader: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
19
11
|
type DocsHeader = ReturnType<typeof DocsHeader>;
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { page } from '$app/state';
|
|
3
|
-
import type {
|
|
4
|
-
DocsmithConfig,
|
|
5
|
-
NavGroup,
|
|
6
|
-
DocsContentItem,
|
|
7
|
-
ResolvedVersion
|
|
8
|
-
} from '../../core/index.js';
|
|
3
|
+
import type { DocsmithConfig, NavGroup } from '../../core/index.js';
|
|
9
4
|
import type { TocItem } from '../../toc/index.js';
|
|
10
5
|
import DocsSidebar from './docs-sidebar.svelte';
|
|
11
6
|
import TableOfContents from '../chrome/table-of-contents.svelte';
|
|
@@ -17,6 +12,7 @@
|
|
|
17
12
|
import { Separator } from '../shadcn/separator/index.js';
|
|
18
13
|
import * as Sheet from '../shadcn/sheet/index.js';
|
|
19
14
|
import { useSearch } from '../../search/context.svelte.js';
|
|
15
|
+
import { useDocsPage } from '../docs-page-context.js';
|
|
20
16
|
import BookOpenText from '@lucide/svelte/icons/book-open-text';
|
|
21
17
|
import Menu from '@lucide/svelte/icons/menu';
|
|
22
18
|
import PanelRight from '@lucide/svelte/icons/panel-right';
|
|
@@ -30,11 +26,7 @@
|
|
|
30
26
|
tocItems = [],
|
|
31
27
|
tocActiveId = null,
|
|
32
28
|
logo,
|
|
33
|
-
actions
|
|
34
|
-
versions = [],
|
|
35
|
-
active,
|
|
36
|
-
content = [],
|
|
37
|
-
pathname = ''
|
|
29
|
+
actions
|
|
38
30
|
}: {
|
|
39
31
|
config: DocsmithConfig;
|
|
40
32
|
/** Sidebar groups; omit on non-doc pages (the landing/`page` layout). */
|
|
@@ -47,17 +39,10 @@
|
|
|
47
39
|
tocActiveId?: string | null;
|
|
48
40
|
logo?: Snippet;
|
|
49
41
|
actions?: Snippet;
|
|
50
|
-
/** Declared versions; renders the switcher in the drawer once there's more than one. */
|
|
51
|
-
versions?: ResolvedVersion[];
|
|
52
|
-
/** The active version, for the switcher's current selection. */
|
|
53
|
-
active?: ResolvedVersion;
|
|
54
|
-
/** Content index, so the switcher can map the current page across versions. */
|
|
55
|
-
content?: DocsContentItem[];
|
|
56
|
-
/** Current normalized pathname, for the switcher's page mapping. */
|
|
57
|
-
pathname?: string;
|
|
58
42
|
} = $props();
|
|
59
43
|
|
|
60
44
|
const search = useSearch();
|
|
45
|
+
const docsPage = useDocsPage();
|
|
61
46
|
|
|
62
47
|
let isMenuOpen = $state(false);
|
|
63
48
|
let isTocOpen = $state(false);
|
|
@@ -95,9 +80,9 @@
|
|
|
95
80
|
<span class="inline-block">{config.title}</span>
|
|
96
81
|
</a>
|
|
97
82
|
</div>
|
|
98
|
-
{#if
|
|
83
|
+
{#if docsPage.view.versionLinks.length > 1}
|
|
99
84
|
<div class="px-7 pb-3">
|
|
100
|
-
<VersionSwitcher {
|
|
85
|
+
<VersionSwitcher links={docsPage.view.versionLinks} />
|
|
101
86
|
</div>
|
|
102
87
|
{/if}
|
|
103
88
|
<ScrollArea class="my-4 h-[calc(100vh-8rem)] pb-10 pl-2">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DocsmithConfig, NavGroup
|
|
1
|
+
import type { DocsmithConfig, NavGroup } from '../../core/index.js';
|
|
2
2
|
import type { TocItem } from '../../toc/index.js';
|
|
3
3
|
import type { Snippet } from 'svelte';
|
|
4
4
|
type $$ComponentProps = {
|
|
@@ -13,14 +13,6 @@ type $$ComponentProps = {
|
|
|
13
13
|
tocActiveId?: string | null;
|
|
14
14
|
logo?: Snippet;
|
|
15
15
|
actions?: Snippet;
|
|
16
|
-
/** Declared versions; renders the switcher in the drawer once there's more than one. */
|
|
17
|
-
versions?: ResolvedVersion[];
|
|
18
|
-
/** The active version, for the switcher's current selection. */
|
|
19
|
-
active?: ResolvedVersion;
|
|
20
|
-
/** Content index, so the switcher can map the current page across versions. */
|
|
21
|
-
content?: DocsContentItem[];
|
|
22
|
-
/** Current normalized pathname, for the switcher's page mapping. */
|
|
23
|
-
pathname?: string;
|
|
24
16
|
};
|
|
25
17
|
declare const DocsMobileHeader: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
26
18
|
type DocsMobileHeader = ReturnType<typeof DocsMobileHeader>;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
} from '../../core/index.js';
|
|
11
11
|
import { createToc } from '../../toc/index.js';
|
|
12
12
|
import { createSearchState } from '../../search/context.svelte.js';
|
|
13
|
+
import { setDocsPage } from '../docs-page-context.js';
|
|
13
14
|
import Search from '../chrome/search.svelte';
|
|
14
15
|
import BackgroundPattern from '../chrome/background-pattern.svelte';
|
|
15
16
|
import ThemeProvider from '../chrome/theme-provider.svelte';
|
|
@@ -107,7 +108,7 @@
|
|
|
107
108
|
// `search` loader is static for the shell's lifetime, so reading it once at
|
|
108
109
|
// init is intentional.
|
|
109
110
|
// svelte-ignore state_referenced_locally
|
|
110
|
-
|
|
111
|
+
if (search) createSearchState();
|
|
111
112
|
|
|
112
113
|
// Every rule about the page being read is resolved in one pure module
|
|
113
114
|
// (`core/docs-page.ts`): the active version and the content scoped to it, the
|
|
@@ -125,16 +126,23 @@
|
|
|
125
126
|
})
|
|
126
127
|
);
|
|
127
128
|
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
// One route to the chrome. The headers, the switcher and the search palette
|
|
130
|
+
// read what they need off this instead of taking it as props through two
|
|
131
|
+
// intermediate layers.
|
|
132
|
+
setDocsPage(() => view);
|
|
132
133
|
|
|
134
|
+
// `timeZone: 'UTC'` is not cosmetic. `lastUpdated` is a calendar day, which
|
|
135
|
+
// parses to UTC midnight, so formatting in the ambient zone shifts it a day
|
|
136
|
+
// west of UTC — and shifts it on the client but not on the server, so the
|
|
137
|
+
// rendered date changes under hydration.
|
|
133
138
|
const lastUpdatedLabel = $derived.by(() =>
|
|
134
139
|
view.lastUpdated
|
|
135
|
-
? new Intl.DateTimeFormat('en', {
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
? new Intl.DateTimeFormat('en', {
|
|
141
|
+
year: 'numeric',
|
|
142
|
+
month: 'short',
|
|
143
|
+
day: 'numeric',
|
|
144
|
+
timeZone: 'UTC'
|
|
145
|
+
}).format(view.lastUpdated)
|
|
138
146
|
: undefined
|
|
139
147
|
);
|
|
140
148
|
const showFooterMeta = $derived(Boolean(view.editHref || lastUpdatedLabel));
|
|
@@ -145,6 +153,16 @@
|
|
|
145
153
|
|
|
146
154
|
const breadcrumbs = $derived(view.breadcrumbs.map((title) => ({ title })));
|
|
147
155
|
|
|
156
|
+
// The archived-version banner, or nothing. Its "view this page in <current>"
|
|
157
|
+
// link is the current version's entry in the same list the switcher renders,
|
|
158
|
+
// so the two can't disagree about where the reader lands.
|
|
159
|
+
const archivedBanner = $derived.by(() => {
|
|
160
|
+
const { isArchived, activeVersion, currentVersion, versionLinks } = view;
|
|
161
|
+
if (!isArchived || !activeVersion || !currentVersion) return undefined;
|
|
162
|
+
const href = versionLinks.find((link) => link.id === currentVersion.id)?.href;
|
|
163
|
+
return href ? { active: activeVersion, current: currentVersion, href } : undefined;
|
|
164
|
+
});
|
|
165
|
+
|
|
148
166
|
// In-page TOC, scanned from the rendered content and re-scanned after every
|
|
149
167
|
// navigation (client-side included) so it never goes stale.
|
|
150
168
|
let contentEl = $state<HTMLElement | null>(null);
|
|
@@ -194,15 +212,7 @@
|
|
|
194
212
|
|
|
195
213
|
<!-- One header system everywhere: DocsHeader on desktop, DocsMobileHeader
|
|
196
214
|
below lg. The `page` layout just omits the sidebar nav and in-page TOC. -->
|
|
197
|
-
<DocsHeader
|
|
198
|
-
{config}
|
|
199
|
-
{logo}
|
|
200
|
-
{actions}
|
|
201
|
-
{versions}
|
|
202
|
-
active={view.activeVersion}
|
|
203
|
-
{content}
|
|
204
|
-
pathname={view.pathname}
|
|
205
|
-
/>
|
|
215
|
+
<DocsHeader {config} {logo} {actions} />
|
|
206
216
|
|
|
207
217
|
{#if layout === 'page'}
|
|
208
218
|
<DocsMobileHeader {config} {logo} {actions} />
|
|
@@ -219,10 +229,6 @@
|
|
|
219
229
|
tocActiveId={toc.activeId}
|
|
220
230
|
{logo}
|
|
221
231
|
{actions}
|
|
222
|
-
{versions}
|
|
223
|
-
active={view.activeVersion}
|
|
224
|
-
{content}
|
|
225
|
-
pathname={view.pathname}
|
|
226
232
|
/>
|
|
227
233
|
|
|
228
234
|
<div class="mx-auto flex w-full max-w-7xl flex-1 gap-12 px-4 md:px-6 lg:px-8 lg:pt-10">
|
|
@@ -234,13 +240,8 @@
|
|
|
234
240
|
tabindex="-1"
|
|
235
241
|
class="min-w-0 flex-1 py-6 lg:py-0"
|
|
236
242
|
>
|
|
237
|
-
{#if
|
|
238
|
-
<VersionBanner
|
|
239
|
-
active={view.activeVersion}
|
|
240
|
-
current={view.currentVersion}
|
|
241
|
-
pathname={view.pathname}
|
|
242
|
-
{content}
|
|
243
|
-
/>
|
|
243
|
+
{#if archivedBanner}
|
|
244
|
+
<VersionBanner {...archivedBanner} />
|
|
244
245
|
{/if}
|
|
245
246
|
|
|
246
247
|
<div class="flex items-start justify-between gap-4">
|
package/dist/core/changelog.d.ts
CHANGED
|
@@ -19,7 +19,10 @@ export type ChangelogGroup = {
|
|
|
19
19
|
export type ChangelogRelease = {
|
|
20
20
|
/** Version string as it appears in the changelog, e.g. `0.8.0`. */
|
|
21
21
|
version: string;
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Release day (`YYYY-MM-DD`) from the git history, when it can be determined.
|
|
24
|
+
* Rendered as a UTC calendar day, so it reads the same for every reader.
|
|
25
|
+
*/
|
|
23
26
|
date?: string;
|
|
24
27
|
groups: ChangelogGroup[];
|
|
25
28
|
/**
|
package/dist/core/content.d.ts
CHANGED
|
@@ -23,7 +23,12 @@ export type DocsContentItem = {
|
|
|
23
23
|
description?: string;
|
|
24
24
|
/** Source file path relative to the app cwd, for the "Edit this page" link. */
|
|
25
25
|
sourcePath?: string;
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* The day (`YYYY-MM-DD`) the page's source file last changed, from git, or
|
|
28
|
+
* from the page's own `lastUpdated` frontmatter when it has one. A calendar
|
|
29
|
+
* day rather than a timestamp: it is rendered as a UTC day, so it reads the
|
|
30
|
+
* same for every reader and matches on the server and the client.
|
|
31
|
+
*/
|
|
27
32
|
lastUpdated?: string;
|
|
28
33
|
/** Estimated reading time in whole minutes (at ~200 wpm), min 1. */
|
|
29
34
|
readingTime?: number;
|
package/dist/core/docs-page.d.ts
CHANGED
|
@@ -13,6 +13,15 @@ import { type NavGroup, type NavItem } from './nav.js';
|
|
|
13
13
|
import { type ResolvedVersion } from './version.js';
|
|
14
14
|
/** The page's build-time headings, as extracted into the content index. */
|
|
15
15
|
type PageToc = NonNullable<DocsContentItem['toc']>;
|
|
16
|
+
/** One declared version, and where switching to it should take the reader. */
|
|
17
|
+
export type VersionLink = {
|
|
18
|
+
id: string;
|
|
19
|
+
label: string;
|
|
20
|
+
/** This page under that version, or its landing when the page isn't there. */
|
|
21
|
+
href: string;
|
|
22
|
+
/** Whether this is the version being read. */
|
|
23
|
+
active: boolean;
|
|
24
|
+
};
|
|
16
25
|
/** Everything `DocsShell` renders about the current page. */
|
|
17
26
|
export type DocsPageView = {
|
|
18
27
|
/** The current path, trailing slash stripped. Match content against this. */
|
|
@@ -53,6 +62,12 @@ export type DocsPageView = {
|
|
|
53
62
|
breadcrumbs: string[];
|
|
54
63
|
/** The page's server-rendered TOC, from {@link entry}. */
|
|
55
64
|
toc: PageToc;
|
|
65
|
+
/**
|
|
66
|
+
* Every declared version with the URL that keeps the reader on this page, in
|
|
67
|
+
* switcher order. Empty on an unversioned site, so the switcher and the
|
|
68
|
+
* archived-version banner both render off this one list.
|
|
69
|
+
*/
|
|
70
|
+
versionLinks: VersionLink[];
|
|
56
71
|
};
|
|
57
72
|
/**
|
|
58
73
|
* Resolve the page being read. `pathname` is taken raw (normalized here, so the
|
package/dist/core/docs-page.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { navFromContent, flattenNav, navTrail } from './nav.js';
|
|
2
|
-
import { activeVersion, currentVersion, scopeContent } from './version.js';
|
|
2
|
+
import { activeVersion, currentVersion, mapPathToVersion, scopeContent } from './version.js';
|
|
3
3
|
import { normalizePath } from '../utils/normalize-path.js';
|
|
4
4
|
/**
|
|
5
5
|
* Resolve the page being read. `pathname` is taken raw (normalized here, so the
|
|
@@ -43,10 +43,27 @@ export function resolveDocsPage(input) {
|
|
|
43
43
|
next: pageIndex >= 0 && pageIndex < flatNav.length - 1 ? flatNav[pageIndex + 1] : undefined,
|
|
44
44
|
title,
|
|
45
45
|
breadcrumbs,
|
|
46
|
-
toc: entry?.toc ?? []
|
|
46
|
+
toc: entry?.toc ?? [],
|
|
47
|
+
versionLinks: active
|
|
48
|
+
? versions.map((version) => ({
|
|
49
|
+
id: version.id,
|
|
50
|
+
label: version.label,
|
|
51
|
+
// Switching to the version already being read is a no-op, so its
|
|
52
|
+
// link is this page. Mapping it like the others would send a reader
|
|
53
|
+
// who is off the docs tree to the docs landing instead.
|
|
54
|
+
href: version.id === active.id
|
|
55
|
+
? pathname
|
|
56
|
+
: mapPathToVersion(pathname, active, version, scopeContent(content, version.id).map((item) => item.path)),
|
|
57
|
+
active: version.id === active.id
|
|
58
|
+
}))
|
|
59
|
+
: []
|
|
47
60
|
};
|
|
48
61
|
}
|
|
49
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* A `YYYY-MM-DD` day as a Date, or `undefined` when absent or unparseable. The
|
|
64
|
+
* result is UTC midnight, so it must be formatted in UTC to read back as the
|
|
65
|
+
* same day.
|
|
66
|
+
*/
|
|
50
67
|
function parseDate(iso) {
|
|
51
68
|
if (!iso)
|
|
52
69
|
return undefined;
|
package/dist/core/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ export { defineConfig, type DocsmithConfig, type DocsmithLink, type DocsmithFoot
|
|
|
2
2
|
export type { DocsContentItem, SearchDoc, LlmsDoc } from './content.js';
|
|
3
3
|
export { resolveVersions, activeVersion, currentVersion, currentOnly, scopeContent, mapPathToVersion, type DocsVersion, type DocsVersions, type ResolvedVersion } from './version.js';
|
|
4
4
|
export { navFromContent, flattenNav, navTrail, isNavGroup, type NavItem, type NavGroup, type NavNode } from './nav.js';
|
|
5
|
-
export { resolveDocsPage, type DocsPageView } from './docs-page.js';
|
|
5
|
+
export { resolveDocsPage, type DocsPageView, type VersionLink } from './docs-page.js';
|