@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.
Files changed (79) hide show
  1. package/README.md +16 -16
  2. package/index.ts +6 -1
  3. package/package.json +20 -8
  4. package/src/components/DocsSidebar.astro +63 -23
  5. package/src/components/FeatureCard.astro +8 -8
  6. package/src/components/NavLink.astro +1 -1
  7. package/src/components/TableOfContents.astro +8 -7
  8. package/src/components/ThemeToggler.astro +16 -37
  9. package/src/components/shortcodes/Blockquote.astro +31 -0
  10. package/src/components/shortcodes/CSSOnly.astro +22 -0
  11. package/src/components/shortcodes/Callout.astro +6 -2
  12. package/src/components/shortcodes/Code.astro +289 -0
  13. package/src/components/shortcodes/DeprecatedIn.astro +18 -0
  14. package/src/components/shortcodes/Example.astro +132 -0
  15. package/src/components/shortcodes/Icon.astro +57 -0
  16. package/src/components/shortcodes/InFigma.astro +26 -0
  17. package/src/components/shortcodes/JsDocs.astro +64 -0
  18. package/src/components/shortcodes/Placeholder.astro +28 -0
  19. package/src/components/shortcodes/ResizableExample.astro +126 -0
  20. package/src/components/shortcodes/ScssDocs.astro +108 -0
  21. package/src/components/shortcodes/ScssDocsSimple.astro +66 -0
  22. package/src/js/color-modes.js +3 -3
  23. package/src/js/example-mode.js +75 -0
  24. package/src/js/search.js +501 -39
  25. package/src/js/theme-color.js +1 -1
  26. package/src/layouts/DocsLayout.astro +18 -21
  27. package/src/layouts/RedirectLayout.astro +1 -0
  28. package/src/layouts/SingleLayout.astro +3 -3
  29. package/src/layouts/footer/Footer.astro +5 -5
  30. package/src/layouts/footer/Scripts.astro +14 -7
  31. package/src/layouts/head/Analytics.astro +12 -6
  32. package/src/layouts/head/Favicons.astro +0 -2
  33. package/src/layouts/head/Head.astro +2 -7
  34. package/src/layouts/head/Stylesheet.astro +18 -11
  35. package/src/layouts/header/Header.astro +2 -5
  36. package/src/layouts/header/Navigation.astro +40 -42
  37. package/src/layouts/header/SearchDialog.astro +74 -0
  38. package/src/layouts/header/SearchTrigger.astro +41 -0
  39. package/src/layouts/header/Skippy.astro +1 -1
  40. package/src/libs/highlight.ts +91 -0
  41. package/src/libs/icon.ts +75 -0
  42. package/src/libs/image.ts +12 -1
  43. package/src/libs/layout.ts +18 -0
  44. package/src/libs/markdown.ts +128 -0
  45. package/src/libs/placeholder.ts +250 -0
  46. package/src/libs/rehype.ts +0 -17
  47. package/src/libs/shortcodes.ts +129 -0
  48. package/src/libs/site.ts +95 -0
  49. package/src/libs/toc.ts +40 -6
  50. package/src/libs/utils.ts +34 -82
  51. package/src/libs/vite.ts +45 -0
  52. package/src/scss/_anchor.scss +20 -16
  53. package/src/scss/_callouts.scss +29 -28
  54. package/src/scss/_content.scss +72 -103
  55. package/src/scss/_footer.scss +18 -19
  56. package/src/scss/_layout.scss +56 -61
  57. package/src/scss/_navbar.scss +19 -126
  58. package/src/scss/_placeholder-img.scss +11 -7
  59. package/src/scss/_scrolling.scss +14 -12
  60. package/src/scss/_search.scss +418 -0
  61. package/src/scss/_shiki.scss +120 -0
  62. package/src/scss/_sidebar.scss +137 -132
  63. package/src/scss/_skippy.scss +6 -4
  64. package/src/scss/_snippets.scss +181 -0
  65. package/src/scss/_toc.scss +97 -93
  66. package/src/scss/_vars.scss +89 -0
  67. package/src/scss/main.scss +75 -81
  68. package/src/js/icon-loader.js +0 -229
  69. package/src/libs/chassis.ts +0 -38
  70. package/src/scss/_brand.scss +0 -59
  71. package/src/scss/_buttons.scss +0 -33
  72. package/src/scss/_clipboard-js.scss +0 -63
  73. package/src/scss/_code.scss +0 -116
  74. package/src/scss/_colors.scss +0 -140
  75. package/src/scss/_docsearch.scss +0 -212
  76. package/src/scss/_masthead.scss +0 -124
  77. package/src/scss/_settings.scss +0 -29
  78. package/src/scss/_syntax.scss +0 -160
  79. package/src/scss/_variables.scss +0 -78
@@ -0,0 +1,289 @@
1
+ ---
2
+ import fs from 'node:fs'
3
+ import path from 'node:path'
4
+ import { transformerNotationDiff, transformerNotationHighlight } from '@shikijs/transformers'
5
+ import { getConfig } from '@libs/config'
6
+ import { highlightCode } from '../../libs/highlight'
7
+ import Icon from './Icon.astro'
8
+
9
+ interface Props {
10
+ /**
11
+ * If extra JS snippet should be added to StackBlitz or not.
12
+ * @default false
13
+ */
14
+ addStackblitzJs?: boolean
15
+ /**
16
+ * The CSS class(es) to be added to the `pre` HTML element when rendering code blocks in Markdown.
17
+ * Note that this prop is not used when the component is invoked directly.
18
+ */
19
+ class?: string
20
+ /**
21
+ * The code to highlight.
22
+ * If an array is passed, elements will be joined with a new line.
23
+ */
24
+ code?: string | string[]
25
+ /**
26
+ * The CSS class(es) to be added to the `div` wrapper HTML element.
27
+ */
28
+ containerClass?: string
29
+ /**
30
+ * The language attribute from Shiki/Astro markdown processing
31
+ */
32
+ 'data-language'?: string
33
+ /**
34
+ * The language to use for highlighting.
35
+ * @see https://shiki.style/languages
36
+ */
37
+ lang?: string
38
+ /**
39
+ * If the `filePath` prop is defined, this prop can be used to specify a regex containing a match group to extract
40
+ * only a part of the file.
41
+ */
42
+ fileMatch?: string
43
+ /**
44
+ * A path to the file containing the code to highlight relative to the root of the repository.
45
+ * This takes precedence over the `code` prop.
46
+ */
47
+ filePath?: string
48
+ /**
49
+ * A file path to display in the highlight toolbar instead of the language label.
50
+ */
51
+ file?: string
52
+ /**
53
+ * Defines if the `<Code>` component is nested inside an `<Example>` component or not.
54
+ * @default false
55
+ */
56
+ nestedInExample?: boolean
57
+ /**
58
+ * If true, hides the highlight toolbar (language label and copy button).
59
+ * @default false
60
+ */
61
+ noToolbar?: boolean
62
+ /**
63
+ * If true, displays line numbers in the code block.
64
+ * @default false
65
+ */
66
+ lineNumbers?: boolean
67
+ /**
68
+ * If true, displays color mode and stackblitz buttons in the toolbar.
69
+ * @default false
70
+ */
71
+ hasPreview?: boolean
72
+ }
73
+
74
+ const {
75
+ addStackblitzJs = false,
76
+ class: className,
77
+ code,
78
+ containerClass,
79
+ 'data-language': dataLanguage,
80
+ file,
81
+ fileMatch,
82
+ filePath,
83
+ lang,
84
+ nestedInExample = false,
85
+ noToolbar = false,
86
+ lineNumbers = false,
87
+ hasPreview = false
88
+ } = Astro.props
89
+
90
+ const fileUrl = file
91
+ ? `${getConfig().repo}/blob/v${getConfig().current_version}/${file}`.replaceAll('\\', '/')
92
+ : null
93
+
94
+ // Extract language from multiple possible sources (for markdown code blocks)
95
+ // Priority: lang prop > data-language attribute > className pattern
96
+ let detectedLang = lang || dataLanguage
97
+ if (!detectedLang && className) {
98
+ const langMatch = className.match(/language-(\w+)/)
99
+ if (langMatch) {
100
+ detectedLang = langMatch[1]
101
+ }
102
+ }
103
+
104
+ // Format language for display (e.g., "html" -> "HTML", "javascript" -> "JavaScript")
105
+ const displayLang = detectedLang
106
+ ? detectedLang === 'js'
107
+ ? 'JavaScript'
108
+ : detectedLang === 'ts'
109
+ ? 'TypeScript'
110
+ : detectedLang === 'html'
111
+ ? 'HTML'
112
+ : detectedLang === 'css'
113
+ ? 'CSS'
114
+ : detectedLang === 'scss'
115
+ ? 'SCSS'
116
+ : detectedLang === 'bash' || detectedLang === 'sh'
117
+ ? 'Shell'
118
+ : detectedLang === 'powershell'
119
+ ? 'PowerShell'
120
+ : detectedLang.toUpperCase()
121
+ : ''
122
+
123
+ let codeToDisplay = filePath
124
+ ? fs.readFileSync(path.join(process.cwd(), filePath), 'utf8')
125
+ : Array.isArray(code)
126
+ ? code.join('\n')
127
+ : code
128
+
129
+ if (filePath && fileMatch && codeToDisplay) {
130
+ const matches = [...codeToDisplay.matchAll(new RegExp(fileMatch, 'g'))]
131
+
132
+ if (matches.length === 0) {
133
+ throw new Error(
134
+ `The file at ${filePath} does not contain a match for the regex '${fileMatch}'.`
135
+ )
136
+ }
137
+
138
+ codeToDisplay = matches.map((m) => m[0]).join('\n\n')
139
+ }
140
+
141
+ const diffTransformers = [transformerNotationDiff(), transformerNotationHighlight()]
142
+
143
+ let highlightedCode: string | null = null
144
+ if (codeToDisplay && detectedLang) {
145
+ const { html } = await highlightCode(codeToDisplay, detectedLang, diffTransformers)
146
+ highlightedCode = html
147
+ }
148
+ ---
149
+
150
+ <script>
151
+ import { Tooltip } from '@chassis-ui/css'
152
+ import { initCopyButtons } from '@libs/clipboard'
153
+
154
+ document.querySelectorAll('.button-edit').forEach((button) => {
155
+ Tooltip.getOrCreateInstance(button, { title: 'Edit on StackBlitz' })
156
+ })
157
+
158
+ initCopyButtons('.button-clipboard', (trigger) => {
159
+ const snippet = trigger.closest('.cxd-code-snippet') || trigger.closest('.cxd-example-snippet')
160
+ const activeTab = snippet?.querySelector('.code-tab-content.active .astro-code')
161
+ if (activeTab) {
162
+ return activeTab.textContent?.trim() || ''
163
+ }
164
+
165
+ return snippet?.querySelector('.astro-code')?.textContent?.trim() || ''
166
+ })
167
+ </script>
168
+
169
+ {
170
+ nestedInExample && !noToolbar && (
171
+ <div class="cxd-snippet-toolbar">
172
+ {file ? (
173
+ <a
174
+ class="text-decoration-none font-code fg-subtle text-uppercase"
175
+ href={fileUrl}
176
+ target="_blank"
177
+ rel="noopener noreferrer"
178
+ >
179
+ {file}
180
+ </a>
181
+ ) : (
182
+ <small class="font-code fg-subtle text-uppercase">{displayLang}</small>
183
+ )}
184
+ <div class="d-flex ms-auto gap-2xsmall">
185
+ {hasPreview && (
186
+ <>
187
+ <button
188
+ type="button"
189
+ class="button-mode"
190
+ title="Toggle color mode"
191
+ aria-label="Toggle color mode"
192
+ onclick="toggleTheme(this)"
193
+ >
194
+ <Icon name="swatchbook-solid" />
195
+ </button>
196
+ <span class="vr mx-2xsmall" />
197
+ <button
198
+ type="button"
199
+ class="button-edit"
200
+ title="Try it on StackBlitz"
201
+ aria-label="Try it on StackBlitz"
202
+ data-sb-js-snippet={addStackblitzJs ? true : undefined}
203
+ >
204
+ <Icon name="lightning-solid" />
205
+ </button>
206
+ </>
207
+ )}
208
+ <button
209
+ type="button"
210
+ class="button-clipboard"
211
+ title="Copy to clipboard"
212
+ aria-label="Copy to clipboard"
213
+ >
214
+ <Icon name="clipboard-outline" />
215
+ </button>
216
+ </div>
217
+ </div>
218
+ )
219
+ }
220
+
221
+ {
222
+ nestedInExample ? (
223
+ <>
224
+ {highlightedCode ? (
225
+ <div class:list={['cxd-code', { 'line-numbers': lineNumbers }]}>
226
+ <Fragment set:html={highlightedCode} />
227
+ </div>
228
+ ) : (
229
+ <div class:list={['cxd-code', { 'line-numbers': lineNumbers }]}>
230
+ {/* prettier-ignore */}
231
+ <pre class={className}><slot /></pre>
232
+ </div>
233
+ )}
234
+ </>
235
+ ) : (
236
+ <div class:list={['cxd-code-snippet', containerClass]} data-pagefind-ignore>
237
+ {!noToolbar && (
238
+ <div class="cxd-snippet-toolbar">
239
+ {file ? (
240
+ <a
241
+ class="text-decoration-none font-code fg-subtle"
242
+ href={fileUrl}
243
+ target="_blank"
244
+ rel="noopener noreferrer"
245
+ >
246
+ {file}
247
+ </a>
248
+ ) : (
249
+ <small class="font-code fg-subtle text-uppercase">{displayLang}</small>
250
+ )}
251
+ <div class="d-flex ms-auto gap-2xsmall">
252
+ <button
253
+ type="button"
254
+ class="button-clipboard"
255
+ title="Copy to clipboard"
256
+ aria-label="Copy to clipboard"
257
+ >
258
+ <Icon name="clipboard-outline" />
259
+ </button>
260
+ </div>
261
+ </div>
262
+ )}
263
+ <slot name="pre" />
264
+ {!Astro.slots.has('pre') && noToolbar ? (
265
+ <div class="cxd-clipboard">
266
+ <button
267
+ type="button"
268
+ class="button-clipboard"
269
+ title="Copy to clipboard"
270
+ aria-label="Copy to clipboard"
271
+ >
272
+ <Icon name="clipboard-outline" />
273
+ </button>
274
+ </div>
275
+ ) : null}
276
+
277
+ {highlightedCode ? (
278
+ <div class:list={['cxd-code', { 'line-numbers': lineNumbers }]}>
279
+ <Fragment set:html={highlightedCode} />
280
+ </div>
281
+ ) : (
282
+ <div class:list={['cxd-code', { 'line-numbers': lineNumbers }]}>
283
+ {/* prettier-ignore */}
284
+ <pre class={className}><slot /></pre>
285
+ </div>
286
+ )}
287
+ </div>
288
+ )
289
+ }
@@ -0,0 +1,18 @@
1
+ ---
2
+ /**
3
+ * Deprecated In
4
+ *
5
+ * Badge indicating the version in which a feature was deprecated.
6
+ */
7
+
8
+ interface Props {
9
+ /** Version number when the feature was deprecated (e.g. `"2.1.0"`). */
10
+ version: string
11
+ }
12
+
13
+ const { version } = Astro.props
14
+ ---
15
+
16
+ <span class="badge large warning smooth mb-medium rounded-medium">
17
+ Deprecated in v{version}
18
+ </span>
@@ -0,0 +1,132 @@
1
+ ---
2
+ import { replacePlaceholdersInHtml } from '../../libs/placeholder'
3
+ import { replaceIconsInHtml } from '../../libs/icon'
4
+ import Code from './Code.astro'
5
+ import Icon from './Icon.astro'
6
+
7
+ interface Props {
8
+ /**
9
+ * Defines if extra JS snippet should be added to StackBlitz or not.
10
+ * @default false
11
+ */
12
+ addStackblitzJs?: boolean
13
+ /**
14
+ * The example code.
15
+ * If an array is passed, elements will be joined with a new line.
16
+ */
17
+ code: string | string[]
18
+ /**
19
+ * Custom markup to display in the source code section, different from the preview code.
20
+ * If provided, this will be used instead of the `code` prop for the source display.
21
+ */
22
+ customMarkup?: string | string[]
23
+ /**
24
+ * The CSS class(es) to be added to the preview wrapping `div` element.
25
+ */
26
+ class?: string
27
+ /**
28
+ * A file path to display in the highlight toolbar instead of the language label.
29
+ */
30
+ file?: string
31
+ /**
32
+ * The preview wrapping `div` element ID.
33
+ */
34
+ id?: string
35
+ /**
36
+ * Language used to display the code.
37
+ * @default 'html'
38
+ */
39
+ lang?: string
40
+ /**
41
+ * Defines if the markup should be visible or not.
42
+ * @default true
43
+ */
44
+ showMarkup?: boolean
45
+ /**
46
+ * Defines if the preview should be visible or not.
47
+ * @default true
48
+ */
49
+ showPreview?: boolean
50
+ /**
51
+ * If true, displays line numbers in the code block.
52
+ * @default false
53
+ */
54
+ lineNumbers?: boolean
55
+ }
56
+
57
+ const {
58
+ addStackblitzJs = false,
59
+ code,
60
+ customMarkup,
61
+ class: className,
62
+ file,
63
+ id,
64
+ lang = 'html',
65
+ lineNumbers = false,
66
+ showMarkup = true,
67
+ showPreview = true
68
+ } = Astro.props
69
+
70
+ let markup = Array.isArray(code) ? code.join('\n') : code
71
+ markup = replacePlaceholdersInHtml(markup)
72
+ markup = replaceIconsInHtml(markup)
73
+ markup = markup
74
+ .split('\n')
75
+ .map((line) => line.trimEnd())
76
+ .join('\n')
77
+
78
+ // Use customMarkup for source code display if provided, otherwise use the processed markup
79
+ let sourceMarkup = customMarkup
80
+ ? Array.isArray(customMarkup)
81
+ ? customMarkup.join('\n')
82
+ : customMarkup
83
+ : markup
84
+
85
+ const simplifiedMarkup = sourceMarkup
86
+ .replace(
87
+ /<svg.*class="cxd-placeholder-image(?:-large)?(?: *?cxd-placeholder-image-large)? ?(.*?)".*?<\/svg>/g,
88
+ (_match, classes) => `<img src="..."${classes ? ` class="${classes}"` : ''} alt="...">`
89
+ )
90
+ .replace(
91
+ /<img.*class="cxd-placeholder-image(?:-large)?(?: *?cxd-placeholder-image-large)? ?(.*?)".*?>/g,
92
+ (_match, classes) => `<img src="..."${classes ? ` class="${classes}"` : ''} alt="...">`
93
+ )
94
+ .replace(/(<svg class="icon\b[^"]*")\s+width="\d+"\s+height="\d+"/g, '$1')
95
+ .replace(/href="\/static\/icons\/chassis-icons\.svg#/g, 'href="#')
96
+ ---
97
+
98
+ <div class="cxd-example-snippet cxd-code-snippet not-prose" data-pagefind-ignore>
99
+ {
100
+ showPreview && (
101
+ <div id={id} class:list={['cxd-example m-0 border-0 context', className]}>
102
+ {!showMarkup && (
103
+ <div class="cxd-mode">
104
+ <button
105
+ type="button"
106
+ class="button-mode"
107
+ title="Toggle color mode"
108
+ aria-label="Toggle color mode"
109
+ onclick="toggleTheme(this)"
110
+ >
111
+ <Icon name="swatchbook-solid" />
112
+ </button>
113
+ </div>
114
+ )}
115
+ <Fragment set:html={markup} />
116
+ </div>
117
+ )
118
+ }
119
+ {
120
+ showMarkup && (
121
+ <Code
122
+ code={simplifiedMarkup}
123
+ lang={lang}
124
+ file={file}
125
+ lineNumbers={lineNumbers}
126
+ nestedInExample={true}
127
+ addStackblitzJs={addStackblitzJs}
128
+ hasPreview={showPreview}
129
+ />
130
+ )
131
+ }
132
+ </div>
@@ -0,0 +1,57 @@
1
+ ---
2
+ /**
3
+ * Icon
4
+ *
5
+ * Renders a Chassis icon, either as an SVG referencing the icon sprite
6
+ * or as a font glyph via the `cx-{name}` icon font class.
7
+ */
8
+
9
+ interface Props {
10
+ /** Icon name/id, e.g. `folder-tree`. */
11
+ name: string
12
+ /** Additional CSS class(es) to add alongside the standard `icon` class. */
13
+ class?: string
14
+ /** Width/height (in px) applied to the SVG. Ignored in `font` mode. */
15
+ size?: number
16
+ /** Render as a `<span class="icon cx-{name}">` font glyph instead of an SVG `<use>`. */
17
+ font?: boolean
18
+ /** Accessible name. When set, the icon is exposed to assistive tech instead of hidden. */
19
+ title?: string
20
+ /** Path to the SVG sprite file. Ignored in `font` mode. */
21
+ sprite?: string
22
+ /** Any other attribute (e.g. `style`, `role`) is passed through to the rendered element. */
23
+ [key: string]: unknown
24
+ }
25
+
26
+ const {
27
+ name,
28
+ class: className,
29
+ size = 24,
30
+ font = false,
31
+ title,
32
+ sprite = '/static/icons/chassis-icons.svg',
33
+ ...rest
34
+ } = Astro.props
35
+ ---
36
+
37
+ {
38
+ font ? (
39
+ <span
40
+ class:list={['icon', `cx-${name}`, className]}
41
+ aria-hidden={title ? undefined : 'true'}
42
+ aria-label={title}
43
+ {...rest}
44
+ />
45
+ ) : (
46
+ <svg
47
+ class:list={['icon', className]}
48
+ width={size}
49
+ height={size}
50
+ aria-hidden={title ? undefined : 'true'}
51
+ {...rest}
52
+ >
53
+ {title && <title>{title}</title>}
54
+ <use href={`${sprite}#${name}`} />
55
+ </svg>
56
+ )
57
+ }
@@ -0,0 +1,26 @@
1
+ ---
2
+ /**
3
+ * In Figma
4
+ *
5
+ * Badge indicating a variant exists in the Figma component library with bound
6
+ * design tokens. Renders with a tooltip that can be customized.
7
+ */
8
+
9
+ interface Props {
10
+ /** Custom tooltip text. Defaults to a generated message based on `plural`. */
11
+ tooltip?: string
12
+ /** When true, uses plural phrasing in the default tooltip text. */
13
+ plural?: boolean
14
+ }
15
+
16
+ const { tooltip, plural } = Astro.props
17
+ const tooltipText =
18
+ tooltip ??
19
+ `This variant${plural ? 's' : ''} exist${plural ? '' : 's'} in the Figma component library with bound design tokens.`
20
+ ---
21
+
22
+ <span
23
+ class="badge large primary smooth mb-medium rounded-medium"
24
+ data-cx-toggle="tooltip"
25
+ title={tooltipText}>In Figma</span
26
+ >
@@ -0,0 +1,64 @@
1
+ ---
2
+ import fs from 'node:fs'
3
+ import Code from './Code.astro'
4
+
5
+ // Prints everything between `// js-docs-start "name"` and `// js-docs-end "name"`
6
+ // comments in the docs.
7
+
8
+ interface Props {
9
+ /**
10
+ * Reference name used to find the content to display within the content of the `file` prop.
11
+ */
12
+ name: string
13
+ /**
14
+ * File path that contains the content to display relative to the root of the repository.
15
+ */
16
+ file: string
17
+ }
18
+
19
+ const { name, file } = Astro.props
20
+
21
+ if (!name || !file) {
22
+ throw new Error(
23
+ `Missing required parameter(s) for the '<JsDocs />' component, expected both 'name' and 'file' but got 'name: ${name}' and 'file: ${file}'.`
24
+ )
25
+ }
26
+
27
+ let content: string
28
+
29
+ try {
30
+ const fileContent = fs.readFileSync(file, 'utf8')
31
+
32
+ const matches = fileContent.match(
33
+ new RegExp(`// js-docs-start ${name}\n((?:.|\n)*)// js-docs-end ${name}`, 'm')
34
+ )
35
+
36
+ if (!matches || !matches[1]) {
37
+ throw new Error(
38
+ `Failed to find the content named '${name}', make sure that '// js-docs-start ${name}' and '// js-docs-end ${name}' are defined.`
39
+ )
40
+ }
41
+
42
+ content = matches[1]
43
+
44
+ // Fix the identation by removing extra spaces at the beginning of each line
45
+ const lines = content.split('\n')
46
+ const spaceCounts = lines
47
+ .filter((line) => line.trim().length > 0)
48
+ .map((line) => line.match(/^ */)![0].length)
49
+ const minSpaces = spaceCounts.length ? Math.min(...spaceCounts) : 0
50
+ content = lines
51
+ .map((line) => line.slice(minSpaces))
52
+ .join('\n')
53
+ .trim()
54
+ } catch (error) {
55
+ throw new Error(
56
+ `Failed to find the content to render in the '<JsDocs />' component at '${file}'.`,
57
+ {
58
+ cause: error
59
+ }
60
+ )
61
+ }
62
+ ---
63
+
64
+ <Code containerClass="cxd-example-snippet cxd-file-ref" code={content} file={file} lang="js" />
@@ -0,0 +1,28 @@
1
+ ---
2
+ import { getPlaceholder, type PlaceholderOptions } from '../../libs/placeholder'
3
+
4
+ type Props = Partial<PlaceholderOptions>
5
+
6
+ const {
7
+ options: { background, color, showText, showTitle, text, title },
8
+ props,
9
+ type
10
+ } = getPlaceholder(Astro.props)
11
+ ---
12
+
13
+ {
14
+ type === 'img' ? (
15
+ // eslint-disable-next-line astro/jsx-a11y/alt-text
16
+ <img {...props} />
17
+ ) : (
18
+ <svg {...props}>
19
+ {showTitle && <title>{title}</title>}
20
+ <rect width="100%" height="100%" fill={background} />
21
+ {showText && (
22
+ <text x="50%" y="50%" fill={color} dy=".3em">
23
+ {text}
24
+ </text>
25
+ )}
26
+ </svg>
27
+ )
28
+ }