@chassis-ui/docs 0.5.1 → 0.6.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/src/libs/toc.ts CHANGED
@@ -37,7 +37,9 @@ export function generateToc(allHeadings: MarkdownHeading[], config: TocConfig):
37
37
 
38
38
  const previousEntry = toc[toc.length - 1]
39
39
 
40
- if (heading.depth === previousEntry.depth) {
40
+ // A heading at the depth of the previous top-level entry, or shallower, starts a new
41
+ // top-level entry. A page whose first heading is an `<h3>` has later `<h2>`s here.
42
+ if (heading.depth <= previousEntry.depth) {
41
43
  toc.push({ ...heading, children: [] })
42
44
  continue
43
45
  }
@@ -1,4 +1,7 @@
1
- // Local docs variables
1
+ // The Sass variables and custom properties of the docs.
2
+ //
3
+ // This partial is public: a site may `@use "@chassis-ui/docs/scss/vars"` in its own
4
+ // stylesheets. Removing or renaming a variable is a breaking change.
2
5
  @use "@chassis-ui/css/scss/functions" as *;
3
6
  @use "@chassis-ui/css/scss/mixins" as *;
4
7
 
package/src/site.ts ADDED
@@ -0,0 +1,150 @@
1
+ // What pages and components read from the site. It is backed by the modules that the
2
+ // integration provides, so it works only in code that Astro renders: not in
3
+ // `astro.config.ts`, and not in the browser.
4
+
5
+ import path from 'node:path'
6
+ import type { z } from 'astro/zod'
7
+ import config from 'virtual:chassis-docs/config'
8
+ import sidebar from 'virtual:chassis-docs/sidebar'
9
+ import * as paths from 'virtual:chassis-docs/paths'
10
+ import { getCollection, getEntry, type render } from 'astro:content'
11
+ import { loadData } from './libs/config'
12
+ import { joinDocsPath } from './libs/docs-path'
13
+ import { getNodeModulesFsPaths, resolvePackageFilePath } from './libs/paths'
14
+ import { replaceConfigInText, replaceDocsrefInText } from './libs/remark'
15
+ import type { ChassisConfig, DocsPage, Sidebar } from './libs/schema'
16
+ import { resolveSiteFileUrl, resolveSourceFsPath, resolveSourceUrl } from './libs/source'
17
+
18
+ /**
19
+ * The parsed `config.yml`.
20
+ *
21
+ * A site with keys of its own names its config type: `getConfig<SiteConfig>()`, where
22
+ * `SiteConfig` is inferred from the schema that the site passes to the integration.
23
+ */
24
+ export function getConfig<TConfig extends ChassisConfig = ChassisConfig>(): TConfig {
25
+ return config as TConfig
26
+ }
27
+
28
+ /** The parsed `data/sidebar.yml`. Empty when the site has no sidebar file. */
29
+ export function getSidebar(): Sidebar {
30
+ return sidebar
31
+ }
32
+
33
+ /** URL path of a docs page, e.g. `getDocsPath('/components/button/')`. */
34
+ export function getDocsPath(inputPath: string): string {
35
+ return joinDocsPath(config.docsPath, inputPath)
36
+ }
37
+
38
+ /** Absolute path of the site's root: the directory that holds `astro.config.ts`. */
39
+ export function getSiteRoot(): string {
40
+ return paths.root
41
+ }
42
+
43
+ /** Absolute path of a file in the site's root. */
44
+ export function getSiteFsPath(file = ''): string {
45
+ return path.resolve(paths.root, file)
46
+ }
47
+
48
+ /** Absolute path of a file in the site's `public` directory. */
49
+ export function getPublicFsPath(file = ''): string {
50
+ return path.join(paths.publicDir, file)
51
+ }
52
+
53
+ /** Absolute path of a file or directory that a `file` prop names. */
54
+ export function getSourceFsPath(file = ''): string {
55
+ return resolveSourceFsPath(paths.sourceDir, file)
56
+ }
57
+
58
+ /** URL of a source file on GitHub, in the tag of the current version. */
59
+ export function getSourceUrl(file: string): string {
60
+ return resolveSourceUrl(config, file)
61
+ }
62
+
63
+ /** URL of a file of the site on GitHub, on the site's branch. */
64
+ export function getSiteFileUrl(filePath: string): string {
65
+ return resolveSiteFileUrl(config, filePath)
66
+ }
67
+
68
+ /**
69
+ * Absolute path of a file of the package, named by its public path, e.g.
70
+ * `getPackageFilePath('js/color-modes.js')`.
71
+ */
72
+ export function getPackageFilePath(file: string): string {
73
+ return resolvePackageFilePath(file, paths.packageRoot)
74
+ }
75
+
76
+ /** The `node_modules` directories that the site resolves packages from, nearest first. */
77
+ export function getNodeModulesPaths(): string[] {
78
+ return getNodeModulesFsPaths(paths.root)
79
+ }
80
+
81
+ /**
82
+ * Returns a `getData(name)` function for the site's own data files. Each key of
83
+ * `definitions` is the name of a YAML file in `dir`, and its value is the schema of the file.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * import { createDataLoader } from '@chassis-ui/docs/site'
88
+ * import { z } from '@chassis-ui/docs/schema'
89
+ *
90
+ * export const getData = createDataLoader({
91
+ * breakpoints: z.object({ name: z.string() }).array()
92
+ * })
93
+ * ```
94
+ */
95
+ export function createDataLoader<TDefinitions extends Record<string, z.ZodType>>(
96
+ definitions: TDefinitions,
97
+ options: { dir?: string } = {}
98
+ ) {
99
+ const cache = new Map<keyof TDefinitions, unknown>()
100
+
101
+ return function getData<TName extends keyof TDefinitions & string>(
102
+ name: TName
103
+ ): z.infer<TDefinitions[TName]> {
104
+ if (!cache.has(name)) {
105
+ cache.set(
106
+ name,
107
+ loadData({
108
+ file: path.join(options.dir ?? 'data', `${name}.yml`),
109
+ root: paths.root,
110
+ schema: definitions[name]
111
+ })
112
+ )
113
+ }
114
+
115
+ return cache.get(name) as z.infer<TDefinitions[TName]>
116
+ }
117
+ }
118
+
119
+ type RenderableEntry = Parameters<typeof render>[0]
120
+
121
+ // The package cannot know the collections of the site, so their names are not type-checked.
122
+ const getSiteCollection = getCollection as unknown as (_name: string) => Promise<DocsPage[]>
123
+ const getSiteEntry = getEntry as unknown as (
124
+ _collection: string,
125
+ _id: string
126
+ ) => Promise<RenderableEntry | undefined>
127
+
128
+ let docsPages: Promise<DocsPage[]> | undefined
129
+
130
+ /** The entries of the site's `docs` collection. */
131
+ export function getDocsPages(): Promise<DocsPage[]> {
132
+ docsPages ??= getSiteCollection('docs')
133
+
134
+ return docsPages
135
+ }
136
+
137
+ /** An entry of the site's `callouts` collection, or `undefined` when there is none. */
138
+ export function getCallout(name: string): Promise<RenderableEntry | undefined> {
139
+ return getSiteEntry('callouts', name)
140
+ }
141
+
142
+ /** Replaces each `[[config:key]]` in `text` with the value of that key of `config.yml`. */
143
+ export function resolveConfigRefs(text: string): string {
144
+ return replaceConfigInText(text, config)
145
+ }
146
+
147
+ /** Replaces each `[[docsref:/path]]` in `text` with the URL path of that docs page. */
148
+ export function resolveDocsrefs(text: string): string {
149
+ return replaceDocsrefInText(text, { docsPath: config.docsPath })
150
+ }
package/virtual.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ // Modules that the integration provides. A site gets these declarations from the
2
+ // integration. This file is for type-checking the package on its own.
3
+
4
+ declare module 'virtual:chassis-docs/config' {
5
+ const config: import('./src/libs/schema').ChassisConfig
6
+ export default config
7
+ }
8
+
9
+ declare module 'virtual:chassis-docs/sidebar' {
10
+ const sidebar: import('./src/libs/schema').Sidebar
11
+ export default sidebar
12
+ }
13
+
14
+ declare module 'virtual:chassis-docs/paths' {
15
+ /** The site's root. */
16
+ export const root: string
17
+ /** The site's `public` directory. */
18
+ export const publicDir: string
19
+ /** The directory that `file` props are relative to. */
20
+ export const sourceDir: string
21
+ /** The directory of `@chassis-ui/docs`. */
22
+ export const packageRoot: string
23
+ }
24
+
25
+ declare module 'virtual:chassis-docs/styles' {}