@chassis-ui/docs 0.6.0 → 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.
@@ -10,7 +10,6 @@ import type { Layout } from '../../libs/layout'
10
10
  import Stylesheet from './Stylesheet.astro'
11
11
  import Favicons from './Favicons.astro'
12
12
  import Social from './Social.astro'
13
- import Analytics from './Analytics.astro'
14
13
  import 'virtual:chassis-docs/styles'
15
14
 
16
15
  interface Props {
@@ -41,6 +40,14 @@ const pageTitle = isHome
41
40
 
42
41
  <link rel="preconnect" href="https://fonts.googleapis.com" />
43
42
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
43
+ <!--
44
+ A link, not an `@import` in the styles, so that the browser finds it with the page and
45
+ not after the stylesheet that imports it
46
+ -->
47
+ <link
48
+ rel="stylesheet"
49
+ href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Inter:wght@100..900&family=Archivo+Narrow:ital,wght@0,400..700;1,400..700&display=swap"
50
+ />
44
51
 
45
52
  <meta name="description" content={description} />
46
53
 
@@ -59,4 +66,3 @@ const pageTitle = isHome
59
66
  <slot name="styles" />
60
67
  <Favicons />
61
68
  <Social description={description} layout={layout} thumbnail={thumbnail} title={title} />
62
- <Analytics />
@@ -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">
@@ -94,6 +94,7 @@ const isActive = (path: string) => {
94
94
  <NavLink active={isActive('/tokens')} href="/tokens">Tokens</NavLink>
95
95
  <NavLink active={isActive('/figma')} href="/figma">Figma</NavLink>
96
96
  <NavLink active={isActive('/css')} href="/css">CSS</NavLink>
97
+ <NavLink active={isActive('/react')} href="/react">React</NavLink>
97
98
  <NavLink active={isActive('/assets')} href="/assets">Assets</NavLink>
98
99
  <NavLink active={isActive('/icons')} href="/icons">Icons</NavLink>
99
100
  <li class="nav-item col-12 lg:col-auto lg: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
+ }
@@ -1,5 +1,5 @@
1
1
  import { codeToHtml, type ShikiTransformer } from 'shiki'
2
- import { DOCS_SHIKI_THEMES } from './markdown'
2
+ import { DOCS_SHIKI_THEMES, focusableTransformer } from './markdown'
3
3
 
4
4
  /**
5
5
  * Shiki transformer that renames the `shiki` CSS class on `<pre>` elements to
@@ -44,7 +44,7 @@ export async function highlightCode(
44
44
  lang,
45
45
  themes: DOCS_SHIKI_THEMES,
46
46
  defaultColor: false,
47
- transformers: [...extraTransformers, classTransformer]
47
+ transformers: [...extraTransformers, classTransformer, focusableTransformer]
48
48
  })
49
49
 
50
50
  return { html: replaceShikiClasses(highlighted) }
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
  }
@@ -35,6 +35,17 @@ const addLanguageAttributeTransformer: ShikiTransformer = {
35
35
  }
36
36
  }
37
37
 
38
+ /**
39
+ * Shiki transformer that puts `<pre>` in the tab order. A code block that is wider than the
40
+ * page scrolls sideways, and a keyboard can scroll it only when it can take focus.
41
+ */
42
+ export const focusableTransformer: ShikiTransformer = {
43
+ name: 'focusable-pre',
44
+ pre(node) {
45
+ node.properties['tabindex'] = '0'
46
+ }
47
+ }
48
+
38
49
  /**
39
50
  * Options accepted by `getDocsMarkdownConfig`.
40
51
  */
@@ -121,7 +132,8 @@ export function getDocsMarkdownConfig(options: DocsMarkdownConfigOptions): Markd
121
132
  transformers: [
122
133
  transformerNotationDiff(),
123
134
  transformerNotationHighlight(),
124
- addLanguageAttributeTransformer
135
+ addLanguageAttributeTransformer,
136
+ focusableTransformer
125
137
  ]
126
138
  }
127
139
  }
@@ -38,7 +38,7 @@ const zHeadingRange = z.object({
38
38
  * ```
39
39
  */
40
40
  export const configSchema = z.strictObject({
41
- /** Google Analytics is loaded in production builds when `googleId` is set. */
41
+ /** Google Analytics is offered in production builds when `googleId` is set, and loads after the visitor accepts. */
42
42
  analytics: z.strictObject({ googleId: z.string().optional() }).default({}),
43
43
  /** Heading levels that get an anchor link. */
44
44
  anchors: zHeadingRange.default({ min: 2, max: 5 }),
@@ -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. */
@@ -0,0 +1,14 @@
1
+ //
2
+ // Consent
3
+ //
4
+
5
+ @layer custom {
6
+ // Above the sticky header, below dialogs and drawers
7
+ .cxd-consent {
8
+ position: fixed;
9
+ inset-block-end: 0;
10
+ inset-inline: 0;
11
+ z-index: 1030;
12
+ padding-block: var(--cx-space-md);
13
+ }
14
+ }
@@ -14,7 +14,8 @@
14
14
  }
15
15
  }
16
16
 
17
- a {
17
+ a,
18
+ .cxd-footer-link {
18
19
  color: var(--cx-fg-color);
19
20
  text-decoration: none;
20
21
 
@@ -24,5 +25,14 @@
24
25
  text-decoration: underline;
25
26
  }
26
27
  }
28
+
29
+ // A button that looks like the links next to it
30
+ .cxd-footer-link {
31
+ padding: 0;
32
+ font: inherit;
33
+ cursor: pointer;
34
+ background: none;
35
+ border: 0;
36
+ }
27
37
  }
28
38
  }
@@ -1,6 +1,5 @@
1
1
  @use "@chassis-ui/css/scss/mixins" as *;
2
2
 
3
- @forward "./fonts";
4
3
  @forward "./navbar";
5
4
  @forward "./content";
6
5
  @forward "./skippy";
@@ -8,6 +7,7 @@
8
7
  @forward "./layout";
9
8
  @forward "./toc";
10
9
  @forward "./footer";
10
+ @forward "./consent";
11
11
  @forward "./snippets";
12
12
  @forward "./callouts";
13
13
  @forward "./placeholder-img";
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' {}
@@ -1,31 +0,0 @@
1
- ---
2
- /**
3
- * Analytics
4
- *
5
- * Google Analytics script tags. Rendered in production builds, when `analytics.googleId` is
6
- * set in `config.yml`.
7
- */
8
-
9
- import { getConfig } from '../../site'
10
-
11
- const isProd = import.meta.env.PROD
12
- const { googleId } = getConfig().analytics
13
- ---
14
-
15
- {
16
- isProd && googleId && (
17
- <>
18
- <script is:inline async src={`https://www.googletagmanager.com/gtag/js?id=${googleId}`} />
19
- <script
20
- is:inline
21
- set:html={`
22
- window.dataLayer = window.dataLayer || [];
23
- function gtag(){dataLayer.push(arguments);}
24
- gtag('js', new Date());
25
-
26
- gtag('config', '${googleId}');
27
- `}
28
- />
29
- </>
30
- )
31
- }
@@ -1 +0,0 @@
1
- @import "https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Inter:wght@100..900&family=Archivo+Narrow:ital,wght@0,400..700;1,400..700&display=swap";