@chassis-ui/docs 0.5.1 → 0.6.0-next.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 +256 -0
- package/README.md +227 -71
- package/UPGRADING.md +243 -0
- package/index.ts +7 -1
- package/package.json +31 -8
- package/src/components/DocsSidebar.astro +9 -9
- package/src/components/shortcodes/Callout.astro +4 -4
- package/src/components/shortcodes/Code.astro +3 -3
- package/src/components/shortcodes/JsDocs.astro +6 -7
- package/src/components/shortcodes/ScssDocs.astro +7 -9
- package/src/components/shortcodes/ScssDocsSimple.astro +6 -7
- package/src/integration.ts +271 -0
- package/src/js/clipboard.ts +65 -0
- package/src/layouts/BaseLayout.astro +7 -9
- package/src/layouts/DocsLayout.astro +11 -13
- package/src/layouts/RedirectLayout.astro +1 -1
- package/src/layouts/head/Analytics.astro +6 -4
- package/src/layouts/head/Head.astro +2 -2
- package/src/layouts/head/Social.astro +5 -6
- package/src/layouts/header/Navigation.astro +28 -19
- package/src/libs/config.ts +138 -0
- package/src/libs/docs-path.ts +12 -0
- package/src/libs/highlight.ts +4 -44
- package/src/libs/paths.ts +160 -0
- package/src/libs/remark.ts +184 -0
- package/src/libs/schema.ts +211 -0
- package/src/libs/shortcodes.ts +86 -71
- package/src/libs/snippet.ts +21 -0
- package/src/libs/source.ts +17 -40
- package/src/libs/toc.ts +3 -1
- package/src/scss/_vars.scss +4 -1
- package/src/site.ts +150 -0
- package/virtual.d.ts +25 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import type { AstroIntegration, AstroUserConfig, ViteUserConfig } from 'astro'
|
|
5
|
+
import type { z } from 'astro/zod'
|
|
6
|
+
import { loadConfig, loadSidebar } from './libs/config'
|
|
7
|
+
import { joinDocsPath } from './libs/docs-path'
|
|
8
|
+
import { getDocsMarkdownConfig, type DocsMarkdownConfigOptions } from './libs/markdown'
|
|
9
|
+
import { getInstalledPackageFsPath, getPackageRoot } from './libs/paths'
|
|
10
|
+
import { remarkCxConfig, remarkCxDocsref } from './libs/remark'
|
|
11
|
+
import { configSchema, type ChassisConfig, type Sidebar } from './libs/schema'
|
|
12
|
+
import { chassisAutoImport, type ChassisAutoImportOptions } from './libs/shortcodes'
|
|
13
|
+
import { getSiteUrl } from './libs/site'
|
|
14
|
+
|
|
15
|
+
export interface ChassisDocsOptions<TSchema extends z.ZodType = typeof configSchema> {
|
|
16
|
+
/**
|
|
17
|
+
* The config, for a site that has loaded it with `loadConfig()` to use it in
|
|
18
|
+
* `astro.config.ts`. `configFile` is then only watched, and `configSchema` is not used.
|
|
19
|
+
*/
|
|
20
|
+
config?: ChassisConfig
|
|
21
|
+
/**
|
|
22
|
+
* Path of the config file, from the site's root.
|
|
23
|
+
* @default 'config.yml'
|
|
24
|
+
*/
|
|
25
|
+
configFile?: string
|
|
26
|
+
/**
|
|
27
|
+
* Schema of the config file: `configSchema` from `@chassis-ui/docs/schema`, or an
|
|
28
|
+
* extension of it when the site has keys of its own.
|
|
29
|
+
*/
|
|
30
|
+
configSchema?: TSchema
|
|
31
|
+
/**
|
|
32
|
+
* Path of the sidebar data file, from the site's root. `false` for a site that does not
|
|
33
|
+
* render `<DocsSidebar>`.
|
|
34
|
+
* @default 'data/sidebar.yml' when the file exists
|
|
35
|
+
*/
|
|
36
|
+
sidebarFile?: string | false
|
|
37
|
+
/**
|
|
38
|
+
* Stylesheets that every page loads, from the site's root. A site's stylesheet is expected
|
|
39
|
+
* to `@use "@chassis-ui/docs/scss/main"`.
|
|
40
|
+
* @default ['src/scss/docs.scss'] when the file exists, the package's styles otherwise
|
|
41
|
+
*/
|
|
42
|
+
styles?: string[]
|
|
43
|
+
/** Which shortcodes are imported into every MDX file. */
|
|
44
|
+
shortcodes?: Pick<ChassisAutoImportOptions, 'dir' | 'include' | 'exclude'>
|
|
45
|
+
/** Plugins of the site. They run after the plugins of the package. */
|
|
46
|
+
markdown?: Pick<DocsMarkdownConfigOptions, 'rehypePlugins' | 'remarkPlugins' | 'remarkRehype'>
|
|
47
|
+
/**
|
|
48
|
+
* What happens when a `[[docsref:]]` link points to a page that was not built.
|
|
49
|
+
* @default 'error'
|
|
50
|
+
*/
|
|
51
|
+
brokenDocsrefs?: 'error' | 'warn' | 'ignore'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type VitePlugin = Extract<NonNullable<ViteUserConfig['plugins']>[number], { name: string }>
|
|
55
|
+
|
|
56
|
+
const virtualPrefix = 'virtual:chassis-docs/'
|
|
57
|
+
const resolvedPrefix = '\0' + virtualPrefix
|
|
58
|
+
|
|
59
|
+
function virtualModules(modules: Record<string, string>): VitePlugin {
|
|
60
|
+
return {
|
|
61
|
+
name: 'chassis-docs:virtual',
|
|
62
|
+
resolveId(id) {
|
|
63
|
+
if (id.startsWith(virtualPrefix) && id.slice(virtualPrefix.length) in modules) {
|
|
64
|
+
return '\0' + id
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
load(id) {
|
|
68
|
+
if (id.startsWith(resolvedPrefix)) {
|
|
69
|
+
return modules[id.slice(resolvedPrefix.length)]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// The declarations of `virtual.d.ts`, for a site.
|
|
76
|
+
const virtualTypes = `declare module 'virtual:chassis-docs/config' {
|
|
77
|
+
const config: import('@chassis-ui/docs/schema').ChassisConfig
|
|
78
|
+
export default config
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
declare module 'virtual:chassis-docs/sidebar' {
|
|
82
|
+
const sidebar: import('@chassis-ui/docs/schema').Sidebar
|
|
83
|
+
export default sidebar
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare module 'virtual:chassis-docs/paths' {
|
|
87
|
+
export const root: string
|
|
88
|
+
export const publicDir: string
|
|
89
|
+
export const sourceDir: string
|
|
90
|
+
export const packageRoot: string
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
declare module 'virtual:chassis-docs/styles' {}
|
|
94
|
+
`
|
|
95
|
+
|
|
96
|
+
// The folder of `@chassis-ui/css` with its default `_chassis-tokens.scss`, when the site has
|
|
97
|
+
// the package installed.
|
|
98
|
+
function getDefaultTokensLoadPath(root: string): string | undefined {
|
|
99
|
+
try {
|
|
100
|
+
return path.join(getInstalledPackageFsPath('@chassis-ui/css', root), 'scss/vendor')
|
|
101
|
+
} catch {
|
|
102
|
+
return undefined
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Append `index.html` when the path names a page, and drop the hash.
|
|
107
|
+
function toBuiltFilePath(docsPath: string): string {
|
|
108
|
+
const withoutHash = docsPath.split('#')[0]
|
|
109
|
+
|
|
110
|
+
return withoutHash.includes('.') ? withoutHash : path.join(withoutHash, 'index.html')
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The Astro integration of `@chassis-ui/docs`. A site adds it in `astro.config.ts`.
|
|
115
|
+
*
|
|
116
|
+
* It reads `config.yml` and `data/sidebar.yml`, gives them to the layouts and components of
|
|
117
|
+
* the package, sets `site` and `markdown` of the Astro config, and imports the shortcodes
|
|
118
|
+
* into every MDX file.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* import { defineConfig } from 'astro/config'
|
|
123
|
+
* import { chassisDocs } from '@chassis-ui/docs/integration'
|
|
124
|
+
*
|
|
125
|
+
* export default defineConfig({
|
|
126
|
+
* integrations: [chassisDocs()]
|
|
127
|
+
* })
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export function chassisDocs<TSchema extends z.ZodType = typeof configSchema>(
|
|
131
|
+
options: ChassisDocsOptions<TSchema> = {}
|
|
132
|
+
): AstroIntegration {
|
|
133
|
+
const { brokenDocsrefs = 'error' } = options
|
|
134
|
+
|
|
135
|
+
// Docs paths that `[[docsref:]]` links name, collected while the pages are rendered.
|
|
136
|
+
const linkedDocsPaths = new Set<string>()
|
|
137
|
+
let config: ChassisConfig
|
|
138
|
+
let typeDefinitions = ''
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
name: '@chassis-ui/docs',
|
|
142
|
+
hooks: {
|
|
143
|
+
'astro:config:setup': ({ config: astroConfig, command, updateConfig, addWatchFile }) => {
|
|
144
|
+
const root = path.resolve(fileURLToPath(astroConfig.root))
|
|
145
|
+
const configFile = path.resolve(root, options.configFile ?? 'config.yml')
|
|
146
|
+
|
|
147
|
+
config =
|
|
148
|
+
options.config ??
|
|
149
|
+
loadConfig({
|
|
150
|
+
file: configFile,
|
|
151
|
+
schema: (options.configSchema ?? configSchema) as z.ZodType<ChassisConfig>
|
|
152
|
+
})
|
|
153
|
+
addWatchFile(configFile)
|
|
154
|
+
|
|
155
|
+
let sidebar: Sidebar = []
|
|
156
|
+
|
|
157
|
+
if (options.sidebarFile !== false) {
|
|
158
|
+
const sidebarFile = path.resolve(root, options.sidebarFile ?? 'data/sidebar.yml')
|
|
159
|
+
|
|
160
|
+
// The default file is optional. A file that the site names must exist.
|
|
161
|
+
if (options.sidebarFile !== undefined || fs.existsSync(sidebarFile)) {
|
|
162
|
+
sidebar = loadSidebar({ file: sidebarFile })
|
|
163
|
+
addWatchFile(sidebarFile)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const defaultStyles = path.join(root, 'src/scss/docs.scss')
|
|
168
|
+
const styles = options.styles
|
|
169
|
+
? options.styles.map((file) => path.resolve(root, file))
|
|
170
|
+
: fs.existsSync(defaultStyles)
|
|
171
|
+
? [defaultStyles]
|
|
172
|
+
: ['@chassis-ui/docs/scss/main.scss']
|
|
173
|
+
|
|
174
|
+
const autoImport = chassisAutoImport({ root, ...options.shortcodes })
|
|
175
|
+
typeDefinitions = autoImport.typeDefinitions
|
|
176
|
+
|
|
177
|
+
const paths = {
|
|
178
|
+
root,
|
|
179
|
+
publicDir: path.resolve(fileURLToPath(astroConfig.publicDir)),
|
|
180
|
+
sourceDir: path.resolve(root, config.sourceDir),
|
|
181
|
+
packageRoot: getPackageRoot()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const tokensLoadPath = getDefaultTokensLoadPath(root)
|
|
185
|
+
|
|
186
|
+
const update: AstroUserConfig = {
|
|
187
|
+
// A `site` that the Astro config sets itself is kept.
|
|
188
|
+
...(astroConfig.site ? {} : { site: getSiteUrl(config) }),
|
|
189
|
+
markdown: getDocsMarkdownConfig({
|
|
190
|
+
anchors: config.anchors,
|
|
191
|
+
remarkPlugins: [
|
|
192
|
+
autoImport.plugin(),
|
|
193
|
+
[remarkCxConfig, { config }],
|
|
194
|
+
[
|
|
195
|
+
remarkCxDocsref,
|
|
196
|
+
{
|
|
197
|
+
docsPath: config.docsPath,
|
|
198
|
+
onDocsPath:
|
|
199
|
+
command === 'build'
|
|
200
|
+
? (docsPath: string) => linkedDocsPaths.add(docsPath)
|
|
201
|
+
: undefined
|
|
202
|
+
}
|
|
203
|
+
],
|
|
204
|
+
...(options.markdown?.remarkPlugins ?? [])
|
|
205
|
+
],
|
|
206
|
+
rehypePlugins: options.markdown?.rehypePlugins,
|
|
207
|
+
remarkRehype: options.markdown?.remarkRehype
|
|
208
|
+
}),
|
|
209
|
+
vite: {
|
|
210
|
+
// Scripts of the package and of the site both import `@chassis-ui/css`, and two
|
|
211
|
+
// copies of it register every listener twice. In the dev server, a script of the
|
|
212
|
+
// package would be pre-bundled with a copy of its own, and a script of the site
|
|
213
|
+
// would get a pre-bundled copy while the package gets the source. Both packages
|
|
214
|
+
// are served from source, and every import resolves to the site's copy.
|
|
215
|
+
optimizeDeps: {
|
|
216
|
+
exclude: ['@chassis-ui/docs', '@chassis-ui/css'],
|
|
217
|
+
// The one CommonJS dependency of the package's scripts. It has no default export
|
|
218
|
+
// unless it is pre-bundled.
|
|
219
|
+
include: ['@chassis-ui/docs > clipboard']
|
|
220
|
+
},
|
|
221
|
+
resolve: {
|
|
222
|
+
dedupe: ['@chassis-ui/css']
|
|
223
|
+
},
|
|
224
|
+
// The styles of `@chassis-ui/css` load the design tokens as `chassis-tokens`. This
|
|
225
|
+
// adds its default as the last load path, after the site's own load paths, so a
|
|
226
|
+
// site with a `_chassis-tokens.scss` of its own puts that folder in its config.
|
|
227
|
+
...(tokensLoadPath
|
|
228
|
+
? { css: { preprocessorOptions: { scss: { loadPaths: [tokensLoadPath] } } } }
|
|
229
|
+
: {}),
|
|
230
|
+
plugins: [
|
|
231
|
+
virtualModules({
|
|
232
|
+
config: `export default ${JSON.stringify(config)}`,
|
|
233
|
+
sidebar: `export default ${JSON.stringify(sidebar)}`,
|
|
234
|
+
paths: Object.entries(paths)
|
|
235
|
+
.map(([name, value]) => `export const ${name} = ${JSON.stringify(value)}`)
|
|
236
|
+
.join('\n'),
|
|
237
|
+
styles: styles.map((file) => `import ${JSON.stringify(file)}`).join('\n')
|
|
238
|
+
})
|
|
239
|
+
]
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// The user config is wider than what `updateConfig()` declares for `markdown`.
|
|
244
|
+
updateConfig(update as Parameters<typeof updateConfig>[0])
|
|
245
|
+
},
|
|
246
|
+
'astro:config:done': ({ injectTypes }) => {
|
|
247
|
+
injectTypes({ filename: 'virtual.d.ts', content: virtualTypes })
|
|
248
|
+
injectTypes({ filename: 'auto-import.d.ts', content: typeDefinitions })
|
|
249
|
+
},
|
|
250
|
+
'astro:build:done': ({ dir, logger }) => {
|
|
251
|
+
if (brokenDocsrefs === 'ignore') return
|
|
252
|
+
|
|
253
|
+
const broken = [...linkedDocsPaths].filter((docsPath) => {
|
|
254
|
+
const builtPath = toBuiltFilePath(joinDocsPath(config.docsPath, docsPath))
|
|
255
|
+
|
|
256
|
+
return !fs.existsSync(path.join(fileURLToPath(dir), builtPath))
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
if (broken.length === 0) return
|
|
260
|
+
|
|
261
|
+
const message = `These [[docsref:]] links point to a page or file that was not built:\n${broken.map((docsPath) => ` - ${docsPath}`).join('\n')}`
|
|
262
|
+
|
|
263
|
+
if (brokenDocsrefs === 'error') {
|
|
264
|
+
throw new Error(message)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
logger.warn(message)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import ClipboardJS from 'clipboard'
|
|
2
|
+
import { Tooltip } from '@chassis-ui/css'
|
|
3
|
+
|
|
4
|
+
const btnTitle = 'Copy'
|
|
5
|
+
|
|
6
|
+
export function initCopyButtons(
|
|
7
|
+
selector: string,
|
|
8
|
+
textFn: (_element: Element) => string
|
|
9
|
+
): ClipboardJS {
|
|
10
|
+
document.querySelectorAll(selector).forEach((btn) => {
|
|
11
|
+
Tooltip.getOrCreateInstance(btn, { title: btnTitle })
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const clipboard = new ClipboardJS(selector, { text: textFn })
|
|
15
|
+
|
|
16
|
+
clipboard.on('success', (event) => {
|
|
17
|
+
const useEl = event.trigger.querySelector('.icon use')
|
|
18
|
+
const tooltipBtn = Tooltip.getInstance(event.trigger)
|
|
19
|
+
const originalHref = useEl?.getAttribute('href')
|
|
20
|
+
|
|
21
|
+
if (originalHref === '#check-solid') {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
tooltipBtn?.setContent({ '.tooltip-inner': 'Copied!' })
|
|
26
|
+
|
|
27
|
+
event.trigger.addEventListener(
|
|
28
|
+
'hidden.cx.tooltip',
|
|
29
|
+
() => {
|
|
30
|
+
tooltipBtn?.setContent({ '.tooltip-inner': btnTitle })
|
|
31
|
+
},
|
|
32
|
+
{ once: true }
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
event.clearSelection()
|
|
36
|
+
|
|
37
|
+
if (useEl) {
|
|
38
|
+
useEl.setAttribute('href', '#check-solid')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
if (useEl && originalHref) {
|
|
43
|
+
useEl.setAttribute('href', originalHref)
|
|
44
|
+
}
|
|
45
|
+
}, 2000)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
clipboard.on('error', (event) => {
|
|
49
|
+
const modifierKey = /mac/i.test(navigator.userAgent) ? '\u2318' : 'Ctrl-'
|
|
50
|
+
const fallbackMsg = `Press ${modifierKey}C to copy`
|
|
51
|
+
const tooltipBtn = Tooltip.getInstance(event.trigger)
|
|
52
|
+
|
|
53
|
+
tooltipBtn?.setContent({ '.tooltip-inner': fallbackMsg })
|
|
54
|
+
|
|
55
|
+
event.trigger.addEventListener(
|
|
56
|
+
'hidden.cx.tooltip',
|
|
57
|
+
() => {
|
|
58
|
+
tooltipBtn?.setContent({ '.tooltip-inner': btnTitle })
|
|
59
|
+
},
|
|
60
|
+
{ once: true }
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return clipboard
|
|
65
|
+
}
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* Main layout wrapper for all pages with configurable HTML attributes and layout modes.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { CollectionEntry } from 'astro:content'
|
|
9
|
-
import { getConfig } from '@libs/config'
|
|
10
8
|
import type { Layout, LayoutOverridesHTMLAttributes } from '../libs/layout'
|
|
9
|
+
import type { DocsFrontmatter } from '../libs/schema'
|
|
10
|
+
import { getConfig } from '../site'
|
|
11
11
|
import Head from './head/Head.astro'
|
|
12
12
|
import Header from './header/Header.astro'
|
|
13
13
|
import Scripts from './footer/Scripts.astro'
|
|
@@ -42,11 +42,11 @@ type Props = {
|
|
|
42
42
|
// The following props are automatically set by Astro (if defined) based on the markdown frontmatter when rendering a
|
|
43
43
|
// markdown page. They can be accessed through the `Astro.props.frontmatter` object but note that they won't be set when
|
|
44
44
|
// not rendering a markdown page.
|
|
45
|
-
type MarkdownProps = { frontmatter?:
|
|
45
|
+
type MarkdownProps = { frontmatter?: DocsFrontmatter }
|
|
46
46
|
|
|
47
|
-
// This type is used to define the shape of the `
|
|
47
|
+
// This type is used to define the shape of the `extraJs` frontmatter property which allows adding extra JavaScript
|
|
48
48
|
// files to a page by passing an array of objects containing the `src` and `async` properties.
|
|
49
|
-
type ExtraJS = NonNullable<
|
|
49
|
+
type ExtraJS = NonNullable<DocsFrontmatter['extraJs']>[number]
|
|
50
50
|
|
|
51
51
|
const { frontmatter, layout, overrides, robots } = Astro.props
|
|
52
52
|
|
|
@@ -96,10 +96,8 @@ const mainProps = overrides?.main ?? {}
|
|
|
96
96
|
</Scripts>
|
|
97
97
|
|
|
98
98
|
{
|
|
99
|
-
frontmatter?.
|
|
100
|
-
frontmatter.
|
|
101
|
-
<script is:inline async={js.async} src={js.src} />
|
|
102
|
-
))
|
|
99
|
+
frontmatter?.extraJs &&
|
|
100
|
+
frontmatter.extraJs.map((js: ExtraJS) => <script is:inline async={js.async} src={js.src} />)
|
|
103
101
|
}
|
|
104
102
|
|
|
105
103
|
{
|
|
@@ -6,13 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { MarkdownHeading } from 'astro'
|
|
9
|
-
import type { CollectionEntry } from 'astro:content'
|
|
10
|
-
import { getConfig } from '@libs/config'
|
|
11
|
-
import { docsPages } from '@libs/content'
|
|
12
|
-
import { getChassisDocsPath } from '@libs/path'
|
|
13
9
|
import type { LayoutOverridesHTMLAttributes } from '../libs/layout'
|
|
14
|
-
import {
|
|
10
|
+
import type { DocsFrontmatter } from '../libs/schema'
|
|
15
11
|
import { getSlug, processMarkdownToHtml } from '../libs/utils'
|
|
12
|
+
import { getConfig, getDocsPages, getDocsPath, getSiteFileUrl } from '../site'
|
|
16
13
|
import BaseLayout from './BaseLayout.astro'
|
|
17
14
|
import DocsSidebar from '../components/DocsSidebar.astro'
|
|
18
15
|
import TableOfContents from '../components/TableOfContents.astro'
|
|
@@ -20,11 +17,11 @@ import Icon from '../components/shortcodes/Icon.astro'
|
|
|
20
17
|
|
|
21
18
|
interface Props {
|
|
22
19
|
/** Frontmatter data from the docs collection */
|
|
23
|
-
frontmatter:
|
|
20
|
+
frontmatter: DocsFrontmatter
|
|
24
21
|
/** Markdown headings for table of contents */
|
|
25
22
|
headings?: MarkdownHeading[]
|
|
26
23
|
/** Document ID from the docs collection */
|
|
27
|
-
id:
|
|
24
|
+
id: string
|
|
28
25
|
/**
|
|
29
26
|
* Path of the page's source file from the site's root. Looked up from the docs collection
|
|
30
27
|
* by `id` when omitted.
|
|
@@ -36,7 +33,8 @@ const { frontmatter, headings, id } = Astro.props
|
|
|
36
33
|
|
|
37
34
|
// "View on GitHub" links to the page's own source file. The old link, which assumed the
|
|
38
35
|
// file sat at `<id>.mdx` in the repository root, is kept only when no file path is known.
|
|
39
|
-
const filePath =
|
|
36
|
+
const filePath =
|
|
37
|
+
Astro.props.filePath ?? (await getDocsPages()).find((page) => page.id === id)?.filePath
|
|
40
38
|
const githubUrl = filePath ? getSiteFileUrl(filePath) : `${getConfig().repo}/blob/${id}.mdx`
|
|
41
39
|
|
|
42
40
|
type DocSection = NonNullable<typeof frontmatter.sections>[number]
|
|
@@ -86,11 +84,11 @@ if (frontmatter.toc) {
|
|
|
86
84
|
<div class="md:d-flex md:flex-row-reverse justify-content-between align-items-start">
|
|
87
85
|
<div class="mb-md md:mb-0 d-flex text-nowrap">
|
|
88
86
|
{
|
|
89
|
-
// This is needed because we want to show the badge if
|
|
87
|
+
// This is needed because we want to show the badge if showBadge isn't present or is set to false
|
|
90
88
|
frontmatter.added &&
|
|
91
|
-
((frontmatter.added.
|
|
92
|
-
frontmatter.added.
|
|
93
|
-
frontmatter.added.
|
|
89
|
+
((frontmatter.added.showBadge !== undefined &&
|
|
90
|
+
frontmatter.added.showBadge === true) ||
|
|
91
|
+
frontmatter.added.showBadge === undefined) && (
|
|
94
92
|
<span class="badge success smooth rounded-md me-xs">
|
|
95
93
|
Added in v{frontmatter.added.version}
|
|
96
94
|
</span>
|
|
@@ -153,7 +151,7 @@ if (frontmatter.toc) {
|
|
|
153
151
|
<div class="md:col-6">
|
|
154
152
|
<a
|
|
155
153
|
class="d-block text-decoration-none"
|
|
156
|
-
href={
|
|
154
|
+
href={getDocsPath(
|
|
157
155
|
`${parentDirectory ? parentDirectory + '/' : ''}${section.slug ? section.slug : getSlug(section.title)}/`
|
|
158
156
|
)}
|
|
159
157
|
>
|
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Analytics
|
|
4
4
|
*
|
|
5
|
-
* Analytics script tags
|
|
5
|
+
* Google Analytics script tags. Rendered in production builds, when `analytics.googleId` is
|
|
6
|
+
* set in `config.yml`.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
|
-
import { getConfig } from '
|
|
9
|
+
import { getConfig } from '../../site'
|
|
10
|
+
|
|
9
11
|
const isProd = import.meta.env.PROD
|
|
10
|
-
const googleId = getConfig().analytics
|
|
12
|
+
const { googleId } = getConfig().analytics
|
|
11
13
|
---
|
|
12
14
|
|
|
13
15
|
{
|
|
14
|
-
isProd && (
|
|
16
|
+
isProd && googleId && (
|
|
15
17
|
<>
|
|
16
18
|
<script is:inline async src={`https://www.googletagmanager.com/gtag/js?id=${googleId}`} />
|
|
17
19
|
<script
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* HTML head section with meta tags, stylesheets, and SEO configuration.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { getConfig } from '
|
|
8
|
+
import { getConfig } from '../../site'
|
|
9
9
|
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
13
|
import Analytics from './Analytics.astro'
|
|
14
|
-
import '
|
|
14
|
+
import 'virtual:chassis-docs/styles'
|
|
15
15
|
|
|
16
16
|
interface Props {
|
|
17
17
|
/** Page description for meta tags */
|
|
@@ -5,11 +5,9 @@
|
|
|
5
5
|
* Social media meta tags (Open Graph, Twitter Cards).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import path from 'node:path'
|
|
9
|
-
import { getConfig } from '@libs/config'
|
|
10
|
-
import { getDocsPublicFsPath } from '@libs/path'
|
|
11
8
|
import { getRemoteImageSize, getStaticImageSize } from '../../libs/image'
|
|
12
9
|
import type { Layout } from '../../libs/layout'
|
|
10
|
+
import { getConfig, getPublicFsPath } from '../../site'
|
|
13
11
|
|
|
14
12
|
interface Props {
|
|
15
13
|
/** Page description */
|
|
@@ -28,12 +26,13 @@ const socialImageUrl = new URL(thumbnail, Astro.site)
|
|
|
28
26
|
const isRemoteThumbnail = /^https?:\/\//i.test(thumbnail)
|
|
29
27
|
const socialImageSize = isRemoteThumbnail
|
|
30
28
|
? await getRemoteImageSize(thumbnail)
|
|
31
|
-
: await getStaticImageSize(
|
|
29
|
+
: await getStaticImageSize(getPublicFsPath(thumbnail))
|
|
30
|
+
const { xUsername } = getConfig()
|
|
32
31
|
---
|
|
33
32
|
|
|
34
33
|
<meta name="twitter:card" content="summary_lg_image" />
|
|
35
|
-
<meta name="twitter:site" content
|
|
36
|
-
<meta name="twitter:creator" content
|
|
34
|
+
{xUsername && <meta name="twitter:site" content={`@${xUsername}`} />}
|
|
35
|
+
{xUsername && <meta name="twitter:creator" content={`@${xUsername}`} />}
|
|
37
36
|
<meta name="twitter:title" content={title} />
|
|
38
37
|
<meta name="twitter:description" content={description} />
|
|
39
38
|
<meta name="twitter:image" content={socialImageUrl} />
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Main site navigation bar with menu items and theme toggler.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { getConfig } from '@libs/config'
|
|
9
8
|
import type { Layout } from '../../libs/layout'
|
|
9
|
+
import { getConfig } 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'
|
|
@@ -19,6 +19,7 @@ interface Props {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const { layout } = Astro.props
|
|
22
|
+
const { figmaHandle, githubOrg } = getConfig()
|
|
22
23
|
const { pathname } = Astro.url
|
|
23
24
|
const isActive = (path: string) => {
|
|
24
25
|
if (path === '/') {
|
|
@@ -106,24 +107,32 @@ const isActive = (path: string) => {
|
|
|
106
107
|
<hr class="lg:d-none m-0" />
|
|
107
108
|
|
|
108
109
|
<ul class="navbar-nav flex-row flex-wrap lg:ms-auto align-items-center">
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
110
|
+
{
|
|
111
|
+
figmaHandle && (
|
|
112
|
+
<NavLink
|
|
113
|
+
class="px-0 lg:px-xs"
|
|
114
|
+
href={`https://figma.com/@${figmaHandle}`}
|
|
115
|
+
target="_blank"
|
|
116
|
+
rel="noopener"
|
|
117
|
+
>
|
|
118
|
+
<Icon name="figma-brand" title="Figma" />
|
|
119
|
+
<small class="lg:d-none ms-xs">Figma Community</small>
|
|
120
|
+
</NavLink>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
{
|
|
124
|
+
githubOrg && (
|
|
125
|
+
<NavLink
|
|
126
|
+
class="px-0 lg:px-xs"
|
|
127
|
+
href={`https://github.com/${githubOrg}`}
|
|
128
|
+
target="_blank"
|
|
129
|
+
rel="noopener"
|
|
130
|
+
>
|
|
131
|
+
<Icon name="github-brand" title="GitHub" />
|
|
132
|
+
<small class="lg:d-none ms-xs">GitHub</small>
|
|
133
|
+
</NavLink>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
127
136
|
<li class="nav-item col-12 lg:col-auto">
|
|
128
137
|
<div class="vr d-none lg:d-flex h-100 lg:mx-2xs"></div>
|
|
129
138
|
<hr class="lg:d-none" />
|