@writedocs/generator 0.4.7 → 0.4.9

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/astro.config.mjs CHANGED
@@ -26,6 +26,8 @@ import { remarkAutoHydrateSnippets } from './src/lib/mdx-auto-hydrate.js';
26
26
  import { remarkInjectBuiltinComponents } from './src/lib/mdx-inject-builtins.js';
27
27
  import { remarkTitleAnchorIds } from './src/lib/mdx-title-anchor-ids.js';
28
28
  import { remarkSubstituteVariables } from './src/lib/mdx-substitute-variables.js';
29
+ import { remarkMintlifyTreeLists, remarkMintlifyPromptText } from './src/lib/mdx-mintlify.js';
30
+ import { remarkUnknownComponentFallback } from './src/lib/mdx-unknown-components.js';
29
31
  import { writedocsTempDir, writedocsBuildStagingDir } from './src/lib/writedocs-temp-dir.js';
30
32
  import { stylesAssetFallback } from './src/lib/styles-asset-integration.js';
31
33
  import {
@@ -363,6 +365,17 @@ export default defineConfig({
363
365
  // as raw text first.
364
366
  remarkPlugins: [
365
367
  remarkMath,
368
+ // Mintlify's Markdown-list <Tree> and <Prompt> source text - see
369
+ // lib/mdx-mintlify.js. Before remarkInjectBuiltinComponents, so
370
+ // the <Tree.Folder>/<Tree.File> elements they add are already in
371
+ // the tree when it looks for components to import.
372
+ remarkMintlifyTreeLists,
373
+ remarkMintlifyPromptText,
374
+ // An unknown component becomes a fragment (its children still
375
+ // render) with a warning, instead of failing the whole build - see
376
+ // lib/mdx-unknown-components.js. After remarkMintlifyTreeLists, so
377
+ // the <Tree.Folder>/<Tree.File> elements it adds count as known.
378
+ remarkUnknownComponentFallback,
366
379
  remarkInjectBuiltinComponents,
367
380
  // Runs after remarkInjectBuiltinComponents (order doesn't actually
368
381
  // matter between them - that plugin only ever prepends an import
package/bin/writedocs.js CHANGED
@@ -1,139 +1,167 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import dotenv from 'dotenv';
7
- import { runDev } from '../src/cli/dev.js';
8
- import { runBuild } from '../src/cli/build.js';
9
- import { runInit } from '../src/cli/init.js';
10
- import { requireBuildKey } from '../src/cli/build-auth.js';
11
- // O MESMO modulo que o build usa (via loadDocsConfig, que reexporta daqui) e
12
- // que a plataforma importa por `@writedocs/generator/config-schema` - e o que
13
- // faz os tres reportarem os mesmos problemas com as mesmas palavras, em vez de
14
- // cada um manter a sua copia do schema.
15
- //
16
- // `.js`, e nao o `.ts` que e a fonte de verdade: este arquivo e carregado por
17
- // node puro, sem o transform do Astro/Vite, e o Node RECUSA type stripping para
18
- // qualquer arquivo sob node_modules - por desenho, em qualquer versao
19
- // (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING). Ou seja: importar o `.ts` aqui
20
- // funciona a partir do checkout e falha 100% das vezes para quem instala o
21
- // pacote, que foi exatamente o que quebrou o `validate` no 0.2.0. O `.js` e
22
- // gerado do `.ts` pelo script `prepare` (package.json), entao ele existe tanto
23
- // no checkout quanto dentro do tarball, e o consumidor nao roda build nenhum.
24
- // Ver a mesma regra ja escrita em src/cli/write-redirects-file.js.
25
- import {
26
- validateDocsConfig,
27
- formatValidationIssuesDetailed,
28
- unknownRootKeyIssues,
29
- } from '../src/lib/config-schema.js';
30
-
31
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
32
- const packageRoot = path.resolve(__dirname, '..');
33
- // Read rather than hardcode - a literal version string here silently drifts
34
- // from package.json's own "version" the moment either one is bumped without
35
- // the other (exactly what `npm version <bump>` does: it only touches
36
- // package.json). `writedocs --version` should always reflect what actually
37
- // got published, not whatever this string happened to say at the time this
38
- // line was last hand-edited.
39
- const { version } = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf-8'));
40
-
41
- const program = new Command();
42
- program
43
- .name('writedocs')
44
- .description('Static site generator for writedocs.json + MDX')
45
- .version(version);
46
-
47
- program
48
- .command('dev')
49
- .description('Start a local dev server with hot reload')
50
- .argument('[dir]', 'content directory (contains writedocs.json and docs/)', '.')
51
- .option('-p, --port <port>', 'port to run on')
52
- .action(async (dir, opts) => {
53
- await runDev({
54
- contentDir: path.resolve(process.cwd(), dir),
55
- packageRoot,
56
- port: opts.port,
57
- });
58
- });
59
-
60
- program
61
- // { hidden: true } keeps `build` out of `writedocs --help` - it's not a
62
- // command ordinary users are meant to discover or run themselves. See
63
- // src/cli/build-auth.js for the second layer: even someone who knows the
64
- // command exists still can't run it without the right key.
65
- .command('build', { hidden: true })
66
- .description('Build a static site into <dir>/dist')
67
- .argument('[dir]', 'content directory (contains writedocs.json and docs/)', '.')
68
- .option('-k, --key <key>', 'build authorization key (or set WRITEDOCS_API_KEY)')
69
- .action(async (dir, opts) => {
70
- const contentDir = path.resolve(process.cwd(), dir);
71
- // Project-scoped, not global: a .env sitting next to this project's own
72
- // writedocs.json (WRITEDOCS_KEY_SERVER_URL, WRITEDOCS_API_KEY) is picked
73
- // up automatically, so build doesn't need those exported by hand every
74
- // session. dotenv never overwrites a var already set in the real
75
- // environment - an explicit `export`/CI secret still wins over the file.
76
- dotenv.config({ path: path.join(contentDir, '.env'), quiet: true });
77
- await requireBuildKey(opts.key || process.env.WRITEDOCS_API_KEY);
78
- await runBuild({ contentDir, packageRoot });
79
- });
80
-
81
- program
82
- // Visivel, ao contrario do `build`: validar a propria configuracao e
83
- // exatamente o tipo de coisa que um usuario deve poder rodar sozinho, no CI
84
- // inclusive. Sem chave, sem dotenv, sem rede - le um arquivo e sai 0 ou 1.
85
- .command('validate')
86
- .description('Validate writedocs.json against the schema')
87
- .argument('[dir]', 'content directory (contains writedocs.json)', '.')
88
- .action(async (dir) => {
89
- const contentDir = path.resolve(process.cwd(), dir);
90
- const configPath = path.join(contentDir, 'writedocs.json');
91
- if (!fs.existsSync(configPath)) {
92
- // Mesma mensagem que loadDocsConfig() ja da pro mesmo caso.
93
- console.error(
94
- `[writedocs] writedocs.json not found at ${configPath}. Run "writedocs init" to scaffold one.`
95
- );
96
- process.exit(1);
97
- }
98
-
99
- const rawText = fs.readFileSync(configPath, 'utf-8');
100
- const result = validateDocsConfig(rawText);
101
- // Chave desconhecida na raiz e AVISO, nunca erro: a raiz nao e `.strict()`
102
- // de proposito (tornar strict quebraria configs existentes), entao o Zod
103
- // descarta a chave em silencio. Sem JSON parseavel nao ha chave pra avaliar.
104
- const warnings = result.kind === 'invalid_json' ? [] : unknownRootKeyIssues(rawText);
105
- const nomeArquivo = path.basename(configPath);
106
-
107
- if (!result.ok) {
108
- // A versao longa (linha, frase humana, sugestao) em vez da curta que o
109
- // `writedocs build` imprime: aqui o usuario pediu explicitamente um
110
- // diagnostico, e tem a tela inteira pra ele.
111
- console.error(`[writedocs] ${configPath} failed validation:\n`);
112
- console.error(formatValidationIssuesDetailed(result.issues, { fileName: nomeArquivo }));
113
- console.error('');
114
- }
115
-
116
- if (warnings.length > 0) {
117
- console.error(`[writedocs] ${warnings.length} warning${warnings.length === 1 ? '' : 's'}:\n`);
118
- console.error(formatValidationIssuesDetailed(warnings, { fileName: nomeArquivo }));
119
- console.error('');
120
- }
121
-
122
- if (!result.ok) process.exit(1);
123
- // Aviso nao invalida: um config so com avisos continua valido, e sai 0 -
124
- // o mesmo criterio que a plataforma usa pra marcar o projeto como `valid`.
125
- console.log(`[writedocs] ${configPath} is valid.`);
126
- });
127
-
128
- program
129
- .command('init')
130
- .description('Scaffold a writedocs.json and starter docs/ folder')
131
- .argument('[dir]', 'directory to scaffold into', '.')
132
- .action(async (dir) => {
133
- await runInit({ targetDir: path.resolve(process.cwd(), dir) });
134
- });
135
-
136
- program.parseAsync(process.argv).catch((err) => {
137
- console.error(`[writedocs] ${err.message}`);
138
- process.exit(1);
139
- });
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import dotenv from 'dotenv';
7
+ import { runDev } from '../src/cli/dev.js';
8
+ import { runBuild } from '../src/cli/build.js';
9
+ import { runInit } from '../src/cli/init.js';
10
+ import { requireBuildKey } from '../src/cli/build-auth.js';
11
+ // O MESMO modulo que o build usa (via loadDocsConfig, que reexporta daqui) e
12
+ // que a plataforma importa por `@writedocs/generator/config-schema` - e o que
13
+ // faz os tres reportarem os mesmos problemas com as mesmas palavras, em vez de
14
+ // cada um manter a sua copia do schema.
15
+ //
16
+ // `.js`, e nao o `.ts` que e a fonte de verdade: este arquivo e carregado por
17
+ // node puro, sem o transform do Astro/Vite, e o Node RECUSA type stripping para
18
+ // qualquer arquivo sob node_modules - por desenho, em qualquer versao
19
+ // (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING). Ou seja: importar o `.ts` aqui
20
+ // funciona a partir do checkout e falha 100% das vezes para quem instala o
21
+ // pacote, que foi exatamente o que quebrou o `validate` no 0.2.0. O `.js` e
22
+ // gerado do `.ts` pelo script `prepare` (package.json), entao ele existe tanto
23
+ // no checkout quanto dentro do tarball, e o consumidor nao roda build nenhum.
24
+ // Ver a mesma regra ja escrita em src/cli/write-redirects-file.js.
25
+ import {
26
+ validateDocsConfig,
27
+ formatValidationIssuesDetailed,
28
+ unknownRootKeyIssues,
29
+ } from '../src/lib/config-schema.js';
30
+
31
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
32
+ const packageRoot = path.resolve(__dirname, '..');
33
+ // Read rather than hardcode - a literal version string here silently drifts
34
+ // from package.json's own "version" the moment either one is bumped without
35
+ // the other (exactly what `npm version <bump>` does: it only touches
36
+ // package.json). `writedocs --version` should always reflect what actually
37
+ // got published, not whatever this string happened to say at the time this
38
+ // line was last hand-edited.
39
+ const { version } = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf-8'));
40
+
41
+ const program = new Command();
42
+ program
43
+ .name('writedocs')
44
+ .description('Static site generator for writedocs.json + MDX')
45
+ .version(version);
46
+
47
+ program
48
+ .command('dev')
49
+ .description('Start a local dev server with hot reload')
50
+ .argument('[dir]', 'content directory (contains writedocs.json and docs/)', '.')
51
+ .option('-p, --port <port>', 'port to run on')
52
+ .action(async (dir, opts) => {
53
+ await runDev({
54
+ contentDir: path.resolve(process.cwd(), dir),
55
+ packageRoot,
56
+ port: opts.port,
57
+ });
58
+ });
59
+
60
+ program
61
+ // { hidden: true } keeps `build` out of `writedocs --help` - it's not a
62
+ // command ordinary users are meant to discover or run themselves. See
63
+ // src/cli/build-auth.js for the second layer: even someone who knows the
64
+ // command exists still can't run it without the right key.
65
+ .command('build', { hidden: true })
66
+ .description('Build a static site into <dir>/dist')
67
+ .argument('[dir]', 'content directory (contains writedocs.json and docs/)', '.')
68
+ .option('-k, --key <key>', 'build authorization key (or set WRITEDOCS_API_KEY)')
69
+ .action(async (dir, opts) => {
70
+ const contentDir = path.resolve(process.cwd(), dir);
71
+ // Project-scoped, not global: a .env sitting next to this project's own
72
+ // writedocs.json (WRITEDOCS_KEY_SERVER_URL, WRITEDOCS_API_KEY) is picked
73
+ // up automatically, so build doesn't need those exported by hand every
74
+ // session. dotenv never overwrites a var already set in the real
75
+ // environment - an explicit `export`/CI secret still wins over the file.
76
+ dotenv.config({ path: path.join(contentDir, '.env'), quiet: true });
77
+ await requireBuildKey(opts.key || process.env.WRITEDOCS_API_KEY);
78
+ await runBuild({ contentDir, packageRoot });
79
+ });
80
+
81
+ program
82
+ // Visivel, ao contrario do `build`: validar a propria configuracao e
83
+ // exatamente o tipo de coisa que um usuario deve poder rodar sozinho, no CI
84
+ // inclusive. Sem chave, sem dotenv, sem rede - le um arquivo e sai 0 ou 1.
85
+ .command('validate')
86
+ .description('Validate writedocs.json and every page - frontmatter, MDX, navigation, components, icons')
87
+ .argument('[dir]', 'content directory (contains writedocs.json)', '.')
88
+ .option('--config-only', 'check writedocs.json only, not the pages')
89
+ .action(async (dir, options) => {
90
+ const contentDir = path.resolve(process.cwd(), dir);
91
+ const configPath = path.join(contentDir, 'writedocs.json');
92
+ if (!fs.existsSync(configPath)) {
93
+ // Mesma mensagem que loadDocsConfig() ja da pro mesmo caso.
94
+ console.error(
95
+ `[writedocs] writedocs.json not found at ${configPath}. Run "writedocs init" to scaffold one.`
96
+ );
97
+ process.exit(1);
98
+ }
99
+
100
+ const rawText = fs.readFileSync(configPath, 'utf-8');
101
+ const result = validateDocsConfig(rawText);
102
+ // Chave desconhecida na raiz e AVISO, nunca erro: a raiz nao e `.strict()`
103
+ // de proposito (tornar strict quebraria configs existentes), entao o Zod
104
+ // descarta a chave em silencio. Sem JSON parseavel nao ha chave pra avaliar.
105
+ const warnings = result.kind === 'invalid_json' ? [] : unknownRootKeyIssues(rawText);
106
+ const nomeArquivo = path.basename(configPath);
107
+
108
+ if (!result.ok) {
109
+ // A versao longa (linha, frase humana, sugestao) em vez da curta que o
110
+ // `writedocs build` imprime: aqui o usuario pediu explicitamente um
111
+ // diagnostico, e tem a tela inteira pra ele.
112
+ console.error(`[writedocs] ${configPath} failed validation:\n`);
113
+ console.error(formatValidationIssuesDetailed(result.issues, { fileName: nomeArquivo }));
114
+ console.error('');
115
+ }
116
+
117
+ if (warnings.length > 0) {
118
+ console.error(`[writedocs] ${warnings.length} warning${warnings.length === 1 ? '' : 's'}:\n`);
119
+ console.error(formatValidationIssuesDetailed(warnings, { fileName: nomeArquivo }));
120
+ console.error('');
121
+ }
122
+
123
+ // The pages: everything that would fail the build (errors) or build
124
+ // differently than written (warnings), in one pass - see
125
+ // src/lib/content-check.js. Runs even when writedocs.json itself is
126
+ // invalid, so one run reports both; only the navigation/icon checks
127
+ // need writedocs.json to at least be valid JSON.
128
+ let content = null;
129
+ if (!options.configOnly) {
130
+ const { checkContent, formatContentIssues } = await import('../src/lib/content-check.js');
131
+ content = await checkContent(contentDir, result.kind === 'invalid_json' ? null : rawText);
132
+ if (content.errors.length > 0) {
133
+ console.error(`[writedocs] ${content.errors.length} error${content.errors.length === 1 ? '' : 's'} in the pages:\n`);
134
+ console.error(formatContentIssues(content.errors));
135
+ console.error('');
136
+ }
137
+ if (content.warnings.length > 0) {
138
+ console.error(`[writedocs] ${content.warnings.length} warning${content.warnings.length === 1 ? '' : 's'} in the pages:\n`);
139
+ console.error(formatContentIssues(content.warnings));
140
+ console.error('');
141
+ }
142
+ }
143
+
144
+ if (!result.ok || (content && content.errors.length > 0)) process.exit(1);
145
+ // Aviso nao invalida: um config so com avisos continua valido, e sai 0 -
146
+ // o mesmo criterio que a plataforma usa pra marcar o projeto como `valid`.
147
+ console.log(`[writedocs] ${configPath} is valid.`);
148
+ if (content) {
149
+ console.log(
150
+ `[writedocs] Checked ${content.pages} page${content.pages === 1 ? '' : 's'}: no errors` +
151
+ (content.warnings.length ? `, ${content.warnings.length} warning${content.warnings.length === 1 ? '' : 's'} above.` : '.')
152
+ );
153
+ }
154
+ });
155
+
156
+ program
157
+ .command('init')
158
+ .description('Scaffold a writedocs.json and starter docs/ folder')
159
+ .argument('[dir]', 'directory to scaffold into', '.')
160
+ .action(async (dir) => {
161
+ await runInit({ targetDir: path.resolve(process.cwd(), dir) });
162
+ });
163
+
164
+ program.parseAsync(process.argv).catch((err) => {
165
+ console.error(`[writedocs] ${err.message}`);
166
+ process.exit(1);
167
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@writedocs/generator",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "Static site generator for docs — a writedocs.json + MDX folder in, a static site out.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -59,6 +59,7 @@
59
59
  "@iconify-json/ri": "^1.2.10",
60
60
  "@iconify-json/simple-icons": "^1.2.89",
61
61
  "@iconify-json/tabler": "^1.2.35",
62
+ "@mdx-js/mdx": "^3.1.1",
62
63
  "@shikijs/transformers": "^4.3.1",
63
64
  "@tailwindcss/vite": "^4.3.2",
64
65
  "astro": "7.2.9",
@@ -7,7 +7,7 @@
7
7
  // and Card.astro (the two places writedocs.json icon strings get rendered)
8
8
  // don't each need their own copy of the resolveIcon() call + branch.
9
9
  import { Icon } from 'astro-icon/components';
10
- import { resolveIcon } from '../lib/config';
10
+ import { resolveIcon, iconExists } from '../lib/config';
11
11
 
12
12
  interface Props {
13
13
  icon?: string;
@@ -21,7 +21,19 @@ interface Props {
21
21
  style?: string;
22
22
  }
23
23
  const { icon, class: className = 'wd-icon', style } = Astro.props as Props;
24
- const resolved = icon ? resolveIcon(icon) : null;
24
+ // An icon name no installed collection has renders nothing, with a warning
25
+ // (once per name - a sidebar icon renders on every page), instead of
26
+ // failing the whole build the way astro-icon does on a missing name.
27
+ // `writedocs validate` lists the same names ahead of time.
28
+ let resolved = icon ? resolveIcon(icon) : null;
29
+ if (icon && resolved?.kind === 'iconify' && !iconExists(icon)) {
30
+ const warned: Set<string> = ((globalThis as any).__wdWarnedIcons ??= new Set());
31
+ if (!warned.has(icon)) {
32
+ warned.add(icon);
33
+ console.warn(`[writedocs] unknown icon "${icon}" - no installed icon set has it, so it's left out.`);
34
+ }
35
+ resolved = null;
36
+ }
25
37
  ---
26
38
  {resolved && (
27
39
  resolved.kind === 'iconify' ? (
@@ -0,0 +1,61 @@
1
+ ---
2
+ // Mintlify's <Color> - a palette of <Color.Item> swatches. `variant`:
3
+ // compact (default) - one grid of swatches.
4
+ // table - <Color.Row title="..."> rows, each a titled line of
5
+ // swatches.
6
+ // Color.Row/Color.Item are ColorRow.astro/ColorItem.astro, attached as
7
+ // properties in components/compound.ts so the dotted names resolve in MDX.
8
+ interface Props {
9
+ variant?: 'compact' | 'table';
10
+ }
11
+ const { variant = 'compact' } = Astro.props as Props;
12
+ ---
13
+ <div class:list={['wd-color', `wd-color-${variant}`]}><slot /></div>
14
+ <script>
15
+ // Click (or Enter/Space) on a swatch copies the value currently shown -
16
+ // for a light/dark pair, the one matching the site's theme right now.
17
+ function initColorCopy(root: ParentNode) {
18
+ root.querySelectorAll<HTMLElement>('.wd-color-item[data-light]').forEach((item) => {
19
+ if (item.dataset.wdInit) return;
20
+ item.dataset.wdInit = 'true';
21
+ const copy = async () => {
22
+ const dark = document.documentElement.dataset.theme === 'dark';
23
+ const value = (dark ? item.dataset.dark : item.dataset.light) ?? '';
24
+ const label = item.querySelector<HTMLElement>('.wd-color-copied');
25
+ try {
26
+ await navigator.clipboard.writeText(value);
27
+ if (label) label.textContent = 'Copied';
28
+ } catch {
29
+ if (label) label.textContent = 'Copy failed';
30
+ }
31
+ setTimeout(() => label && (label.textContent = ''), 1200);
32
+ };
33
+ item.addEventListener('click', copy);
34
+ item.addEventListener('keydown', (e) => {
35
+ if (e.key === 'Enter' || e.key === ' ') {
36
+ e.preventDefault();
37
+ copy();
38
+ }
39
+ });
40
+ });
41
+ }
42
+ initColorCopy(document);
43
+ document.addEventListener('astro:page-load', () => initColorCopy(document));
44
+ </script>
45
+ <style>
46
+ .wd-color {
47
+ margin: 1.25rem 0;
48
+ }
49
+ .wd-color-compact {
50
+ display: grid;
51
+ grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
52
+ gap: 1rem;
53
+ }
54
+ .wd-color-table {
55
+ display: flex;
56
+ flex-direction: column;
57
+ border: 1px solid var(--wd-border);
58
+ border-radius: 0.6rem;
59
+ overflow: hidden;
60
+ }
61
+ </style>
@@ -0,0 +1,93 @@
1
+ ---
2
+ // Mintlify's <Color.Item name="..." value="..."> - one swatch. `value` is
3
+ // any CSS color, or { light, dark } for a theme-aware pair: the swatch and
4
+ // the value text switch with the site's theme toggle ([data-theme] on
5
+ // <html>), via the two custom properties below. Click copies the value
6
+ // (Color.astro's script).
7
+ interface Props {
8
+ name?: string;
9
+ value?: string | { light: string; dark: string };
10
+ }
11
+ const { name, value } = Astro.props as Props;
12
+ const light = typeof value === 'string' ? value : value?.light;
13
+ const dark = typeof value === 'string' ? value : value?.dark;
14
+ const themed = typeof value === 'object' && value !== null && light !== dark;
15
+ const style = light ? `--wd-swatch-light: ${light}; --wd-swatch-dark: ${dark ?? light}` : undefined;
16
+ ---
17
+ <div
18
+ class="wd-color-item"
19
+ data-light={light}
20
+ data-dark={dark}
21
+ role={light ? 'button' : undefined}
22
+ tabindex={light ? 0 : undefined}
23
+ title={light ? 'Copy value' : undefined}
24
+ style={style}
25
+ >
26
+ <div class="wd-color-swatch"></div>
27
+ <div class="wd-color-name">{name}</div>
28
+ {light && (
29
+ <div class="wd-color-value">
30
+ {themed ? (
31
+ <>
32
+ <span class="wd-color-value-light">{light}</span>
33
+ <span class="wd-color-value-dark">{dark}</span>
34
+ </>
35
+ ) : (
36
+ light
37
+ )}
38
+ <span class="wd-color-copied" aria-live="polite"></span>
39
+ </div>
40
+ )}
41
+ </div>
42
+ <style>
43
+ .wd-color-item {
44
+ min-width: 0;
45
+ }
46
+ .wd-color-item[role='button'] {
47
+ cursor: pointer;
48
+ }
49
+ /* A checkerboard under the swatch, so a translucent color (rgba, hsla)
50
+ reads as translucent rather than as a lighter solid. */
51
+ .wd-color-swatch {
52
+ height: 3.5rem;
53
+ border: 1px solid var(--wd-border);
54
+ border-radius: 0.5rem;
55
+ background:
56
+ linear-gradient(var(--wd-swatch-light, transparent), var(--wd-swatch-light, transparent)),
57
+ repeating-conic-gradient(var(--wd-surface) 0% 25%, var(--wd-background) 0% 50%) 0 0 / 12px 12px;
58
+ }
59
+ :global([data-theme='dark']) .wd-color-swatch {
60
+ background:
61
+ linear-gradient(var(--wd-swatch-dark, transparent), var(--wd-swatch-dark, transparent)),
62
+ repeating-conic-gradient(var(--wd-surface) 0% 25%, var(--wd-background) 0% 50%) 0 0 / 12px 12px;
63
+ }
64
+ .wd-color-item[role='button']:hover .wd-color-swatch,
65
+ .wd-color-item[role='button']:focus-visible .wd-color-swatch {
66
+ border-color: var(--wd-primary);
67
+ }
68
+ .wd-color-name {
69
+ margin-top: 0.4rem;
70
+ font-size: 0.85rem;
71
+ font-weight: 600;
72
+ overflow-wrap: anywhere;
73
+ }
74
+ .wd-color-value {
75
+ font-family: monospace;
76
+ font-size: 0.75rem;
77
+ color: var(--wd-text-muted);
78
+ overflow-wrap: anywhere;
79
+ }
80
+ .wd-color-value-dark {
81
+ display: none;
82
+ }
83
+ :global([data-theme='dark']) .wd-color-value-light {
84
+ display: none;
85
+ }
86
+ :global([data-theme='dark']) .wd-color-value-dark {
87
+ display: inline;
88
+ }
89
+ .wd-color-copied {
90
+ margin-left: 0.35rem;
91
+ color: var(--wd-primary);
92
+ }
93
+ </style>
@@ -0,0 +1,39 @@
1
+ ---
2
+ // Mintlify's <Color.Row title="..."> - one titled row inside
3
+ // <Color variant="table">. `title` takes inline Markdown.
4
+ import { inlineMarkdown } from '../lib/inline-markdown.js';
5
+ interface Props {
6
+ title?: string;
7
+ }
8
+ const { title } = Astro.props as Props;
9
+ ---
10
+ <div class="wd-color-row">
11
+ <div class="wd-color-row-title" set:html={inlineMarkdown(title ?? '')} />
12
+ <div class="wd-color-row-items"><slot /></div>
13
+ </div>
14
+ <style>
15
+ .wd-color-row {
16
+ display: grid;
17
+ grid-template-columns: 9rem minmax(0, 1fr);
18
+ gap: 1rem;
19
+ align-items: center;
20
+ padding: 1rem;
21
+ }
22
+ .wd-color-row + .wd-color-row {
23
+ border-top: 1px solid var(--wd-border);
24
+ }
25
+ .wd-color-row-title {
26
+ font-weight: 600;
27
+ font-size: 0.9rem;
28
+ }
29
+ .wd-color-row-items {
30
+ display: grid;
31
+ grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
32
+ gap: 1rem;
33
+ }
34
+ @media (max-width: 640px) {
35
+ .wd-color-row {
36
+ grid-template-columns: minmax(0, 1fr);
37
+ }
38
+ }
39
+ </style>