@stainless-api/docs 0.1.0-beta.5 → 0.1.0-beta.50
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 +381 -0
- package/eslint-suppressions.json +47 -0
- package/locals.d.ts +14 -0
- package/package.json +42 -38
- package/plugin/buildAlgoliaIndex.ts +31 -6
- package/plugin/cms/server.ts +98 -56
- package/plugin/cms/sidebar-builder.ts +7 -26
- package/plugin/cms/worker.ts +3 -3
- package/plugin/components/MethodDescription.tsx +54 -0
- package/plugin/components/SDKSelect.astro +7 -87
- package/plugin/components/SnippetCode.tsx +11 -7
- package/plugin/components/search/SearchAlgolia.astro +5 -33
- package/plugin/components/search/SearchIsland.tsx +37 -23
- package/plugin/generateAPIReferenceLink.ts +2 -2
- package/plugin/globalJs/ai-dropdown-options.ts +235 -0
- package/plugin/globalJs/method-descriptions.ts +33 -0
- package/plugin/globalJs/navigation.ts +7 -27
- package/plugin/helpers/getPageLoadEvent.ts +1 -1
- package/plugin/index.ts +54 -34
- package/plugin/languages.ts +2 -2
- package/plugin/loadPluginConfig.ts +112 -32
- package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
- package/plugin/react/Routing.tsx +176 -80
- package/plugin/referencePlaceholderUtils.ts +1 -1
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +5 -1
- package/plugin/routes/Docs.astro +60 -85
- package/plugin/routes/Overview.astro +10 -16
- package/plugin/routes/markdown.ts +7 -7
- package/plugin/vendor/preview.worker.docs.js +17973 -16561
- package/plugin/vendor/templates/go.md +1 -1
- package/plugin/vendor/templates/python.md +1 -1
- package/resolveSrcFile.ts +10 -0
- package/scripts/vendor_deps.ts +1 -1
- package/shared/getSharedLogger.ts +15 -0
- package/shared/terminalUtils.ts +3 -0
- package/src/content.config.ts +9 -0
- package/stl-docs/components/AIDropdown.tsx +63 -0
- package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
- package/stl-docs/components/Head.astro +16 -0
- package/stl-docs/components/Header.astro +6 -8
- package/stl-docs/components/PageTitle.astro +82 -0
- package/stl-docs/components/TableOfContents.astro +34 -0
- package/stl-docs/components/ThemeSelect.astro +118 -141
- package/stl-docs/components/content-panel/ContentPanel.astro +16 -46
- package/stl-docs/components/headers/DefaultHeader.astro +1 -1
- package/stl-docs/components/headers/HeaderLinks.astro +1 -1
- package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
- package/stl-docs/components/headers/StackedHeader.astro +29 -24
- package/stl-docs/components/icons/chat-gpt.tsx +17 -0
- package/stl-docs/components/icons/claude.tsx +10 -0
- package/stl-docs/components/icons/cursor.tsx +10 -0
- package/stl-docs/components/icons/gemini.tsx +19 -0
- package/stl-docs/components/icons/markdown.tsx +10 -0
- package/stl-docs/components/index.ts +1 -0
- package/stl-docs/components/mintlify-compat/Accordion.astro +7 -38
- package/stl-docs/components/mintlify-compat/AccordionGroup.astro +9 -23
- package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
- package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
- package/stl-docs/components/mintlify-compat/Step.astro +30 -32
- package/stl-docs/components/mintlify-compat/Steps.astro +8 -10
- package/stl-docs/components/mintlify-compat/callouts/Callout.astro +10 -3
- package/stl-docs/components/mintlify-compat/callouts/Check.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Danger.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Info.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Note.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Tip.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Warning.astro +7 -3
- package/stl-docs/components/mintlify-compat/card.css +33 -35
- package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -75
- package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
- package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
- package/stl-docs/components/nav-tabs/buildNavLinks.ts +4 -3
- package/stl-docs/components/pagination/HomeLink.astro +10 -0
- package/stl-docs/components/pagination/Pagination.astro +174 -0
- package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
- package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
- package/stl-docs/components/pagination/util.ts +71 -0
- package/stl-docs/components/scripts.ts +1 -0
- package/stl-docs/components/{Sidebar.astro → sidebars/BaseSidebar.astro} +2 -3
- package/stl-docs/components/sidebars/SDKSelectSidebar.astro +8 -0
- package/stl-docs/disableCalloutSyntax.ts +36 -0
- package/stl-docs/index.ts +98 -26
- package/stl-docs/loadStlDocsConfig.ts +37 -5
- package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +64 -0
- package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +34 -0
- package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
- package/stl-docs/tabsMiddleware.ts +12 -4
- package/styles/code.css +104 -141
- package/styles/fonts.css +32 -17
- package/styles/links.css +11 -48
- package/styles/method-descriptions.css +36 -0
- package/styles/overrides.css +49 -57
- package/styles/page.css +90 -59
- package/styles/sdk_select.css +9 -7
- package/styles/search.css +58 -69
- package/styles/sidebar.css +211 -131
- package/styles/{variables.css → sl-variables.css} +3 -2
- package/styles/stldocs-variables.css +6 -0
- package/styles/toc.css +41 -34
- package/theme.css +12 -2
- package/tsconfig.json +2 -5
- package/virtual-module.d.ts +8 -4
- package/components/variables.css +0 -139
- package/plugin/globalJs/ai-dropdown.ts +0 -57
- package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -86
- package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -64
- /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
const dirName = import.meta.dirname;
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a source file path relative to the stl-starlight package.
|
|
5
|
+
* @param projectPath - The relative path to the source file.
|
|
6
|
+
* @returns The absolute path to the source file.
|
|
7
|
+
*/
|
|
8
|
+
export function resolveSrcFile(...projectPath: string[]) {
|
|
9
|
+
return join(dirName, ...projectPath);
|
|
10
|
+
}
|
package/scripts/vendor_deps.ts
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AstroIntegrationLogger } from 'astro';
|
|
2
|
+
|
|
3
|
+
let sharedLogger: AstroIntegrationLogger | null = null;
|
|
4
|
+
|
|
5
|
+
// This is probably temporary, but it's a quick way to share a logger between our many integrations
|
|
6
|
+
// we want to share a logger so they have the same "stainless" label
|
|
7
|
+
|
|
8
|
+
export function setSharedLogger(logger: AstroIntegrationLogger) {
|
|
9
|
+
sharedLogger = logger;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// a fallback is probably not required, but it's a good safeguard in case we somehow call a logger before the shared logger is set
|
|
13
|
+
export function getSharedLogger({ fallback }: { fallback: AstroIntegrationLogger }) {
|
|
14
|
+
return sharedLogger ?? fallback;
|
|
15
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Stub here so that `astro sync` generates the correct types for the `docs` content collection
|
|
2
|
+
|
|
3
|
+
import { defineCollection } from 'astro:content';
|
|
4
|
+
import { docsLoader } from '@astrojs/starlight/loaders';
|
|
5
|
+
import { docsSchema } from '@astrojs/starlight/schema';
|
|
6
|
+
|
|
7
|
+
export const collections = {
|
|
8
|
+
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
|
9
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { DropdownButton } from '@stainless-api/ui-primitives';
|
|
2
|
+
import { CopyIcon } from 'lucide-react';
|
|
3
|
+
import { ChatGPTIcon } from './icons/chat-gpt';
|
|
4
|
+
import { ClaudeIcon } from './icons/claude';
|
|
5
|
+
import { GeminiIcon } from './icons/gemini';
|
|
6
|
+
import { MarkdownIcon } from './icons/markdown';
|
|
7
|
+
import { CursorIcon } from './icons/cursor';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
|
|
10
|
+
import { getAIDropdownOptions, type DropdownIcon } from '../../plugin/globalJs/ai-dropdown-options';
|
|
11
|
+
|
|
12
|
+
const iconMap: { [key in DropdownIcon]: React.ReactNode } = {
|
|
13
|
+
markdown: <MarkdownIcon />,
|
|
14
|
+
copy: <CopyIcon size={16} />,
|
|
15
|
+
claude: <ClaudeIcon />,
|
|
16
|
+
chatgpt: <ChatGPTIcon />,
|
|
17
|
+
gemini: <GeminiIcon />,
|
|
18
|
+
cursor: <CursorIcon />,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const { primaryAction, groups } = getAIDropdownOptions();
|
|
22
|
+
|
|
23
|
+
function ItemLabel({ label }: { label: string[] }) {
|
|
24
|
+
if (label.length > 1) {
|
|
25
|
+
return (
|
|
26
|
+
<DropdownButton.MenuItemText subtle>
|
|
27
|
+
{label[0]}
|
|
28
|
+
<strong>{label[1]}</strong>
|
|
29
|
+
</DropdownButton.MenuItemText>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<DropdownButton.MenuItemText>
|
|
35
|
+
<strong>{label[0]}</strong>
|
|
36
|
+
</DropdownButton.MenuItemText>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function AIDropdown() {
|
|
41
|
+
return (
|
|
42
|
+
<DropdownButton data-dropdown-id="ai-dropdown-button">
|
|
43
|
+
<DropdownButton.PrimaryAction>
|
|
44
|
+
{iconMap[primaryAction.icon]}
|
|
45
|
+
<DropdownButton.PrimaryActionText>{primaryAction.label}</DropdownButton.PrimaryActionText>
|
|
46
|
+
</DropdownButton.PrimaryAction>
|
|
47
|
+
<DropdownButton.Trigger />
|
|
48
|
+
<DropdownButton.Menu>
|
|
49
|
+
{groups.map((group) => (
|
|
50
|
+
<React.Fragment key={group.reactKey}>
|
|
51
|
+
{group.options.map((option) => (
|
|
52
|
+
<DropdownButton.MenuItem value={option.id} isExternalLink={option.external} key={option.id}>
|
|
53
|
+
<DropdownButton.Icon>{iconMap[option.icon]}</DropdownButton.Icon>
|
|
54
|
+
<ItemLabel label={option.label} />
|
|
55
|
+
</DropdownButton.MenuItem>
|
|
56
|
+
))}
|
|
57
|
+
{group.isLast ? null : <hr />}
|
|
58
|
+
</React.Fragment>
|
|
59
|
+
))}
|
|
60
|
+
</DropdownButton.Menu>
|
|
61
|
+
</DropdownButton>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ChevronRight } from 'lucide-react';
|
|
2
|
-
import { Join } from '@stainless-api/docs-ui/
|
|
3
|
-
import style from '@stainless-api/docs-ui/
|
|
2
|
+
import { Join } from '@stainless-api/docs-ui/components';
|
|
3
|
+
import style from '@stainless-api/docs-ui/style';
|
|
4
4
|
import type { StarlightRouteData } from '@astrojs/starlight/route-data';
|
|
5
5
|
|
|
6
6
|
type Breadcrumb = { title: string; href: string };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Default from '@astrojs/starlight/components/Head.astro';
|
|
3
|
+
|
|
4
|
+
// TODO: for users who are overriding the font stack in their own styles, how can we know that and
|
|
5
|
+
// preload their font instead of ours?
|
|
6
|
+
import geistPath from '../../assets/fonts/geist/geist-latin.woff2';
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<Default />
|
|
10
|
+
|
|
11
|
+
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous" href={geistPath} />
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import { wireAIDropdown } from '../../plugin/globalJs/ai-dropdown-options.ts';
|
|
15
|
+
wireAIDropdown();
|
|
16
|
+
</script>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import config from 'virtual:starlight/user-config';
|
|
3
3
|
|
|
4
|
-
import { HEADER_LAYOUT } from 'virtual:stl-
|
|
4
|
+
import { HEADER_LAYOUT } from 'virtual:stl-docs-virtual-module';
|
|
5
5
|
import DefaultHeader from './headers/DefaultHeader.astro';
|
|
6
6
|
import StackedHeader from './headers/StackedHeader.astro';
|
|
7
7
|
|
|
@@ -23,12 +23,9 @@ const shouldRenderSearch = !!(
|
|
|
23
23
|
|
|
24
24
|
<style is:global>
|
|
25
25
|
@layer starlight.core {
|
|
26
|
-
header
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
&.header {
|
|
30
|
-
border-bottom-color: var(--sl-color-hairline);
|
|
31
|
-
}
|
|
26
|
+
header,
|
|
27
|
+
header.header {
|
|
28
|
+
border-color: var(--stl-color-border-faint);
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
.header {
|
|
@@ -44,9 +41,10 @@ const shouldRenderSearch = !!(
|
|
|
44
41
|
overflow: clip;
|
|
45
42
|
/* Avoid clipping focus ring around link inside title wrapper. */
|
|
46
43
|
padding: 0.25rem;
|
|
47
|
-
padding-left: 0;
|
|
48
44
|
margin: -0.25rem;
|
|
49
45
|
min-width: 0;
|
|
46
|
+
/* Max height should match button height */
|
|
47
|
+
max-height: 32px;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
.default-tabs-container {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
ENABLE_PROSE_MARKDOWN_RENDERING,
|
|
4
|
+
ENABLE_CONTEXT_MENU,
|
|
5
|
+
RENDER_PAGE_DESCRIPTIONS,
|
|
6
|
+
} from 'virtual:stl-docs-virtual-module';
|
|
7
|
+
import type { StarlightRouteData } from '@astrojs/starlight/route-data';
|
|
8
|
+
import Default from '@astrojs/starlight/components/PageTitle.astro';
|
|
9
|
+
import { ContentBreadcrumbs } from './ContentBreadcrumbs';
|
|
10
|
+
import { AIDropdown } from './AIDropdown';
|
|
11
|
+
|
|
12
|
+
function sidebarHasEntry(sidebarEntry: StarlightRouteData['sidebar'], currentPath?: string) {
|
|
13
|
+
if (!currentPath) return false;
|
|
14
|
+
const normalizePath = (path: string) => {
|
|
15
|
+
return path.endsWith('/') ? path : path + '/';
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const normalizedCurrent = normalizePath(currentPath);
|
|
19
|
+
|
|
20
|
+
for (const entry of sidebarEntry) {
|
|
21
|
+
if (entry.type === 'link') {
|
|
22
|
+
const normalizedHref = normalizePath(entry.href);
|
|
23
|
+
if (normalizedHref === normalizedCurrent) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
} else if (entry.type === 'group') {
|
|
27
|
+
const hasInGroup = sidebarHasEntry(entry.entries, currentPath);
|
|
28
|
+
if (hasInGroup) return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const skipRenderingStarlightTitle = Astro.locals._stlStarlightPage?.skipRenderingStarlightTitle ?? false;
|
|
36
|
+
|
|
37
|
+
const hasMarkdownRoute = Astro.locals._stlStarlightPage?.hasMarkdownRoute ?? true;
|
|
38
|
+
// ⬆️ hopefully this is temporary. But for now, we don't have a markdown representation of the API reference overview page
|
|
39
|
+
|
|
40
|
+
const currentPath = Astro.url.pathname;
|
|
41
|
+
|
|
42
|
+
function shouldShowAIDropdown() {
|
|
43
|
+
// Hide if there is no associated sidebar entry. This applies to pages like the 404 page.
|
|
44
|
+
const hasSidebarEntry = sidebarHasEntry(Astro.locals.starlightRoute.sidebar, currentPath);
|
|
45
|
+
if (!hasSidebarEntry) return false;
|
|
46
|
+
|
|
47
|
+
if (!hasMarkdownRoute) return false;
|
|
48
|
+
|
|
49
|
+
if (!ENABLE_PROSE_MARKDOWN_RENDERING) return false;
|
|
50
|
+
if (!ENABLE_CONTEXT_MENU) return false;
|
|
51
|
+
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const showAIDropdown = shouldShowAIDropdown();
|
|
56
|
+
|
|
57
|
+
const description = Astro.locals.starlightRoute.entry.data.description;
|
|
58
|
+
const shouldRenderDescription = RENDER_PAGE_DESCRIPTIONS;
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
{
|
|
62
|
+
skipRenderingStarlightTitle ? null : (
|
|
63
|
+
<>
|
|
64
|
+
<div class="stl-ui-not-prose stl-page-nav-container stl-prose-page-nav-container">
|
|
65
|
+
<ContentBreadcrumbs currentPath={currentPath} sidebarEntry={Astro.locals.starlightRoute.sidebar} />
|
|
66
|
+
{showAIDropdown && <AIDropdown />}
|
|
67
|
+
</div>
|
|
68
|
+
<Default />
|
|
69
|
+
{!!description && shouldRenderDescription && <p class="description">{description}</p>}
|
|
70
|
+
</>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
<style>
|
|
75
|
+
p.description {
|
|
76
|
+
font-size: var(--stl-typography-scale-xl);
|
|
77
|
+
font-weight: 400;
|
|
78
|
+
line-height: 1.4;
|
|
79
|
+
letter-spacing: -0.02em;
|
|
80
|
+
margin-top: 0.4em;
|
|
81
|
+
}
|
|
82
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Default from '@astrojs/starlight/components/TableOfContents.astro';
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<Default {...Astro.props} />
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
/**
|
|
9
|
+
* Starlight will mark TOC links as active as they are scrolled to. However, it does not mark
|
|
10
|
+
* a link as active if it cannot be scrolled to on the page. This happens for small sections at
|
|
11
|
+
* the bottom of the page which are not large enough to scroll to the top of the viewport.
|
|
12
|
+
*
|
|
13
|
+
* This script will mark a section as active if its corresponding hash is in the URL, even if
|
|
14
|
+
* it cannot be scrolled to.
|
|
15
|
+
*/
|
|
16
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
17
|
+
const tocLinks = document.querySelectorAll('starlight-toc a') as NodeListOf<HTMLAnchorElement>;
|
|
18
|
+
|
|
19
|
+
function updateAriaCurrent() {
|
|
20
|
+
const current = decodeURIComponent(window.location.hash || '');
|
|
21
|
+
tocLinks.forEach((link) => {
|
|
22
|
+
const linkHash = decodeURIComponent(link.hash || link.getAttribute('href') || '');
|
|
23
|
+
if (linkHash === current) {
|
|
24
|
+
link.setAttribute('aria-current', 'true');
|
|
25
|
+
} else {
|
|
26
|
+
link.removeAttribute('aria-current');
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
window.addEventListener('hashchange', updateAriaCurrent);
|
|
32
|
+
updateAriaCurrent();
|
|
33
|
+
});
|
|
34
|
+
</script>
|
|
@@ -1,94 +1,133 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
DropdownTrigger,
|
|
5
|
-
DropdownMenu,
|
|
6
|
-
DropdownItem,
|
|
7
|
-
} from '@stainless-api/docs-ui/src/components/dropdown';
|
|
2
|
+
import { Dropdown } from '@stainless-api/docs/components';
|
|
3
|
+
import { ChevronsUpDownIcon } from 'lucide-react';
|
|
8
4
|
|
|
9
5
|
const options = [
|
|
10
6
|
{
|
|
11
7
|
value: 'auto',
|
|
12
8
|
label: 'Auto',
|
|
13
|
-
icon:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
icon: `
|
|
10
|
+
<svg
|
|
11
|
+
width="24"
|
|
12
|
+
height="24"
|
|
13
|
+
viewBox="0 0 24 24"
|
|
14
|
+
fill="none"
|
|
15
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
16
|
+
>
|
|
17
|
+
<path
|
|
21
18
|
d="M21 5C21 4.44771 20.5523 4 20 4H4C3.44772 4 3 4.44772 3 5V15C3 15.5523 3.44772 16 4 16H20C20.5523 16 21 15.5523 21 15V5ZM23 15C23 16.6569 21.6569 18 20 18H13V20H16C16.5523 20 17 20.4477 17 21C17 21.5523 16.5523 22 16 22H8C7.44772 22 7 21.5523 7 21C7 20.4477 7.44772 20 8 20H11V18H4C2.34315 18 1 16.6569 1 15V5C1 3.34315 2.34315 2 4 2H20C21.6569 2 23 3.34315 23 5V15Z"
|
|
22
|
-
fill="
|
|
23
|
-
|
|
19
|
+
fill="var(--stl-color-foreground)"
|
|
20
|
+
></path>
|
|
21
|
+
</svg>
|
|
22
|
+
`,
|
|
24
23
|
},
|
|
25
24
|
{
|
|
26
25
|
value: 'light',
|
|
27
26
|
label: 'Light',
|
|
28
|
-
icon:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
icon: `
|
|
28
|
+
<svg
|
|
29
|
+
width="24"
|
|
30
|
+
height="24"
|
|
31
|
+
viewBox="0 0 24 24"
|
|
32
|
+
fill="none"
|
|
33
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
34
|
+
>
|
|
35
|
+
<path
|
|
36
36
|
d="M11 22V20C11 19.4477 11.4477 19 12 19C12.5523 19 13 19.4477 13 20V22C13 22.5523 12.5523 23 12 23C11.4477 23 11 22.5523 11 22ZM5.63281 16.9531C6.02332 16.5626 6.65635 16.5626 7.04688 16.9531C7.4374 17.3436 7.4374 17.9767 7.04688 18.3672L5.6377 19.7773C5.24717 20.1679 4.61318 20.1679 4.22266 19.7773C3.83232 19.387 3.83259 18.7538 4.22266 18.3633L5.63281 16.9531ZM16.9531 16.9531C17.3191 16.5871 17.8982 16.5637 18.291 16.8838L18.3672 16.9531L19.7773 18.3633L19.8457 18.4385C20.1663 18.8313 20.1435 19.4111 19.7773 19.7773C19.4113 20.1433 18.8322 20.1658 18.4395 19.8457L18.3633 19.7773L16.9531 18.3672L16.8848 18.291C16.5643 17.8983 16.5871 17.3193 16.9531 16.9531ZM15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15C13.6569 15 15 13.6569 15 12ZM4 11C4.55228 11 5 11.4477 5 12C5 12.5523 4.55228 13 4 13H2C1.44772 13 1 12.5523 1 12C1 11.4477 1.44772 11 2 11H4ZM22 11C22.5523 11 23 11.4477 23 12C23 12.5523 22.5523 13 22 13H20C19.4477 13 19 12.5523 19 12C19 11.4477 19.4477 11 20 11H22ZM7.04688 5.63281C7.4374 6.02334 7.4374 6.65635 7.04688 7.04688C6.65634 7.43728 6.0233 7.43736 5.63281 7.04688L4.22266 5.63672L5.6377 4.22266L7.04688 5.63281ZM18.3633 4.22266C18.7538 3.83235 19.3869 3.83224 19.7773 4.22266C20.1678 4.61311 20.1677 5.24618 19.7773 5.63672L18.3672 7.04688C17.9767 7.4374 17.3436 7.4374 16.9531 7.04688C16.5626 6.65635 16.5626 6.02332 16.9531 5.63281L18.3633 4.22266ZM4.22266 4.22266C4.61318 3.83213 5.24717 3.83213 5.6377 4.22266L4.22266 5.63672C3.83254 5.24621 3.83238 4.61307 4.22266 4.22266ZM11 4V2C11 1.44772 11.4477 1 12 1C12.5523 1 13 1.44772 13 2V4C13 4.55228 12.5523 5 12 5C11.4477 5 11 4.55228 11 4ZM17 12C17 14.7614 14.7614 17 12 17C9.23858 17 7 14.7614 7 12C7 9.23858 9.23858 7 12 7C14.7614 7 17 9.23858 17 12Z"
|
|
37
|
-
fill="
|
|
38
|
-
|
|
37
|
+
fill="var(--stl-color-foreground)"
|
|
38
|
+
></path>
|
|
39
|
+
</svg>
|
|
40
|
+
`,
|
|
39
41
|
},
|
|
40
42
|
{
|
|
41
43
|
value: 'dark',
|
|
42
44
|
label: 'Dark',
|
|
43
|
-
icon:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
icon: `
|
|
46
|
+
<svg
|
|
47
|
+
width="24"
|
|
48
|
+
height="24"
|
|
49
|
+
viewBox="0 0 24 24"
|
|
50
|
+
fill="none"
|
|
51
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
52
|
+
>
|
|
53
|
+
<path
|
|
54
|
+
d="M9.13569 7.5C9.13569 6.37669 9.39314 5.28007 9.87397 4.28809C9.05381 4.51419 8.27063 4.87087 7.55561 5.34863C6.24009 6.22764 5.21483 7.47676 4.60932 8.93848C4.00386 10.4002 3.84465 12.0088 4.15327 13.5605C4.46195 15.1124 5.2239 16.5384 6.34272 17.6572C7.46154 18.776 8.88756 19.538 10.4394 19.8467C11.9912 20.1553 13.5997 19.9961 15.0615 19.3906C16.5232 18.7851 17.7723 17.7599 18.6513 16.4443C19.1292 15.7291 19.4848 14.9454 19.7109 14.125C18.719 14.6057 17.6231 14.8643 16.4999 14.8643C14.5469 14.8643 12.6739 14.088 11.2929 12.707C9.91191 11.326 9.13569 9.45304 9.13569 7.5ZM11.1357 7.5C11.1357 8.92261 11.701 10.287 12.707 11.293C13.7129 12.2989 15.0773 12.8643 16.4999 12.8643C17.9226 12.8643 19.287 12.2989 20.2929 11.293C20.5789 11.007 21.0091 10.9214 21.3828 11.0762C21.7564 11.231 22 11.5956 22 12C22 13.9778 21.4132 15.9112 20.3144 17.5557C19.2156 19.2001 17.6543 20.4824 15.8271 21.2393C13.9998 21.9961 11.9886 22.1935 10.0488 21.8076C8.10909 21.4217 6.32711 20.4697 4.92866 19.0713C3.53021 17.6728 2.57822 15.8909 2.19233 13.9512C1.80648 12.0114 2.00382 10.0001 2.76069 8.17285C3.51756 6.34567 4.79987 4.78434 6.44429 3.68555C8.08878 2.58673 10.0221 2 11.9999 2C12.4044 2 12.769 2.24359 12.9238 2.61719C13.0786 2.99086 12.993 3.42103 12.707 3.70703C11.701 4.71297 11.1357 6.07739 11.1357 7.5Z"
|
|
55
|
+
fill="var(--stl-color-foreground)"
|
|
56
|
+
></path>
|
|
57
|
+
</svg>
|
|
58
|
+
`,
|
|
54
59
|
},
|
|
55
60
|
];
|
|
56
61
|
---
|
|
57
62
|
|
|
58
|
-
<
|
|
59
|
-
<Dropdown
|
|
60
|
-
<
|
|
61
|
-
<span class="stl-dropdown-icon">
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
</
|
|
63
|
+
<Dropdown data-theme-select>
|
|
64
|
+
<Dropdown.Trigger>
|
|
65
|
+
<Dropdown.TriggerSelectedItem>
|
|
66
|
+
<span class="stl-dropdown-icon"></span>
|
|
67
|
+
</Dropdown.TriggerSelectedItem>
|
|
68
|
+
<Dropdown.TriggerIcon>
|
|
69
|
+
<ChevronsUpDownIcon size={16} />
|
|
70
|
+
</Dropdown.TriggerIcon>
|
|
71
|
+
</Dropdown.Trigger>
|
|
72
|
+
<Dropdown.Menu>
|
|
73
|
+
{
|
|
74
|
+
options.map(({ value, label, icon }) => (
|
|
75
|
+
<Dropdown.MenuItem value={value}>
|
|
76
|
+
<Dropdown.Icon>
|
|
77
|
+
<Fragment set:html={icon} />
|
|
78
|
+
</Dropdown.Icon>
|
|
79
|
+
<Dropdown.MenuItemText>{label}</Dropdown.MenuItemText>
|
|
80
|
+
<Dropdown.MenuItemTemplate>
|
|
81
|
+
<span class="stl-dropdown-icon">
|
|
82
|
+
<Fragment set:html={icon} />
|
|
83
|
+
</span>
|
|
84
|
+
</Dropdown.MenuItemTemplate>
|
|
85
|
+
</Dropdown.MenuItem>
|
|
86
|
+
))
|
|
87
|
+
}
|
|
88
|
+
</Dropdown.Menu>
|
|
89
|
+
</Dropdown>
|
|
81
90
|
|
|
82
|
-
{/* Inlined to avoid FOUC.
|
|
91
|
+
{/* Inlined to avoid FOUC. All theme selects are initialized here */}
|
|
83
92
|
<script is:inline>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
window.didInitThemePickers = window.didInitThemePickers ?? false;
|
|
94
|
+
|
|
95
|
+
// Only run once.
|
|
96
|
+
if (!window.didInitThemePickers) {
|
|
97
|
+
window.didInitThemePickers = true;
|
|
98
|
+
|
|
99
|
+
// The stored theme will be either 'auto', 'light', 'dark' or null.
|
|
100
|
+
const storedTheme = typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');
|
|
101
|
+
|
|
102
|
+
// This theme is either 'light' or 'dark'. It's used for setting the data-theme attribute.
|
|
103
|
+
const theme =
|
|
104
|
+
!storedTheme || storedTheme === 'auto'
|
|
105
|
+
? window.matchMedia('(prefers-color-scheme: light)').matches
|
|
106
|
+
? 'light'
|
|
107
|
+
: 'dark'
|
|
108
|
+
: storedTheme;
|
|
109
|
+
|
|
110
|
+
document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';
|
|
111
|
+
|
|
112
|
+
const themeSelects = document.querySelectorAll('[data-theme-select]');
|
|
113
|
+
const selectedThemeValue = storedTheme || 'auto';
|
|
114
|
+
|
|
115
|
+
themeSelects.forEach((select) => {
|
|
116
|
+
const tmpl = select.querySelector(`[data-value="${selectedThemeValue}"] template`);
|
|
117
|
+
const selectedSlot = select.querySelector('[data-part="trigger-selected"]');
|
|
118
|
+
|
|
119
|
+
selectedSlot.innerHTML = '';
|
|
120
|
+
if (tmpl) {
|
|
121
|
+
selectedSlot.appendChild(tmpl.content.cloneNode(true));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
88
126
|
</script>
|
|
89
127
|
|
|
90
128
|
<script>
|
|
91
129
|
import { getPageLoadEvent } from '../../plugin/helpers/getPageLoadEvent';
|
|
130
|
+
import { initDropdown } from '@stainless-api/docs/components/scripts';
|
|
92
131
|
|
|
93
132
|
const storageKey = 'starlight-theme';
|
|
94
133
|
|
|
@@ -100,115 +139,54 @@ const options = [
|
|
|
100
139
|
const loadTheme = (): Theme => parseTheme(localStorage.getItem(storageKey));
|
|
101
140
|
|
|
102
141
|
const storeTheme = (theme: Theme) => {
|
|
103
|
-
localStorage.setItem(storageKey, theme
|
|
142
|
+
localStorage.setItem(storageKey, parseTheme(theme));
|
|
104
143
|
};
|
|
105
144
|
|
|
106
145
|
const getPreferredColorScheme = (): Theme =>
|
|
107
146
|
window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
|
108
147
|
|
|
109
|
-
const highlightSelected = (doc: Document, theme: Theme) => {
|
|
110
|
-
doc.querySelectorAll('.theme-select-container.stldocs-dropdown').forEach((container) => {
|
|
111
|
-
const icons = container.querySelectorAll('.stl-dropdown-icon svg');
|
|
112
|
-
icons.forEach((icon, index) => {
|
|
113
|
-
const themeForIcon = ['auto', 'light', 'dark'][index];
|
|
114
|
-
icon.classList.toggle('selected', theme === themeForIcon);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
container.querySelectorAll('.stldocs-dropdown-item').forEach((option) => {
|
|
118
|
-
const label = option.querySelector('.stl-dropdown-label')?.textContent?.toLowerCase();
|
|
119
|
-
option.classList.toggle('selected', label === theme);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const menu = container.querySelector('.stldocs-dropdown-menu');
|
|
123
|
-
menu?.classList.remove('open');
|
|
124
|
-
});
|
|
125
|
-
};
|
|
126
|
-
|
|
127
148
|
const applyTheme = (doc: Document, theme: Theme) => {
|
|
128
149
|
const effective = theme === 'auto' ? getPreferredColorScheme() : theme;
|
|
129
150
|
doc.documentElement.dataset.theme = effective;
|
|
130
151
|
storeTheme(theme);
|
|
131
|
-
StarlightThemeProvider?.updatePickers?.(theme);
|
|
132
|
-
highlightSelected(doc, theme);
|
|
133
152
|
};
|
|
134
153
|
|
|
135
154
|
function setupThemeMode(doc: Document) {
|
|
136
|
-
// Attach to all instances of .theme-select-container.stldocs-dropdown. We need this because
|
|
137
|
-
// the theme component is used in the mobile dropdown and the desktop sidebar.
|
|
138
|
-
doc.querySelectorAll('.theme-select-container.stldocs-dropdown').forEach((container) => {
|
|
139
|
-
const trigger = container.querySelector('.stldocs-dropdown-trigger');
|
|
140
|
-
const menu = container.querySelector('.stldocs-dropdown-menu');
|
|
141
|
-
|
|
142
|
-
if (trigger && menu) {
|
|
143
|
-
trigger.addEventListener('click', (e) => {
|
|
144
|
-
e.stopPropagation();
|
|
145
|
-
|
|
146
|
-
doc.querySelectorAll('.theme-select-container .stldocs-dropdown-menu.open').forEach((otherMenu) => {
|
|
147
|
-
if (otherMenu !== menu) otherMenu.classList.remove('open');
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
menu.classList.toggle('open');
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
container.querySelectorAll('.stldocs-dropdown-item').forEach((option) => {
|
|
154
|
-
option.addEventListener('click', () => {
|
|
155
|
-
const label = option.querySelector('.stl-dropdown-label')?.textContent?.toLowerCase() ?? '';
|
|
156
|
-
if (['auto', 'light', 'dark'].includes(label)) {
|
|
157
|
-
applyTheme(doc, label as Theme);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// Close dropdown if you click outside
|
|
165
|
-
doc.addEventListener('click', (e) => {
|
|
166
|
-
doc.querySelectorAll('.theme-select-container .stldocs-dropdown-menu.open').forEach((menu) => {
|
|
167
|
-
if (e.target instanceof HTMLElement && !menu.contains(e.target)) {
|
|
168
|
-
menu.classList.remove('open');
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// React to system preference changes
|
|
174
155
|
matchMedia('(prefers-color-scheme: light)').addEventListener('change', () => {
|
|
175
156
|
if (loadTheme() === 'auto') applyTheme(doc, 'auto');
|
|
176
157
|
});
|
|
177
158
|
|
|
178
159
|
applyTheme(doc, loadTheme());
|
|
160
|
+
return loadTheme();
|
|
179
161
|
}
|
|
180
162
|
|
|
181
163
|
document.addEventListener('astro:before-swap', (event) => {
|
|
182
164
|
applyTheme(event.newDocument, loadTheme());
|
|
183
165
|
});
|
|
184
166
|
|
|
185
|
-
document.addEventListener(getPageLoadEvent(), (
|
|
186
|
-
setupThemeMode(document);
|
|
167
|
+
document.addEventListener(getPageLoadEvent(), () => {
|
|
168
|
+
const initialTheme = setupThemeMode(document);
|
|
169
|
+
const themeSelects = document.querySelectorAll<HTMLElement>('[data-theme-select]');
|
|
170
|
+
themeSelects.forEach((select) => {
|
|
171
|
+
initDropdown({
|
|
172
|
+
root: select,
|
|
173
|
+
onSelect: (value: string) => applyTheme(document, value as Theme),
|
|
174
|
+
initialValue: initialTheme as string,
|
|
175
|
+
});
|
|
176
|
+
});
|
|
187
177
|
});
|
|
188
178
|
</script>
|
|
189
179
|
|
|
190
180
|
<style is:global>
|
|
191
|
-
.theme-select-root {
|
|
192
|
-
background-color: unset;
|
|
193
|
-
display: flex;
|
|
194
|
-
align-items: center;
|
|
195
|
-
}
|
|
196
181
|
.stl-dropdown-icon svg {
|
|
197
182
|
width: 16px;
|
|
198
183
|
height: 16px;
|
|
199
184
|
|
|
200
185
|
path {
|
|
201
|
-
fill: var(--
|
|
186
|
+
fill: var(--stl-color-foreground-reduced);
|
|
202
187
|
}
|
|
203
188
|
}
|
|
204
189
|
|
|
205
|
-
.stldocs-dropdown-trigger .stl-dropdown-icon svg {
|
|
206
|
-
display: none;
|
|
207
|
-
|
|
208
|
-
&.selected {
|
|
209
|
-
display: flex;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
190
|
.stl-dropdown-icon {
|
|
213
191
|
display: flex;
|
|
214
192
|
align-items: center;
|
|
@@ -217,8 +195,7 @@ const options = [
|
|
|
217
195
|
height: 16px;
|
|
218
196
|
}
|
|
219
197
|
|
|
220
|
-
span.stl-dropdown-icon
|
|
221
|
-
span.stl-dropdown-chevron {
|
|
198
|
+
span.stl-dropdown-icon {
|
|
222
199
|
padding-left: 0;
|
|
223
200
|
padding-right: 0%;
|
|
224
201
|
}
|