@stainless-api/docs 0.1.0-beta.7 → 0.1.0-beta.70

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 (120) hide show
  1. package/CHANGELOG.md +554 -0
  2. package/README.md +1 -1
  3. package/eslint-suppressions.json +52 -0
  4. package/locals.d.ts +17 -0
  5. package/package.json +51 -40
  6. package/plugin/assets/languages/csharp.svg +1 -0
  7. package/plugin/buildAlgoliaIndex.ts +32 -7
  8. package/plugin/cms/server.ts +130 -58
  9. package/plugin/cms/sidebar-builder.ts +7 -26
  10. package/plugin/cms/worker.ts +83 -5
  11. package/plugin/components/MethodDescription.tsx +54 -0
  12. package/plugin/components/SDKSelect.astro +7 -87
  13. package/plugin/components/SnippetCode.tsx +53 -8
  14. package/plugin/components/search/SearchAlgolia.astro +45 -28
  15. package/plugin/components/search/SearchIsland.tsx +38 -24
  16. package/plugin/create-playground.shim.tsx +3 -0
  17. package/plugin/generateAPIReferenceLink.ts +2 -2
  18. package/plugin/globalJs/ai-dropdown-options.ts +243 -0
  19. package/plugin/globalJs/code-snippets.ts +15 -8
  20. package/plugin/globalJs/copy.ts +81 -16
  21. package/plugin/globalJs/method-descriptions.ts +33 -0
  22. package/plugin/globalJs/navigation.ts +7 -4
  23. package/plugin/helpers/generateDocsRoutes.ts +27 -0
  24. package/plugin/index.ts +178 -35
  25. package/plugin/languages.ts +5 -2
  26. package/plugin/loadPluginConfig.ts +121 -32
  27. package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
  28. package/plugin/react/Routing.tsx +208 -129
  29. package/plugin/referencePlaceholderUtils.ts +1 -1
  30. package/plugin/replaceSidebarPlaceholderMiddleware.ts +5 -1
  31. package/plugin/routes/Docs.astro +62 -89
  32. package/plugin/routes/DocsStatic.astro +1 -1
  33. package/plugin/routes/Overview.astro +10 -16
  34. package/plugin/routes/markdown.ts +9 -8
  35. package/plugin/vendor/preview.worker.docs.js +19768 -17702
  36. package/plugin/vendor/templates/go.md +1 -1
  37. package/plugin/vendor/templates/python.md +1 -1
  38. package/resolveSrcFile.ts +10 -0
  39. package/scripts/vendor_deps.ts +5 -5
  40. package/shared/getProsePages.ts +42 -0
  41. package/shared/getSharedLogger.ts +15 -0
  42. package/shared/terminalUtils.ts +3 -0
  43. package/src/content.config.ts +9 -0
  44. package/stl-docs/components/AIDropdown.tsx +63 -0
  45. package/stl-docs/components/AiChatIsland.tsx +14 -0
  46. package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +10 -18
  47. package/stl-docs/components/Head.astro +16 -0
  48. package/stl-docs/components/Header.astro +6 -8
  49. package/stl-docs/components/PageFrame.astro +18 -0
  50. package/stl-docs/components/PageTitle.astro +82 -0
  51. package/stl-docs/components/TableOfContents.astro +34 -0
  52. package/stl-docs/components/ThemeProvider.astro +36 -0
  53. package/stl-docs/components/ThemeSelect.astro +84 -139
  54. package/stl-docs/components/content-panel/ContentPanel.astro +16 -25
  55. package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
  56. package/stl-docs/components/headers/StackedHeader.astro +29 -24
  57. package/stl-docs/components/icons/chat-gpt.tsx +17 -0
  58. package/stl-docs/components/icons/claude.tsx +10 -0
  59. package/stl-docs/components/icons/cursor.tsx +10 -0
  60. package/stl-docs/components/icons/gemini.tsx +19 -0
  61. package/stl-docs/components/icons/markdown.tsx +10 -0
  62. package/stl-docs/components/index.ts +1 -0
  63. package/stl-docs/components/mintlify-compat/Accordion.astro +7 -5
  64. package/stl-docs/components/mintlify-compat/AccordionGroup.astro +7 -3
  65. package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
  66. package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
  67. package/stl-docs/components/mintlify-compat/callouts/Callout.astro +1 -1
  68. package/stl-docs/components/mintlify-compat/callouts/Check.astro +1 -1
  69. package/stl-docs/components/mintlify-compat/callouts/Danger.astro +1 -1
  70. package/stl-docs/components/mintlify-compat/callouts/Info.astro +1 -1
  71. package/stl-docs/components/mintlify-compat/callouts/Note.astro +1 -1
  72. package/stl-docs/components/mintlify-compat/callouts/Tip.astro +1 -1
  73. package/stl-docs/components/mintlify-compat/callouts/Warning.astro +1 -1
  74. package/stl-docs/components/mintlify-compat/card.css +33 -35
  75. package/stl-docs/components/mintlify-compat/index.ts +2 -4
  76. package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -70
  77. package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
  78. package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
  79. package/stl-docs/components/nav-tabs/buildNavLinks.ts +3 -2
  80. package/stl-docs/components/pagination/HomeLink.astro +10 -0
  81. package/stl-docs/components/pagination/Pagination.astro +175 -0
  82. package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
  83. package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
  84. package/stl-docs/components/pagination/util.ts +71 -0
  85. package/stl-docs/components/scripts.ts +1 -0
  86. package/stl-docs/disableCalloutSyntax.ts +36 -0
  87. package/stl-docs/index.ts +141 -50
  88. package/stl-docs/loadStlDocsConfig.ts +45 -5
  89. package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +61 -0
  90. package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +39 -0
  91. package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
  92. package/stl-docs/proseSearchIndexing.ts +450 -0
  93. package/stl-docs/tabsMiddleware.ts +11 -3
  94. package/styles/code.css +108 -140
  95. package/styles/fonts.css +32 -17
  96. package/styles/links.css +11 -48
  97. package/styles/method-descriptions.css +36 -0
  98. package/styles/overrides.css +48 -60
  99. package/styles/page.css +92 -52
  100. package/styles/sdk_select.css +9 -7
  101. package/styles/search.css +56 -69
  102. package/styles/sidebar.css +211 -131
  103. package/styles/{variables.css → sl-variables.css} +3 -2
  104. package/styles/stldocs-variables.css +6 -0
  105. package/styles/toc.css +41 -34
  106. package/theme.css +10 -10
  107. package/tsconfig.json +2 -5
  108. package/virtual-module.d.ts +26 -4
  109. package/components/variables.css +0 -135
  110. package/stl-docs/components/mintlify-compat/Step.astro +0 -58
  111. package/stl-docs/components/mintlify-compat/Steps.astro +0 -17
  112. /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
  113. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
  114. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
  115. /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
  116. /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
  117. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
  118. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
  119. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
  120. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
@@ -16,51 +16,49 @@ const { cols } = Astro.props;
16
16
  </div>
17
17
 
18
18
  <style>
19
- @layer stl-ui-mintlify-compat {
20
- .stl-ui-mintlify-compat-columns {
21
- display: grid;
22
- gap: 1rem;
23
- grid-template-columns: 1fr;
19
+ .stl-ui-mintlify-compat-columns {
20
+ display: grid;
21
+ gap: 1rem;
22
+ grid-template-columns: 1fr;
24
23
 
25
- > [data-stl-ui-element] {
26
- margin: 0;
27
- }
24
+ > [data-stl-ui-element] {
25
+ margin: 0;
28
26
  }
27
+ }
29
28
 
30
- @media (min-width: 50rem) {
31
- .stl-ui-mintlify-compat-columns--2 {
32
- grid-template-columns: repeat(2, minmax(0, 1fr));
33
- }
34
- .stl-ui-mintlify-compat-columns--3 {
35
- grid-template-columns: repeat(3, minmax(0, 1fr));
36
- }
37
- .stl-ui-mintlify-compat-columns--4 {
38
- grid-template-columns: repeat(4, minmax(0, 1fr));
39
- }
40
- .stl-ui-mintlify-compat-columns--5 {
41
- grid-template-columns: repeat(5, minmax(0, 1fr));
42
- }
43
- .stl-ui-mintlify-compat-columns--6 {
44
- grid-template-columns: repeat(6, minmax(0, 1fr));
45
- }
46
- .stl-ui-mintlify-compat-columns--7 {
47
- grid-template-columns: repeat(7, minmax(0, 1fr));
48
- }
49
- .stl-ui-mintlify-compat-columns--8 {
50
- grid-template-columns: repeat(8, minmax(0, 1fr));
51
- }
52
- .stl-ui-mintlify-compat-columns--9 {
53
- grid-template-columns: repeat(9, minmax(0, 1fr));
54
- }
55
- .stl-ui-mintlify-compat-columns--10 {
56
- grid-template-columns: repeat(10, minmax(0, 1fr));
57
- }
58
- .stl-ui-mintlify-compat-columns--11 {
59
- grid-template-columns: repeat(11, minmax(0, 1fr));
60
- }
61
- .stl-ui-mintlify-compat-columns--12 {
62
- grid-template-columns: repeat(12, minmax(0, 1fr));
63
- }
29
+ @media (min-width: 50rem) {
30
+ .stl-ui-mintlify-compat-columns--2 {
31
+ grid-template-columns: repeat(2, minmax(0, 1fr));
32
+ }
33
+ .stl-ui-mintlify-compat-columns--3 {
34
+ grid-template-columns: repeat(3, minmax(0, 1fr));
35
+ }
36
+ .stl-ui-mintlify-compat-columns--4 {
37
+ grid-template-columns: repeat(4, minmax(0, 1fr));
38
+ }
39
+ .stl-ui-mintlify-compat-columns--5 {
40
+ grid-template-columns: repeat(5, minmax(0, 1fr));
41
+ }
42
+ .stl-ui-mintlify-compat-columns--6 {
43
+ grid-template-columns: repeat(6, minmax(0, 1fr));
44
+ }
45
+ .stl-ui-mintlify-compat-columns--7 {
46
+ grid-template-columns: repeat(7, minmax(0, 1fr));
47
+ }
48
+ .stl-ui-mintlify-compat-columns--8 {
49
+ grid-template-columns: repeat(8, minmax(0, 1fr));
50
+ }
51
+ .stl-ui-mintlify-compat-columns--9 {
52
+ grid-template-columns: repeat(9, minmax(0, 1fr));
53
+ }
54
+ .stl-ui-mintlify-compat-columns--10 {
55
+ grid-template-columns: repeat(10, minmax(0, 1fr));
56
+ }
57
+ .stl-ui-mintlify-compat-columns--11 {
58
+ grid-template-columns: repeat(11, minmax(0, 1fr));
59
+ }
60
+ .stl-ui-mintlify-compat-columns--12 {
61
+ grid-template-columns: repeat(12, minmax(0, 1fr));
64
62
  }
65
63
  }
66
64
  </style>
@@ -12,26 +12,24 @@ const { caption } = Astro.props;
12
12
  </div>
13
13
 
14
14
  <style>
15
- @layer stl-ui-mintlify-compat {
16
- .stl-ui-mintlify-compat-frame {
17
- padding: 6px;
18
- border-radius: 10px;
19
- background-color: var(--sl-color-gray-7);
20
- border: 1px solid var(--sl-color-gray-6);
15
+ .stl-ui-mintlify-compat-frame {
16
+ padding: 6px;
17
+ border-radius: 10px;
18
+ background-color: var(--stl-color-ui-background);
19
+ border: 1px solid var(--stl-color-border);
21
20
 
22
- .stl-ui-mintlify-compat-frame-content {
23
- border-radius: 8px;
24
- overflow: hidden;
25
- }
21
+ .stl-ui-mintlify-compat-frame-content {
22
+ border-radius: 8px;
23
+ overflow: hidden;
24
+ }
26
25
 
27
- .stl-ui-mintlify-compat-frame-caption {
28
- text-align: center;
29
- padding-top: 12px;
30
- padding-bottom: 6px;
31
- font-size: var(--sl-text-body);
32
- color: var(--sl-color-gray-3);
33
- line-height: 100%;
34
- }
26
+ .stl-ui-mintlify-compat-frame-caption {
27
+ text-align: center;
28
+ padding-top: 12px;
29
+ padding-bottom: 6px;
30
+ font-size: var(--stl-typography-scale-base);
31
+ color: var(--stl-color-foreground-reduced);
32
+ line-height: 100%;
35
33
  }
36
34
  }
37
35
  </style>
@@ -3,7 +3,7 @@ import { Callout as StainlessCallout, type CalloutVariant } from '@stainless-api
3
3
 
4
4
  export interface Props {
5
5
  variant?: CalloutVariant;
6
- children: unknown;
6
+ children: astroHTML.JSX.Children;
7
7
  }
8
8
 
9
9
  const { variant } = Astro.props;
@@ -2,7 +2,7 @@
2
2
  import { Callout } from '@stainless-api/ui-primitives';
3
3
 
4
4
  export interface Props {
5
- children: unknown;
5
+ children: astroHTML.JSX.Children;
6
6
  }
7
7
  ---
8
8
 
@@ -2,7 +2,7 @@
2
2
  import { Callout } from '@stainless-api/ui-primitives';
3
3
 
4
4
  export interface Props {
5
- children: unknown;
5
+ children: astroHTML.JSX.Children;
6
6
  }
7
7
  ---
8
8
 
@@ -2,7 +2,7 @@
2
2
  import { Callout } from '@stainless-api/ui-primitives';
3
3
 
4
4
  export interface Props {
5
- children: unknown;
5
+ children: astroHTML.JSX.Children;
6
6
  }
7
7
  ---
8
8
 
@@ -2,7 +2,7 @@
2
2
  import { Callout } from '@stainless-api/ui-primitives';
3
3
 
4
4
  export interface Props {
5
- children: unknown;
5
+ children: astroHTML.JSX.Children;
6
6
  }
7
7
  ---
8
8
 
@@ -2,7 +2,7 @@
2
2
  import { Callout } from '@stainless-api/ui-primitives';
3
3
 
4
4
  export interface Props {
5
- children: unknown;
5
+ children: astroHTML.JSX.Children;
6
6
  }
7
7
  ---
8
8
 
@@ -2,7 +2,7 @@
2
2
  import { Callout } from '@stainless-api/ui-primitives';
3
3
 
4
4
  export interface Props {
5
- children: unknown;
5
+ children: astroHTML.JSX.Children;
6
6
  }
7
7
  ---
8
8
 
@@ -1,44 +1,42 @@
1
- @layer stl-ui-mintlify-compat {
2
- .stl-ui-mintlify-compat-card {
3
- border-radius: 12px;
4
- padding: 16px;
5
- font-size: var(--sl-text-body);
6
- display: flex;
7
- gap: 8px;
8
- border: 1px solid var(--sl-color-hairline);
9
- flex-direction: column;
1
+ .stl-ui-mintlify-compat-card {
2
+ border-radius: 12px;
3
+ padding: 16px;
4
+ font-size: var(--stl-typography-scale-base);
5
+ display: flex;
6
+ gap: 8px;
7
+ border: 1px solid var(--stl-color-border);
8
+ flex-direction: column;
10
9
 
11
- .stl-ui-mintlify-compat-card-icon svg {
12
- color: var(--sl-color-accent);
13
- }
10
+ .stl-ui-mintlify-compat-card-icon svg {
11
+ color: var(--sl-color-accent);
12
+ }
14
13
 
15
- .stl-ui-mintlify-compat-card-title {
16
- font-weight: 600;
17
- font-size: 1.125rem;
18
- display: flex;
19
- align-items: center;
20
- gap: 8px;
21
- margin-top: 8px;
22
- }
14
+ .stl-ui-mintlify-compat-card-title {
15
+ font-weight: 600;
16
+ font-size: 1.125rem;
17
+ display: flex;
18
+ align-items: center;
19
+ gap: 8px;
20
+ margin-top: 8px;
21
+ }
23
22
 
24
- .stl-ui-mintlify-compat-card-content {
25
- margin-top: 0;
26
- color: var(--sl-color-text-secondary);
27
- }
23
+ .stl-ui-mintlify-compat-card-content {
24
+ margin-top: 0;
25
+ color: var(--stl-color-foreground-reduced);
28
26
  }
27
+ }
29
28
 
30
- a.stl-ui-mintlify-compat-card {
31
- text-decoration: none;
32
- color: var(--sl-color-text-secondary);
29
+ a.stl-ui-mintlify-compat-card {
30
+ text-decoration: none;
31
+ color: var(--stl-color-foreground-reduced);
33
32
 
34
- &:hover {
35
- border-color: var(--sl-color-accent);
36
- }
33
+ &:hover {
34
+ border-color: var(--sl-color-accent);
37
35
  }
36
+ }
38
37
 
39
- .stl-ui-mintlify-compat-card-group {
40
- display: grid;
41
- gap: 1rem;
42
- grid-template-columns: repeat(2, minmax(0, 1fr));
43
- }
38
+ .stl-ui-mintlify-compat-card-group {
39
+ display: grid;
40
+ gap: 1rem;
41
+ grid-template-columns: repeat(2, minmax(0, 1fr));
44
42
  }
@@ -3,13 +3,11 @@ import Tab from './Tab.astro';
3
3
  import Tabs from './Tabs.astro';
4
4
  import Frame from './Frame.astro';
5
5
  import Columns from './Columns.astro';
6
- import Steps from './Steps.astro';
7
- import Step from './Step.astro';
8
6
  import Accordion from './Accordion.astro';
9
7
  import AccordionGroup from './AccordionGroup.astro';
10
8
 
11
9
  export * from './callouts';
12
10
  export * from './Card';
13
11
 
14
- export { Tab, Tabs, Frame, Columns, Steps, Step, AccordionGroup, Accordion };
15
- export { Button } from '@stainless-api/ui-primitives';
12
+ export { Tab, Tabs, Frame, Columns, AccordionGroup, Accordion };
13
+ export { Button, Steps, Step } from '@stainless-api/ui-primitives';
@@ -1,76 +1,52 @@
1
1
  ---
2
- import { Dropdown, DropdownTrigger, DropdownMenu, DropdownItem } from '@stainless-api/docs-ui/src/components/dropdown';
3
- import { Icon } from '@astrojs/starlight/components';
2
+ import { Dropdown } from '@stainless-api/docs/components';
4
3
  import { buildNavLinks } from './buildNavLinks';
5
-
6
- export interface Props {
7
- useHamburgerIcon?: boolean;
8
- }
9
-
10
- const { useHamburgerIcon = false } = Astro.props as Props;
11
- const BUTTON_ID = 'nav-dropdown-button';
4
+ import { ChevronsUpDownIcon } from 'lucide-react';
12
5
 
13
6
  const navLinks = buildNavLinks(Astro.locals.starlightRoute);
14
7
 
15
- const buttonText = (navLinks.find((item) => item.active) ?? navLinks[0]).label;
8
+ const buttonText = (navLinks.find((item) => item.active) ?? navLinks[0]!).label;
16
9
  ---
17
10
 
18
- <div class="stldocs-root nav-dropdown-root">
19
- <Dropdown id="nav-dropdown">
20
- <DropdownTrigger
21
- className={`dropdown-toggle stldocs-button-tertiary nav-dropdown-button`}
22
- type="button"
23
- id={BUTTON_ID}
24
- aria-expanded="false"
25
- withChevron={!useHamburgerIcon}
26
- isIcon
27
- >
28
- {useHamburgerIcon ? <Icon name="bars" size="16px" /> : buttonText}
29
- </DropdownTrigger>
30
- <DropdownMenu className="dropdown-menu" position="below" aria-labelledby={BUTTON_ID}>
31
- {
32
- navLinks.map((item) => (
33
- <DropdownItem key={item.link} href={item.link} className="dropdown-item">
34
- {item.label}
35
- </DropdownItem>
36
- ))
37
- }
38
- </DropdownMenu>
39
- </Dropdown>
40
- </div>
11
+ <Dropdown id="nav-dropdown" className="nav-dropdown-root">
12
+ <Dropdown.Trigger>
13
+ <Dropdown.TriggerSelectedItem>{buttonText}</Dropdown.TriggerSelectedItem>
14
+ <Dropdown.TriggerIcon>
15
+ <ChevronsUpDownIcon size={16} />
16
+ </Dropdown.TriggerIcon>
17
+ </Dropdown.Trigger>
18
+ <Dropdown.Menu className="dropdown-menu">
19
+ {
20
+ navLinks.map((item) => (
21
+ <Dropdown.MenuItem
22
+ key={item.link}
23
+ href={item.link}
24
+ className="dropdown-item"
25
+ value={item.label}
26
+ isSelected={item.label === buttonText}
27
+ >
28
+ {item.label}
29
+ <Dropdown.MenuItemTemplate>{item.label}</Dropdown.MenuItemTemplate>
30
+ </Dropdown.MenuItem>
31
+ ))
32
+ }
33
+ </Dropdown.Menu>
34
+ </Dropdown>
41
35
 
42
36
  <script>
43
- import { initDropdown } from '@stainless-api/docs-ui/src/components/scripts/dropdown';
37
+ import { initDropdown } from '@stainless-api/docs/components/scripts';
44
38
  import { getPageLoadEvent } from '../../../plugin/helpers/getPageLoadEvent';
45
39
 
46
40
  document.addEventListener(getPageLoadEvent(), () => {
47
41
  initDropdown({
48
- dropdownId: 'nav-dropdown',
49
- isFixed: true,
42
+ root: document.getElementById('nav-dropdown'),
50
43
  });
51
44
  });
52
45
  </script>
53
- <style is:global>
54
- .nav-dropdown-root .dropdown-menu.stldocs-dropdown-menu {
55
- display: none;
56
- position: fixed;
57
- z-index: 1000;
58
- width: 200px;
59
- margin: 0.125rem 0 0;
60
- font-size: 1rem;
61
- text-align: left;
62
- list-style: none;
63
- background-clip: padding-box;
64
- }
65
-
66
- .nav-dropdown-root .dropdown-menu.open {
67
- display: block;
68
- }
69
- </style>
70
46
 
71
47
  <style>
72
48
  :root {
73
- --menu-font-size: calc(var(--sl-text-body) * 0.9);
49
+ --menu-font-size: calc(var(--stl-typography-scale-base) * 0.9);
74
50
  }
75
51
 
76
52
  .dropdown {
@@ -78,24 +54,9 @@ const buttonText = (navLinks.find((item) => item.active) ?? navLinks[0]).label;
78
54
  }
79
55
 
80
56
  .dropdown-item {
81
- clear: both;
82
- color: var(--sl-color-text);
57
+ color: inherit;
83
58
  text-align: inherit;
84
59
  text-decoration: none;
85
60
  white-space: nowrap;
86
61
  }
87
-
88
- .dropdown-item:focus {
89
- color: #1e2125;
90
- background-color: #e9ecef;
91
- }
92
-
93
- .nav-dropdown-root {
94
- background-color: var(--sl-color-bg-nav);
95
- }
96
-
97
- .nav-dropdown-button {
98
- color: var(--sl-color-text);
99
- font-weight: 500;
100
- }
101
62
  </style>
@@ -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
  }