@chassis-ui/docs 0.1.10 → 0.3.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/README.md +16 -16
- package/index.ts +6 -1
- package/package.json +20 -8
- package/src/components/DocsSidebar.astro +63 -23
- package/src/components/FeatureCard.astro +8 -8
- package/src/components/NavLink.astro +1 -1
- package/src/components/TableOfContents.astro +8 -7
- package/src/components/ThemeToggler.astro +16 -37
- package/src/components/shortcodes/Blockquote.astro +31 -0
- package/src/components/shortcodes/CSSOnly.astro +22 -0
- package/src/components/shortcodes/Callout.astro +6 -2
- package/src/components/shortcodes/Code.astro +289 -0
- package/src/components/shortcodes/DeprecatedIn.astro +18 -0
- package/src/components/shortcodes/Example.astro +132 -0
- package/src/components/shortcodes/Icon.astro +57 -0
- package/src/components/shortcodes/InFigma.astro +26 -0
- package/src/components/shortcodes/JsDocs.astro +64 -0
- package/src/components/shortcodes/Placeholder.astro +28 -0
- package/src/components/shortcodes/ResizableExample.astro +126 -0
- package/src/components/shortcodes/ScssDocs.astro +108 -0
- package/src/components/shortcodes/ScssDocsSimple.astro +66 -0
- package/src/js/color-modes.js +3 -3
- package/src/js/example-mode.js +75 -0
- package/src/js/search.js +501 -39
- package/src/js/theme-color.js +1 -1
- package/src/layouts/DocsLayout.astro +18 -21
- package/src/layouts/RedirectLayout.astro +1 -0
- package/src/layouts/SingleLayout.astro +3 -3
- package/src/layouts/footer/Footer.astro +5 -5
- package/src/layouts/footer/Scripts.astro +14 -7
- package/src/layouts/head/Analytics.astro +12 -6
- package/src/layouts/head/Favicons.astro +0 -2
- package/src/layouts/head/Head.astro +2 -7
- package/src/layouts/head/Stylesheet.astro +18 -11
- package/src/layouts/header/Header.astro +2 -5
- package/src/layouts/header/Navigation.astro +40 -42
- package/src/layouts/header/SearchDialog.astro +74 -0
- package/src/layouts/header/SearchTrigger.astro +41 -0
- package/src/layouts/header/Skippy.astro +1 -1
- package/src/libs/highlight.ts +91 -0
- package/src/libs/icon.ts +75 -0
- package/src/libs/image.ts +12 -1
- package/src/libs/layout.ts +18 -0
- package/src/libs/markdown.ts +128 -0
- package/src/libs/placeholder.ts +250 -0
- package/src/libs/rehype.ts +0 -17
- package/src/libs/shortcodes.ts +129 -0
- package/src/libs/site.ts +95 -0
- package/src/libs/toc.ts +40 -6
- package/src/libs/utils.ts +34 -82
- package/src/libs/vite.ts +45 -0
- package/src/scss/_anchor.scss +20 -16
- package/src/scss/_callouts.scss +29 -28
- package/src/scss/_content.scss +72 -103
- package/src/scss/_footer.scss +18 -19
- package/src/scss/_layout.scss +56 -61
- package/src/scss/_navbar.scss +19 -126
- package/src/scss/_placeholder-img.scss +11 -7
- package/src/scss/_scrolling.scss +14 -12
- package/src/scss/_search.scss +418 -0
- package/src/scss/_shiki.scss +120 -0
- package/src/scss/_sidebar.scss +137 -132
- package/src/scss/_skippy.scss +6 -4
- package/src/scss/_snippets.scss +181 -0
- package/src/scss/_toc.scss +97 -93
- package/src/scss/_vars.scss +89 -0
- package/src/scss/main.scss +75 -81
- package/src/js/icon-loader.js +0 -229
- package/src/libs/chassis.ts +0 -38
- package/src/scss/_brand.scss +0 -59
- package/src/scss/_buttons.scss +0 -33
- package/src/scss/_clipboard-js.scss +0 -63
- package/src/scss/_code.scss +0 -116
- package/src/scss/_colors.scss +0 -140
- package/src/scss/_docsearch.scss +0 -212
- package/src/scss/_masthead.scss +0 -124
- package/src/scss/_settings.scss +0 -29
- package/src/scss/_syntax.scss +0 -160
- package/src/scss/_variables.scss +0 -78
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<footer class="cxd-footer py-6xlarge">
|
|
10
|
-
<div class="container
|
|
10
|
+
<div class="container 2xlarge fg-subtle">
|
|
11
11
|
<div class="row">
|
|
12
|
-
<div class="col-
|
|
12
|
+
<div class="medium:col-10 large:col-5 mb-medium">
|
|
13
13
|
<a
|
|
14
14
|
class="d-inline-flex align-items-center mb-xsmall text-body-emphasis text-decoration-none"
|
|
15
15
|
href="/"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
and distribution of the software.
|
|
23
23
|
</p>
|
|
24
24
|
</div>
|
|
25
|
-
<div class="col-
|
|
25
|
+
<div class="small:col-4 large:col-2 large:offset-1 mb-medium">
|
|
26
26
|
<p class="h6 mb-xsmall">Docs</p>
|
|
27
27
|
<ul class="nav">
|
|
28
28
|
<li><a href="/tokens">Design Tokens</a></li>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<li><a href="/icons">Icon Generator</a></li>
|
|
33
33
|
</ul>
|
|
34
34
|
</div>
|
|
35
|
-
<div class="col-
|
|
35
|
+
<div class="small:col-4 large:col-2 mb-medium">
|
|
36
36
|
<p class="h6 mb-xsmall">Github</p>
|
|
37
37
|
<ul class="nav">
|
|
38
38
|
<li><a href="https://github.com/chassis-ui/tokens">Chassis Tokens</a></li>
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
<li><a href="https://github.com/chassis-ui/icons">Chassis Icons</a></li>
|
|
43
43
|
</ul>
|
|
44
44
|
</div>
|
|
45
|
-
<div class="col-
|
|
45
|
+
<div class="small:col-4 large:col-2 mb-medium">
|
|
46
46
|
<p class="h6 mb-xsmall">Project</p>
|
|
47
47
|
<ul class="nav">
|
|
48
48
|
<li><a href="/about">About</a></li>
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* JavaScript imports for site functionality.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { getChassisJsProps } from '../../libs/chassis'
|
|
9
8
|
import type { Layout } from '../../libs/layout'
|
|
9
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
10
10
|
|
|
11
11
|
interface Props {
|
|
12
12
|
/** Current layout context */
|
|
@@ -14,14 +14,21 @@ interface Props {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const { layout } = Astro.props
|
|
17
|
-
---
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
function getChassisJsProps() {
|
|
19
|
+
// __CHASSIS_JS_SRC__ is an optional dev-mode override injected via vite.define by the
|
|
20
|
+
// host project's integration. When set, it replaces the default public-dir bundle path.
|
|
21
|
+
const src =
|
|
22
|
+
(import.meta.env.DEV && (globalThis as any).__CHASSIS_JS_SRC__) ||
|
|
23
|
+
(import.meta.env.PROD ? '/static/js/chassis.bundle.min.js' : '/static/js/chassis.bundle.js')
|
|
20
24
|
|
|
21
|
-
<script src
|
|
22
|
-
|
|
23
|
-
{layout === 'docs' && <script src="../../js/sidebar.js" />}
|
|
25
|
+
const cxJsLinkProps: HTMLAttributes<'script'> = { type: 'module', src }
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
return cxJsLinkProps
|
|
28
|
+
}
|
|
29
|
+
---
|
|
26
30
|
|
|
31
|
+
<script src="../../js/search.js"></script>
|
|
32
|
+
<script is:inline {...getChassisJsProps()}></script>
|
|
33
|
+
{layout === 'docs' && <script src="../../js/sidebar.js" />}
|
|
27
34
|
<slot name="scripts" />
|
|
@@ -6,18 +6,24 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { getConfig } from '@libs/config'
|
|
9
|
+
const isProd = import.meta.env.PROD
|
|
9
10
|
const googleId = getConfig().analytics.google_id
|
|
10
11
|
---
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
{
|
|
14
|
+
isProd && (
|
|
15
|
+
<>
|
|
16
|
+
<script is:inline async src={`https://www.googletagmanager.com/gtag/js?id=${googleId}`} />
|
|
17
|
+
<script
|
|
18
|
+
is:inline
|
|
19
|
+
set:html={`
|
|
17
20
|
window.dataLayer = window.dataLayer || [];
|
|
18
21
|
function gtag(){dataLayer.push(arguments);}
|
|
19
22
|
gtag('js', new Date());
|
|
20
23
|
|
|
21
24
|
gtag('config', '${googleId}');
|
|
22
25
|
`}
|
|
23
|
-
/>
|
|
26
|
+
/>
|
|
27
|
+
</>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
@@ -16,8 +16,6 @@ import '@scss/docs.scss'
|
|
|
16
16
|
interface Props {
|
|
17
17
|
/** Page description for meta tags */
|
|
18
18
|
description: string
|
|
19
|
-
/** Text direction (for RTL languages) */
|
|
20
|
-
direction?: 'rtl'
|
|
21
19
|
/** Current layout context */
|
|
22
20
|
layout: Layout
|
|
23
21
|
/** Robots meta tag value */
|
|
@@ -28,7 +26,7 @@ interface Props {
|
|
|
28
26
|
title: string
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
const { description,
|
|
29
|
+
const { description, layout, robots, thumbnail, title } = Astro.props
|
|
32
30
|
|
|
33
31
|
const canonicalUrl = new URL(Astro.url.pathname, Astro.site)
|
|
34
32
|
|
|
@@ -45,19 +43,16 @@ const pageTitle = isHome
|
|
|
45
43
|
|
|
46
44
|
<meta name="author" content={getConfig().authors} />
|
|
47
45
|
<meta name="generator" content={Astro.generator} />
|
|
48
|
-
<meta name="docsearch:language" content="en" />
|
|
49
46
|
|
|
50
47
|
<link rel="canonical" href={canonicalUrl} />
|
|
51
48
|
|
|
52
|
-
<link rel="preconnect" href={`https://${getConfig().algolia.app_id}-dsn.algolia.net`} crossorigin />
|
|
53
|
-
|
|
54
49
|
<title>{pageTitle}</title>
|
|
55
50
|
|
|
56
51
|
{robots && <meta name="robots" content={robots} />}
|
|
57
52
|
|
|
58
53
|
<script src="../../js/color-modes.js"></script>
|
|
59
54
|
|
|
60
|
-
<Stylesheet
|
|
55
|
+
<Stylesheet />
|
|
61
56
|
<slot name="styles" />
|
|
62
57
|
<Favicons />
|
|
63
58
|
<Social description={description} layout={layout} thumbnail={thumbnail} title={title} />
|
|
@@ -5,18 +5,25 @@
|
|
|
5
5
|
* Stylesheet link tags for external CSS resources.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import type { Layout } from '../../libs/layout'
|
|
8
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
10
|
+
function getChassisCssProps() {
|
|
11
|
+
let cxCssLinkHref = '/static/css/chassis'
|
|
12
|
+
|
|
13
|
+
if (import.meta.env.PROD) {
|
|
14
|
+
cxCssLinkHref = `${cxCssLinkHref}.min`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
cxCssLinkHref = `${cxCssLinkHref}.css`
|
|
17
18
|
|
|
18
|
-
const
|
|
19
|
+
const cxCssLinkProps: HTMLAttributes<'link'> = {
|
|
20
|
+
href: cxCssLinkHref,
|
|
21
|
+
rel: 'stylesheet'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return cxCssLinkProps
|
|
25
|
+
}
|
|
19
26
|
---
|
|
20
27
|
|
|
21
|
-
<link {...getChassisCssProps(
|
|
22
|
-
<link rel="stylesheet" href={`/static/icons/chassis-icons.
|
|
28
|
+
<link {...getChassisCssProps()} />
|
|
29
|
+
<link rel="stylesheet" href={`/static/icons/chassis-icons.css`} />
|
|
@@ -5,23 +5,20 @@
|
|
|
5
5
|
* Site header with navigation and page title.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { CollectionEntry } from 'astro:content'
|
|
9
8
|
import type { Layout } from '../../libs/layout'
|
|
10
9
|
import Skippy from './Skippy.astro'
|
|
11
10
|
import Navigation from './Navigation.astro'
|
|
12
11
|
|
|
13
12
|
interface Props {
|
|
14
|
-
/** Version when the feature was added */
|
|
15
|
-
addedIn?: CollectionEntry<'docs'>['data']['added']
|
|
16
13
|
/** Current layout context */
|
|
17
14
|
layout: Layout
|
|
18
15
|
/** Page title */
|
|
19
16
|
title: string
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
const { layout
|
|
19
|
+
const { layout } = Astro.props
|
|
23
20
|
---
|
|
24
21
|
|
|
25
22
|
<Skippy layout={layout} />
|
|
26
23
|
|
|
27
|
-
<Navigation layout={layout}
|
|
24
|
+
<Navigation layout={layout} />
|
|
@@ -9,12 +9,13 @@ import { getConfig } from '@libs/config'
|
|
|
9
9
|
import type { Layout } from '../../libs/layout'
|
|
10
10
|
import NavLink from '../../components/NavLink.astro'
|
|
11
11
|
import ThemeToggler from '../../components/ThemeToggler.astro'
|
|
12
|
+
import SearchTrigger from './SearchTrigger.astro'
|
|
13
|
+
import SearchDialog from './SearchDialog.astro'
|
|
14
|
+
import Icon from '../../components/shortcodes/Icon.astro'
|
|
12
15
|
|
|
13
16
|
interface Props {
|
|
14
17
|
/** Current layout context */
|
|
15
18
|
layout: Layout
|
|
16
|
-
/** Page title for the navbar */
|
|
17
|
-
title: string
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
const { layout } = Astro.props
|
|
@@ -31,111 +32,108 @@ const isActive = (path: string) => {
|
|
|
31
32
|
}
|
|
32
33
|
---
|
|
33
34
|
|
|
34
|
-
<header class="navbar navbar-expand
|
|
35
|
-
<nav class="container
|
|
35
|
+
<header class="navbar translucent large:navbar-expand cxd-navbar sticky-top">
|
|
36
|
+
<nav class="container 2xlarge" aria-label="Site navigation">
|
|
36
37
|
{
|
|
37
38
|
layout === 'docs' && (
|
|
38
39
|
<div class="cxd-navbar-toggle">
|
|
39
40
|
<button
|
|
40
|
-
class="navbar-toggler
|
|
41
|
+
class="button icon-only navbar-toggler"
|
|
41
42
|
type="button"
|
|
42
|
-
data-cx-toggle="
|
|
43
|
+
data-cx-toggle="drawer"
|
|
43
44
|
data-cx-target="#cxdSidebar"
|
|
44
45
|
aria-controls="cxdSidebar"
|
|
45
46
|
aria-label="Toggle docs navigation"
|
|
46
47
|
>
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
</svg>
|
|
50
|
-
<span class="d-none fs-6 pe-2xsmall">Browse</span>
|
|
48
|
+
<Icon name="bars-solid" class="icon-large" />
|
|
49
|
+
<span class="d-none large:d-inline fs-6 pe-2xsmall">Browse</span>
|
|
51
50
|
</button>
|
|
52
51
|
</div>
|
|
53
52
|
)
|
|
54
53
|
}
|
|
55
|
-
{layout !== 'docs' && <div class="d-
|
|
54
|
+
{layout !== 'docs' && <div class="large:d-none" style="width: 4.25rem;" />}
|
|
56
55
|
|
|
57
|
-
<a class="navbar-brand
|
|
56
|
+
<a class="navbar-brand m-0 py-small large:me-medium" href="/" aria-label="Chassis">
|
|
58
57
|
<img src="/static/images/site-logo.svg" alt="Chassis UI" width="123" height="32" />
|
|
59
58
|
</a>
|
|
60
59
|
|
|
61
60
|
<div class="d-flex">
|
|
62
|
-
<div class="cxd-search"
|
|
61
|
+
<div class="cxd-search"><SearchTrigger placeholder="Search docs…" /></div>
|
|
63
62
|
|
|
64
63
|
<button
|
|
65
|
-
class="
|
|
64
|
+
class="button icon-only navbar-toggler"
|
|
66
65
|
type="button"
|
|
67
|
-
data-cx-toggle="
|
|
66
|
+
data-cx-toggle="drawer"
|
|
68
67
|
data-cx-target="#cxdNavbar"
|
|
69
68
|
aria-controls="cxdNavbar"
|
|
70
69
|
aria-label="Toggle navigation"
|
|
71
70
|
>
|
|
72
|
-
<
|
|
71
|
+
<Icon name="ellipsis-h-solid" />
|
|
73
72
|
</button>
|
|
74
73
|
</div>
|
|
75
74
|
|
|
76
|
-
<
|
|
77
|
-
class="
|
|
78
|
-
role="dialog"
|
|
79
|
-
tabindex="-1"
|
|
75
|
+
<dialog
|
|
76
|
+
class="max-large:drawer drawer-end flex-grow-1"
|
|
80
77
|
id="cxdNavbar"
|
|
81
78
|
aria-labelledby="cxdNavbarOffcanvasLabel"
|
|
82
79
|
>
|
|
83
|
-
<div class="
|
|
84
|
-
<
|
|
80
|
+
<div class="drawer-header">
|
|
81
|
+
<h2 class="drawer-title" id="cxdNavbarOffcanvasLabel">Chassis</h2>
|
|
85
82
|
<button
|
|
86
83
|
type="button"
|
|
87
84
|
class="close-button close-button-white"
|
|
88
|
-
data-cx-dismiss="
|
|
85
|
+
data-cx-dismiss="drawer"
|
|
89
86
|
aria-label="Close"
|
|
90
87
|
data-cx-target="#cxdNavbar"></button>
|
|
91
88
|
</div>
|
|
92
89
|
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
<ul class="navbar-nav flex-row flex-wrap cxd-navbar-nav mx-0 mx-
|
|
90
|
+
<hr class="large:d-none m-0" />
|
|
91
|
+
<div class="drawer-body large:p-0">
|
|
92
|
+
<ul class="navbar-nav flex-row flex-wrap cxd-navbar-nav mx-0 large:mx-medium">
|
|
96
93
|
<NavLink active={isActive('/tokens')} href="/tokens">Tokens</NavLink>
|
|
97
94
|
<NavLink active={isActive('/figma')} href="/figma">Figma</NavLink>
|
|
98
95
|
<NavLink active={isActive('/css')} href="/css">CSS</NavLink>
|
|
99
96
|
<NavLink active={isActive('/assets')} href="/assets">Assets</NavLink>
|
|
100
97
|
<NavLink active={isActive('/icons')} href="/icons">Icons</NavLink>
|
|
101
|
-
<li class="nav-item col-12 col-
|
|
102
|
-
<div class="vr d-none d-
|
|
103
|
-
<hr class="d-
|
|
98
|
+
<li class="nav-item col-12 large:col-auto large:d-flex">
|
|
99
|
+
<div class="vr d-none large:d-flex my-auto large:mx-small"></div>
|
|
100
|
+
<hr class="large:d-none" />
|
|
104
101
|
</li>
|
|
105
102
|
<NavLink active={isActive('/examples')} href="/examples">Examples</NavLink>
|
|
106
103
|
</ul>
|
|
107
104
|
|
|
108
|
-
<hr class="d-
|
|
105
|
+
<hr class="large:d-none m-0" />
|
|
109
106
|
|
|
110
|
-
<ul class="navbar-nav flex-row flex-wrap ms-
|
|
107
|
+
<ul class="navbar-nav flex-row flex-wrap large:ms-auto align-items-center">
|
|
111
108
|
<NavLink
|
|
112
|
-
class="
|
|
109
|
+
class="px-0 large:px-small"
|
|
113
110
|
href={getConfig().github_org}
|
|
114
111
|
target="_blank"
|
|
115
112
|
rel="noopener"
|
|
116
113
|
>
|
|
117
|
-
<
|
|
118
|
-
<small class="d-
|
|
114
|
+
<Icon name="github-brand" title="GitHub" />
|
|
115
|
+
<small class="large:d-none ms-xsmall">GitHub</small>
|
|
119
116
|
</NavLink>
|
|
120
117
|
<NavLink
|
|
121
|
-
class="
|
|
118
|
+
class="px-0 large:px-small"
|
|
122
119
|
href={`https://x.com/${getConfig().x}`}
|
|
123
120
|
target="_blank"
|
|
124
121
|
rel="noopener"
|
|
125
122
|
>
|
|
126
|
-
<
|
|
127
|
-
<small class="d-
|
|
123
|
+
<Icon name="x-twitter-brand" title="X" />
|
|
124
|
+
<small class="large:d-none ms-xsmall">X</small>
|
|
128
125
|
</NavLink>
|
|
129
|
-
<li class="nav-item col-12 col-
|
|
130
|
-
<div class="vr d-none d-
|
|
131
|
-
<hr class="d-
|
|
126
|
+
<li class="nav-item col-12 large:col-auto">
|
|
127
|
+
<div class="vr d-none large:d-flex h-100 large:mx-2xsmall"></div>
|
|
128
|
+
<hr class="large:d-none" />
|
|
132
129
|
</li>
|
|
133
130
|
|
|
134
|
-
<li class="nav-item
|
|
131
|
+
<li class="nav-item">
|
|
135
132
|
<ThemeToggler layout={layout} />
|
|
136
133
|
</li>
|
|
137
134
|
</ul>
|
|
138
135
|
</div>
|
|
139
|
-
</
|
|
136
|
+
</dialog>
|
|
140
137
|
</nav>
|
|
141
138
|
</header>
|
|
139
|
+
<SearchDialog placeholder="Search docs…" />
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Search Dialog
|
|
4
|
+
*
|
|
5
|
+
* Modal dialog containing the Pagefind search input and results. Opened by
|
|
6
|
+
* `SearchTrigger` or the ⌘K / Ctrl+K / "/" keyboard shortcuts defined in
|
|
7
|
+
* `src/js/search.js`. Uses native `<dialog>` with `showModal()`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import Icon from '../../components/shortcodes/Icon.astro'
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
/** HTML `id` of the dialog element. Must match the `target` in `SearchTrigger`. */
|
|
14
|
+
id?: string
|
|
15
|
+
/** Placeholder text for the search input and the visually-hidden label. */
|
|
16
|
+
placeholder?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { id = 'cxdSearchDialog', placeholder = 'Search docs…' } = Astro.props
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<dialog
|
|
23
|
+
class="modal dialog large cxd-search-dialog scrollable"
|
|
24
|
+
id={id}
|
|
25
|
+
aria-labelledby={`${id}-label`}
|
|
26
|
+
>
|
|
27
|
+
<search class="modal-header cxd-search-form">
|
|
28
|
+
<label class="visually-hidden" id={`${id}-label`} for={`${id}-input`}>
|
|
29
|
+
{placeholder}
|
|
30
|
+
</label>
|
|
31
|
+
<cxd-search-input>
|
|
32
|
+
<div class="form-input">
|
|
33
|
+
<div class="input-help">
|
|
34
|
+
<Icon name="search-solid" />
|
|
35
|
+
</div>
|
|
36
|
+
<input
|
|
37
|
+
id={`${id}-input`}
|
|
38
|
+
type="search"
|
|
39
|
+
class="ghost-input cxd-search-input"
|
|
40
|
+
placeholder={placeholder}
|
|
41
|
+
autocomplete="off"
|
|
42
|
+
spellcheck="false"
|
|
43
|
+
enterkeyhint="search"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
</cxd-search-input>
|
|
47
|
+
<button
|
|
48
|
+
type="button"
|
|
49
|
+
class="close-button"
|
|
50
|
+
aria-label="Close"
|
|
51
|
+
data-cx-dismiss="dialog"
|
|
52
|
+
data-cx-target={`#${id}`}>×</button
|
|
53
|
+
>
|
|
54
|
+
</search>
|
|
55
|
+
|
|
56
|
+
<div class="modal-body cxd-search-body">
|
|
57
|
+
<cxd-search-results></cxd-search-results>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="modal-footer cxd-search-footer">
|
|
60
|
+
<ul class="list horizontal cxd-search-shortcuts-list">
|
|
61
|
+
<li class="list-item">
|
|
62
|
+
<kbd class="cxd-search-shortcut-key font-2xsmall">⮐</kbd>
|
|
63
|
+
<span class="cxd-search-shortcut-label">to select</span>
|
|
64
|
+
</li><li class="list-item">
|
|
65
|
+
<kbd class="cxd-search-shortcut-key font-small">↑</kbd>
|
|
66
|
+
<kbd class="cxd-search-shortcut-key font-small">↓</kbd>
|
|
67
|
+
<span class="cxd-search-shortcut-label">to navigate</span>
|
|
68
|
+
</li><li class="list-item">
|
|
69
|
+
<kbd class="cxd-search-shortcut-key font-xsmall">ESC</kbd>
|
|
70
|
+
<span class="cxd-search-shortcut-label">to close</span>
|
|
71
|
+
</li>
|
|
72
|
+
</ul>
|
|
73
|
+
</div>
|
|
74
|
+
</dialog>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Search Trigger
|
|
4
|
+
*
|
|
5
|
+
* Button that opens the `SearchDialog`. Displays a platform-aware keyboard
|
|
6
|
+
* shortcut hint (⌘K on Mac, Ctrl K elsewhere) that `search.js` fills in after
|
|
7
|
+
* detecting the platform — rendered hidden until then so non-JS visitors never
|
|
8
|
+
* see a misleading hint.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import Icon from '../../components/shortcodes/Icon.astro'
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
/** Additional CSS classes to apply to the trigger button. */
|
|
15
|
+
class?: string
|
|
16
|
+
/** Accessible label and visible placeholder text inside the trigger. */
|
|
17
|
+
placeholder?: string
|
|
18
|
+
/** CSS selector for the dialog to open. Must match `SearchDialog`'s `id`. */
|
|
19
|
+
target?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { class: className, placeholder = 'Search docs…', target = '#cxdSearchDialog' } = Astro.props
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
class:list={['cxd-search-trigger', className]}
|
|
28
|
+
data-cx-toggle="dialog"
|
|
29
|
+
data-cx-target={target}
|
|
30
|
+
aria-haspopup="dialog"
|
|
31
|
+
aria-label={placeholder}
|
|
32
|
+
>
|
|
33
|
+
<Icon name="search-solid" size={16} />
|
|
34
|
+
<span class="cxd-search-trigger-label">{placeholder}</span>
|
|
35
|
+
{
|
|
36
|
+
/* Shortcut hint is empty + hidden until search.js detects the platform and
|
|
37
|
+
fills in either ⌘K (Mac) or Ctrl K (other). Without JS the shortcut
|
|
38
|
+
itself doesn't work, so showing nothing is more honest than guessing. */
|
|
39
|
+
}
|
|
40
|
+
<span class="cxd-search-trigger-shortcut" hidden></span>
|
|
41
|
+
</button>
|
|
@@ -16,7 +16,7 @@ const { layout } = Astro.props
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
<div class="skippy visually-hidden-focusable overflow-hidden">
|
|
19
|
-
<div class="container
|
|
19
|
+
<div class="container xlarge">
|
|
20
20
|
<a class="d-inline-flex p-xsmall m-xsmall" href="#content">Skip to main content</a>
|
|
21
21
|
{
|
|
22
22
|
layout === 'docs' && (
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { codeToHtml, type ShikiTransformer } from 'shiki'
|
|
2
|
+
import { DOCS_SHIKI_THEMES } from './markdown'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shiki transformer that renames the `shiki` CSS class on `<pre>` elements to
|
|
6
|
+
* `astro-code` so that Astro's built-in syntax highlighting styles apply.
|
|
7
|
+
*/
|
|
8
|
+
const classTransformer: ShikiTransformer = {
|
|
9
|
+
name: 'class-name-transformer',
|
|
10
|
+
pre(node) {
|
|
11
|
+
if (typeof node.properties.class === 'string') {
|
|
12
|
+
node.properties.class = node.properties.class.replace(/shiki/g, 'astro-code')
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Shiki transformer that wraps non-comment lines in a `<span class="line">`
|
|
19
|
+
* element. Applied only to shell languages (bash, sh, powershell) where line
|
|
20
|
+
* wrapping is needed for the copy-button to correctly extract individual commands.
|
|
21
|
+
*/
|
|
22
|
+
const lineWrapperTransformer: ShikiTransformer = {
|
|
23
|
+
name: 'line-wrapper',
|
|
24
|
+
line(node) {
|
|
25
|
+
const hasOnlyComments = node.children.every(
|
|
26
|
+
(child) =>
|
|
27
|
+
child.type === 'element' &&
|
|
28
|
+
child.properties?.class &&
|
|
29
|
+
Array.isArray(child.properties.class) &&
|
|
30
|
+
child.properties.class.some((cls) => typeof cls === 'string' && cls.includes('comment'))
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
if (!hasOnlyComments) {
|
|
34
|
+
node.properties = node.properties || {}
|
|
35
|
+
const existing = node.properties.class ?? ''
|
|
36
|
+
const classes = typeof existing === 'string' ? existing.split(' ') : []
|
|
37
|
+
if (!classes.includes('line')) classes.push('line')
|
|
38
|
+
node.properties.class = classes.join(' ').trim()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Replaces any remaining `shiki` / `shiki-themes` class strings in the
|
|
45
|
+
* serialized HTML that the transformer may have missed (e.g. in inline styles
|
|
46
|
+
* converted by `transformerStyleToClass`).
|
|
47
|
+
*/
|
|
48
|
+
function replaceShikiClasses(html: string): string {
|
|
49
|
+
return html
|
|
50
|
+
.replace(/class=(["'])shiki(\s+)/g, 'class=$1astro-code$2')
|
|
51
|
+
.replace(/class=(["'])shiki(["'])/g, 'class=$1astro-code$2')
|
|
52
|
+
.replace(/shiki-themes/g, 'astro-code-themes')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Highlights a code string using Shiki with the GitHub light/dark dual theme.
|
|
57
|
+
*
|
|
58
|
+
* Inline styles are converted to CSS classes via `transformerStyleToClass` so
|
|
59
|
+
* that a single `<style>` block can be emitted per page rather than repeating
|
|
60
|
+
* styles on every token. The returned `css` string must be injected into the
|
|
61
|
+
* page (e.g. inside a `<style>` tag) for the highlighted output to render correctly.
|
|
62
|
+
*
|
|
63
|
+
* For shell languages (`bash`, `sh`, `powershell`) each non-comment line is
|
|
64
|
+
* additionally wrapped in `<span class="line">` to support per-line copy.
|
|
65
|
+
*
|
|
66
|
+
* @param code - Source code to highlight.
|
|
67
|
+
* @param lang - Shiki language identifier (e.g. `"html"`, `"ts"`, `"bash"`).
|
|
68
|
+
* @param extraTransformers - Additional Shiki transformers to apply before the built-ins.
|
|
69
|
+
* @returns An object with `html` (the highlighted markup) and `css` (the extracted styles).
|
|
70
|
+
*/
|
|
71
|
+
export async function highlightCode(
|
|
72
|
+
code: string,
|
|
73
|
+
lang: string,
|
|
74
|
+
extraTransformers: ShikiTransformer[] = []
|
|
75
|
+
): Promise<{ html: string }> {
|
|
76
|
+
const shouldWrapLines = ['bash', 'sh', 'powershell'].includes(lang)
|
|
77
|
+
|
|
78
|
+
const transformers: ShikiTransformer[] = [...extraTransformers, classTransformer]
|
|
79
|
+
if (shouldWrapLines) {
|
|
80
|
+
transformers.push(lineWrapperTransformer)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const highlighted = await codeToHtml(code, {
|
|
84
|
+
lang,
|
|
85
|
+
themes: DOCS_SHIKI_THEMES,
|
|
86
|
+
defaultColor: false,
|
|
87
|
+
transformers
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
return { html: replaceShikiClasses(highlighted) }
|
|
91
|
+
}
|