@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 +13 -0
- package/bin/writedocs.js +167 -139
- package/package.json +2 -1
- package/src/components/AppIcon.astro +14 -2
- package/src/components/Color.astro +61 -0
- package/src/components/ColorItem.astro +93 -0
- package/src/components/ColorRow.astro +39 -0
- package/src/components/GitHubRepo.astro +156 -0
- package/src/components/Panel.astro +11 -0
- package/src/components/Prompt.astro +143 -0
- package/src/components/Tile.astro +65 -0
- package/src/components/Tree.astro +213 -0
- package/src/components/TreeFile.astro +17 -0
- package/src/components/TreeFolder.astro +28 -0
- package/src/components/Update.astro +171 -0
- package/src/components/View.astro +214 -0
- package/src/components/Visibility.astro +11 -0
- package/src/components/compound.ts +21 -0
- package/src/components/index.ts +7 -0
- package/src/content.config.ts +6 -127
- package/src/lib/config-schema.js +124 -0
- package/src/lib/config-schema.ts +1574 -1437
- package/src/lib/config.ts +7 -140
- package/src/lib/content-check.js +232 -0
- package/src/lib/icons.js +109 -0
- package/src/lib/inline-markdown.js +29 -0
- package/src/lib/mdx-inject-builtins.js +16 -3
- package/src/lib/mdx-mintlify.js +99 -0
- package/src/lib/mdx-title-anchor-ids.js +7 -2
- package/src/lib/mdx-unknown-components.js +96 -0
- package/src/lib/pages.js +78 -0
- package/src/lib/visibility.js +29 -0
- package/src/pages/[...slug].astro +23 -1
- package/src/pages/[...slug].md.ts +4 -1
- package/src/pages/llms-full.txt.ts +3 -1
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
|
|
87
|
-
.argument('[dir]', 'content directory (contains writedocs.json)', '.')
|
|
88
|
-
.
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
console.error(
|
|
113
|
-
console.error(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
console.error(
|
|
119
|
-
console.error(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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.
|
|
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
|
-
|
|
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>
|