@chassis-ui/docs 0.10.0 → 0.11.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 +10 -0
- package/README.md +15 -11
- package/UPGRADING.md +144 -2
- package/package.json +1 -1
- package/src/components/shortcodes/Example.astro +7 -3
- package/src/components/shortcodes/Icon.astro +2 -2
- package/src/components/shortcodes/ResizableExample.astro +7 -3
- package/src/integration.ts +23 -5
- package/src/js/example-mode.js +3 -3
- package/src/js/search.js +2 -2
- package/src/layouts/head/Favicons.astro +1 -1
- package/src/layouts/head/Head.astro +2 -2
- package/src/layouts/head/Stylesheet.astro +3 -11
- package/src/libs/icon.ts +11 -4
- package/src/libs/static-version.ts +53 -0
- package/src/site.ts +13 -0
- package/virtual.d.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @chassis-ui/docs
|
|
2
2
|
|
|
3
|
+
## 0.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- **Breaking.** The head links the web app manifest of the docs build of `chassis-assets`, `other/manifest.json` under the static path, in place of `images/manifest.json`, which each site provided itself. chassis-assets added it in `v0.5.0` of `app/docs` on 2026-10-23, with a maskable icon. A site moves its `vendor/assets` submodule to `v0.5.0` or later with `pnpm sync-submodules`, and deletes its own `images/manifest.json`; with an earlier commit the page links a manifest that is not there. The starter keeps a manifest with its own name at `static/other/manifest.json`. See [UPGRADING.md](https://github.com/chassis-ui/website/blob/main/packages/docs/UPGRADING.md#from-010-to-011).
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- The head links the Chassis CSS, `icons/chassis-icons.css` and `fonts/fonts.css` with `?v=` and the first 8 characters of the MD5 hash of the file, and the `<Icon>` shortcode, the icons of `<Example>` and `<ResizableExample>`, the search results and the color mode button of the examples load the sprite the same way: `/static/css/chassis.min.css?v=8e2106f6`. A new file is a new URL, so a host can let the browser keep these files for good, and a new CSS reaches a visitor with the pages that need it. The hash is read from the file of the site's `public` directory at the path of the URL; without that file the URL has no version, as before. `getVersionedStaticPath(file)` of `@chassis-ui/docs/site` returns such a URL, `replaceIconsInHtml()` takes the sprite as a third argument, and `virtual:chassis-docs/static` exports `spritePath`.
|
|
12
|
+
|
|
3
13
|
## 0.10.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -184,15 +184,15 @@ export const collections = {
|
|
|
184
184
|
|
|
185
185
|
The layouts link to files under `/static/`, which the site puts into `static/` of its `public` directory:
|
|
186
186
|
|
|
187
|
-
| URL | From
|
|
188
|
-
| ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
189
|
-
| `/static/css/chassis.css`, `/static/css/chassis.min.css` | the `dist` folder of `@chassis-ui/css`
|
|
190
|
-
| `/static/icons/chassis-icons.svg`, `/static/icons/chassis-icons.css` | the `icons` folder of `@chassis-ui/icons`
|
|
191
|
-
| `/static/images/site-logo.svg`, the logo of the navigation bar and the footer. The build inlines it, and fails without the file | the docs build of `chassis-assets`
|
|
192
|
-
| `/static/images/favicon.png`, `favicon-16x16.png`, `favicon-32x32.png` and `apple-touch-icon.png` | the docs build of `chassis-assets`
|
|
193
|
-
| `/static/images/social-image.png`, the image of a page without a `thumbnail`. The build reads its size, and fails without the file | the docs build of `chassis-assets`
|
|
194
|
-
| `/static/fonts/fonts.css`, and the font files it loads | the docs build of `chassis-assets`
|
|
195
|
-
| `/static/
|
|
187
|
+
| URL | From |
|
|
188
|
+
| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
189
|
+
| `/static/css/chassis.css`, `/static/css/chassis.min.css` | the `dist` folder of `@chassis-ui/css` |
|
|
190
|
+
| `/static/icons/chassis-icons.svg`, `/static/icons/chassis-icons.css` | the `icons` folder of `@chassis-ui/icons` |
|
|
191
|
+
| `/static/images/site-logo.svg`, the logo of the navigation bar and the footer. The build inlines it, and fails without the file | the docs build of `chassis-assets` |
|
|
192
|
+
| `/static/images/favicon.png`, `favicon-16x16.png`, `favicon-32x32.png` and `apple-touch-icon.png` | the docs build of `chassis-assets` |
|
|
193
|
+
| `/static/images/social-image.png`, the image of a page without a `thumbnail`. The build reads its size, and fails without the file | the docs build of `chassis-assets` |
|
|
194
|
+
| `/static/fonts/fonts.css`, and the font files it loads | the docs build of `chassis-assets` |
|
|
195
|
+
| `/static/other/manifest.json`, the web app manifest | the docs build of `chassis-assets`, `v0.5.0` or later. A site may put its own in its `static/other/`, as the starter does |
|
|
196
196
|
|
|
197
197
|
`chassis-docs vendor` builds the docs build of `chassis-assets` in the `vendor/assets` submodule. See [Commands](#commands).
|
|
198
198
|
|
|
@@ -210,9 +210,9 @@ The sites of the Chassis projects read these files besides, by name, from the do
|
|
|
210
210
|
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
211
211
|
| `icons/cx-sprite.svg` | The home page of each of the seven sites, which imports it. The build fails without it |
|
|
212
212
|
| `images/apple-touch-icon.png`, `images/favicon.png` | Each of the seven sites, which copies them to `/apple-touch-icon.png` and `/favicon.ico` |
|
|
213
|
-
| `images/android-chrome-192x192.png`, `images/android-chrome-512x512.png` |
|
|
213
|
+
| `images/android-chrome-192x192.png`, `images/android-chrome-512x512.png` | `other/manifest.json` of the docs build, which the head links |
|
|
214
214
|
| `images/home/` | The home page of the website. The home page of chassis-tokens reads `comp-gallery-*` of it |
|
|
215
|
-
| `images/logo/
|
|
215
|
+
| `images/logo/logo-{light,dark}.svg` | The about page of the website |
|
|
216
216
|
| `images/social-image.png` | The blog of the website, for a post without an image |
|
|
217
217
|
| `images/site-logo.svg` | The examples of the navbar page of chassis-css. The README of `@chassis-ui/react`, by its URL on chassis-ui.com |
|
|
218
218
|
| `images/figma/components/` | The component pages of chassis-figma |
|
|
@@ -242,6 +242,8 @@ Two kinds of URL are the site's own to move:
|
|
|
242
242
|
|
|
243
243
|
A social image named in the frontmatter as `static/images/…` is read from the `public` directory and linked under `staticPath`.
|
|
244
244
|
|
|
245
|
+
The layouts link the Chassis CSS, the icon stylesheet, `fonts/fonts.css` and the icon sprite with a version: `/static/css/chassis.min.css?v=8e2106f6`, the first 8 characters of the MD5 hash of the file. A new file is a new URL, so a host can let the browser keep these files for good. The version is read from the file of `public` at the path of the URL, so a site under a prefix whose `public` holds the files in `static/` links them without one.
|
|
246
|
+
|
|
245
247
|
### 5. Use the layouts
|
|
246
248
|
|
|
247
249
|
```astro
|
|
@@ -283,6 +285,7 @@ chassisDocs({
|
|
|
283
285
|
| `getSiteRoot()`, `getSiteFsPath(file)` | Absolute path of the site's root, or of a file in it |
|
|
284
286
|
| `getPublicFsPath(file)` | Absolute path of a file in the `public` directory |
|
|
285
287
|
| `getStaticPath(file)` | URL path of a static file, under `staticPath` of the config |
|
|
288
|
+
| `getVersionedStaticPath(file)` | The same, with `?v=` and a hash of the file in `public` |
|
|
286
289
|
| `getSourceFsPath(file)` | Absolute path of a file that a `file` prop names |
|
|
287
290
|
| `getSourceUrl(file)` | URL of a source file on GitHub, at the tag of the current version |
|
|
288
291
|
| `getSiteFileUrl(filePath)` | URL of a file of the site on GitHub, on the site's branch |
|
|
@@ -417,6 +420,7 @@ The integration provides five modules: `virtual:chassis-docs/config`, `virtual:c
|
|
|
417
420
|
|
|
418
421
|
| `@chassis-ui/docs` | Requires Astro | Requires `@chassis-ui/css` | Requires Node | Built with |
|
|
419
422
|
| ------------------ | -------------------------- | -------------------------- | ------------- | -------------------------------------- |
|
|
423
|
+
| 0.11.0 | `^7.0.0` | `>=0.10.0` | `>=22.12.0` | Astro 7.3.8, css 0.10.0, tokens 0.10.0 |
|
|
420
424
|
| 0.10.0 | `^7.0.0` | `>=0.10.0` | `>=22.12.0` | Astro 7.3.8, css 0.10.0, tokens 0.10.0 |
|
|
421
425
|
| 0.9.0 | `^7.0.0` | `>=0.10.0` | `>=22.12.0` | Astro 7.3.8, css 0.10.0, tokens 0.10.0 |
|
|
422
426
|
| 0.8.0 | `^7.0.0` | `>=0.6.0` | `>=22.12.0` | Astro 7.3.5, css 0.7.1, tokens 0.7.0 |
|
package/UPGRADING.md
CHANGED
|
@@ -1,5 +1,138 @@
|
|
|
1
1
|
# Upgrading @chassis-ui/docs
|
|
2
2
|
|
|
3
|
+
## From 0.10 to 0.11
|
|
4
|
+
|
|
5
|
+
0.11.0 links the web app manifest of the docs build of `chassis-assets`,
|
|
6
|
+
`other/manifest.json` under the static path, in place of `images/manifest.json`, which each
|
|
7
|
+
site provided itself. chassis-assets added the manifest, with a maskable icon, in `v0.5.0`
|
|
8
|
+
of `app/docs` on 2026-10-23.
|
|
9
|
+
|
|
10
|
+
### 1. Update the dependency and the assets
|
|
11
|
+
|
|
12
|
+
In the package of the site, then from the root of the repository:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pnpm add -D @chassis-ui/docs@^0.11.0
|
|
16
|
+
pnpm sync-submodules
|
|
17
|
+
git add vendor/assets
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The docs build has `other/manifest.json` from `v0.5.0` on. With an earlier commit the page
|
|
21
|
+
links a manifest that is not there. Stage or commit the pin before you run `pnpm vendor` or a
|
|
22
|
+
build, which check the submodule out at the commit that the repository records.
|
|
23
|
+
|
|
24
|
+
### 2. Remove the site's own manifest
|
|
25
|
+
|
|
26
|
+
Delete `images/manifest.json` from the files that the site copies into `public/static/`,
|
|
27
|
+
`static/static/images/` in most Chassis repositories. A site that keeps a manifest with a name
|
|
28
|
+
of its own puts it at `static/other/manifest.json` of what it copies after the docs build, as
|
|
29
|
+
the starter does, and names the icons `../images/…`.
|
|
30
|
+
|
|
31
|
+
### What changes in the package
|
|
32
|
+
|
|
33
|
+
- **The head links `other/manifest.json`** under the static path, and no longer
|
|
34
|
+
`images/manifest.json`.
|
|
35
|
+
- The pages link the Chassis CSS, `icons/chassis-icons.css`, `fonts/fonts.css` and the icon
|
|
36
|
+
sprite with `?v=` and a hash of the file, so a host can cache them for good.
|
|
37
|
+
|
|
38
|
+
### Check the result
|
|
39
|
+
|
|
40
|
+
Open the page in a browser and check that the manifest loads: in Chrome, Application >
|
|
41
|
+
Manifest names the site and shows its icons.
|
|
42
|
+
|
|
43
|
+
## From 0.8 to 0.10
|
|
44
|
+
|
|
45
|
+
0.9 and 0.10 are both breaking minors, and a site on 0.8 takes them in one upgrade: the
|
|
46
|
+
steps of [From 0.8 to 0.9](#from-08-to-09) and [From 0.9 to 0.10](#from-09-to-010) together,
|
|
47
|
+
in this order. 0.9 reads the typography names of `@chassis-ui/css` 0.10. 0.10 links one font
|
|
48
|
+
stylesheet, `fonts/fonts.css`, and inlines the logo, after chassis-assets changed both on
|
|
49
|
+
`app/docs` on 2026-10-19.
|
|
50
|
+
|
|
51
|
+
### 1. Update the dependencies
|
|
52
|
+
|
|
53
|
+
In the package of the site, `packages/site` in most Chassis repositories:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
pnpm add -D @chassis-ui/docs@^0.10.0 @chassis-ui/css@^0.10.0 @chassis-ui/tokens@^0.10.0
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The default token source of css, `scss/vendor/_chassis-tokens.scss`, forwards the
|
|
60
|
+
`@chassis-ui/tokens` that the site installs, and css 0.10 reads tokens that only tokens 0.10
|
|
61
|
+
has, so the three move together. A site that takes css or tokens from its own workspace keeps
|
|
62
|
+
that dependency and moves the workspace to 0.10. css 0.8 to 0.10 have changes of their own.
|
|
63
|
+
Read the [changelog of css](https://github.com/chassis-ui/css/blob/main/packages/css/CHANGELOG.md)
|
|
64
|
+
first.
|
|
65
|
+
|
|
66
|
+
### 2. Move the `vendor/assets` submodule
|
|
67
|
+
|
|
68
|
+
From the root of the repository:
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
pnpm sync-submodules
|
|
72
|
+
git add vendor/assets
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`sync-submodules` moves the submodule to the latest commit of `app/docs` and builds it. The
|
|
76
|
+
docs build has `fonts/fonts.css` and the `ui-*` font files from `db6d64b` on, and the logo
|
|
77
|
+
for inline use from `4382de9` on. With a commit before `db6d64b` the pages show the fallback
|
|
78
|
+
fonts.
|
|
79
|
+
|
|
80
|
+
Stage the pin, or commit it, before you run `pnpm vendor` or a build: `vendor` checks the
|
|
81
|
+
submodule out at the commit that the repository records, and a build from the old pin links a
|
|
82
|
+
stylesheet that is not there.
|
|
83
|
+
|
|
84
|
+
chassis-assets has no submodule: its site is built from its own `source/`, which has
|
|
85
|
+
`fonts.css` from `db6d64b` on. A site that does not copy the docs build provides
|
|
86
|
+
`fonts/fonts.css` and the font files it names itself.
|
|
87
|
+
|
|
88
|
+
### 3. Rename the typography names in your own pages and styles
|
|
89
|
+
|
|
90
|
+
The table under [From 0.8 to 0.9](#2-rename-the-typography-names-in-your-own-pages-and-styles)
|
|
91
|
+
lists them: `.h1` to `.h6` are `.font-h1` to `.font-h6`, `.font-text` is `.font-ui`, the
|
|
92
|
+
`--cx-*-text-*` properties are `--cx-*-ui-*`, and the `$font-context-*` maps are `$font-*`.
|
|
93
|
+
css 0.10 keeps `.h1` to `.h6`, `.font-text` and `--cx-font-family-text` as deprecated names.
|
|
94
|
+
The other old names are gone: a Sass name that is gone fails the build, and a class or a
|
|
95
|
+
custom property that is gone does nothing, so look for those in the pages.
|
|
96
|
+
|
|
97
|
+
### 4. Look for the old files of the docs build in your own files
|
|
98
|
+
|
|
99
|
+
The package links the new files, but a page or a stylesheet of your own may name the old
|
|
100
|
+
ones:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
git grep -nE "fonts/(text|display|code)\.css|text-[a-z0-9-]*\.woff2|site-logo\.svg" -- ':!vendor'
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- **`fonts/text.css`, `fonts/display.css`, `fonts/code.css`:** link `fonts/fonts.css`.
|
|
107
|
+
- **`text-*.woff2`:** the files of the `text` role are `ui-*.woff2` now, such as
|
|
108
|
+
`ui-latin.woff2` and `ui-normal.woff2`.
|
|
109
|
+
- **`images/site-logo.svg` in an `<img>`:** the logo from `4382de9` on has no `xmlns`, so a
|
|
110
|
+
browser does not show it as an image, and its paths take their colors from the classes
|
|
111
|
+
`icon-default` and `icon-primary` of the page. Inline it, as the navigation bar does, or use a
|
|
112
|
+
file of `images/logo/`, which an `<img>` shows, such as `images/logo/chassis-logo-brand.svg`.
|
|
113
|
+
|
|
114
|
+
### What changes on the pages
|
|
115
|
+
|
|
116
|
+
- **The head links `fonts/fonts.css`** under the static path, in place of the three
|
|
117
|
+
stylesheets of the roles.
|
|
118
|
+
- **The navigation bar and the footer inline the logo,** `2rem` high, in the colors of the
|
|
119
|
+
theme. The build reads `static/images/site-logo.svg` of the site's `public` directory and
|
|
120
|
+
fails without it. The link of the logo in the footer has the margin `mb-md`, where it was
|
|
121
|
+
`mb-xs`.
|
|
122
|
+
- **The search of the header is `5rem` wide** from the `lg` breakpoint, the icon and the
|
|
123
|
+
shortcut, and `12.5rem` from `xl`, where it was 200px.
|
|
124
|
+
- **The footer and the docs sidebar use `.font-h6` and `.font-h5`,** and `.cxd-subtitle`
|
|
125
|
+
reads `$font-lead`.
|
|
126
|
+
- **From css 0.10 and tokens 0.10:** the headings and the titles are in the display family,
|
|
127
|
+
Montserrat, the default tokens have new base colors, and buttons, badges and the other
|
|
128
|
+
components that had one lose their background gradient.
|
|
129
|
+
|
|
130
|
+
### Check the result
|
|
131
|
+
|
|
132
|
+
Build the site before and after the upgrade and compare the pages in a browser, in both color
|
|
133
|
+
modes and between 1024 and 1280 pixels, where the search of the header changes. In the
|
|
134
|
+
network panel, no request under `/static/fonts/` may fail.
|
|
135
|
+
|
|
3
136
|
## From 0.9 to 0.10
|
|
4
137
|
|
|
5
138
|
0.10.0 links one font stylesheet, `fonts/fonts.css`, in place of `fonts/text.css`,
|
|
@@ -11,14 +144,20 @@ and the classes `icon-default` and `icon-primary` of the page color its paths.
|
|
|
11
144
|
|
|
12
145
|
### 1. Update the dependency and the assets
|
|
13
146
|
|
|
147
|
+
In the package of the site, then from the root of the repository:
|
|
148
|
+
|
|
14
149
|
```sh
|
|
15
150
|
pnpm add -D @chassis-ui/docs@^0.10.0
|
|
16
151
|
pnpm sync-submodules
|
|
152
|
+
git add vendor/assets
|
|
17
153
|
```
|
|
18
154
|
|
|
19
155
|
The docs build of `chassis-assets` has `fonts/fonts.css` from `db6d64b` of `app/docs` on. With
|
|
20
|
-
an earlier commit the pages show the fallback fonts.
|
|
21
|
-
|
|
156
|
+
an earlier commit the pages show the fallback fonts. Stage or commit the pin before you run
|
|
157
|
+
`pnpm vendor` or a build, which check the submodule out at the commit that the repository
|
|
158
|
+
records. A site that does not copy the docs build provides `fonts/fonts.css` itself. Step 2
|
|
159
|
+
and step 4 of [From 0.8 to 0.10](#from-08-to-010) say more, and how to find the old files in
|
|
160
|
+
your own pages.
|
|
22
161
|
|
|
23
162
|
### What changes in the package
|
|
24
163
|
|
|
@@ -30,6 +169,9 @@ provides `fonts/fonts.css` itself.
|
|
|
30
169
|
logo of an earlier docs build, with its own colors, a width and a height, shows at the same
|
|
31
170
|
height.
|
|
32
171
|
- **The link of the logo in the footer has the bottom margin `mb-md`,** where it was `mb-xs`.
|
|
172
|
+
- **The search of the header is `5rem` wide** from the `lg` breakpoint, the icon and the
|
|
173
|
+
shortcut, and `12.5rem` from `xl`, where it was 200px, so that no link of the header runs
|
|
174
|
+
under it between 1024 and 1280 pixels.
|
|
33
175
|
|
|
34
176
|
### Check the result
|
|
35
177
|
|
package/package.json
CHANGED
|
@@ -3,7 +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
|
+
import { getStaticPath, getVersionedStaticPath } from '../../site'
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
9
9
|
/**
|
|
@@ -70,7 +70,11 @@ const {
|
|
|
70
70
|
|
|
71
71
|
let markup = Array.isArray(code) ? code.join('\n') : code
|
|
72
72
|
markup = replacePlaceholdersInHtml(markup)
|
|
73
|
-
markup = replaceIconsInHtml(
|
|
73
|
+
markup = replaceIconsInHtml(
|
|
74
|
+
markup,
|
|
75
|
+
getStaticPath(),
|
|
76
|
+
getVersionedStaticPath('icons/chassis-icons.svg')
|
|
77
|
+
)
|
|
74
78
|
markup = markup
|
|
75
79
|
.split('\n')
|
|
76
80
|
.map((line) => line.trimEnd())
|
|
@@ -93,7 +97,7 @@ const simplifiedMarkup = sourceMarkup
|
|
|
93
97
|
(_match, classes) => `<img src="..."${classes ? ` class="${classes}"` : ''} alt="...">`
|
|
94
98
|
)
|
|
95
99
|
.replace(/(<svg class="icon\b[^"]*")\s+width="\d+"\s+height="\d+"/g, '$1')
|
|
96
|
-
.replace(/href="\/static\/icons\/chassis-icons\.svg
|
|
100
|
+
.replace(/href="\/static\/icons\/chassis-icons\.svg(?:\?v=[0-9a-f]+)?#/g, 'href="#')
|
|
97
101
|
---
|
|
98
102
|
|
|
99
103
|
<div class="cxd-example-snippet cxd-code-snippet not-prose" data-pagefind-ignore>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { getVersionedStaticPath } from '../../site'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Icon
|
|
@@ -31,7 +31,7 @@ const {
|
|
|
31
31
|
size = 24,
|
|
32
32
|
font = false,
|
|
33
33
|
title,
|
|
34
|
-
sprite =
|
|
34
|
+
sprite = getVersionedStaticPath('icons/chassis-icons.svg'),
|
|
35
35
|
...rest
|
|
36
36
|
} = Astro.props
|
|
37
37
|
---
|
|
@@ -3,7 +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
|
+
import { getStaticPath, getVersionedStaticPath } from '../../site'
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
9
9
|
/**
|
|
@@ -68,7 +68,11 @@ const {
|
|
|
68
68
|
|
|
69
69
|
let markup = Array.isArray(code) ? code.join('\n') : code
|
|
70
70
|
markup = replacePlaceholdersInHtml(markup)
|
|
71
|
-
markup = replaceIconsInHtml(
|
|
71
|
+
markup = replaceIconsInHtml(
|
|
72
|
+
markup,
|
|
73
|
+
getStaticPath(),
|
|
74
|
+
getVersionedStaticPath('icons/chassis-icons.svg')
|
|
75
|
+
)
|
|
72
76
|
|
|
73
77
|
// The resizable container needs `overflow: hidden` for the CSS `resize` handle
|
|
74
78
|
// to work, which clips popovers like menus/dropdowns when they open. Render them
|
|
@@ -95,7 +99,7 @@ const simplifiedMarkup = sourceMarkup
|
|
|
95
99
|
(_match, classes) => `<img src="..."${classes ? ` class="${classes}"` : ''} alt="...">`
|
|
96
100
|
)
|
|
97
101
|
.replace(/(<svg class="icon\b[^"]*")\s+width="\d+"\s+height="\d+"/g, '$1')
|
|
98
|
-
.replace(/href="\/static\/icons\/chassis-icons\.svg
|
|
102
|
+
.replace(/href="\/static\/icons\/chassis-icons\.svg(?:\?v=[0-9a-f]+)?#/g, 'href="#')
|
|
99
103
|
---
|
|
100
104
|
|
|
101
105
|
<div class="cxd-example-snippet cxd-code-snippet" data-pagefind-ignore>
|
package/src/integration.ts
CHANGED
|
@@ -4,13 +4,14 @@ import { fileURLToPath } from 'node:url'
|
|
|
4
4
|
import type { AstroIntegration, AstroUserConfig, ViteUserConfig } from 'astro'
|
|
5
5
|
import type { z } from 'astro/zod'
|
|
6
6
|
import { loadConfig, loadSidebar } from './libs/config'
|
|
7
|
-
import { joinDocsPath } from './libs/docs-path'
|
|
7
|
+
import { joinDocsPath, joinStaticPath } from './libs/docs-path'
|
|
8
8
|
import { getDocsMarkdownConfig, type DocsMarkdownConfigOptions } from './libs/markdown'
|
|
9
9
|
import { getInstalledPackageFsPath, getPackageRoot } from './libs/paths'
|
|
10
10
|
import { remarkCxConfig, remarkCxDocsref } from './libs/remark'
|
|
11
11
|
import { configSchema, type ChassisConfig, type Sidebar } from './libs/schema'
|
|
12
12
|
import { chassisAutoImport, type ChassisAutoImportOptions } from './libs/shortcodes'
|
|
13
13
|
import { getSiteUrl } from './libs/site'
|
|
14
|
+
import { versionStaticPath } from './libs/static-version'
|
|
14
15
|
|
|
15
16
|
export interface ChassisDocsOptions<TSchema extends z.ZodType = typeof configSchema> {
|
|
16
17
|
/**
|
|
@@ -56,7 +57,8 @@ type VitePlugin = Extract<NonNullable<ViteUserConfig['plugins']>[number], { name
|
|
|
56
57
|
const virtualPrefix = 'virtual:chassis-docs/'
|
|
57
58
|
const resolvedPrefix = '\0' + virtualPrefix
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
// The code of each module, or a function that returns it when the module is loaded.
|
|
61
|
+
function virtualModules(modules: Record<string, string | (() => string)>): VitePlugin {
|
|
60
62
|
return {
|
|
61
63
|
name: 'chassis-docs:virtual',
|
|
62
64
|
resolveId(id) {
|
|
@@ -66,7 +68,9 @@ function virtualModules(modules: Record<string, string>): VitePlugin {
|
|
|
66
68
|
},
|
|
67
69
|
load(id) {
|
|
68
70
|
if (id.startsWith(resolvedPrefix)) {
|
|
69
|
-
|
|
71
|
+
const code = modules[id.slice(resolvedPrefix.length)]
|
|
72
|
+
|
|
73
|
+
return typeof code === 'function' ? code() : code
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
}
|
|
@@ -92,6 +96,7 @@ declare module 'virtual:chassis-docs/paths' {
|
|
|
92
96
|
|
|
93
97
|
declare module 'virtual:chassis-docs/static' {
|
|
94
98
|
export const staticPath: string
|
|
99
|
+
export const spritePath: string
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
declare module 'virtual:chassis-docs/styles' {}
|
|
@@ -238,8 +243,21 @@ export function chassisDocs<TSchema extends z.ZodType = typeof configSchema>(
|
|
|
238
243
|
paths: Object.entries(paths)
|
|
239
244
|
.map(([name, value]) => `export const ${name} = ${JSON.stringify(value)}`)
|
|
240
245
|
.join('\n'),
|
|
241
|
-
// A config that was not loaded with `loadConfig()` may lack the default.
|
|
242
|
-
|
|
246
|
+
// A config that was not loaded with `loadConfig()` may lack the default. The
|
|
247
|
+
// version of the sprite is read when a script loads the module: a site's own
|
|
248
|
+
// integration may copy the file into `public` after this hook.
|
|
249
|
+
static: () => {
|
|
250
|
+
const staticPath = config.staticPath ?? '/static'
|
|
251
|
+
const spritePath = versionStaticPath(
|
|
252
|
+
joinStaticPath(staticPath, 'icons/chassis-icons.svg'),
|
|
253
|
+
paths.publicDir
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
return [
|
|
257
|
+
`export const staticPath = ${JSON.stringify(staticPath)}`,
|
|
258
|
+
`export const spritePath = ${JSON.stringify(spritePath)}`
|
|
259
|
+
].join('\n')
|
|
260
|
+
},
|
|
243
261
|
styles: styles.map((file) => `import ${JSON.stringify(file)}`).join('\n')
|
|
244
262
|
})
|
|
245
263
|
]
|
package/src/js/example-mode.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Tooltip } from '@chassis-ui/css'
|
|
2
|
-
import {
|
|
2
|
+
import { spritePath } from 'virtual:chassis-docs/static'
|
|
3
3
|
|
|
4
4
|
// Helper to detect the user's preferred theme
|
|
5
5
|
function getPreferredTheme() {
|
|
@@ -44,7 +44,7 @@ function toggleTheme(button) {
|
|
|
44
44
|
const iconUse = button.querySelector('use')
|
|
45
45
|
if (iconUse) {
|
|
46
46
|
const iconHref = newTheme === 'dark' ? 'sun-solid' : 'moon-solid'
|
|
47
|
-
iconUse.setAttribute('href', `${
|
|
47
|
+
iconUse.setAttribute('href', `${spritePath}#${iconHref}`)
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -65,7 +65,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
65
65
|
const example = button.closest('.cxd-example-snippet')?.querySelector('.cxd-example')
|
|
66
66
|
const currentTheme = example?.getAttribute('data-cx-theme') || preferredTheme
|
|
67
67
|
const iconHref = currentTheme === 'dark' ? 'sun-solid' : 'moon-solid'
|
|
68
|
-
iconUse.setAttribute('href', `${
|
|
68
|
+
iconUse.setAttribute('href', `${spritePath}#${iconHref}`)
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
// Add event listener if not already set through onclick
|
package/src/js/search.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// is needed here.
|
|
14
14
|
|
|
15
15
|
import { getInstanceManager } from '@pagefind/component-ui'
|
|
16
|
-
import {
|
|
16
|
+
import { spritePath } from 'virtual:chassis-docs/static'
|
|
17
17
|
|
|
18
18
|
const DIALOG_SELECTOR = '#cxdSearchDialog'
|
|
19
19
|
// The rows that are links. The loading skeleton reuses the class on a `<div>`,
|
|
@@ -237,7 +237,7 @@ const escapeHtml = (value) => String(value ?? '').replace(/[&<>"']/g, (char) =>
|
|
|
237
237
|
const renderItem = ({ url, titleHtml, excerptHtml = '', icon, sub = false }) => `
|
|
238
238
|
<a class="cxd-search-item${sub ? ' cxd-search-subitem' : ''}" href="${escapeHtml(url)}">
|
|
239
239
|
<svg class="icon cxd-search-item-icon" width="16" height="16" aria-hidden="true">
|
|
240
|
-
<use href="${
|
|
240
|
+
<use href="${spritePath}#${icon}"></use>
|
|
241
241
|
</svg>
|
|
242
242
|
<div class="cxd-search-item-body">
|
|
243
243
|
<div class="cxd-search-item-title">${titleHtml}</div>
|
|
@@ -11,6 +11,6 @@ import { getStaticPath } from '../../site'
|
|
|
11
11
|
<link rel="apple-touch-icon" href={getStaticPath('images/apple-touch-icon.png')} sizes="180x180" />
|
|
12
12
|
<link rel="icon" href={getStaticPath('images/favicon-32x32.png')} sizes="32x32" type="image/png" />
|
|
13
13
|
<link rel="icon" href={getStaticPath('images/favicon-16x16.png')} sizes="16x16" type="image/png" />
|
|
14
|
-
<link rel="manifest" href={getStaticPath('
|
|
14
|
+
<link rel="manifest" href={getStaticPath('other/manifest.json')} />
|
|
15
15
|
<link rel="icon" href={getStaticPath('images/favicon.png')} />
|
|
16
16
|
<meta name="theme-color" content="#00A4CC" />
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* HTML head section with meta tags, stylesheets, and SEO configuration.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { getConfig,
|
|
8
|
+
import { getConfig, getVersionedStaticPath } from '../../site'
|
|
9
9
|
import { isHomePath } from '../../libs/docs-path'
|
|
10
10
|
import type { Layout } from '../../libs/layout'
|
|
11
11
|
import Stylesheet from './Stylesheet.astro'
|
|
@@ -46,7 +46,7 @@ const pageTitle = isHome
|
|
|
46
46
|
family of every role. A link, not an `@import` in the styles, so that the browser finds it
|
|
47
47
|
with the page and not after the stylesheet that imports it
|
|
48
48
|
-->
|
|
49
|
-
<link rel="stylesheet" href={
|
|
49
|
+
<link rel="stylesheet" href={getVersionedStaticPath('fonts/fonts.css')} />
|
|
50
50
|
|
|
51
51
|
<meta name="description" content={description} />
|
|
52
52
|
|
|
@@ -6,19 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { HTMLAttributes } from 'astro/types'
|
|
9
|
-
import {
|
|
9
|
+
import { getVersionedStaticPath } from '../../site'
|
|
10
10
|
|
|
11
11
|
function getChassisCssProps() {
|
|
12
|
-
let cxCssLinkHref = getStaticPath('css/chassis')
|
|
13
|
-
|
|
14
|
-
if (import.meta.env.PROD) {
|
|
15
|
-
cxCssLinkHref = `${cxCssLinkHref}.min`
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
cxCssLinkHref = `${cxCssLinkHref}.css`
|
|
19
|
-
|
|
20
12
|
const cxCssLinkProps: HTMLAttributes<'link'> = {
|
|
21
|
-
href:
|
|
13
|
+
href: getVersionedStaticPath(import.meta.env.PROD ? 'css/chassis.min.css' : 'css/chassis.css'),
|
|
22
14
|
rel: 'stylesheet'
|
|
23
15
|
}
|
|
24
16
|
|
|
@@ -27,4 +19,4 @@ function getChassisCssProps() {
|
|
|
27
19
|
---
|
|
28
20
|
|
|
29
21
|
<link {...getChassisCssProps()} />
|
|
30
|
-
<link rel="stylesheet" href={
|
|
22
|
+
<link rel="stylesheet" href={getVersionedStaticPath('icons/chassis-icons.css')} />
|
package/src/libs/icon.ts
CHANGED
|
@@ -18,9 +18,16 @@ interface IconOptions {
|
|
|
18
18
|
* This is needed because the `<Example />` shortcode renders its `code` prop as raw HTML via `set:html`
|
|
19
19
|
* rather than as MDX, so nested Astro components (like `<Icon />`, similar to `<Placeholder />`) are never
|
|
20
20
|
* actually invoked — they need to be expanded to their rendered markup ahead of time.
|
|
21
|
+
*
|
|
22
|
+
* @param staticPath The `staticPath` of the site.
|
|
23
|
+
* @param sprite URL of the sprite that an icon without a `sprite` attribute uses.
|
|
21
24
|
* @see src/components/shortcodes/Icon.astro
|
|
22
25
|
*/
|
|
23
|
-
export function replaceIconsInHtml(
|
|
26
|
+
export function replaceIconsInHtml(
|
|
27
|
+
html: string,
|
|
28
|
+
staticPath = '/static',
|
|
29
|
+
sprite = `${staticPath}/icons/chassis-icons.svg`
|
|
30
|
+
) {
|
|
24
31
|
return html.replace(iconRegex, (match) => {
|
|
25
32
|
const document = htmlparser2.parseDocument(match, { xmlMode: true })
|
|
26
33
|
const iconElement = document.firstChild
|
|
@@ -34,11 +41,11 @@ export function replaceIconsInHtml(html: string, staticPath = '/static') {
|
|
|
34
41
|
throw new Error('Invalid icon element.')
|
|
35
42
|
}
|
|
36
43
|
|
|
37
|
-
return renderIconToString(getOptionsWithDefaults(iconElement.attribs,
|
|
44
|
+
return renderIconToString(getOptionsWithDefaults(iconElement.attribs, sprite))
|
|
38
45
|
})
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
function getOptionsWithDefaults(attribs: Record<string, string>,
|
|
48
|
+
function getOptionsWithDefaults(attribs: Record<string, string>, sprite: string): IconOptions {
|
|
42
49
|
if (!attribs.name) {
|
|
43
50
|
throw new Error('Icon element is missing the required "name" attribute.')
|
|
44
51
|
}
|
|
@@ -48,7 +55,7 @@ function getOptionsWithDefaults(attribs: Record<string, string>, staticPath: str
|
|
|
48
55
|
class: attribs.class,
|
|
49
56
|
size: attribs.size ? Number(attribs.size.replace(/[{}]/g, '')) : 24,
|
|
50
57
|
font: attribs.font !== undefined && attribs.font !== '{false}',
|
|
51
|
-
sprite: attribs.sprite ||
|
|
58
|
+
sprite: attribs.sprite || sprite,
|
|
52
59
|
title: attribs.title
|
|
53
60
|
}
|
|
54
61
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
// The hash of each file, kept until its size or time of change differs: a page of the build
|
|
6
|
+
// reads the same stylesheet as every other page, and the dev server sees a file copied anew.
|
|
7
|
+
const versions = new Map<string, { mtimeMs: number; size: number; version: string }>()
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The first 8 characters of the MD5 hash of a file's content, or `undefined` when there is
|
|
11
|
+
* no file at `fsPath`.
|
|
12
|
+
*/
|
|
13
|
+
export function getFileVersion(fsPath: string): string | undefined {
|
|
14
|
+
let stats: fs.Stats
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
stats = fs.statSync(fsPath)
|
|
18
|
+
} catch {
|
|
19
|
+
return undefined
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!stats.isFile()) return undefined
|
|
23
|
+
|
|
24
|
+
const cached = versions.get(fsPath)
|
|
25
|
+
|
|
26
|
+
if (cached && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) {
|
|
27
|
+
return cached.version
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const version = createHash('md5').update(fs.readFileSync(fsPath)).digest('hex').slice(0, 8)
|
|
31
|
+
versions.set(fsPath, { mtimeMs: stats.mtimeMs, size: stats.size, version })
|
|
32
|
+
|
|
33
|
+
return version
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Adds `?v=` and the version of the file to the URL path of a file of the public directory:
|
|
38
|
+
* `/static/css/chassis.min.css?v=8e2106f6`. A new content is a new URL, so the file can be
|
|
39
|
+
* kept by the browser until the page names another. A path that the public directory has no
|
|
40
|
+
* file at is returned as it is.
|
|
41
|
+
*
|
|
42
|
+
* @param urlPath URL path of the file, e.g. `"/static/css/chassis.min.css"`.
|
|
43
|
+
* @param publicDir Absolute path of the site's `public` directory.
|
|
44
|
+
*/
|
|
45
|
+
export function versionStaticPath(urlPath: string, publicDir: string): string {
|
|
46
|
+
const fsPath = path.join(publicDir, urlPath)
|
|
47
|
+
|
|
48
|
+
if (path.relative(publicDir, fsPath).startsWith('..')) return urlPath
|
|
49
|
+
|
|
50
|
+
const version = getFileVersion(fsPath)
|
|
51
|
+
|
|
52
|
+
return version ? `${urlPath}?v=${version}` : urlPath
|
|
53
|
+
}
|
package/src/site.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { getNodeModulesFsPaths, resolvePackageFilePath } from './libs/paths'
|
|
|
14
14
|
import { replaceConfigInText, replaceDocsrefInText } from './libs/remark'
|
|
15
15
|
import type { ChassisConfig, DocsPage, Sidebar } from './libs/schema'
|
|
16
16
|
import { resolveSiteFileUrl, resolveSourceFsPath, resolveSourceUrl } from './libs/source'
|
|
17
|
+
import { versionStaticPath } from './libs/static-version'
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* The parsed `config.yml`.
|
|
@@ -43,6 +44,18 @@ export function getStaticPath(file = ''): string {
|
|
|
43
44
|
return joinStaticPath(config.staticPath ?? '/static', file)
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* URL path of a static file with the version of its content:
|
|
49
|
+
* `getVersionedStaticPath('css/chassis.min.css')` is
|
|
50
|
+
* `/static/css/chassis.min.css?v=8e2106f6`. The version is read from the file of the site's
|
|
51
|
+
* `public` directory, so a page links the file of its own build, and a browser that keeps
|
|
52
|
+
* the file fetches it again when it changes. Without that file, the path is the one of
|
|
53
|
+
* `getStaticPath()`.
|
|
54
|
+
*/
|
|
55
|
+
export function getVersionedStaticPath(file: string): string {
|
|
56
|
+
return versionStaticPath(getStaticPath(file), paths.publicDir)
|
|
57
|
+
}
|
|
58
|
+
|
|
46
59
|
/** Absolute path of the site's root: the directory that holds `astro.config.ts`. */
|
|
47
60
|
export function getSiteRoot(): string {
|
|
48
61
|
return paths.root
|
package/virtual.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ declare module 'virtual:chassis-docs/paths' {
|
|
|
25
25
|
declare module 'virtual:chassis-docs/static' {
|
|
26
26
|
/** `staticPath` of the config, for scripts that run in the browser. */
|
|
27
27
|
export const staticPath: string
|
|
28
|
+
/** URL of the icon sprite, with the version of its content. */
|
|
29
|
+
export const spritePath: string
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
declare module 'virtual:chassis-docs/styles' {}
|