@chassis-ui/docs 0.6.1 → 0.6.2

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @chassis-ui/docs
2
2
 
3
+ ## 0.6.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Add the `staticPath` key of `config.yml`: the URL path that the pages load the static files from, `/static` by default. A site that is served under a path of another host, such as `chassis-ui.com/css`, sets it to `/css/static` and rewrites that path to `/static`, so that its files no longer depend on the `Referer` header to be found. The layouts, the `Icon` shortcode and the scripts of the package use it, and `getStaticPath()` of `@chassis-ui/docs/site` returns a URL under it for the site's own files. See [A site under a prefix](https://github.com/chassis-ui/website/tree/main/packages/docs#a-site-under-a-prefix) in the README.
8
+
3
9
  ## 0.6.1
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -106,23 +106,24 @@ repo: 'https://github.com/chassis-ui/css'
106
106
  currentVersion: '0.5.2'
107
107
  ```
108
108
 
109
- | Key | Required | Meaning |
110
- | --------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------- |
111
- | `title`, `subtitle`, `description`, `authors` | yes | Used in the page title and the meta tags |
112
- | `baseURL` | yes | Canonical URL of the site |
113
- | `docsPath` | yes | URL path of the docs pages. Starts with `/` |
114
- | `repo` | yes | URL of the repository |
115
- | `currentVersion` | yes | Version that the site documents. Links to source files use the tag `v<currentVersion>` |
116
- | `githubOrg` | no | GitHub organisation name, not a URL. The header links to it |
117
- | `figmaHandle` | no | Figma Community handle. The header links to it |
118
- | `xUsername` | no | X handle. Used in the social meta tags |
119
- | `analytics.googleId` | no | Google Analytics ID. In production builds, loaded after the visitor accepts in a consent banner |
120
- | `anchors.min`, `anchors.max` | no | Heading levels that get an anchor link. Default 2 to 5 |
121
- | `toc.min`, `toc.max` | no | Heading levels in the table of contents. Default 2 to 6 |
122
- | `sourceDir` | no | Directory that `file` props are relative to, from the site's root, e.g. `"../css"`. Default `"."` |
123
- | `sourcePath` | no | The same directory from the root of the repository, e.g. `"packages/css"` |
124
- | `sitePath` | no | The site's root from the root of the repository, e.g. `"packages/site"` |
125
- | `siteBranch` | no | The branch that "View on GitHub" links to. Default `main` |
109
+ | Key | Required | Meaning |
110
+ | --------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
111
+ | `title`, `subtitle`, `description`, `authors` | yes | Used in the page title and the meta tags |
112
+ | `baseURL` | yes | Canonical URL of the site |
113
+ | `docsPath` | yes | URL path of the docs pages. Starts with `/` |
114
+ | `staticPath` | no | URL path that the pages load the static files from. Default `/static`. See [A site under a prefix](#a-site-under-a-prefix) |
115
+ | `repo` | yes | URL of the repository |
116
+ | `currentVersion` | yes | Version that the site documents. Links to source files use the tag `v<currentVersion>` |
117
+ | `githubOrg` | no | GitHub organisation name, not a URL. The header links to it |
118
+ | `figmaHandle` | no | Figma Community handle. The header links to it |
119
+ | `xUsername` | no | X handle. Used in the social meta tags |
120
+ | `analytics.googleId` | no | Google Analytics ID. In production builds, loaded after the visitor accepts in a consent banner |
121
+ | `anchors.min`, `anchors.max` | no | Heading levels that get an anchor link. Default 2 to 5 |
122
+ | `toc.min`, `toc.max` | no | Heading levels in the table of contents. Default 2 to 6 |
123
+ | `sourceDir` | no | Directory that `file` props are relative to, from the site's root, e.g. `"../css"`. Default `"."` |
124
+ | `sourcePath` | no | The same directory from the root of the repository, e.g. `"packages/css"` |
125
+ | `sitePath` | no | The site's root from the root of the repository, e.g. `"packages/site"` |
126
+ | `siteBranch` | no | The branch that "View on GitHub" links to. Default `main` |
126
127
 
127
128
  `file` props are those of `<ScssDocs>`, `<ScssDocsSimple>`, `<JsDocs>` and `<Code filePath>`.
128
129
 
@@ -181,7 +182,7 @@ export const collections = {
181
182
 
182
183
  ### 4. Provide the static files
183
184
 
184
- The layouts link to files under `/static/`, which the site puts into its `public` directory:
185
+ The layouts link to files under `/static/`, which the site puts into `static/` of its `public` directory:
185
186
 
186
187
  | URL | From |
187
188
  | -------------------------------------------------------------------- | ----------------------------------------- |
@@ -195,6 +196,27 @@ These helpers find the folders, whether `node_modules` is in the site's root or
195
196
 
196
197
  A site that type-checks with `astro check` declares the `@chassis-ui/css` module, which has no types: `declare module '@chassis-ui/css'`.
197
198
 
199
+ #### A site under a prefix
200
+
201
+ A site that is served under a path of another host, such as `chassis-ui.com/css`, cannot use `/static/` there: that path belongs to the host's own site. It loads its static files under a path of its own instead:
202
+
203
+ ```yaml
204
+ # config.yml
205
+ staticPath: '/css/static'
206
+ ```
207
+
208
+ The layouts, the `Icon` shortcode and the scripts of the package then link `/css/static/css/chassis.min.css` and so on. The files do not move: they stay in `static/` of the `public` directory. Two rewrites make the path answer:
209
+
210
+ - on the host, from `/css/static/*` to `/static/*` of the site's deployment. chassis-ui.com has one for each Chassis site.
211
+ - in the site's own `vercel.json`, from `/css/static/(.*)` to `/static/$1`, so that the deployment also works when it is opened directly.
212
+
213
+ Two kinds of URL are the site's own to move:
214
+
215
+ - URLs that the site writes itself, in its pages and components. `getStaticPath('images/hero.png')` of `@chassis-ui/docs/site` returns the URL under `staticPath`.
216
+ - The files that Astro builds, when the site puts them under `static/` with `build.assets`. Astro's `build.assetsPrefix` adds the prefix to them, `'/css'` here.
217
+
218
+ A social image named in the frontmatter as `static/images/…` is read from the `public` directory and linked under `staticPath`.
219
+
198
220
  ### 5. Use the layouts
199
221
 
200
222
  ```astro
@@ -233,6 +255,7 @@ chassisDocs({
233
255
  | `getCallout(name)` | An entry of the `callouts` collection |
234
256
  | `getSiteRoot()`, `getSiteFsPath(file)` | Absolute path of the site's root, or of a file in it |
235
257
  | `getPublicFsPath(file)` | Absolute path of a file in the `public` directory |
258
+ | `getStaticPath(file)` | URL path of a static file, under `staticPath` of the config |
236
259
  | `getSourceFsPath(file)` | Absolute path of a file that a `file` prop names |
237
260
  | `getSourceUrl(file)` | URL of a source file on GitHub, at the tag of the current version |
238
261
  | `getSiteFileUrl(filePath)` | URL of a file of the site on GitHub, on the site's branch |
@@ -343,7 +366,7 @@ These import paths are the public API.
343
366
 
344
367
  No other path resolves: `exports` in `package.json` lists these and nothing else. The layouts and components are listed by name, so the folders inside `layouts/` and `components/` are not reachable.
345
368
 
346
- The integration provides four modules: `virtual:chassis-docs/config`, `virtual:chassis-docs/sidebar`, `virtual:chassis-docs/paths` and `virtual:chassis-docs/styles`. Use the functions of `@chassis-ui/docs/site` instead of importing them.
369
+ The integration provides five modules: `virtual:chassis-docs/config`, `virtual:chassis-docs/sidebar`, `virtual:chassis-docs/paths`, `virtual:chassis-docs/static` and `virtual:chassis-docs/styles`. Use the functions of `@chassis-ui/docs/site` instead of importing them.
347
370
 
348
371
  ## Compatibility
349
372
 
@@ -351,6 +374,7 @@ The integration provides four modules: `virtual:chassis-docs/config`, `virtual:c
351
374
 
352
375
  | `@chassis-ui/docs` | Requires Astro | Requires `@chassis-ui/css` | Requires Node | Built with |
353
376
  | ------------------ | -------------------------- | -------------------------- | ------------- | ------------------------------------ |
377
+ | 0.6.2 | `^7.0.0` | `^0.5.0-0` | `>=22.12.0` | Astro 7.3.5, css 0.5.2, tokens 0.6.0 |
354
378
  | 0.6.1 | `^7.0.0` | `^0.5.0-0` | `>=22.12.0` | Astro 7.3.5, css 0.5.2, tokens 0.6.0 |
355
379
  | 0.6.0 | `^7.0.0` | `^0.5.0-0` | `>=22.12.0` | Astro 7.3.5, css 0.5.2, tokens 0.5.3 |
356
380
  | 0.5.1 | `^7.0.0` | `^0.5.0-0` | `>=22.12.0` | Astro 7.3.5, css 0.5.2, tokens 0.5.3 |
@@ -378,7 +402,7 @@ A change is breaking when it changes something that this README documents:
378
402
  - the keys of `config.yml`, and the schemas of the sidebar and the content collections
379
403
  - the props and slots of the layouts, components and shortcodes
380
404
  - the `[[config:]]` and `[[docsref:]]` syntax
381
- - the URLs under `/static/` that the layouts link to
405
+ - the URLs under `staticPath`, `/static/` by default, that the layouts link to
382
406
  - the supported versions of Node, Astro and `@chassis-ui/css`
383
407
 
384
408
  Everything else may change in a patch release: the rendered HTML, class names, the content of the styles, and every file that is not reachable through a documented import path.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@chassis-ui/docs",
3
3
  "description": "Shared Astro components and layouts for Chassis documentation sites.",
4
- "version": "0.6.1",
4
+ "version": "0.6.2",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
@@ -3,6 +3,7 @@ import { replacePlaceholdersInHtml } from '../../libs/placeholder'
3
3
  import { replaceIconsInHtml } from '../../libs/icon'
4
4
  import Code from './Code.astro'
5
5
  import Icon from './Icon.astro'
6
+ import { getStaticPath } from '../../site'
6
7
 
7
8
  interface Props {
8
9
  /**
@@ -69,7 +70,7 @@ const {
69
70
 
70
71
  let markup = Array.isArray(code) ? code.join('\n') : code
71
72
  markup = replacePlaceholdersInHtml(markup)
72
- markup = replaceIconsInHtml(markup)
73
+ markup = replaceIconsInHtml(markup, getStaticPath())
73
74
  markup = markup
74
75
  .split('\n')
75
76
  .map((line) => line.trimEnd())
@@ -1,4 +1,6 @@
1
1
  ---
2
+ import { getStaticPath } from '../../site'
3
+
2
4
  /**
3
5
  * Icon
4
6
  *
@@ -29,7 +31,7 @@ const {
29
31
  size = 24,
30
32
  font = false,
31
33
  title,
32
- sprite = '/static/icons/chassis-icons.svg',
34
+ sprite = getStaticPath('icons/chassis-icons.svg'),
33
35
  ...rest
34
36
  } = Astro.props
35
37
  ---
@@ -3,6 +3,7 @@ import { replacePlaceholdersInHtml } from '../../libs/placeholder'
3
3
  import { replaceIconsInHtml } from '../../libs/icon'
4
4
  import Code from './Code.astro'
5
5
  import Icon from './Icon.astro'
6
+ import { getStaticPath } from '../../site'
6
7
 
7
8
  interface Props {
8
9
  /**
@@ -67,7 +68,7 @@ const {
67
68
 
68
69
  let markup = Array.isArray(code) ? code.join('\n') : code
69
70
  markup = replacePlaceholdersInHtml(markup)
70
- markup = replaceIconsInHtml(markup)
71
+ markup = replaceIconsInHtml(markup, getStaticPath())
71
72
 
72
73
  // The resizable container needs `overflow: hidden` for the CSS `resize` handle
73
74
  // to work, which clips popovers like menus/dropdowns when they open. Render them
@@ -90,6 +90,10 @@ declare module 'virtual:chassis-docs/paths' {
90
90
  export const packageRoot: string
91
91
  }
92
92
 
93
+ declare module 'virtual:chassis-docs/static' {
94
+ export const staticPath: string
95
+ }
96
+
93
97
  declare module 'virtual:chassis-docs/styles' {}
94
98
  `
95
99
 
@@ -234,6 +238,8 @@ export function chassisDocs<TSchema extends z.ZodType = typeof configSchema>(
234
238
  paths: Object.entries(paths)
235
239
  .map(([name, value]) => `export const ${name} = ${JSON.stringify(value)}`)
236
240
  .join('\n'),
241
+ // A config that was not loaded with `loadConfig()` may lack the default.
242
+ static: `export const staticPath = ${JSON.stringify(config.staticPath ?? '/static')}`,
237
243
  styles: styles.map((file) => `import ${JSON.stringify(file)}`).join('\n')
238
244
  })
239
245
  ]
@@ -1,4 +1,5 @@
1
1
  import { Tooltip } from '@chassis-ui/css'
2
+ import { staticPath } from 'virtual:chassis-docs/static'
2
3
 
3
4
  // Helper to detect the user's preferred theme
4
5
  function getPreferredTheme() {
@@ -43,7 +44,7 @@ function toggleTheme(button) {
43
44
  const iconUse = button.querySelector('use')
44
45
  if (iconUse) {
45
46
  const iconHref = newTheme === 'dark' ? 'sun-solid' : 'moon-solid'
46
- iconUse.setAttribute('href', `/static/icons/chassis-icons.svg#${iconHref}`)
47
+ iconUse.setAttribute('href', `${staticPath}/icons/chassis-icons.svg#${iconHref}`)
47
48
  }
48
49
  }
49
50
 
@@ -64,7 +65,7 @@ document.addEventListener('DOMContentLoaded', () => {
64
65
  const example = button.closest('.cxd-example-snippet')?.querySelector('.cxd-example')
65
66
  const currentTheme = example?.getAttribute('data-cx-theme') || preferredTheme
66
67
  const iconHref = currentTheme === 'dark' ? 'sun-solid' : 'moon-solid'
67
- iconUse.setAttribute('href', `/static/icons/chassis-icons.svg#${iconHref}`)
68
+ iconUse.setAttribute('href', `${staticPath}/icons/chassis-icons.svg#${iconHref}`)
68
69
  }
69
70
 
70
71
  // Add event listener if not already set through onclick
package/src/js/search.js CHANGED
@@ -13,6 +13,7 @@
13
13
  // is needed here.
14
14
 
15
15
  import { getInstanceManager } from '@pagefind/component-ui'
16
+ import { staticPath } from 'virtual:chassis-docs/static'
16
17
 
17
18
  const DIALOG_SELECTOR = '#cxdSearchDialog'
18
19
  const SUB_RESULTS_LIMIT = 3
@@ -233,7 +234,7 @@ const escapeHtml = (value) => String(value ?? '').replace(/[&<>"']/g, (char) =>
233
234
  const renderItem = ({ url, titleHtml, excerptHtml = '', icon, sub = false }) => `
234
235
  <a class="cxd-search-item${sub ? ' cxd-search-subitem' : ''}" href="${escapeHtml(url)}">
235
236
  <svg class="icon cxd-search-item-icon" width="16" height="16" aria-hidden="true">
236
- <use href="/static/icons/chassis-icons.svg#${icon}"></use>
237
+ <use href="${staticPath}/icons/chassis-icons.svg#${icon}"></use>
237
238
  </svg>
238
239
  <div class="cxd-search-item-body">
239
240
  <div class="cxd-search-item-title">${titleHtml}</div>
@@ -4,6 +4,8 @@
4
4
  *
5
5
  * Site footer with logo, license information, and navigation links.
6
6
  */
7
+
8
+ import { getStaticPath } from '../../site'
7
9
  ---
8
10
 
9
11
  <footer class="cxd-footer py-6xl">
@@ -15,7 +17,7 @@
15
17
  href="/"
16
18
  aria-label="Chassis"
17
19
  >
18
- <img src="/static/images/site-logo.svg" alt="Chassis UI" height="32" />
20
+ <img src={getStaticPath('images/site-logo.svg')} alt="Chassis UI" height="32" />
19
21
  </a>
20
22
  <p class="mb-xs">
21
23
  This project is licensed under the MIT License, which allows for free use, modification,
@@ -4,11 +4,13 @@
4
4
  *
5
5
  * Favicon and app icon link tags for various platforms.
6
6
  */
7
+
8
+ import { getStaticPath } from '../../site'
7
9
  ---
8
10
 
9
- <link rel="apple-touch-icon" href={'/static/images/apple-touch-icon.png'} sizes="180x180" />
10
- <link rel="icon" href={'/static/images/favicon-32x32.png'} sizes="32x32" type="image/png" />
11
- <link rel="icon" href={'/static/images/favicon-16x16.png'} sizes="16x16" type="image/png" />
12
- <link rel="manifest" href={'/static/images/manifest.json'} />
13
- <link rel="icon" href={'/static/images/favicon.png'} />
11
+ <link rel="apple-touch-icon" href={getStaticPath('images/apple-touch-icon.png')} sizes="180x180" />
12
+ <link rel="icon" href={getStaticPath('images/favicon-32x32.png')} sizes="32x32" type="image/png" />
13
+ <link rel="icon" href={getStaticPath('images/favicon-16x16.png')} sizes="16x16" type="image/png" />
14
+ <link rel="manifest" href={getStaticPath('images/manifest.json')} />
15
+ <link rel="icon" href={getStaticPath('images/favicon.png')} />
14
16
  <meta name="theme-color" content="#00A4CC" />
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { getRemoteImageSize, getStaticImageSize } from '../../libs/image'
9
9
  import type { Layout } from '../../libs/layout'
10
- import { getConfig, getPublicFsPath } from '../../site'
10
+ import { getConfig, getPublicFsPath, getStaticPath } from '../../site'
11
11
 
12
12
  interface Props {
13
13
  /** Page description */
@@ -22,7 +22,10 @@ interface Props {
22
22
 
23
23
  const { description, layout, thumbnail, title } = Astro.props
24
24
 
25
- const socialImageUrl = new URL(thumbnail, Astro.site)
25
+ // A file in `static/` of the `public` directory is read from there, and linked under
26
+ // `staticPath` of the config.
27
+ const staticFile = thumbnail.match(/^\/?static\/(.+)$/)?.[1]
28
+ const socialImageUrl = new URL(staticFile ? getStaticPath(staticFile) : thumbnail, Astro.site)
26
29
  const isRemoteThumbnail = /^https?:\/\//i.test(thumbnail)
27
30
  const socialImageSize = isRemoteThumbnail
28
31
  ? await getRemoteImageSize(thumbnail)
@@ -6,9 +6,10 @@
6
6
  */
7
7
 
8
8
  import type { HTMLAttributes } from 'astro/types'
9
+ import { getStaticPath } from '../../site'
9
10
 
10
11
  function getChassisCssProps() {
11
- let cxCssLinkHref = '/static/css/chassis'
12
+ let cxCssLinkHref = getStaticPath('css/chassis')
12
13
 
13
14
  if (import.meta.env.PROD) {
14
15
  cxCssLinkHref = `${cxCssLinkHref}.min`
@@ -26,4 +27,4 @@ function getChassisCssProps() {
26
27
  ---
27
28
 
28
29
  <link {...getChassisCssProps()} />
29
- <link rel="stylesheet" href={`/static/icons/chassis-icons.css`} />
30
+ <link rel="stylesheet" href={getStaticPath('icons/chassis-icons.css')} />
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { Layout } from '../../libs/layout'
9
- import { getConfig } from '../../site'
9
+ import { getConfig, getStaticPath } from '../../site'
10
10
  import NavLink from '../../components/NavLink.astro'
11
11
  import ThemeToggler from '../../components/ThemeToggler.astro'
12
12
  import SearchTrigger from './SearchTrigger.astro'
@@ -55,7 +55,7 @@ const isActive = (path: string) => {
55
55
  {layout !== 'docs' && <div class="lg:d-none" style="width: 4.25rem;" />}
56
56
 
57
57
  <a class="navbar-brand m-0 py-sm lg:me-md" href="/" aria-label="Chassis">
58
- <img src="/static/images/site-logo.svg" alt="Chassis UI" width="123" height="32" />
58
+ <img src={getStaticPath('images/site-logo.svg')} alt="Chassis UI" width="123" height="32" />
59
59
  </a>
60
60
 
61
61
  <div class="d-flex">
@@ -10,3 +10,10 @@ export function joinDocsPath(docsPath: string, inputPath: string): string {
10
10
 
11
11
  return page ? `${base}/${page}` : base
12
12
  }
13
+
14
+ /** Joins the static path of the config and a file: `('/css/static', 'css/chassis.css')`. */
15
+ export function joinStaticPath(staticPath: string, file = ''): string {
16
+ const name = file.replace(/^\/+/, '')
17
+
18
+ return name ? `${staticPath}/${name}` : staticPath
19
+ }
package/src/libs/icon.ts CHANGED
@@ -20,7 +20,7 @@ interface IconOptions {
20
20
  * actually invoked — they need to be expanded to their rendered markup ahead of time.
21
21
  * @see src/components/shortcodes/Icon.astro
22
22
  */
23
- export function replaceIconsInHtml(html: string) {
23
+ export function replaceIconsInHtml(html: string, staticPath = '/static') {
24
24
  return html.replace(iconRegex, (match) => {
25
25
  const document = htmlparser2.parseDocument(match, { xmlMode: true })
26
26
  const iconElement = document.firstChild
@@ -34,11 +34,11 @@ export function replaceIconsInHtml(html: string) {
34
34
  throw new Error('Invalid icon element.')
35
35
  }
36
36
 
37
- return renderIconToString(getOptionsWithDefaults(iconElement.attribs))
37
+ return renderIconToString(getOptionsWithDefaults(iconElement.attribs, staticPath))
38
38
  })
39
39
  }
40
40
 
41
- function getOptionsWithDefaults(attribs: Record<string, string>): IconOptions {
41
+ function getOptionsWithDefaults(attribs: Record<string, string>, staticPath: string): IconOptions {
42
42
  if (!attribs.name) {
43
43
  throw new Error('Icon element is missing the required "name" attribute.')
44
44
  }
@@ -48,7 +48,7 @@ function getOptionsWithDefaults(attribs: Record<string, string>): IconOptions {
48
48
  class: attribs.class,
49
49
  size: attribs.size ? Number(attribs.size.replace(/[{}]/g, '')) : 24,
50
50
  font: attribs.font !== undefined && attribs.font !== '{false}',
51
- sprite: attribs.sprite || '/static/icons/chassis-icons.svg',
51
+ sprite: attribs.sprite || `${staticPath}/icons/chassis-icons.svg`,
52
52
  title: attribs.title
53
53
  }
54
54
  }
@@ -70,6 +70,16 @@ export const configSchema = z.strictObject({
70
70
  sourceDir: z.string().default('.'),
71
71
  /** The same directory from the root of the repository, e.g. `"packages/css"`. */
72
72
  sourcePath: z.string().optional(),
73
+ /**
74
+ * URL path that the pages load the static files from, e.g. `"/css/static"`. The files stay
75
+ * in `static/` of the `public` directory: a site under a prefix of another host sets this
76
+ * and rewrites the path to `/static`.
77
+ */
78
+ staticPath: z
79
+ .string()
80
+ .regex(/^\/(.*[^/])?$/, 'Expected a URL path that starts with "/" and has no trailing slash')
81
+ .refine((value) => value !== '/', 'Expected a path below the root, such as "/static"')
82
+ .default('/static'),
73
83
  subtitle: z.string(),
74
84
  title: z.string(),
75
85
  /** Heading levels that the table of contents lists. */
package/src/site.ts CHANGED
@@ -9,7 +9,7 @@ import sidebar from 'virtual:chassis-docs/sidebar'
9
9
  import * as paths from 'virtual:chassis-docs/paths'
10
10
  import { getCollection, getEntry, type render } from 'astro:content'
11
11
  import { loadData } from './libs/config'
12
- import { joinDocsPath } from './libs/docs-path'
12
+ import { joinDocsPath, joinStaticPath } from './libs/docs-path'
13
13
  import { getNodeModulesFsPaths, resolvePackageFilePath } from './libs/paths'
14
14
  import { replaceConfigInText, replaceDocsrefInText } from './libs/remark'
15
15
  import type { ChassisConfig, DocsPage, Sidebar } from './libs/schema'
@@ -35,6 +35,14 @@ export function getDocsPath(inputPath: string): string {
35
35
  return joinDocsPath(config.docsPath, inputPath)
36
36
  }
37
37
 
38
+ /**
39
+ * URL path of a static file, under `staticPath` of the config:
40
+ * `getStaticPath('images/site-logo.svg')` is `/static/images/site-logo.svg` by default.
41
+ */
42
+ export function getStaticPath(file = ''): string {
43
+ return joinStaticPath(config.staticPath ?? '/static', file)
44
+ }
45
+
38
46
  /** Absolute path of the site's root: the directory that holds `astro.config.ts`. */
39
47
  export function getSiteRoot(): string {
40
48
  return paths.root
package/virtual.d.ts CHANGED
@@ -22,4 +22,9 @@ declare module 'virtual:chassis-docs/paths' {
22
22
  export const packageRoot: string
23
23
  }
24
24
 
25
+ declare module 'virtual:chassis-docs/static' {
26
+ /** `staticPath` of the config, for scripts that run in the browser. */
27
+ export const staticPath: string
28
+ }
29
+
25
30
  declare module 'virtual:chassis-docs/styles' {}