@chassis-ui/docs 0.6.2 → 0.7.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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @chassis-ui/docs
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - **Breaking.** The package needs `@chassis-ui/css` 0.6.0 or later: the peer range is `>=0.6.0`, it was `^0.5.0-0`. The layouts use the CSS grid of css 0.6, `.grid` with `col-span-*`, in place of the flexbox grid, `.row` with `.col-*`, which css 0.6 deprecates and css 0.7 removes. The header of `SingleLayout`, the sections list of `DocsLayout`, the footer and the lists of the header are grids. `NavLink` no longer sets a width: the lists of the header are two columns below `lg` by themselves. The loading rows of the search use the fraction widths, `w-4/12`. `.cxd-gutter` sets `--cx-container-padding` in place of `--cx-gutter-x`, with the same page margin of 1rem. The pages look as before, except that the footer columns are separated by the gutter of the breakpoint and move by a few pixels. See [UPGRADING.md](https://github.com/chassis-ui/website/blob/main/packages/docs/UPGRADING.md#from-06-to-07) for the classes to replace in a site's own pages.
8
+
9
+ ## 0.6.3
10
+
11
+ ### Patch Changes
12
+
13
+ - The home page of a site under a path gets the home form of the title, `title · subtitle`. The layouts took the page at `/` as the home page, so a site with `baseURL` `https://chassis-ui.com/css/` never got it: its home page is at `/css/`. The home page is now the page at the path of `baseURL`. The title of such a home page changes with this release, and the `title` prop of its layout is used for the social tags only. Keep `title · subtitle` within 70 characters where the site validates its HTML.
14
+ - The color mode script is inline in the head and runs before the first paint. It was a module, which runs after the document is parsed, so a page in dark mode showed light first.
15
+ - Five fixes of the search dialog. The page scrolls again after a search result on the current page is opened: the dialog closed without removing the scroll lock of the body. The input has the focus when the dialog is opened with the button, so typing works at once. The keyboard shortcuts open the dialog as the button does: the page behind it no longer scrolls, and a click outside closes it. A click or Enter on a loading placeholder no longer closes the dialog and saves an empty visit. Escape closes the dialog in Safari when the focus is in the empty input.
16
+
3
17
  ## 0.6.2
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -23,7 +23,7 @@ pnpm add @chassis-ui/docs
23
23
  ```json
24
24
  {
25
25
  "@astrojs/markdown-remark": "^7.0.0",
26
- "@chassis-ui/css": "^0.5.0-0",
26
+ "@chassis-ui/css": ">=0.6.0",
27
27
  "@pagefind/component-ui": "^1.0.0",
28
28
  "@shikijs/transformers": "^4.3.1",
29
29
  "astro": "^7.0.0",
@@ -109,7 +109,7 @@ currentVersion: '0.5.2'
109
109
  | Key | Required | Meaning |
110
110
  | --------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
111
111
  | `title`, `subtitle`, `description`, `authors` | yes | Used in the page title and the meta tags |
112
- | `baseURL` | yes | Canonical URL of the site |
112
+ | `baseURL` | yes | Canonical URL of the site. The page at its path is the home page: `/css/` for `https://chassis-ui.com/css/` |
113
113
  | `docsPath` | yes | URL path of the docs pages. Starts with `/` |
114
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
115
  | `repo` | yes | URL of the repository |
@@ -207,7 +207,7 @@ staticPath: '/css/static'
207
207
 
208
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
209
 
210
- - on the host, from `/css/static/*` to `/static/*` of the site's deployment. chassis-ui.com has one for each Chassis site.
210
+ - on the host, from `/css/static/*` to `/static/*` of the site's deployment.
211
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
212
 
213
213
  Two kinds of URL are the site's own to move:
@@ -229,6 +229,8 @@ import SingleLayout from '@chassis-ui/docs/layouts/SingleLayout.astro'
229
229
  </SingleLayout>
230
230
  ```
231
231
 
232
+ The `<title>` of a page is its `title` and the `title` of `config.yml`: `About · Chassis UI`. The home page, which is the page at the path of `baseURL`, gets `title` and `subtitle` of `config.yml` instead: `Chassis UI · Design Systems that Scale & Sync`. Its own `title` is used for the social tags only. html-validate reports a `<title>` of more than 70 characters, so keep the two within that.
233
+
232
234
  ## Shortcodes
233
235
 
234
236
  Every component in `@chassis-ui/docs/shortcodes/` is available in MDX files without an import. So is every component in the site's `src/components/shortcodes/`. A component of the site replaces the package's component of the same name.
@@ -374,6 +376,8 @@ The integration provides five modules: `virtual:chassis-docs/config`, `virtual:c
374
376
 
375
377
  | `@chassis-ui/docs` | Requires Astro | Requires `@chassis-ui/css` | Requires Node | Built with |
376
378
  | ------------------ | -------------------------- | -------------------------- | ------------- | ------------------------------------ |
379
+ | 0.7.0 | `^7.0.0` | `>=0.6.0` | `>=22.12.0` | Astro 7.3.5, css 0.6.0, tokens 0.6.0 |
380
+ | 0.6.3 | `^7.0.0` | `^0.5.0-0` | `>=22.12.0` | Astro 7.3.5, css 0.5.2, tokens 0.6.0 |
377
381
  | 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 |
378
382
  | 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 |
379
383
  | 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 |
package/UPGRADING.md CHANGED
@@ -1,5 +1,69 @@
1
1
  # Upgrading @chassis-ui/docs
2
2
 
3
+ ## From 0.6 to 0.7
4
+
5
+ 0.7.0 needs `@chassis-ui/css` 0.6.0 or later. The layouts use the CSS grid of that version,
6
+ `.grid` with `col-span-*`, in place of the flexbox grid, `.row` with `.col-*`. css 0.6
7
+ deprecates the flexbox grid and css 0.7 removes it.
8
+
9
+ ### 1. Update the dependencies
10
+
11
+ ```sh
12
+ pnpm add -D @chassis-ui/docs@^0.7.0 @chassis-ui/css@^0.6.0
13
+ ```
14
+
15
+ css 0.6.0 has changes of its own. Read its
16
+ [changelog](https://github.com/chassis-ui/css/blob/main/packages/css/CHANGELOG.md) first:
17
+ among them, the default gap of `.grid` is now the gutter token of the breakpoint.
18
+
19
+ ### 2. Move your own pages off the flexbox grid
20
+
21
+ css 0.6 still has the flexbox grid, so the site builds and looks as before without this
22
+ step. css 0.7 removes it. Replace the classes in your own components, pages and content:
23
+
24
+ | Flexbox grid | CSS grid |
25
+ | ---------------------------------------- | -------------------------------------------------- |
26
+ | `row` | `grid` |
27
+ | `col-6`, `md:col-6` | `col-span-6`, `col-span-full md:col-span-6` |
28
+ | `col-12` | `col-span-full` |
29
+ | `row row-cols-1 md:row-cols-3` and `col` | `grid grid-cols-1 md:grid-cols-3`, no class inside |
30
+ | `offset-1` | `col-start-2` |
31
+ | `col lg:col-10 mx-auto` | `col-span-full lg:col-span-10 lg:col-start-2` |
32
+ | `g-md`, `gx-md`, `gy-md` | `gap-md`, `column-gap-md`, `row-gap-md` |
33
+ | `col-auto` | `d-flex` with `gap-*` on the parent |
34
+ | `col-6` outside a `row` | `w-6/12` |
35
+ | `col` outside a `row` | `flex-fill` |
36
+
37
+ - An item without a span is one column wide. A column that was full width below its
38
+ breakpoint, such as `md:col-6`, needs `col-span-full` too.
39
+ - A `row` without a gutter class had a gutter of 1.5rem between columns and none between
40
+ rows. A `grid` has the gutter of the breakpoint in both directions, from 0.5rem to 3rem.
41
+ Add `row-gap-0` where the items have margins of their own.
42
+ - A grid beside the sidebar, or in a card, is narrower than the viewport that the gutter
43
+ follows. Give it a `gap-*` class, and `grid-cols-{n}` in place of twelve columns.
44
+ - An auto margin shrinks a grid item to its content. Center an item with `col-start-*`.
45
+
46
+ The [grid page](https://chassis-ui.com/css/docs/layout/grid/) of Chassis CSS has the full
47
+ table.
48
+
49
+ ### What changes in the package
50
+
51
+ - **`NavLink` sets no width.** Its item was `nav-item col-6 lg:col-auto`, half of the list
52
+ below `lg`. It is `nav-item` now, and the lists of the header are a grid of two columns
53
+ below `lg`. A list of your own that relied on the two columns takes
54
+ `d-grid grid-cols-2 lg:d-flex`.
55
+ - **`.cxd-gutter` sets `--cx-container-padding`.** It set `--cx-gutter-x`, which the
56
+ container stops reading in css 0.7. The page margin of the docs layout is 1rem, as
57
+ before. A rule of your own that set `--cx-gutter-x` on that element sets
58
+ `--cx-container-padding` to half of it.
59
+ - **The footer and the header of `SingleLayout` take the gutter of the breakpoint.** The
60
+ footer columns move by a few pixels, 20 at most on the widest screens.
61
+
62
+ ### Check the result
63
+
64
+ Build the site before and after the upgrade and compare the pages in a browser, at a phone
65
+ width and a desktop width. Apart from the footer columns, nothing of the package moves.
66
+
3
67
  ## From 0.5 to 0.6
4
68
 
5
69
  0.6.0 is a breaking release. In 0.5 a site had to supply five modules behind a `@libs/*`
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.2",
4
+ "version": "0.7.0",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
@@ -70,7 +70,7 @@
70
70
  },
71
71
  "peerDependencies": {
72
72
  "@astrojs/markdown-remark": "^7.0.0",
73
- "@chassis-ui/css": "^0.5.0-0",
73
+ "@chassis-ui/css": ">=0.6.0",
74
74
  "@pagefind/component-ui": "^1.0.0",
75
75
  "@shikijs/transformers": "^4.3.1",
76
76
  "astro": "^7.0.0",
@@ -106,8 +106,16 @@
106
106
  "unist-util-visit": "^5.1.0"
107
107
  },
108
108
  "devDependencies": {
109
+ "@astrojs/markdown-remark": "^7.3.1",
110
+ "@chassis-ui/css": "^0.6.0",
111
+ "@pagefind/component-ui": "^1.5.2",
112
+ "@shikijs/transformers": "^4.5.0",
109
113
  "astro": "^7.3.5",
114
+ "html-validate": "^11.16.1",
115
+ "rehype-autolink-headings": "^7.1.0",
110
116
  "remark-mdx": "^3.1.1",
111
- "vfile": "^6.0.3"
117
+ "sass": "^1.105.1",
118
+ "vfile": "^6.0.3",
119
+ "vnu-jar": "^26.10.2"
112
120
  }
113
121
  }
@@ -21,7 +21,7 @@ interface Props {
21
21
  const { active, class: className, ...props } = Astro.props
22
22
  ---
23
23
 
24
- <li class="nav-item col-6 lg:col-auto">
24
+ <li class="nav-item">
25
25
  <a
26
26
  aria-current={active ? true : undefined}
27
27
  class:list={['nav-link', className, { active }]}
package/src/js/search.js CHANGED
@@ -16,6 +16,9 @@ import { getInstanceManager } from '@pagefind/component-ui'
16
16
  import { staticPath } from 'virtual:chassis-docs/static'
17
17
 
18
18
  const DIALOG_SELECTOR = '#cxdSearchDialog'
19
+ // The rows that are links. The loading skeleton reuses the class on a `<div>`,
20
+ // which must not be followed, focused or saved as a visit.
21
+ const ITEM_SELECTOR = 'a.cxd-search-item'
19
22
  const SUB_RESULTS_LIMIT = 3
20
23
  // How long a search may take before we show the loading skeleton. Most queries
21
24
  // resolve faster, so the previous results stay on-screen instead of flashing.
@@ -294,12 +297,21 @@ class CxdSearchInput extends HTMLElement {
294
297
  return
295
298
  }
296
299
 
300
+ // Safari keeps Escape for the search field, even an empty one, and the
301
+ // dialog never gets its cancel event. With text in the field the key clears
302
+ // it, as in every browser; without text it closes the dialog here.
303
+ if (event.key === 'Escape' && !this.input.value) {
304
+ event.preventDefault()
305
+ closeSearchDialog(this.closest('dialog'))
306
+ return
307
+ }
308
+
297
309
  // Enter follows the first result link.
298
310
  // Always preventDefault so the form never implicit-submits.
299
311
  if (event.key === 'Enter') {
300
312
  event.preventDefault()
301
313
  const dialogEl = this.closest('dialog')
302
- dialogEl?.querySelector('.cxd-search-item')?.click()
314
+ dialogEl?.querySelector(ITEM_SELECTOR)?.click()
303
315
  }
304
316
  }
305
317
 
@@ -339,11 +351,11 @@ class CxdSearchResults extends HTMLElement {
339
351
  }
340
352
 
341
353
  _getLinks() {
342
- return [...this.querySelectorAll('.cxd-search-item')]
354
+ return [...this.querySelectorAll(ITEM_SELECTOR)]
343
355
  }
344
356
 
345
357
  _onKeydown(event) {
346
- const link = event.target.closest('.cxd-search-item')
358
+ const link = event.target.closest(ITEM_SELECTOR)
347
359
  if (!link) return
348
360
 
349
361
  const links = this._getLinks()
@@ -460,8 +472,8 @@ class CxdSearchResults extends HTMLElement {
460
472
  <div class="icon cxd-search-icon skeleton">
461
473
  </div>
462
474
  <div class="cxd-search-item-body">
463
- <div class="skeleton col-4"></div>
464
- <div class="skeleton col-12"></div>
475
+ <div class="skeleton w-4/12"></div>
476
+ <div class="skeleton w-100"></div>
465
477
  </div>
466
478
  </div>
467
479
  `
@@ -617,6 +629,29 @@ const isEditableTarget = (target) => {
617
629
  return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT'
618
630
  }
619
631
 
632
+ const TRIGGER_SELECTOR = `[data-cx-toggle="dialog"][data-cx-target="${DIALOG_SELECTOR}"]`
633
+
634
+ // Puts the caret in the input once the dialog is open. The chassis Dialog
635
+ // focuses the dialog element itself when it opens, so a key typed right after a
636
+ // click on the trigger went nowhere.
637
+ const focusSearchInput = (dialogEl) => {
638
+ requestAnimationFrame(() => {
639
+ if (!dialogEl.open) return
640
+ dialogEl.querySelector('cxd-search-input')?.focus()
641
+ if (!instance.searchTerm) {
642
+ dialogEl.querySelector('cxd-search-results')?._renderEmpty?.()
643
+ }
644
+ })
645
+ }
646
+
647
+ const registerTriggerHandler = () => {
648
+ document.addEventListener('click', (event) => {
649
+ if (!event.target.closest(TRIGGER_SELECTOR)) return
650
+ const dialogEl = document.querySelector(DIALOG_SELECTOR)
651
+ if (dialogEl) focusSearchInput(dialogEl)
652
+ })
653
+ }
654
+
620
655
  const openSearchDialog = () => {
621
656
  const dialogEl = document.querySelector(DIALOG_SELECTOR)
622
657
  if (!dialogEl) return
@@ -626,15 +661,24 @@ const openSearchDialog = () => {
626
661
  return
627
662
  }
628
663
 
629
- // Native showModal() — CSS @starting-style handles the entry animation without
630
- // needing the chassis bundle. Works in both dev (no bundle) and prod.
631
- dialogEl.showModal()
632
- requestAnimationFrame(() => {
633
- dialogEl.querySelector('cxd-search-input')?.focus()
634
- if (!instance.searchTerm) {
635
- dialogEl.querySelector('cxd-search-results')?._renderEmpty?.()
636
- }
637
- })
664
+ // Open through the trigger, so that a shortcut does what the button does: the
665
+ // chassis Dialog locks the scroll of the body, closes on a click on the
666
+ // backdrop and gives the focus back. Without the chassis bundle the click does
667
+ // nothing, and the native showModal() opens the dialog.
668
+ document.querySelector(TRIGGER_SELECTOR)?.click()
669
+ if (!dialogEl.open) {
670
+ dialogEl.showModal()
671
+ focusSearchInput(dialogEl)
672
+ }
673
+ }
674
+
675
+ // Closes through the dismiss button, so that the chassis Dialog animates the
676
+ // dialog out, unlocks the scroll of the body and gives the focus back. Without
677
+ // the chassis bundle the click does nothing, and the native close() closes it.
678
+ const closeSearchDialog = (dialogEl) => {
679
+ if (!dialogEl?.open) return
680
+ dialogEl.querySelector('[data-cx-dismiss="dialog"]')?.click()
681
+ if (dialogEl.open && !dialogEl.classList.contains('hiding')) dialogEl.close()
638
682
  }
639
683
 
640
684
  const registerGlobalShortcuts = () => {
@@ -683,7 +727,7 @@ const setupDialogResetOnClose = () => {
683
727
 
684
728
  const registerResultLinkHandler = () => {
685
729
  document.addEventListener('click', (event) => {
686
- const link = event.target.closest('.cxd-search-item')
730
+ const link = event.target.closest(ITEM_SELECTOR)
687
731
  if (!link) return
688
732
  const dialogEl = link.closest('dialog')
689
733
  if (!dialogEl?.matches(DIALOG_SELECTOR)) return
@@ -697,6 +741,14 @@ const registerResultLinkHandler = () => {
697
741
  })
698
742
 
699
743
  dialogEl.close()
744
+
745
+ // The trigger opens the dialog through the chassis Dialog, which locks the
746
+ // scroll of the body with this class and unlocks it in its own hide(). The
747
+ // native close() above skips that, so the class stays: when the result is on
748
+ // the current page, nothing reloads and the page can no longer scroll.
749
+ if (!document.querySelector('dialog[open]:modal')) {
750
+ document.body.classList.remove('dialog-open')
751
+ }
700
752
  })
701
753
  }
702
754
 
@@ -704,6 +756,7 @@ const registerResultLinkHandler = () => {
704
756
 
705
757
  defineSearchCustomElements()
706
758
  registerGlobalShortcuts()
759
+ registerTriggerHandler()
707
760
  registerResultLinkHandler()
708
761
 
709
762
  if (document.readyState === 'loading') {
@@ -146,9 +146,9 @@ if (frontmatter.toc) {
146
146
  <div class="cxd-content">
147
147
  {
148
148
  frontmatter.sections && (
149
- <div class="row g-xl">
149
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-xl">
150
150
  {frontmatter.sections.map((section: DocSection) => (
151
- <div class="md:col-6">
151
+ <div>
152
152
  <a
153
153
  class="d-block text-decoration-none"
154
154
  href={getDocsPath(
@@ -24,8 +24,8 @@ mainProps['class'] = 'min-vh-100'
24
24
  <BaseLayout {...Astro.props} layout="single" overrides={{ main: mainProps }}>
25
25
  <header class="py-xl md:py-3xl border-bottom border-subtle">
26
26
  <div class="container 2xl">
27
- <div class="row">
28
- <div class="col lg:col-10 2xl:col-8">
27
+ <div class="grid">
28
+ <div class="col-span-full lg:col-span-10 2xl:col-span-8">
29
29
  <h1 class="mt-0">{title}</h1>
30
30
  <p class="font-lead">{description}</p>
31
31
  <slot name="header-content" />
@@ -10,8 +10,8 @@ import { getStaticPath } from '../../site'
10
10
 
11
11
  <footer class="cxd-footer py-6xl">
12
12
  <div class="container 2xl fg-subtle">
13
- <div class="row">
14
- <div class="md:col-10 lg:col-5 mb-md">
13
+ <div class="grid row-gap-0">
14
+ <div class="col-span-full md:col-span-10 lg:col-span-5 mb-md">
15
15
  <a
16
16
  class="d-inline-flex align-items-center mb-xs text-body-emphasis text-decoration-none"
17
17
  href="/"
@@ -30,7 +30,7 @@ import { getStaticPath } from '../../site'
30
30
  >
31
31
  </p>
32
32
  </div>
33
- <div class="sm:col-4 lg:col-2 lg:offset-1 mb-md">
33
+ <div class="col-span-full sm:col-span-4 lg:col-span-2 lg:col-start-7 mb-md">
34
34
  <p class="h6 mb-xs">Docs</p>
35
35
  <ul class="nav">
36
36
  <li><a href="/tokens">Design Tokens</a></li>
@@ -41,7 +41,7 @@ import { getStaticPath } from '../../site'
41
41
  <li><a href="/icons">Icon Generator</a></li>
42
42
  </ul>
43
43
  </div>
44
- <div class="sm:col-4 lg:col-2 mb-md">
44
+ <div class="col-span-full sm:col-span-4 lg:col-span-2 mb-md">
45
45
  <p class="h6 mb-xs">Github</p>
46
46
  <ul class="nav">
47
47
  <li><a href="https://github.com/chassis-ui/tokens">Chassis Tokens</a></li>
@@ -52,7 +52,7 @@ import { getStaticPath } from '../../site'
52
52
  <li><a href="https://github.com/chassis-ui/icons">Chassis Icons</a></li>
53
53
  </ul>
54
54
  </div>
55
- <div class="sm:col-4 lg:col-2 mb-md">
55
+ <div class="col-span-full sm:col-span-4 lg:col-span-2 mb-md">
56
56
  <p class="h6 mb-xs">Project</p>
57
57
  <ul class="nav">
58
58
  <li><a href="/about">About</a></li>
@@ -6,10 +6,12 @@
6
6
  */
7
7
 
8
8
  import { getConfig } from '../../site'
9
+ import { isHomePath } from '../../libs/docs-path'
9
10
  import type { Layout } from '../../libs/layout'
10
11
  import Stylesheet from './Stylesheet.astro'
11
12
  import Favicons from './Favicons.astro'
12
13
  import Social from './Social.astro'
14
+ import colorModes from '../../js/color-modes.js?raw'
13
15
  import 'virtual:chassis-docs/styles'
14
16
 
15
17
  interface Props {
@@ -29,7 +31,8 @@ const { description, layout, robots, thumbnail, title } = Astro.props
29
31
 
30
32
  const canonicalUrl = new URL(Astro.url.pathname, Astro.site)
31
33
 
32
- const isHome = Astro.url.pathname === '/'
34
+ // The home page of a site under a path, such as `/css/`, is not at `/`
35
+ const isHome = isHomePath(getConfig().baseURL, Astro.url.pathname)
33
36
  const pageTitle = isHome
34
37
  ? `${getConfig().title} · ${getConfig().subtitle}`
35
38
  : `${title} · ${getConfig().title}`
@@ -60,7 +63,11 @@ const pageTitle = isHome
60
63
 
61
64
  {robots && <meta name="robots" content={robots} />}
62
65
 
63
- <script src="../../js/color-modes.js"></script>
66
+ <!--
67
+ Inline and not a module, so that it sets the theme before the first paint. A module runs
68
+ after the document is parsed, and a page in dark mode would show light first
69
+ -->
70
+ <script is:inline set:html={colorModes} />
64
71
 
65
72
  <Stylesheet />
66
73
  <slot name="styles" />
@@ -90,14 +90,16 @@ const isActive = (path: string) => {
90
90
 
91
91
  <hr class="lg:d-none m-0" />
92
92
  <div class="drawer-body lg:p-0">
93
- <ul class="navbar-nav flex-row flex-wrap cxd-navbar-nav mx-0 lg:mx-md">
93
+ <ul
94
+ class="navbar-nav d-grid grid-cols-2 lg:d-flex flex-row flex-wrap cxd-navbar-nav mx-0 lg:mx-md"
95
+ >
94
96
  <NavLink active={isActive('/tokens')} href="/tokens">Tokens</NavLink>
95
97
  <NavLink active={isActive('/figma')} href="/figma">Figma</NavLink>
96
98
  <NavLink active={isActive('/css')} href="/css">CSS</NavLink>
97
99
  <NavLink active={isActive('/react')} href="/react">React</NavLink>
98
100
  <NavLink active={isActive('/assets')} href="/assets">Assets</NavLink>
99
101
  <NavLink active={isActive('/icons')} href="/icons">Icons</NavLink>
100
- <li class="nav-item col-12 lg:col-auto lg:d-flex">
102
+ <li class="nav-item col-span-full lg:d-flex">
101
103
  <div class="vr d-none lg:d-flex my-auto lg:mx-sm"></div>
102
104
  <hr class="lg:d-none" />
103
105
  </li>
@@ -107,7 +109,9 @@ const isActive = (path: string) => {
107
109
 
108
110
  <hr class="lg:d-none m-0" />
109
111
 
110
- <ul class="navbar-nav flex-row flex-wrap lg:ms-auto align-items-center">
112
+ <ul
113
+ class="navbar-nav d-grid grid-cols-2 lg:d-flex flex-row flex-wrap lg:ms-auto align-items-center"
114
+ >
111
115
  {
112
116
  figmaHandle && (
113
117
  <NavLink
@@ -134,7 +138,7 @@ const isActive = (path: string) => {
134
138
  </NavLink>
135
139
  )
136
140
  }
137
- <li class="nav-item col-12 lg:col-auto">
141
+ <li class="nav-item col-span-full">
138
142
  <div class="vr d-none lg:d-flex h-100 lg:mx-2xs"></div>
139
143
  <hr class="lg:d-none" />
140
144
  </li>
@@ -17,3 +17,16 @@ export function joinStaticPath(staticPath: string, file = ''): string {
17
17
 
18
18
  return name ? `${staticPath}/${name}` : staticPath
19
19
  }
20
+
21
+ /**
22
+ * Whether a page is the home page of the site: the page at the path of `baseURL`. That is
23
+ * `/` for `https://chassis-ui.com` and `/css/` for `https://chassis-ui.com/css/`.
24
+ *
25
+ * @param baseURL The `baseURL` of the site's `config.yml`.
26
+ * @param pathname URL path of the page, with or without a trailing slash.
27
+ */
28
+ export function isHomePath(baseURL: string, pathname: string): boolean {
29
+ const trim = (value: string) => value.replace(/\/+$/, '')
30
+
31
+ return trim(pathname) === trim(new URL(baseURL).pathname)
32
+ }
@@ -3,7 +3,7 @@
3
3
 
4
4
  @layer custom {
5
5
  .cxd-gutter {
6
- --cx-gutter-x: #{$cxd-gutter-x};
6
+ --cx-container-padding: #{$cxd-gutter-x * .5};
7
7
  }
8
8
 
9
9
  .cxd-layout {