@stainless-api/docs 0.1.0-beta.1 → 0.1.0-beta.100

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.
Files changed (158) hide show
  1. package/CHANGELOG.md +917 -0
  2. package/eslint-suppressions.json +27 -0
  3. package/locals.d.ts +17 -0
  4. package/package.json +50 -40
  5. package/playground-virtual-modules.d.ts +96 -0
  6. package/plugin/assets/languages/cli.svg +14 -0
  7. package/plugin/assets/languages/csharp.svg +1 -0
  8. package/plugin/assets/languages/php.svg +4 -0
  9. package/plugin/buildAlgoliaIndex.ts +40 -39
  10. package/plugin/components/MethodDescription.tsx +54 -0
  11. package/plugin/components/RequestBuilder/ParamEditor.tsx +55 -0
  12. package/plugin/components/RequestBuilder/SnippetStainlessIsland.tsx +107 -0
  13. package/plugin/components/RequestBuilder/index.tsx +37 -0
  14. package/plugin/components/RequestBuilder/props.ts +9 -0
  15. package/plugin/components/RequestBuilder/spec-helpers.ts +47 -0
  16. package/plugin/components/RequestBuilder/styles.css +67 -0
  17. package/plugin/components/SDKSelect.astro +18 -105
  18. package/plugin/components/SnippetCode.tsx +111 -66
  19. package/plugin/components/StainlessIslands.tsx +126 -0
  20. package/plugin/components/search/SearchAlgolia.astro +45 -35
  21. package/plugin/components/search/SearchIsland.tsx +47 -29
  22. package/plugin/generateAPIReferenceLink.ts +2 -2
  23. package/plugin/globalJs/ai-dropdown-options.ts +243 -0
  24. package/plugin/globalJs/code-snippets.ts +40 -11
  25. package/plugin/globalJs/copy.ts +95 -17
  26. package/plugin/globalJs/create-playground.shim.ts +3 -0
  27. package/plugin/globalJs/method-descriptions.ts +33 -0
  28. package/plugin/globalJs/navigation.ts +12 -33
  29. package/plugin/globalJs/playground-data.shim.ts +1 -0
  30. package/plugin/globalJs/playground-data.ts +14 -0
  31. package/plugin/helpers/generateDocsRoutes.ts +59 -0
  32. package/plugin/helpers/getPageLoadEvent.ts +1 -1
  33. package/plugin/helpers/multiSpec.ts +8 -0
  34. package/plugin/index.ts +299 -117
  35. package/plugin/languages.ts +8 -2
  36. package/plugin/loadPluginConfig.ts +254 -102
  37. package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
  38. package/plugin/react/Routing.tsx +210 -140
  39. package/plugin/referencePlaceholderUtils.ts +18 -15
  40. package/plugin/replaceSidebarPlaceholderMiddleware.ts +40 -32
  41. package/plugin/routes/Docs.astro +70 -119
  42. package/plugin/routes/DocsStatic.astro +6 -5
  43. package/plugin/routes/Overview.astro +37 -27
  44. package/plugin/routes/markdown.ts +13 -12
  45. package/plugin/{cms → sidebar-utils}/sidebar-builder.ts +49 -60
  46. package/plugin/specs/FileCache.ts +99 -0
  47. package/plugin/specs/fetchSpecSSR.ts +27 -0
  48. package/plugin/specs/generateSpec.ts +112 -0
  49. package/plugin/specs/index.ts +132 -0
  50. package/plugin/specs/inputResolver.ts +146 -0
  51. package/plugin/{cms → specs}/worker.ts +82 -5
  52. package/plugin/vendor/preview.worker.docs.js +22406 -17955
  53. package/plugin/vendor/templates/cli.md +1 -0
  54. package/plugin/vendor/templates/go.md +4 -2
  55. package/plugin/vendor/templates/java.md +3 -1
  56. package/plugin/vendor/templates/kotlin.md +3 -1
  57. package/plugin/vendor/templates/node.md +4 -2
  58. package/plugin/vendor/templates/python.md +4 -2
  59. package/plugin/vendor/templates/ruby.md +4 -2
  60. package/plugin/vendor/templates/terraform.md +1 -1
  61. package/plugin/vendor/templates/typescript.md +3 -1
  62. package/resolveSrcFile.ts +10 -0
  63. package/scripts/vendor_deps.ts +5 -5
  64. package/shared/getProsePages.ts +42 -0
  65. package/shared/getSharedLogger.ts +15 -0
  66. package/shared/terminalUtils.ts +3 -0
  67. package/shared/virtualModule.ts +54 -1
  68. package/src/content.config.ts +9 -0
  69. package/stl-docs/components/AIDropdown.tsx +63 -0
  70. package/stl-docs/components/AiChatIsland.tsx +14 -0
  71. package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
  72. package/stl-docs/components/Head.astro +20 -0
  73. package/stl-docs/components/Header.astro +7 -9
  74. package/stl-docs/components/PageFrame.astro +18 -0
  75. package/stl-docs/components/PageTitle.astro +82 -0
  76. package/stl-docs/components/TableOfContents.astro +34 -0
  77. package/stl-docs/components/ThemeProvider.astro +36 -0
  78. package/stl-docs/components/ThemeSelect.astro +84 -144
  79. package/stl-docs/components/content-panel/ContentPanel.astro +16 -46
  80. package/stl-docs/components/headers/DefaultHeader.astro +1 -1
  81. package/stl-docs/components/headers/HeaderLinks.astro +1 -1
  82. package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
  83. package/stl-docs/components/headers/StackedHeader.astro +29 -24
  84. package/stl-docs/components/icons/chat-gpt.tsx +17 -0
  85. package/stl-docs/components/icons/claude.tsx +10 -0
  86. package/stl-docs/components/icons/cursor.tsx +10 -0
  87. package/stl-docs/components/icons/gemini.tsx +19 -0
  88. package/stl-docs/components/icons/markdown.tsx +10 -0
  89. package/stl-docs/components/index.ts +1 -0
  90. package/stl-docs/components/mintlify-compat/Accordion.astro +7 -38
  91. package/stl-docs/components/mintlify-compat/AccordionGroup.astro +9 -23
  92. package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
  93. package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
  94. package/stl-docs/components/mintlify-compat/callouts/Callout.astro +10 -3
  95. package/stl-docs/components/mintlify-compat/callouts/Check.astro +7 -3
  96. package/stl-docs/components/mintlify-compat/callouts/Danger.astro +7 -3
  97. package/stl-docs/components/mintlify-compat/callouts/Info.astro +7 -3
  98. package/stl-docs/components/mintlify-compat/callouts/Note.astro +7 -3
  99. package/stl-docs/components/mintlify-compat/callouts/Tip.astro +7 -3
  100. package/stl-docs/components/mintlify-compat/callouts/Warning.astro +7 -3
  101. package/stl-docs/components/mintlify-compat/card.css +33 -35
  102. package/stl-docs/components/mintlify-compat/index.ts +2 -4
  103. package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -75
  104. package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
  105. package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
  106. package/stl-docs/components/nav-tabs/buildNavLinks.ts +4 -3
  107. package/stl-docs/components/pagination/HomeLink.astro +10 -0
  108. package/stl-docs/components/pagination/Pagination.astro +175 -0
  109. package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
  110. package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
  111. package/stl-docs/components/pagination/util.ts +71 -0
  112. package/stl-docs/components/scripts.ts +1 -0
  113. package/stl-docs/components/sidebars/BaseSidebar.astro +87 -0
  114. package/stl-docs/components/sidebars/SDKSelectSidebar.astro +8 -0
  115. package/stl-docs/components/sidebars/SidebarWithComponents.tsx +10 -0
  116. package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +62 -0
  117. package/stl-docs/disableCalloutSyntax.ts +36 -0
  118. package/stl-docs/fonts.ts +186 -0
  119. package/stl-docs/index.ts +159 -43
  120. package/stl-docs/loadStlDocsConfig.ts +60 -9
  121. package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +61 -0
  122. package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +41 -0
  123. package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
  124. package/stl-docs/proseSearchIndexing.ts +606 -0
  125. package/stl-docs/tabsMiddleware.ts +14 -5
  126. package/styles/code.css +133 -136
  127. package/styles/links.css +11 -48
  128. package/styles/method-descriptions.css +36 -0
  129. package/styles/overrides.css +49 -57
  130. package/styles/page.css +100 -59
  131. package/styles/sdk_select.css +9 -7
  132. package/styles/search.css +57 -69
  133. package/styles/sidebar.css +26 -156
  134. package/styles/{variables.css → sl-variables.css} +3 -2
  135. package/styles/stldocs-variables.css +6 -0
  136. package/styles/toc.css +41 -34
  137. package/theme.css +13 -3
  138. package/tsconfig.json +2 -5
  139. package/virtual-module.d.ts +65 -7
  140. package/components/variables.css +0 -139
  141. package/plugin/cms/client.ts +0 -62
  142. package/plugin/cms/server.ts +0 -268
  143. package/plugin/globalJs/ai-dropdown.ts +0 -57
  144. package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -86
  145. package/stl-docs/components/Sidebar.astro +0 -11
  146. package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -64
  147. package/stl-docs/components/mintlify-compat/Step.astro +0 -58
  148. package/stl-docs/components/mintlify-compat/Steps.astro +0 -17
  149. package/styles/fonts.css +0 -68
  150. /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
  151. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
  152. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
  153. /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
  154. /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
  155. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
  156. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
  157. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
  158. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
@@ -7,80 +7,98 @@ import clsx from 'clsx';
7
7
  const navLinks = buildNavLinks(Astro.locals.starlightRoute);
8
8
  ---
9
9
 
10
- <div id="nav-links-container">
11
- <ul class="nav-links" id="nav-links-list">
12
- <li class="mobile-menu-item" data-mobile-only>
13
- <NavDropdown />
14
- </li>
15
- {
16
- navLinks.map((item) => (
17
- <li data-desktop-only>
18
- <Button
19
- href={item.link}
20
- className={clsx('nav-link')}
21
- variant={item.active ? 'accent-muted' : 'ghost'}
22
- >
23
- <span>{item.label}</span>
24
- </Button>
25
- </li>
26
- ))
27
- }
28
- </ul>
29
- <!-- The test container is used to measure the width of the nav links and see if they fit -->
30
- <!-- TODO: probably want to clean this up bc it's duplicated code -->
31
- <ul class="nav-links" id="nav-links-test-container">
32
- {
33
- navLinks.map((item) => (
34
- <li>
35
- <Button href={item.link} className={clsx('nav-link')} variant={item.active ? 'accent' : 'ghost'}>
36
- <span>{item.label}</span>
37
- </Button>
38
- </li>
39
- ))
40
- }
41
- </ul>
10
+ <div id="nav-links-container" class="nav-links-container">
11
+ <div class="desktop-nav-links-container">
12
+ <ul class="nav-links" id="nav-links-list">
13
+ {
14
+ navLinks.map((item) => (
15
+ <li data-desktop-only>
16
+ <Button
17
+ href={item.link}
18
+ className={clsx('nav-link')}
19
+ variant={item.active ? 'accent-muted' : 'ghost'}
20
+ >
21
+ <span>{item.label}</span>
22
+ </Button>
23
+ </li>
24
+ ))
25
+ }
26
+ </ul>
27
+ </div>
28
+ <div class="mobile-nav-dropdown" data-mobile-only>
29
+ <NavDropdown />
30
+ </div>
42
31
  </div>
43
32
 
44
33
  <script>
45
34
  import { getPageLoadEvent } from '../../../plugin/helpers/getPageLoadEvent';
46
35
 
47
- function getRequiredWidth() {
48
- const navLinksTestContainer = document.getElementById('nav-links-test-container');
49
- if (!navLinksTestContainer) return 1000000; // fallback to a large number
36
+ // We need to measure the nav links to see if they fit. We create an offscreen hidden clone for measurement.
37
+ function createOffscreenClone(element: HTMLElement): HTMLElement {
38
+ const clone = element.cloneNode(true) as HTMLElement;
39
+ clone.removeAttribute('id');
40
+ clone.id = 'cloned-nav-links-measurement';
41
+ clone.style.position = 'absolute';
42
+ clone.style.visibility = 'hidden';
43
+ clone.style.top = '0';
44
+ clone.style.left = '0';
45
+ clone.style.width = 'auto';
46
+ clone.style.whiteSpace = 'nowrap';
47
+ clone.style.pointerEvents = 'none';
48
+ clone.style.zIndex = '-9999';
49
+
50
+ clone.querySelectorAll('[data-desktop-only], [data-mobile-only]').forEach((el) => {
51
+ el.removeAttribute('data-desktop-only');
52
+ });
50
53
 
51
- const rw = navLinksTestContainer.scrollWidth;
52
- navLinksTestContainer.remove();
53
- return rw;
54
+ document.body.appendChild(clone);
55
+ return clone;
54
56
  }
55
57
 
56
58
  function initNavbar() {
57
- const masterContainer = document.getElementById('nav-links-container');
58
- if (!masterContainer) return;
59
+ const navLinksContainer = document.getElementById('nav-links-container');
60
+ if (!navLinksContainer) {
61
+ console.error(`NavTabs: #nav-links-container not found`);
62
+ return;
63
+ }
59
64
 
60
- const navLinksContainer = document.getElementById('nav-links-list');
61
- if (!navLinksContainer) return;
65
+ const navLinksList = document.getElementById('nav-links-list');
66
+ if (!navLinksList) {
67
+ console.error(`NavTabs: #nav-links-list not found`);
68
+ return;
69
+ }
70
+
71
+ const measurementClone = createOffscreenClone(navLinksList);
72
+ const requiredWidth = measurementClone.clientWidth;
62
73
 
63
- const requiredWidth = getRequiredWidth();
74
+ let currentMode: 'desktop' | 'mobile' | null = null;
64
75
 
65
76
  function checkIfFits() {
66
- if (!masterContainer) return;
67
77
  if (!navLinksContainer) return;
68
- const availableWidth = masterContainer.clientWidth;
69
- const canFit = availableWidth >= requiredWidth;
78
+
79
+ // 16px buffer helps it feel less crowded before switching modes
80
+ const bufferSpace = 16;
81
+ const availableWidth = navLinksContainer.clientWidth;
82
+ const canFit = availableWidth - bufferSpace >= requiredWidth;
70
83
 
71
84
  const mode = canFit ? 'desktop' : 'mobile';
72
85
 
73
- localStorage.setItem('stl-nav-links-mode', mode);
86
+ // Only update if mode actually changed
87
+ if (mode === currentMode) return;
88
+
89
+ currentMode = mode;
74
90
 
75
- document.documentElement.classList.remove('stl-nav-links-mode-desktop');
76
- document.documentElement.classList.remove('stl-nav-links-mode-mobile');
91
+ localStorage.setItem('stl-nav-links-mode', mode);
77
92
 
93
+ document.documentElement.classList.remove('stl-nav-links-mode-desktop', 'stl-nav-links-mode-mobile');
78
94
  document.documentElement.classList.add('stl-nav-links-mode-' + mode);
79
95
  }
80
96
 
81
- window.addEventListener('resize', () => {
97
+ const resizeObserver = new ResizeObserver(() => {
82
98
  checkIfFits();
83
99
  });
100
+
101
+ resizeObserver.observe(navLinksContainer);
84
102
  checkIfFits();
85
103
  }
86
104
 
@@ -109,55 +127,35 @@ const navLinks = buildNavLinks(Astro.locals.starlightRoute);
109
127
  </style>
110
128
 
111
129
  <style>
112
- /* :root {
113
- --menu-font-size: calc(var(--sl-text-body));
114
- } */
130
+ .nav-links-container {
131
+ flex-grow: 1;
132
+ margin-left: 1rem;
133
+ margin-right: 1rem;
134
+ }
115
135
 
116
- #nav-links-container {
117
- visibility: hidden;
136
+ .desktop-nav-links-container {
118
137
  display: flex;
119
138
  flex-grow: 1;
120
139
  justify-content: flex-start;
121
140
  overflow: hidden;
122
- margin-left: 1rem;
123
- margin-right: 1rem;
124
141
  }
125
142
 
126
143
  .nav-links {
127
144
  display: flex;
128
145
  list-style: none;
129
- gap: 0;
146
+ gap: 4px;
130
147
  padding: 0;
131
148
  margin: 0;
132
149
  white-space: nowrap;
133
150
  overflow: hidden;
134
151
  }
135
152
 
136
- #nav-links-test-container {
137
- position: absolute;
138
- top: 0;
139
- left: 0;
140
- visibility: hidden;
141
- }
142
-
143
- .nav-links li {
144
- display: flex;
145
- align-items: center;
146
- justify-content: center;
147
- }
148
-
149
- .nav-link {
150
- text-decoration: none;
151
- flex: 1;
152
-
153
- &.stl-ui-button--ghost:hover {
154
- color: var(--sl-color-text-accent);
155
- background-color: transparent;
156
- }
153
+ .mobile-nav-dropdown {
154
+ flex-grow: 1;
157
155
  }
158
156
 
159
157
  @media (min-width: 50rem) {
160
- #nav-links-container {
158
+ .desktop-nav-links-container {
161
159
  display: flex;
162
160
  visibility: visible;
163
161
  }
@@ -34,13 +34,7 @@ const navLinks = buildNavLinks(Astro.locals.starlightRoute);
34
34
  align-items: center;
35
35
  padding: 0;
36
36
  list-style: none;
37
- overflow-x: auto;
38
37
  margin-bottom: -1px;
39
- gap: 0.29rem;
40
- }
41
-
42
- .stl-active-secondary-link:hover {
43
- background-color: transparent;
44
38
  }
45
39
 
46
40
  li {
@@ -48,7 +42,21 @@ const navLinks = buildNavLinks(Astro.locals.starlightRoute);
48
42
  border-bottom: 2px solid transparent;
49
43
 
50
44
  &.active {
51
- border-color: var(--sl-color-text-accent);
45
+ border-color: var(--stl-color-accent-border-strong);
46
+ }
47
+
48
+ .stl-ui-button {
49
+ /* match sidebar. TODO: hoist sidebar variables to use those instead of hardcoding? */
50
+ border-width: 0;
51
+ padding: 8px 12px;
52
+ margin-inline: -12px;
53
+ }
54
+ /* cover for button’s negative margin */
55
+ &:not(:first-child) {
56
+ margin-inline-start: 12px;
57
+ }
58
+ &:not(:last-child) {
59
+ margin-inline-end: 12px;
52
60
  }
53
61
  }
54
62
  }
@@ -56,7 +64,6 @@ const navLinks = buildNavLinks(Astro.locals.starlightRoute);
56
64
  @media (min-width: 50rem) {
57
65
  .stl-secondary-nav-tabs {
58
66
  display: block;
59
- padding-left: 0.55rem;
60
67
  }
61
68
  }
62
69
  </style>
@@ -1,9 +1,10 @@
1
1
  import type { StarlightRouteData } from '@astrojs/starlight/route-data';
2
- import { TABS } from 'virtual:stl-stl-starlight-virtual-module';
2
+ import { TABS } from 'virtual:stl-docs-virtual-module';
3
+ import type { StarlightRouteWithStlDocs } from '../../tabsMiddleware';
3
4
 
4
5
  export function buildNavLinks(starlightRoute: StarlightRouteData) {
5
- // TODO: specify the type of Astro.locals.starlightRoute._stlStarlight
6
- const activeTabIndex = starlightRoute._stlStarlight?.activeTabIndex;
6
+ const routeData: StarlightRouteWithStlDocs = starlightRoute;
7
+ const activeTabIndex = routeData?._stlDocs?.activeTabIndex;
7
8
 
8
9
  const navLinks = TABS.map((item, index) => ({
9
10
  ...item,
@@ -0,0 +1,10 @@
1
+ ---
2
+ import { base } from 'astro:config/client';
3
+ import { HomeIcon } from 'lucide-react';
4
+ import PaginationLinkQuiet from './PaginationLinkQuiet.astro';
5
+ ---
6
+
7
+ <PaginationLinkQuiet href={base}>
8
+ <HomeIcon slot="icon" />
9
+ Home
10
+ </PaginationLinkQuiet>
@@ -0,0 +1,175 @@
1
+ ---
2
+ import HomeLink from './HomeLink.astro';
3
+ import PaginationLinkEmphasized from './PaginationLinkEmphasized.astro';
4
+
5
+ import { getPrevNextPage } from './util';
6
+ import config from 'virtual:starlight/user-config';
7
+ const { prev, next } = (await getPrevNextPage(Astro.locals.starlightRoute, config.pagination)) ?? {};
8
+ ---
9
+
10
+ {
11
+ next || prev ? (
12
+ <div class="pagination-links print:hidden stl-ui-not-prose">
13
+ {/* Previous */}
14
+ {!prev && <HomeLink />}
15
+ {/* TODO: intelligently decide whether or not to emphasize the previous page - including user config option (page level?) */}
16
+ {/* {prev && next && (
17
+ <PaginationLinkQuiet href={prev.href}>
18
+ <ChevronLeftIcon slot="icon" />
19
+ Previous
20
+ </PaginationLinkQuiet>
21
+ )} */}
22
+ {prev && (
23
+ <PaginationLinkEmphasized href={prev.href} direction="prev">
24
+ <h2 slot="page-title">{prev.label}</h2>
25
+ {prev.description && <p slot="page-description">{prev.description}</p>}
26
+ </PaginationLinkEmphasized>
27
+ )}
28
+
29
+ {/* Next */}
30
+ {!next && <HomeLink />}
31
+ {next && (
32
+ <PaginationLinkEmphasized href={next.href} direction="next">
33
+ <h2 slot="page-title">{next.label}</h2>
34
+ {next.description && <p slot="page-description">{next.description}</p>}
35
+ </PaginationLinkEmphasized>
36
+ )}
37
+ </div>
38
+ ) : null
39
+ }
40
+
41
+ <style is:global>
42
+ @layer starlight.core {
43
+ .pagination-links,
44
+ .pagination-links a,
45
+ .pagination-links a:hover,
46
+ .pagination-links a[rel='next'],
47
+ .link-title {
48
+ all: revert-layer;
49
+ }
50
+ }
51
+
52
+ .pagination-links {
53
+ --stl-ui-pagination-padding: 8px;
54
+ --stl-ui-pagination-border-radius-inner: var(--stl-ui-layout-border-radius-sml);
55
+
56
+ padding: var(--stl-ui-pagination-padding);
57
+ background-color: var(--stl-color-faint-background);
58
+ border: 1px solid var(--stl-color-border);
59
+ border-radius: calc(var(--stl-ui-pagination-border-radius-inner) + var(--stl-ui-pagination-padding));
60
+
61
+ font-size: var(--stl-typography-scale-sm);
62
+ letter-spacing: normal;
63
+
64
+ display: flex;
65
+ gap: 8px;
66
+
67
+ margin-bottom: 2rem;
68
+ color: inherit; /* stl-ui-not-prose sets color: initial */
69
+
70
+ a {
71
+ border-radius: var(--stl-ui-pagination-border-radius-inner);
72
+ }
73
+ }
74
+
75
+ .pagination-links__link {
76
+ display: flex;
77
+ border-radius: var(--stl-ui-pagination-border-radius-inner);
78
+ padding: 8px 12px;
79
+ display: flex;
80
+ text-decoration: none;
81
+ align-items: center;
82
+ color: inherit;
83
+ }
84
+
85
+ .pagination-links__link--emphasized {
86
+ background-color: var(--stl-color-background);
87
+ border: 1px solid var(--stl-color-border);
88
+ flex: 1 1 50%;
89
+ gap: 12px;
90
+ }
91
+
92
+ .pagination-links__link--quiet {
93
+ flex: 0 1 auto;
94
+ }
95
+
96
+ .pagination-links__button {
97
+ display: flex;
98
+ align-items: center;
99
+ padding: 8px 14px;
100
+ font-weight: 500;
101
+ line-height: 1;
102
+
103
+ svg {
104
+ width: 16px;
105
+ height: 16px;
106
+ margin-block: -4px;
107
+ margin-inline-start: -6px;
108
+ margin-inline-end: 6px;
109
+ }
110
+
111
+ &.pagination-links__link--quiet {
112
+ padding-inline: 22px;
113
+ }
114
+ }
115
+
116
+ .pagination-links__link__divider {
117
+ border: 0;
118
+ border-inline-start: 1px solid var(--stl-color-border);
119
+ align-self: stretch;
120
+ }
121
+
122
+ .pagination-links__page-description {
123
+ padding-block: 4px;
124
+ padding-inline-start: 8px;
125
+ padding-inline-end: 2px;
126
+ line-height: 1.5;
127
+ flex: 1 1 50%;
128
+ width: 0;
129
+
130
+ h2,
131
+ p {
132
+ white-space: nowrap;
133
+ overflow: hidden;
134
+ text-overflow: ellipsis;
135
+ }
136
+ h2 {
137
+ font-size: inherit;
138
+ font-weight: 500;
139
+ }
140
+ p {
141
+ font-size: var(--stl-typography-scale-xs);
142
+ color: var(--stl-color-foreground-muted);
143
+ }
144
+ }
145
+ .pagination-links__link--quiet:hover {
146
+ background-color: var(--stl-color-background-hover);
147
+ }
148
+ .pagination-links__link--emphasized:hover {
149
+ border-color: var(--stl-color-border-strong);
150
+ .pagination-links__page-description h2 {
151
+ text-decoration: underline;
152
+ text-decoration-color: var(--stl-color-foreground-reduced);
153
+ }
154
+ }
155
+
156
+ /* “next” link runs the opposite direction of the “previous” link */
157
+ .pagination-links__link:last-child {
158
+ flex-direction: row-reverse;
159
+
160
+ &.pagination-links__button,
161
+ .pagination-links__button {
162
+ flex-direction: row-reverse;
163
+ svg {
164
+ margin-inline-start: 6px;
165
+ margin-inline-end: -6px;
166
+ }
167
+ }
168
+
169
+ .pagination-links__page-description {
170
+ padding-inline-start: 2px;
171
+ padding-inline-end: 8px;
172
+ text-align: right;
173
+ }
174
+ }
175
+ </style>
@@ -0,0 +1,22 @@
1
+ ---
2
+ import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
3
+ const { href, direction } = Astro.props;
4
+ export interface Props {
5
+ href: string;
6
+ direction: 'prev' | 'next';
7
+ }
8
+ ---
9
+
10
+ <a href={href} class="pagination-links__link pagination-links__link--emphasized">
11
+ <div class="pagination-links__button">
12
+ {{ prev: <ChevronLeftIcon />, next: <ChevronRightIcon /> }[direction]}
13
+ <span>{{ prev: 'Previous', next: 'Next' }[direction]}</span>
14
+ </div>
15
+
16
+ <hr class="pagination-links__link__divider" />
17
+
18
+ <article class="pagination-links__page-description">
19
+ <slot name="page-title" />
20
+ <slot name="page-description" />
21
+ </article>
22
+ </a>
@@ -0,0 +1,13 @@
1
+ ---
2
+ const { href } = Astro.props;
3
+ export interface Props {
4
+ href: string;
5
+ }
6
+ ---
7
+
8
+ <a href={href} class="pagination-links__link pagination-links__button pagination-links__link--quiet">
9
+ <slot name="icon" />
10
+ <span>
11
+ <slot />
12
+ </span>
13
+ </a>
@@ -0,0 +1,71 @@
1
+ import type { StarlightRouteData } from '@astrojs/starlight/route-data';
2
+ import { getCollection } from 'astro:content';
3
+
4
+ export type SidebarEntry = StarlightRouteData['sidebar'][number];
5
+ export type SidebarLink = Extract<SidebarEntry, { type: 'link' }>;
6
+ export type SidebarGroup = Extract<SidebarEntry, { type: 'group' }>;
7
+
8
+ export const flattenSidebar = (sidebar: SidebarEntry[]): SidebarLink[] =>
9
+ sidebar.flatMap((e) => (e.type === 'group' ? flattenSidebar(e.entries) : e));
10
+
11
+ function findParentOfSidebarEntry(sidebar: SidebarEntry[], targetEntry: SidebarEntry): SidebarGroup | null {
12
+ for (const entry of sidebar) {
13
+ if (entry.type === 'group') {
14
+ if (entry.entries.includes(targetEntry)) {
15
+ return entry;
16
+ }
17
+ const foundInChild = findParentOfSidebarEntry(entry.entries, targetEntry);
18
+ if (foundInChild) {
19
+ return foundInChild;
20
+ }
21
+ }
22
+ }
23
+ return null;
24
+ }
25
+
26
+ export async function getPrevNextPage(page: StarlightRouteData, paginationEnabled: boolean) {
27
+ // TODO: respect user `next` / `prev` config from frontmatter the way starlight does
28
+
29
+ if (!paginationEnabled) return null;
30
+
31
+ const docsContent = await getCollection('docs');
32
+ const findSidebarLinkInContent = (link: SidebarLink) =>
33
+ docsContent.find((doc) => {
34
+ if (doc.id === 'index' && link.href === '/') return true;
35
+ return doc.id === link.href.replace(/^\//, '').replace(/\/$/, '');
36
+ });
37
+
38
+ const currentSidebar = page.sidebar;
39
+
40
+ const paginationSequence: (SidebarLink & { description?: string })[] = flattenSidebar(currentSidebar)
41
+ // Remove injected stl-mobile-only-sidebar-item links - TODO: better solution for this
42
+ .filter((link) => !(link.attrs.class ?? '').trim().split(/\s+/).includes('stl-mobile-only-sidebar-item'))
43
+ // Remove data-stldocs-method links from pagination sequence
44
+ .filter((link) => !link.attrs['data-stldocs-method'])
45
+ // Map data-stldocs-overview=readme links so that their name is not just “Overview”
46
+ .map((link) => {
47
+ if (link.attrs['data-stldocs-overview'] && link.label === 'Overview') {
48
+ const parent = findParentOfSidebarEntry(currentSidebar, link);
49
+ if (parent) return { ...link, label: parent.label };
50
+ }
51
+ return link;
52
+ })
53
+ .map((link) => {
54
+ const contentEntry = findSidebarLinkInContent(link);
55
+ if (contentEntry) return { ...link, description: contentEntry.data.description };
56
+ return link;
57
+ });
58
+
59
+ const currentIndex = paginationSequence.findIndex((e) => e.isCurrent);
60
+ if (currentIndex === -1) return null;
61
+
62
+ const prevIndex = currentIndex > 0 ? currentIndex - 1 : null;
63
+ const nextIndex = currentIndex < paginationSequence.length - 1 ? currentIndex + 1 : null;
64
+ const prevSidebarEntry = prevIndex !== null ? (paginationSequence[prevIndex] ?? null) : null;
65
+ const nextSidebarEntry = nextIndex !== null ? (paginationSequence[nextIndex] ?? null) : null;
66
+
67
+ return {
68
+ prev: prevSidebarEntry,
69
+ next: nextSidebarEntry,
70
+ };
71
+ }
@@ -0,0 +1 @@
1
+ export * from '@stainless-api/ui-primitives/scripts';
@@ -0,0 +1,87 @@
1
+ ---
2
+ import HeaderLinks from '../headers/HeaderLinks.astro';
3
+ import { SidebarWithComponents } from './SidebarWithComponents';
4
+ import SidebarPersister from '@astrojs/starlight/components/SidebarPersister.astro';
5
+ import { convertAstroSidebarToStl } from './convertAstroSidebarToStl';
6
+ import { StlSidebarEntry, StlSidebarGroup, StlSidebarLink } from '@stainless-api/docs-ui/components';
7
+ import { LINK_GROUP_TITLES_TO_OVERVIEW_PAGES } from 'virtual:stl-docs-virtual-module';
8
+
9
+ const { sidebar } = Astro.locals.starlightRoute;
10
+
11
+ let stlSidebar = convertAstroSidebarToStl(sidebar);
12
+
13
+ function extractOverviewPage(entry: StlSidebarGroup): {
14
+ overviewLink: StlSidebarLink | null;
15
+ remainingEntries: StlSidebarEntry[];
16
+ } {
17
+ let overviewLink: StlSidebarLink | null = null;
18
+
19
+ const withoutOverview = entry.entries.filter((e) => {
20
+ if (e.type !== 'link') {
21
+ return true;
22
+ }
23
+ const overviewAttr = e.attrs?.['data-stldocs-overview'];
24
+ if (!overviewAttr) {
25
+ return true;
26
+ }
27
+ overviewLink = e;
28
+ return false;
29
+ });
30
+
31
+ return {
32
+ overviewLink,
33
+ remainingEntries: withoutOverview,
34
+ };
35
+ }
36
+
37
+ function linkGroupTitleToOverviewPages(sidebar: StlSidebarEntry[]): StlSidebarEntry[] {
38
+ return sidebar.map((entry) => {
39
+ if (entry.type === 'group') {
40
+ const { overviewLink, remainingEntries } = extractOverviewPage(entry);
41
+
42
+ // group only contained an overview link
43
+ if (overviewLink && remainingEntries.length === 0) {
44
+ return {
45
+ ...overviewLink,
46
+ label: entry.label, // keep the group label
47
+ };
48
+ }
49
+
50
+ // set the group target to the overview link target
51
+
52
+ let target = entry.target;
53
+ let isCurrent = entry.isCurrent;
54
+ let collapsed = entry.collapsed;
55
+ if (overviewLink) {
56
+ target = overviewLink.target;
57
+ isCurrent = overviewLink.isCurrent;
58
+ if (isCurrent) {
59
+ collapsed = false;
60
+ }
61
+ }
62
+
63
+ return {
64
+ ...entry,
65
+ entries: linkGroupTitleToOverviewPages(remainingEntries),
66
+ target,
67
+ isCurrent,
68
+ collapsed,
69
+ };
70
+ } else {
71
+ return entry;
72
+ }
73
+ });
74
+ }
75
+
76
+ if (LINK_GROUP_TITLES_TO_OVERVIEW_PAGES === true) {
77
+ stlSidebar = linkGroupTitleToOverviewPages(stlSidebar);
78
+ }
79
+ ---
80
+
81
+ <div class="stl-sidebar-header-links">
82
+ <HeaderLinks />
83
+ </div>
84
+ <slot name="sdk-select" />
85
+ <SidebarPersister>
86
+ <SidebarWithComponents entries={stlSidebar} withStarlightRestoration />
87
+ </SidebarPersister>
@@ -0,0 +1,8 @@
1
+ ---
2
+ import BaseSidebar from './BaseSidebar.astro';
3
+ import SDKSelect from '../../../plugin/components/SDKSelect.astro';
4
+ ---
5
+
6
+ <BaseSidebar>
7
+ <SDKSelect slot="sdk-select" />
8
+ </BaseSidebar>
@@ -0,0 +1,10 @@
1
+ import { StlSidebar, StlSidebarProps } from '@stainless-api/docs-ui/components';
2
+ import { ComponentProvider } from '@stainless-api/docs-ui/contexts/component';
3
+
4
+ export function SidebarWithComponents(props: StlSidebarProps) {
5
+ return (
6
+ <ComponentProvider>
7
+ <StlSidebar {...props} />
8
+ </ComponentProvider>
9
+ );
10
+ }