starlight-versions 0.3.0 → 0.4.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 ADDED
@@ -0,0 +1,30 @@
1
+ # starlight-versions
2
+
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#15](https://github.com/HiDeoo/starlight-versions/pull/15) [`ecd96ed`](https://github.com/HiDeoo/starlight-versions/commit/ecd96ed4aa4474bb418669e8113bb9e1af0f7536) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Adds support for Astro v5, drops support for Astro v4.
8
+
9
+ ⚠️ **BREAKING CHANGE:** The minimum supported version of Starlight is now `0.30.0`.
10
+
11
+ Please follow the [upgrade guide](https://github.com/withastro/starlight/releases/tag/%40astrojs/starlight%400.30.0) to update your project.
12
+
13
+ After upgrading, you will also need to update the `versions` collection in your `src/content.config.ts` file to use the new `docsVersionsLoader`:
14
+
15
+ ```diff
16
+ // src/content.config.ts
17
+ import { defineCollection } from "astro:content";
18
+ import { docsLoader } from "@astrojs/starlight/loaders";
19
+ import { docsSchema } from "@astrojs/starlight/schema";
20
+ -import { docsVersionsSchema } from 'starlight-versions/schema'
21
+ +import { docsVersionsLoader } from 'starlight-versions/loader'
22
+
23
+ export const collections = {
24
+ docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
25
+ - versions: defineCollection({ type: 'data', schema: docsVersionsSchema() }),
26
+ + versions: defineCollection({ loader: docsVersionsLoader() }),
27
+ };
28
+ ```
29
+
30
+ Note that the [`legacy.collections` flag](https://docs.astro.build/en/reference/legacy-flags/#collections) is not supported by this plugin and you should update your collections to use Astro's new Content Layer API.
@@ -26,18 +26,22 @@ const pagefindTranslations = {
26
26
 
27
27
  const pageVersion = getVersionFromSlug(starlightVersionsConfig, starlightConfig, entry.slug)
28
28
  const pageVersionIdentifier = getVersionIdentifier(pageVersion)
29
+
30
+ const dataAttributes: DOMStringMap = {
31
+ 'data-pagefind-filter': `version:${pageVersionIdentifier}`,
32
+ 'data-translations': JSON.stringify(pagefindTranslations),
33
+ 'data-version': pageVersionIdentifier,
34
+ }
35
+ if (project.trailingSlash === 'never') dataAttributes['data-strip-trailing-slash'] = ''
29
36
  ---
30
37
 
31
- <site-search
32
- data-translations={JSON.stringify(pagefindTranslations)}
33
- data-strip-trailing-slash={project.trailingSlash === 'never'}
34
- data-version={pageVersionIdentifier}
35
- data-pagefind-filter={`version:${pageVersionIdentifier}`}
36
- >
38
+ <site-search class={Astro.props['class']} {...dataAttributes}>
37
39
  <button data-open-modal disabled>
38
- <Icon name="magnifier" label={Astro.locals.t('search.label')} />
40
+ <Icon name="magnifier" />
39
41
  <span class="sl-hidden md:sl-block" aria-hidden="true">{Astro.locals.t('search.label')}</span>
40
- <Icon name="forward-slash" class="sl-hidden md:sl-block" label={Astro.locals.t('search.shortcutLabel')} />
42
+ <kbd class="sl-hidden md:sl-flex" style="display: none;">
43
+ <kbd>{Astro.locals.t('search.ctrlKey')}</kbd><kbd>K</kbd>
44
+ </kbd>
41
45
  </button>
42
46
 
43
47
  <dialog style="padding:0" aria-label={Astro.locals.t('search.label')}>
@@ -72,6 +76,27 @@ const pageVersionIdentifier = getVersionIdentifier(pageVersion)
72
76
  </dialog>
73
77
  </site-search>
74
78
 
79
+ {
80
+ /**
81
+ * This is intentionally inlined to avoid briefly showing an invalid shortcut.
82
+ * Purposely using the deprecated `navigator.platform` property to detect Apple devices, as the
83
+ * user agent is spoofed by some browsers when opening the devtools.
84
+ */
85
+ }
86
+ <script is:inline>
87
+ ;(() => {
88
+ const openBtn = document.querySelector('button[data-open-modal]')
89
+ const shortcut = openBtn?.querySelector('kbd')
90
+ if (!openBtn || !(shortcut instanceof HTMLElement)) return
91
+ const platformKey = shortcut.querySelector('kbd')
92
+ if (platformKey && /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {
93
+ platformKey.textContent = '⌘'
94
+ openBtn.setAttribute('aria-keyshortcuts', 'Meta+K')
95
+ }
96
+ shortcut.style.display = ''
97
+ })()
98
+ </script>
99
+
75
100
  <script>
76
101
  class SiteSearch extends HTMLElement {
77
102
  constructor() {
@@ -95,7 +120,7 @@ const pageVersionIdentifier = getVersionIdentifier(pageVersion)
95
120
  document.body.toggleAttribute('data-search-modal-open', true)
96
121
  this.querySelector('input')?.focus()
97
122
  event?.stopPropagation()
98
- window.addEventListener('click', onClick)
123
+ globalThis.addEventListener('click', onClick)
99
124
  }
100
125
 
101
126
  const closeModal = () => dialog.close()
@@ -106,20 +131,17 @@ const pageVersionIdentifier = getVersionIdentifier(pageVersion)
106
131
 
107
132
  dialog.addEventListener('close', () => {
108
133
  document.body.toggleAttribute('data-search-modal-open', false)
109
- window.removeEventListener('click', onClick)
134
+ globalThis.removeEventListener('click', onClick)
110
135
  })
111
136
 
112
- // Listen for `/`, `ctrl + k`, and `cmd + k` keyboard shortcuts.
113
- window.addEventListener('keydown', (e) => {
114
- const isInput =
115
- document.activeElement instanceof HTMLElement &&
116
- (['input', 'select', 'textarea'].includes(document.activeElement.tagName.toLowerCase()) ||
117
- document.activeElement.isContentEditable)
137
+ // Listen for `ctrl + k` and `cmd + k` keyboard shortcuts.
138
+ globalThis.addEventListener('keydown', (e) => {
118
139
  if ((e.metaKey === true || e.ctrlKey === true) && e.key === 'k') {
119
- dialog.open ? closeModal() : openModal()
120
- e.preventDefault()
121
- } else if (e.key === '/' && !dialog.open && !isInput) {
122
- openModal()
140
+ if (dialog.open) {
141
+ closeModal()
142
+ } else {
143
+ openModal()
144
+ }
123
145
  e.preventDefault()
124
146
  }
125
147
  })
@@ -135,9 +157,9 @@ const pageVersionIdentifier = getVersionIdentifier(pageVersion)
135
157
  const formatURL = shouldStrip ? this.stripTrailingSlash : (path: string) => path
136
158
  const version = this.dataset['version'] ?? 'current'
137
159
 
138
- window.addEventListener('DOMContentLoaded', () => {
160
+ globalThis.addEventListener('DOMContentLoaded', () => {
139
161
  if (import.meta.env.DEV) return
140
- const onIdle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1))
162
+ const onIdle = globalThis.requestIdleCallback || ((cb) => setTimeout(cb, 1))
141
163
  onIdle(async () => {
142
164
  // @ts-expect-error — Missing types for @pagefind/default-ui package.
143
165
  const { PagefindUI } = await import('@pagefind/default-ui')
@@ -189,7 +211,7 @@ const pageVersionIdentifier = getVersionIdentifier(pageVersion)
189
211
  border: 1px solid var(--sl-color-gray-5);
190
212
  border-radius: 0.5rem;
191
213
  padding-inline-start: 0.75rem;
192
- padding-inline-end: 1rem;
214
+ padding-inline-end: 0.5rem;
193
215
  background-color: var(--sl-color-black);
194
216
  color: var(--sl-color-gray-2);
195
217
  font-size: var(--sl-text-sm);
@@ -206,6 +228,18 @@ const pageVersionIdentifier = getVersionIdentifier(pageVersion)
206
228
  }
207
229
  }
208
230
 
231
+ button > kbd {
232
+ border-radius: 0.25rem;
233
+ font-size: var(--sl-text-2xs);
234
+ gap: 0.25em;
235
+ padding-inline: 0.375rem;
236
+ background-color: var(--sl-color-gray-6);
237
+ }
238
+
239
+ kbd {
240
+ font-family: var(--__sl-font);
241
+ }
242
+
209
243
  dialog {
210
244
  margin: 0;
211
245
  background-color: var(--sl-color-gray-6);
@@ -217,7 +251,7 @@ const pageVersionIdentifier = getVersionIdentifier(pageVersion)
217
251
  box-shadow: var(--sl-shadow-lg);
218
252
  }
219
253
  dialog[open] {
220
- display: grid;
254
+ display: flex;
221
255
  }
222
256
 
223
257
  dialog::backdrop {
@@ -227,7 +261,10 @@ const pageVersionIdentifier = getVersionIdentifier(pageVersion)
227
261
  }
228
262
 
229
263
  .dialog-frame {
264
+ position: relative;
265
+ overflow: auto;
230
266
  flex-direction: column;
267
+ flex-grow: 1;
231
268
  gap: 1rem;
232
269
  padding: 1rem;
233
270
  }
@@ -383,6 +420,10 @@ const pageVersionIdentifier = getVersionIdentifier(pageVersion)
383
420
  border-radius: 0 0 var(--sl-search-corners) var(--sl-search-corners);
384
421
  }
385
422
 
423
+ #starlight__search .pagefind-ui__result-inner > .pagefind-ui__result-excerpt {
424
+ display: none;
425
+ }
426
+
386
427
  #starlight__search .pagefind-ui__result-inner > .pagefind-ui__result-title {
387
428
  padding: var(--sl-search-result-pad-block) var(--sl-search-result-pad-inline-end);
388
429
  padding-inline-start: var(--sl-search-result-pad-inline-start);
@@ -6,16 +6,16 @@ import starlightVersionsConfig from 'virtual:starlight-versions-config'
6
6
 
7
7
  import { getVersionFromSlug, getVersionURL } from '../libs/versions'
8
8
 
9
- const { slug } = Astro.props
9
+ const { id } = Astro.props
10
10
 
11
- const pageVersion = getVersionFromSlug(starlightVersionsConfig, starlightConfig, slug)
11
+ const pageVersion = getVersionFromSlug(starlightVersionsConfig, starlightConfig, id)
12
12
  ---
13
13
 
14
14
  <starlight-version-select>
15
15
  <label>
16
16
  <span class="sr-only">Select version</span>
17
17
  <Icon name="seti:clock" class="icon label-icon" />
18
- <select value={pageVersion?.label ?? 'current'}>
18
+ <select value={pageVersion?.label ?? 'current'} autocomplete="off">
19
19
  <option
20
20
  selected={pageVersion === undefined}
21
21
  value={getVersionURL(starlightVersionsConfig, starlightConfig, Astro.url, undefined).pathname}
@@ -101,9 +101,23 @@ const pageVersion = getVersionFromSlug(starlightVersionsConfig, starlightConfig,
101
101
  constructor() {
102
102
  super()
103
103
 
104
- this.querySelector('select')?.addEventListener('change', (event) => {
104
+ const select = this.querySelector('select')
105
+ if (!select) return
106
+
107
+ select?.addEventListener('change', (event) => {
105
108
  if (event.currentTarget instanceof HTMLSelectElement) {
106
- window.location.pathname = event.currentTarget.value
109
+ globalThis.location.pathname = event.currentTarget.value
110
+ }
111
+ })
112
+
113
+ window.addEventListener('pageshow', (event) => {
114
+ if (!event.persisted) return
115
+ const markupSelectedIndex = select.querySelector<HTMLOptionElement>('option[selected]')?.index
116
+
117
+ // If the page was loaded from a cache, the version select selected index might not be in sync with the
118
+ // current page.
119
+ if (markupSelectedIndex !== select.selectedIndex) {
120
+ select.selectedIndex = markupSelectedIndex ?? 0
107
121
  }
108
122
  })
109
123
  }
package/loader.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { glob, type Loader } from 'astro/loaders'
2
+
3
+ import { docsVersionsSchema } from './schema'
4
+
5
+ const extensions = ['json', 'yml', 'yaml']
6
+
7
+ export function docsVersionsLoader(): Loader {
8
+ return {
9
+ name: 'starlight-versions-loader',
10
+ load: (context) => {
11
+ return glob({
12
+ base: `${context.config.srcDir.pathname.replace(context.config.root.pathname, '')}content/versions`,
13
+ pattern: `**/[^_]*.{${extensions.join(',')}}`,
14
+ }).load(context)
15
+ },
16
+ schema: docsVersionsSchema(),
17
+ }
18
+ }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "starlight-versions",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "description": "Starlight plugin to version documentation pages.",
6
6
  "author": "HiDeoo <github@hideoo.dev> (https://hideoo.dev)",
7
7
  "type": "module",
8
8
  "exports": {
9
9
  ".": "./index.ts",
10
- "./schema": "./schema.ts",
10
+ "./loader": "./loader.ts",
11
11
  "./components/VersionBanner.astro": "./components/VersionBanner.astro",
12
12
  "./components/VersionNotice.astro": "./components/VersionNotice.astro",
13
13
  "./components/VersionPagination.astro": "./components/VersionPagination.astro",
@@ -23,30 +23,31 @@
23
23
  "./package.json": "./package.json"
24
24
  },
25
25
  "dependencies": {
26
- "@pagefind/default-ui": "^1.0.3",
26
+ "@pagefind/default-ui": "^1.2.0",
27
27
  "github-slugger": "^2.0.0",
28
- "mdast-util-mdx-jsx": "^3.1.2",
28
+ "mdast-util-mdx-jsx": "^3.1.3",
29
29
  "mdast-util-mdxjs-esm": "^2.0.1",
30
30
  "remark": "^15.0.1",
31
31
  "remark-frontmatter": "^5.0.0",
32
- "remark-mdx": "^3.0.1",
32
+ "remark-mdx": "^3.1.0",
33
33
  "unist-util-visit": "^5.0.0",
34
- "vfile": "^6.0.1",
35
- "yaml": "^2.4.2"
34
+ "vfile": "^6.0.3",
35
+ "yaml": "^2.6.1"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/mdast": "^4.0.4",
39
39
  "fast-glob": "^3.3.2",
40
- "vitest": "^1.6.0"
40
+ "vitest": "2.1.6"
41
41
  },
42
42
  "peerDependencies": {
43
- "@astrojs/starlight": ">=0.28.0"
43
+ "@astrojs/starlight": ">=0.30.0"
44
44
  },
45
45
  "engines": {
46
46
  "node": ">=18"
47
47
  },
48
48
  "publishConfig": {
49
- "access": "public"
49
+ "access": "public",
50
+ "provenance": true
50
51
  },
51
52
  "sideEffects": false,
52
53
  "keywords": [
@@ -66,6 +67,6 @@
66
67
  "bugs": "https://github.com/HiDeoo/starlight-versions/issues",
67
68
  "scripts": {
68
69
  "test": "vitest",
69
- "lint": "prettier -c --cache . && eslint . --cache --max-warnings=0"
70
+ "lint": "eslint . --cache --max-warnings=0"
70
71
  }
71
72
  }