@umami/shiso 0.61.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/bin/shiso.mjs +0 -0
- package/docs.schema.json +81 -20
- package/package.json +3 -2
- package/scripts/check-package.mjs +36 -0
- package/scripts/generate-search-index.mjs +79 -33
- package/scripts/lib/mdast.mjs +23 -0
- package/scripts/lib/slug.mjs +21 -0
- package/scripts/prerender.mjs +24 -17
- package/src/App.tsx +4 -5
- package/src/components/DocContent.tsx +7 -2
- package/src/components/Docs.tsx +13 -5
- package/src/components/Footer.tsx +6 -9
- package/src/components/Header.tsx +13 -3
- package/src/components/LanguageSwitcher.tsx +59 -0
- package/src/components/Layout.tsx +8 -0
- package/src/components/Search.tsx +12 -3
- package/src/components/VersionSwitcher.tsx +60 -0
- package/src/components/docs/PropertiesTable.tsx +7 -7
- package/src/entry-server.tsx +20 -8
- package/src/lib/docs-config.ts +397 -93
- package/src/lib/head.ts +15 -4
- package/src/lib/locale.ts +39 -0
- package/src/lib/search/provider.ts +7 -2
- package/src/lib/search/providers/local.ts +3 -3
- package/src/lib/search.ts +28 -0
- package/src/lib/site-config.ts +35 -22
- package/src/lib/types.ts +39 -2
- package/types/search.d.ts +11 -1
package/src/components/Docs.tsx
CHANGED
|
@@ -3,12 +3,14 @@ import { useLocation, useNavigate } from 'react-router';
|
|
|
3
3
|
import { DocContent } from '@/components/DocContent';
|
|
4
4
|
import { Footer } from '@/components/Footer';
|
|
5
5
|
import { Menu } from '@/components/icons';
|
|
6
|
+
import { LanguageSwitcher } from '@/components/LanguageSwitcher';
|
|
6
7
|
import { PageLinks } from '@/components/PageLinks';
|
|
7
8
|
import { SideNav } from '@/components/SideNav';
|
|
8
9
|
import { Button } from '@/components/ui/button';
|
|
9
10
|
import { Sheet, SheetContent, SheetTitle, SheetTrigger } from '@/components/ui/sheet';
|
|
11
|
+
import { VersionSwitcher } from '@/components/VersionSwitcher';
|
|
10
12
|
import { renderInlineMarkdown } from '@/lib/inline-markdown';
|
|
11
|
-
import {
|
|
13
|
+
import { docsHomeUrl, getScopeByPathname } from '@/lib/site-config';
|
|
12
14
|
import type { DocModule, NormalizedDocsPage, SiteModel } from '@/lib/types';
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -23,7 +25,7 @@ function NotFound({ site }: { site: SiteModel }) {
|
|
|
23
25
|
|
|
24
26
|
useEffect(() => {
|
|
25
27
|
if (redirect) {
|
|
26
|
-
navigate(
|
|
28
|
+
navigate(docsHomeUrl, { replace: true });
|
|
27
29
|
}
|
|
28
30
|
}, [redirect, navigate]);
|
|
29
31
|
|
|
@@ -44,7 +46,9 @@ export interface DocsProps {
|
|
|
44
46
|
export function Docs({ page, doc, site }: DocsProps) {
|
|
45
47
|
const { pathname } = useLocation();
|
|
46
48
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
47
|
-
|
|
49
|
+
// Navigation follows the scope (version/language) that owns the current page.
|
|
50
|
+
const scopeDocs = getScopeByPathname(pathname).docs;
|
|
51
|
+
const { tabs, navigation } = scopeDocs;
|
|
48
52
|
|
|
49
53
|
// Close the mobile menu and start each newly loaded page at the top. Hash
|
|
50
54
|
// links keep their native section-scrolling behavior.
|
|
@@ -82,10 +86,14 @@ export function Docs({ page, doc, site }: DocsProps) {
|
|
|
82
86
|
>
|
|
83
87
|
<SheetTitle className="sr-only">{site.labels.documentationNavigation}</SheetTitle>
|
|
84
88
|
<div className="pt-8">
|
|
89
|
+
<div className="flex items-center gap-2 pb-4 lg:hidden">
|
|
90
|
+
<VersionSwitcher />
|
|
91
|
+
<LanguageSwitcher />
|
|
92
|
+
</div>
|
|
85
93
|
<SideNav
|
|
86
94
|
tabs={tabs}
|
|
87
95
|
navigation={navigation}
|
|
88
|
-
anchors={
|
|
96
|
+
anchors={scopeDocs.anchors}
|
|
89
97
|
drilldown={site.drilldown}
|
|
90
98
|
navigationLabel={site.labels.documentationNavigation}
|
|
91
99
|
expandLabel={site.labels.expand}
|
|
@@ -99,7 +107,7 @@ export function Docs({ page, doc, site }: DocsProps) {
|
|
|
99
107
|
<SideNav
|
|
100
108
|
tabs={tabs}
|
|
101
109
|
navigation={navigation}
|
|
102
|
-
anchors={
|
|
110
|
+
anchors={scopeDocs.anchors}
|
|
103
111
|
isSticky
|
|
104
112
|
drilldown={site.drilldown}
|
|
105
113
|
navigationLabel={site.labels.documentationNavigation}
|
|
@@ -44,15 +44,12 @@ export function Footer({
|
|
|
44
44
|
{attribution || socials.length > 0 ? (
|
|
45
45
|
<div className="flex items-center justify-between gap-4">
|
|
46
46
|
{attribution ? (
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
shiso
|
|
54
|
-
</a>
|
|
55
|
-
</span>
|
|
47
|
+
<a
|
|
48
|
+
href="https://shiso.umami.is?ref=docs-footer"
|
|
49
|
+
className="text-sm hover:text-foreground"
|
|
50
|
+
>
|
|
51
|
+
Powered by <span className="font-bold">shiso</span>
|
|
52
|
+
</a>
|
|
56
53
|
) : (
|
|
57
54
|
<span />
|
|
58
55
|
)}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { useLocation } from 'react-router';
|
|
1
2
|
import { ConfiguredIcon } from '@/components/ConfiguredIcon';
|
|
3
|
+
import { LanguageSwitcher } from '@/components/LanguageSwitcher';
|
|
2
4
|
import { Search } from '@/components/Search';
|
|
3
5
|
import { ThemeToggle } from '@/components/ThemeToggle';
|
|
4
6
|
import { TopNav } from '@/components/TopNav';
|
|
5
|
-
import {
|
|
7
|
+
import { VersionSwitcher } from '@/components/VersionSwitcher';
|
|
8
|
+
import { docsHomeUrl, getScopeByPathname } from '@/lib/site-config';
|
|
6
9
|
import type { NormalizedLink, SiteModel } from '@/lib/types';
|
|
7
10
|
|
|
8
11
|
function NavbarLinkItem({ link, primary = false }: { link: NormalizedLink; primary?: boolean }) {
|
|
@@ -28,8 +31,11 @@ function NavbarLinkItem({ link, primary = false }: { link: NormalizedLink; prima
|
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
export function Header({ site }: { site: SiteModel }) {
|
|
31
|
-
const { logo, navbar, name, appearance,
|
|
32
|
-
const
|
|
34
|
+
const { logo, navbar, name, appearance, labels, search } = site;
|
|
35
|
+
const { pathname } = useLocation();
|
|
36
|
+
// The header renders the navigation of whichever scope owns the current page.
|
|
37
|
+
const docs = getScopeByPathname(pathname).docs;
|
|
38
|
+
const brandHref = logo?.href || docsHomeUrl;
|
|
33
39
|
const hasBrand = !!name || !!logo?.light || !!logo?.dark;
|
|
34
40
|
|
|
35
41
|
return (
|
|
@@ -56,6 +62,10 @@ export function Header({ site }: { site: SiteModel }) {
|
|
|
56
62
|
{name ? <span>{name}</span> : null}
|
|
57
63
|
</a>
|
|
58
64
|
) : null}
|
|
65
|
+
<div className="hidden items-center gap-2 lg:flex">
|
|
66
|
+
<VersionSwitcher />
|
|
67
|
+
<LanguageSwitcher />
|
|
68
|
+
</div>
|
|
59
69
|
</div>
|
|
60
70
|
{docs.showTabs ? <TopNav docs={docs} label={labels.sections} /> : null}
|
|
61
71
|
<div className="flex min-w-0 items-center gap-2 justify-self-end">
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useLocation, useNavigate } from 'react-router';
|
|
2
|
+
import { Check, ChevronRight } from '@/components/icons';
|
|
3
|
+
import { Button } from '@/components/ui/button';
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenu,
|
|
6
|
+
DropdownMenuContent,
|
|
7
|
+
DropdownMenuItem,
|
|
8
|
+
DropdownMenuTrigger,
|
|
9
|
+
} from '@/components/ui/dropdown-menu';
|
|
10
|
+
import { getLanguageScopes } from '@/lib/docs-config';
|
|
11
|
+
import { docsSite, getScopeByPathname } from '@/lib/site-config';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Language selector for multi-language sites. Each option is a language's
|
|
15
|
+
* landing scope — its default version — so switching languages always lands
|
|
16
|
+
* on that language's default-version first page. Hidden languages never
|
|
17
|
+
* appear as options.
|
|
18
|
+
*/
|
|
19
|
+
export function LanguageSwitcher() {
|
|
20
|
+
const { pathname } = useLocation();
|
|
21
|
+
const navigate = useNavigate();
|
|
22
|
+
const current = getScopeByPathname(pathname);
|
|
23
|
+
const options = getLanguageScopes(docsSite);
|
|
24
|
+
|
|
25
|
+
if (!current.language || (options.length < 2 && !current.hidden)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<DropdownMenu>
|
|
31
|
+
<DropdownMenuTrigger
|
|
32
|
+
render={
|
|
33
|
+
<Button
|
|
34
|
+
variant="outline"
|
|
35
|
+
className="h-auto gap-1.5 rounded-md bg-card px-2.5 py-1.5 text-sm font-medium text-foreground"
|
|
36
|
+
/>
|
|
37
|
+
}
|
|
38
|
+
>
|
|
39
|
+
{current.language}
|
|
40
|
+
<ChevronRight className="size-3.5 rotate-90 text-muted-foreground" />
|
|
41
|
+
</DropdownMenuTrigger>
|
|
42
|
+
<DropdownMenuContent align="start" className="min-w-32">
|
|
43
|
+
{options.map(scope => (
|
|
44
|
+
<DropdownMenuItem
|
|
45
|
+
key={scope.id}
|
|
46
|
+
onClick={() => {
|
|
47
|
+
if (scope.language !== current.language) {
|
|
48
|
+
navigate(scope.firstPageUrl);
|
|
49
|
+
}
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<span className="grow">{scope.language}</span>
|
|
53
|
+
{scope.language === current.language ? <Check className="size-3.5" /> : null}
|
|
54
|
+
</DropdownMenuItem>
|
|
55
|
+
))}
|
|
56
|
+
</DropdownMenuContent>
|
|
57
|
+
</DropdownMenu>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
+
import { useLocation } from 'react-router';
|
|
2
3
|
import { Banner } from '@/components/Banner';
|
|
3
4
|
import { Header } from '@/components/Header';
|
|
5
|
+
import { useHead } from '@/lib/head';
|
|
4
6
|
import type { SiteModel } from '@/lib/types';
|
|
5
7
|
|
|
6
8
|
export function Layout({ children, site }: { children: ReactNode; site: SiteModel }) {
|
|
9
|
+
const { pathname } = useLocation();
|
|
10
|
+
|
|
11
|
+
// Keep metadata, document language, and text direction synchronized after
|
|
12
|
+
// client-side navigation. The prerendered values are retained on hydration.
|
|
13
|
+
useHead(pathname);
|
|
14
|
+
|
|
7
15
|
return (
|
|
8
16
|
<div className="flex min-h-dvh flex-col">
|
|
9
17
|
<Banner banner={site.banner} dismissLabel={site.labels.dismissBanner} />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { useNavigate } from 'react-router';
|
|
2
|
+
import { useLocation, useNavigate } from 'react-router';
|
|
3
3
|
import { Search as SearchIcon } from '@/components/icons';
|
|
4
4
|
import { Button } from '@/components/ui/button';
|
|
5
5
|
import {
|
|
@@ -14,6 +14,7 @@ import { Dialog, DialogContent, DialogTitle, DialogTrigger } from '@/components/
|
|
|
14
14
|
import type { SearchResult } from '@/lib/search';
|
|
15
15
|
import type { ResolvedSearchConfig } from '@/lib/search/config';
|
|
16
16
|
import { resolveSearchProvider, type SearchProvider } from '@/lib/search/provider';
|
|
17
|
+
import { getScopeByPathname } from '@/lib/site-config';
|
|
17
18
|
import type { ThemeLabels } from '@/lib/types';
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -22,6 +23,7 @@ import type { ThemeLabels } from '@/lib/types';
|
|
|
22
23
|
*/
|
|
23
24
|
export function Search({ config, labels }: { config: ResolvedSearchConfig; labels: ThemeLabels }) {
|
|
24
25
|
const navigate = useNavigate();
|
|
26
|
+
const { pathname } = useLocation();
|
|
25
27
|
const [open, setOpen] = useState(false);
|
|
26
28
|
const [query, setQuery] = useState('');
|
|
27
29
|
const [results, setResults] = useState<SearchResult[]>([]);
|
|
@@ -66,7 +68,14 @@ export function Search({ config, labels }: { config: ResolvedSearchConfig; label
|
|
|
66
68
|
|
|
67
69
|
try {
|
|
68
70
|
const activeProvider = await loadProvider();
|
|
69
|
-
|
|
71
|
+
// Search stays inside the version/language scope being browsed.
|
|
72
|
+
// Providers that predate the context argument simply ignore it.
|
|
73
|
+
const scope = getScopeByPathname(pathname);
|
|
74
|
+
const nextResults = await activeProvider.search(value, undefined, {
|
|
75
|
+
scopeId: scope.id,
|
|
76
|
+
language: scope.language,
|
|
77
|
+
version: scope.version,
|
|
78
|
+
});
|
|
70
79
|
|
|
71
80
|
if (currentRequest === requestId.current) {
|
|
72
81
|
setResults(nextResults);
|
|
@@ -80,7 +89,7 @@ export function Search({ config, labels }: { config: ResolvedSearchConfig; label
|
|
|
80
89
|
}
|
|
81
90
|
}
|
|
82
91
|
},
|
|
83
|
-
[loadProvider],
|
|
92
|
+
[loadProvider, pathname],
|
|
84
93
|
);
|
|
85
94
|
|
|
86
95
|
const openDialog = useCallback(() => {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useLocation, useNavigate } from 'react-router';
|
|
2
|
+
import { Check, ChevronRight } from '@/components/icons';
|
|
3
|
+
import { Button } from '@/components/ui/button';
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenu,
|
|
6
|
+
DropdownMenuContent,
|
|
7
|
+
DropdownMenuItem,
|
|
8
|
+
DropdownMenuTrigger,
|
|
9
|
+
} from '@/components/ui/dropdown-menu';
|
|
10
|
+
import { docsSite, getScopeByPathname } from '@/lib/site-config';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Version selector for multi-version sites. Options come from the visible
|
|
14
|
+
* version scopes of the active language; selecting one navigates to that
|
|
15
|
+
* scope's first visible page. Hidden versions never appear as options, but a
|
|
16
|
+
* hidden version still shows as the current value while it is being viewed.
|
|
17
|
+
*/
|
|
18
|
+
export function VersionSwitcher() {
|
|
19
|
+
const { pathname } = useLocation();
|
|
20
|
+
const navigate = useNavigate();
|
|
21
|
+
const current = getScopeByPathname(pathname);
|
|
22
|
+
const options = docsSite.scopes.filter(
|
|
23
|
+
scope => scope.version && !scope.hidden && scope.language === current.language,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (!current.version || (options.length < 2 && !current.hidden)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<DropdownMenu>
|
|
32
|
+
<DropdownMenuTrigger
|
|
33
|
+
render={
|
|
34
|
+
<Button
|
|
35
|
+
variant="outline"
|
|
36
|
+
className="h-auto gap-1.5 rounded-md bg-card px-2.5 py-1.5 text-sm font-medium text-foreground"
|
|
37
|
+
/>
|
|
38
|
+
}
|
|
39
|
+
>
|
|
40
|
+
{current.version}
|
|
41
|
+
<ChevronRight className="size-3.5 rotate-90 text-muted-foreground" />
|
|
42
|
+
</DropdownMenuTrigger>
|
|
43
|
+
<DropdownMenuContent align="start" className="min-w-32">
|
|
44
|
+
{options.map(scope => (
|
|
45
|
+
<DropdownMenuItem
|
|
46
|
+
key={scope.id}
|
|
47
|
+
onClick={() => {
|
|
48
|
+
if (scope.id !== current.id) {
|
|
49
|
+
navigate(scope.firstPageUrl);
|
|
50
|
+
}
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<span className="grow">{scope.version}</span>
|
|
54
|
+
{scope.id === current.id ? <Check className="size-3.5" /> : null}
|
|
55
|
+
</DropdownMenuItem>
|
|
56
|
+
))}
|
|
57
|
+
</DropdownMenuContent>
|
|
58
|
+
</DropdownMenu>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -23,17 +23,17 @@ export function PropertiesTable({ children }: PropertiesTableProps) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
|
-
<div className="my-4 overflow-x-auto rounded-lg border border-border
|
|
26
|
+
<div className="my-4 overflow-x-auto rounded-lg border border-border px-6 py-2">
|
|
27
27
|
<table className="m-0 min-w-[40rem] table-fixed border-collapse">
|
|
28
28
|
<thead>
|
|
29
29
|
<tr>
|
|
30
|
-
<th className="w-1/3 border-x-0 border-t-0 border-b border-border bg-transparent px-0 py-
|
|
30
|
+
<th className="w-1/3 border-x-0 border-t-0 border-b border-border bg-transparent px-0 py-2 pr-6 text-left text-sm font-semibold text-foreground">
|
|
31
31
|
Name
|
|
32
32
|
</th>
|
|
33
|
-
<th className="w-1/3 border-x-0 border-t-0 border-b border-border bg-transparent px-0 py-
|
|
33
|
+
<th className="w-1/3 border-x-0 border-t-0 border-b border-border bg-transparent px-0 py-2 pr-6 text-left text-sm font-semibold text-foreground">
|
|
34
34
|
Type
|
|
35
35
|
</th>
|
|
36
|
-
<th className="w-1/3 border-x-0 border-t-0 border-b border-border bg-transparent px-0 py-
|
|
36
|
+
<th className="w-1/3 border-x-0 border-t-0 border-b border-border bg-transparent px-0 py-2 text-left text-sm font-semibold text-foreground">
|
|
37
37
|
Description
|
|
38
38
|
</th>
|
|
39
39
|
</tr>
|
|
@@ -47,7 +47,7 @@ export function PropertiesTable({ children }: PropertiesTableProps) {
|
|
|
47
47
|
return (
|
|
48
48
|
<tr key={row.key ?? name}>
|
|
49
49
|
<td
|
|
50
|
-
className={`${borderClass} border-x-0 border-t-0 border-border px-0 py-
|
|
50
|
+
className={`${borderClass} border-x-0 border-t-0 border-border px-0 py-2 pr-6 align-top text-sm text-foreground`}
|
|
51
51
|
>
|
|
52
52
|
<span className="inline-flex flex-wrap items-center gap-2">
|
|
53
53
|
{name}
|
|
@@ -60,12 +60,12 @@ export function PropertiesTable({ children }: PropertiesTableProps) {
|
|
|
60
60
|
</span>
|
|
61
61
|
</td>
|
|
62
62
|
<td
|
|
63
|
-
className={`${borderClass} border-x-0 border-t-0 border-border px-0 py-
|
|
63
|
+
className={`${borderClass} border-x-0 border-t-0 border-border px-0 py-2 pr-6 align-top text-sm text-foreground`}
|
|
64
64
|
>
|
|
65
65
|
{displayValue(type)}
|
|
66
66
|
</td>
|
|
67
67
|
<td
|
|
68
|
-
className={`${borderClass} border-x-0 border-t-0 border-border px-0 py-
|
|
68
|
+
className={`${borderClass} border-x-0 border-t-0 border-border px-0 py-2 align-top text-sm leading-6 text-foreground [&_p]:m-0`}
|
|
69
69
|
>
|
|
70
70
|
{description}
|
|
71
71
|
{defaultValue ? (
|
package/src/entry-server.tsx
CHANGED
|
@@ -2,13 +2,23 @@ import { renderToString } from 'react-dom/server';
|
|
|
2
2
|
import { StaticRouter } from 'react-router';
|
|
3
3
|
import { App } from '@/App';
|
|
4
4
|
import { getDocModule, getLastModified } from '@/lib/content';
|
|
5
|
+
import { getScopeForPage } from '@/lib/docs-config';
|
|
5
6
|
import { buildHead, renderHeadToString } from '@/lib/head';
|
|
6
7
|
import { BASE_URL, toAbsoluteUrl } from '@/lib/paths';
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
docsHomeUrl,
|
|
10
|
+
docsSite,
|
|
11
|
+
getLocaleByPathname,
|
|
12
|
+
getRedirects,
|
|
13
|
+
getSeo,
|
|
14
|
+
siteName,
|
|
15
|
+
} from '@/lib/site-config';
|
|
8
16
|
|
|
9
17
|
export interface RenderResult {
|
|
10
18
|
html: string;
|
|
11
19
|
head: string;
|
|
20
|
+
/** Attributes for the document element: language and text direction. */
|
|
21
|
+
htmlAttrs: { lang: string; dir: 'ltr' | 'rtl' };
|
|
12
22
|
}
|
|
13
23
|
|
|
14
24
|
export interface SitemapEntry {
|
|
@@ -16,9 +26,9 @@ export interface SitemapEntry {
|
|
|
16
26
|
lastmod?: string;
|
|
17
27
|
}
|
|
18
28
|
|
|
19
|
-
/** Base-relative routes. The prerenderer prepends the deploy base itself. */
|
|
29
|
+
/** Base-relative routes for every scope. The prerenderer prepends the deploy base itself. */
|
|
20
30
|
export function getRoutes(): string[] {
|
|
21
|
-
return
|
|
31
|
+
return docsSite.pages.map(page => page.url);
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
/** Redirect rules with exact-match sources, for static redirect pages. */
|
|
@@ -31,7 +41,7 @@ export { getRedirects };
|
|
|
31
41
|
* "/content/docs/index.mdx", resolved against the project root.
|
|
32
42
|
*/
|
|
33
43
|
export function getMarkdownPages(): { route: string; filePath: string }[] {
|
|
34
|
-
return
|
|
44
|
+
return docsSite.pages.map(page => ({ route: page.url, filePath: page.filePath }));
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
/**
|
|
@@ -43,8 +53,10 @@ export function getSitemapEntries(): SitemapEntry[] {
|
|
|
43
53
|
const { indexing } = getSeo();
|
|
44
54
|
const entries: SitemapEntry[] = [];
|
|
45
55
|
|
|
46
|
-
for (const page of
|
|
47
|
-
|
|
56
|
+
for (const page of docsSite.pages) {
|
|
57
|
+
// Hidden pages and pages of hidden scopes (versions/languages) stay out
|
|
58
|
+
// of the sitemap unless `seo.indexing: "all"` opts them in.
|
|
59
|
+
if ((page.hidden || getScopeForPage(docsSite, page).hidden) && indexing !== 'all') {
|
|
48
60
|
continue;
|
|
49
61
|
}
|
|
50
62
|
|
|
@@ -71,7 +83,7 @@ export function render(url: string): RenderResult {
|
|
|
71
83
|
</StaticRouter>,
|
|
72
84
|
);
|
|
73
85
|
|
|
74
|
-
return { html, head: renderHeadToString(buildHead(url)) };
|
|
86
|
+
return { html, head: renderHeadToString(buildHead(url)), htmlAttrs: getLocaleByPathname(url) };
|
|
75
87
|
}
|
|
76
88
|
|
|
77
|
-
export { siteName };
|
|
89
|
+
export { docsHomeUrl, siteName };
|