@zeropress/build-pages 0.6.1 → 0.6.2
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/README.md +42 -15
- package/action.yml +3 -0
- package/dist/action.js +225 -7
- package/dist/prebuild.js +23 -2
- package/package.json +2 -2
- package/schemas/zeropress-build-pages.config.v0.1.schema.json +7 -0
- package/src/action.js +1 -0
- package/src/index.js +154 -3
- package/src/prebuild.js +30 -2
- package/themes/docs/assets/style.css +212 -0
- package/themes/docs/assets/theme.js +121 -0
- package/themes/docs/layout.html +19 -3
- package/themes/docs/page.html +2 -2
- package/themes/docs/partials/theme-scripts.html +1 -0
- package/themes/docs/post.html +1 -1
- package/themes/docs/theme.json +2 -3
|
@@ -56,6 +56,12 @@
|
|
|
56
56
|
"description": "Whether generated HTML should expose the ZeroPress generator meta tag. Set false for white-label sites.",
|
|
57
57
|
"markdownDescription": "Whether generated HTML should expose `<meta name=\"generator\" content=\"ZeroPress\">`. Set `false` for white-label sites."
|
|
58
58
|
},
|
|
59
|
+
"search": {
|
|
60
|
+
"type": "boolean",
|
|
61
|
+
"default": true,
|
|
62
|
+
"description": "Whether native ZeroPress search should be enabled when the selected theme supports search UI. Set false to omit native search artifacts and hide theme search UI.",
|
|
63
|
+
"markdownDescription": "Whether native ZeroPress search should be enabled when the selected theme supports search UI. Set `false` to omit native search artifacts and hide theme search UI."
|
|
64
|
+
},
|
|
59
65
|
"indexing": {
|
|
60
66
|
"type": "boolean",
|
|
61
67
|
"default": true,
|
|
@@ -292,6 +298,7 @@
|
|
|
292
298
|
"description": "Public documentation.",
|
|
293
299
|
"url": "https://zeropress.dev",
|
|
294
300
|
"expose_generator": true,
|
|
301
|
+
"search": true,
|
|
295
302
|
"indexing": true
|
|
296
303
|
},
|
|
297
304
|
"front_page": {
|
package/src/action.js
CHANGED
package/src/index.js
CHANGED
|
@@ -39,6 +39,8 @@ export async function runBuildPages(options) {
|
|
|
39
39
|
const cwd = path.resolve(options.cwd || process.cwd());
|
|
40
40
|
const copyMarkdownSource = options.copyMarkdownSource !== false;
|
|
41
41
|
const sourceDir = path.resolve(cwd, options.source);
|
|
42
|
+
const publicDirExplicit = hasExplicitPublicDir(options);
|
|
43
|
+
const publicDir = publicDirExplicit ? path.resolve(cwd, options.publicDir) : sourceDir;
|
|
42
44
|
const destinationDir = path.resolve(cwd, options.destination);
|
|
43
45
|
const generatedDir = path.join(cwd, '.zeropress');
|
|
44
46
|
const stagingDir = path.join(cwd, STAGING_DIR);
|
|
@@ -48,18 +50,23 @@ export async function runBuildPages(options) {
|
|
|
48
50
|
assertBuildPagesPathLayout({
|
|
49
51
|
cwd,
|
|
50
52
|
sourceDir,
|
|
53
|
+
publicDir,
|
|
54
|
+
publicDirExplicit,
|
|
51
55
|
destinationDir,
|
|
52
56
|
themeDir,
|
|
53
57
|
generatedDir,
|
|
54
58
|
});
|
|
55
59
|
await assertDirectory(sourceDir, 'Source directory');
|
|
60
|
+
await assertPublicDirectory(publicDir, publicDirExplicit);
|
|
61
|
+
await assertDestinationPath(destinationDir);
|
|
56
62
|
await fs.rm(generatedDir, { recursive: true, force: true });
|
|
57
63
|
await fs.mkdir(generatedDir, { recursive: true });
|
|
58
64
|
|
|
59
65
|
const env = {
|
|
60
66
|
...process.env,
|
|
61
67
|
ZEROPRESS_BUILD_PAGES_SOURCE: sourceDir,
|
|
62
|
-
|
|
68
|
+
ZEROPRESS_BUILD_PAGES_PUBLIC_DIR: publicDir,
|
|
69
|
+
ZEROPRESS_PUBLIC_DIR: publicDir,
|
|
63
70
|
ZEROPRESS_SKIP_UNTITLED_MARKDOWN: String(Boolean(options.skipUntitledMarkdown)),
|
|
64
71
|
ZEROPRESS_COPY_MARKDOWN_SOURCE: String(copyMarkdownSource),
|
|
65
72
|
};
|
|
@@ -85,10 +92,13 @@ export async function runBuildPages(options) {
|
|
|
85
92
|
await fs.rm(destinationDir, { recursive: true, force: true });
|
|
86
93
|
await fs.rm(stagingDir, { recursive: true, force: true });
|
|
87
94
|
await fs.mkdir(stagingDir, { recursive: true });
|
|
88
|
-
await copyPublicStaging(
|
|
95
|
+
await copyPublicStaging(publicDir, stagingDir, {
|
|
89
96
|
excludePaths: [destinationDir, themeDir, generatedDir],
|
|
90
97
|
copyMarkdownSource,
|
|
91
98
|
});
|
|
99
|
+
if (copyMarkdownSource) {
|
|
100
|
+
await copySourceMarkdownFiles(sourceDir, stagingDir, previewData);
|
|
101
|
+
}
|
|
92
102
|
|
|
93
103
|
const previousPublicDir = process.env.ZEROPRESS_PUBLIC_DIR;
|
|
94
104
|
process.env.ZEROPRESS_PUBLIC_DIR = stagingDir;
|
|
@@ -137,6 +147,7 @@ export function parseArgs(argv) {
|
|
|
137
147
|
|
|
138
148
|
const valueOptions = new Set([
|
|
139
149
|
'--source',
|
|
150
|
+
'--public-dir',
|
|
140
151
|
'--destination',
|
|
141
152
|
'--theme',
|
|
142
153
|
'--theme-path',
|
|
@@ -167,6 +178,7 @@ export function parseArgs(argv) {
|
|
|
167
178
|
|
|
168
179
|
return {
|
|
169
180
|
source,
|
|
181
|
+
publicDir: flags['public-dir'] || '',
|
|
170
182
|
destination,
|
|
171
183
|
theme: flags.theme || DEFAULT_THEME,
|
|
172
184
|
themePath: flags['theme-path'] || '',
|
|
@@ -186,6 +198,7 @@ Usage:
|
|
|
186
198
|
|
|
187
199
|
Options:
|
|
188
200
|
--source <dir> Dedicated source directory (required)
|
|
201
|
+
--public-dir <dir> Public passthrough directory (default: source)
|
|
189
202
|
--destination <dir> Output directory (required)
|
|
190
203
|
--theme docs Bundled theme name (default: docs)
|
|
191
204
|
--theme-path <dir> Custom ZeroPress theme directory
|
|
@@ -208,6 +221,10 @@ function resolveThemeDir(cwd, options) {
|
|
|
208
221
|
throw new Error(`Unknown bundled theme: ${options.theme}`);
|
|
209
222
|
}
|
|
210
223
|
|
|
224
|
+
function hasExplicitPublicDir(options) {
|
|
225
|
+
return typeof options.publicDir === 'string' && Boolean(options.publicDir.trim());
|
|
226
|
+
}
|
|
227
|
+
|
|
211
228
|
async function assertDirectory(dir, label) {
|
|
212
229
|
let stat;
|
|
213
230
|
try {
|
|
@@ -223,7 +240,55 @@ async function assertDirectory(dir, label) {
|
|
|
223
240
|
}
|
|
224
241
|
}
|
|
225
242
|
|
|
226
|
-
function
|
|
243
|
+
async function assertPublicDirectory(publicDir, explicit) {
|
|
244
|
+
if (!explicit) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
let stat;
|
|
249
|
+
try {
|
|
250
|
+
stat = await fs.lstat(publicDir);
|
|
251
|
+
} catch (error) {
|
|
252
|
+
if (error?.code === 'ENOENT') {
|
|
253
|
+
throw new Error(`Public directory not found: ${publicDir}`);
|
|
254
|
+
}
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (stat.isSymbolicLink()) {
|
|
259
|
+
throw new Error(`Public directory must not be a symbolic link: ${publicDir}`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (!stat.isDirectory()) {
|
|
263
|
+
throw new Error(`Public path is not a directory: ${publicDir}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function assertDestinationPath(destinationDir) {
|
|
268
|
+
let stat;
|
|
269
|
+
try {
|
|
270
|
+
stat = await fs.lstat(destinationDir);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
if (error?.code === 'ENOENT') {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (!stat.isDirectory()) {
|
|
279
|
+
throw new Error(`Destination path is not a directory: ${destinationDir}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function assertBuildPagesPathLayout({
|
|
284
|
+
cwd,
|
|
285
|
+
sourceDir,
|
|
286
|
+
publicDir,
|
|
287
|
+
publicDirExplicit,
|
|
288
|
+
destinationDir,
|
|
289
|
+
themeDir,
|
|
290
|
+
generatedDir,
|
|
291
|
+
}) {
|
|
227
292
|
if (samePath(sourceDir, cwd)) {
|
|
228
293
|
throw new Error(
|
|
229
294
|
'Source directory must be a dedicated content directory, not the current working directory. '
|
|
@@ -231,11 +296,36 @@ function assertBuildPagesPathLayout({ cwd, sourceDir, destinationDir, themeDir,
|
|
|
231
296
|
);
|
|
232
297
|
}
|
|
233
298
|
|
|
299
|
+
if (publicDirExplicit && samePath(publicDir, cwd)) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
'Public directory must be a dedicated asset directory, not the current working directory. '
|
|
302
|
+
+ `Received: ${formatPath(cwd, publicDir)}`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
234
306
|
assertNoPathOverlap(cwd, 'Source directory', sourceDir, 'internal .zeropress working directory', generatedDir);
|
|
235
307
|
assertNoPathOverlap(cwd, 'Destination directory', destinationDir, 'internal .zeropress working directory', generatedDir);
|
|
236
308
|
assertNoPathOverlap(cwd, 'Theme directory', themeDir, 'internal .zeropress working directory', generatedDir);
|
|
309
|
+
if (!samePath(publicDir, sourceDir)) {
|
|
310
|
+
assertNoPathOverlap(cwd, 'Public directory', publicDir, 'internal .zeropress working directory', generatedDir);
|
|
311
|
+
assertNoPathOverlap(cwd, 'Public directory', publicDir, 'destination directory', destinationDir);
|
|
312
|
+
assertNoPathOverlap(cwd, 'Public directory', publicDir, 'theme directory', themeDir);
|
|
313
|
+
}
|
|
237
314
|
assertNoPathOverlap(cwd, 'Source directory', sourceDir, 'destination directory', destinationDir);
|
|
238
315
|
assertNoPathOverlap(cwd, 'Source directory', sourceDir, 'theme directory', themeDir);
|
|
316
|
+
assertSourceIsNotInsidePublicDirectory(cwd, sourceDir, publicDir);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function assertSourceIsNotInsidePublicDirectory(cwd, sourceDir, publicDir) {
|
|
320
|
+
if (samePath(sourceDir, publicDir) || !isPathInside(publicDir, sourceDir)) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
throw new Error(
|
|
325
|
+
'Source directory must not be inside the public directory. '
|
|
326
|
+
+ `Source directory: ${formatPath(cwd, sourceDir)}; `
|
|
327
|
+
+ `Public directory: ${formatPath(cwd, publicDir)}`,
|
|
328
|
+
);
|
|
239
329
|
}
|
|
240
330
|
|
|
241
331
|
function assertNoPathOverlap(cwd, firstLabel, firstPath, secondLabel, secondPath) {
|
|
@@ -282,6 +372,67 @@ async function copyPublicStaging(sourceDir, targetDir, options) {
|
|
|
282
372
|
}
|
|
283
373
|
}
|
|
284
374
|
|
|
375
|
+
async function copySourceMarkdownFiles(sourceDir, targetDir, previewData) {
|
|
376
|
+
const markdownUrls = new Set();
|
|
377
|
+
|
|
378
|
+
for (const page of previewData?.content?.pages || []) {
|
|
379
|
+
const sourceMarkdownUrl = page?.meta?.source_markdown_url;
|
|
380
|
+
if (typeof sourceMarkdownUrl === 'string' && sourceMarkdownUrl) {
|
|
381
|
+
markdownUrls.add(sourceMarkdownUrl);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
for (const sourceMarkdownUrl of markdownUrls) {
|
|
386
|
+
const relativePath = sourceMarkdownUrlToRelativePath(sourceMarkdownUrl);
|
|
387
|
+
if (!relativePath) {
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const sourcePath = path.join(sourceDir, relativePath);
|
|
392
|
+
if (!isPathInside(sourceDir, sourcePath)) {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const targetPath = path.join(targetDir, relativePath);
|
|
397
|
+
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
398
|
+
await fs.copyFile(sourcePath, targetPath);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function sourceMarkdownUrlToRelativePath(sourceMarkdownUrl) {
|
|
403
|
+
if (
|
|
404
|
+
!sourceMarkdownUrl.startsWith('/')
|
|
405
|
+
|| sourceMarkdownUrl.includes('?')
|
|
406
|
+
|| sourceMarkdownUrl.includes('#')
|
|
407
|
+
) {
|
|
408
|
+
return '';
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const rawSegments = sourceMarkdownUrl.slice(1).split('/');
|
|
412
|
+
const segments = [];
|
|
413
|
+
for (const rawSegment of rawSegments) {
|
|
414
|
+
if (!rawSegment) {
|
|
415
|
+
return '';
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
let segment;
|
|
419
|
+
try {
|
|
420
|
+
segment = decodeURIComponent(rawSegment);
|
|
421
|
+
} catch {
|
|
422
|
+
return '';
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (!segment || segment === '.' || segment === '..' || segment.includes('/') || segment.includes('\\')) {
|
|
426
|
+
return '';
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
segments.push(segment);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const relativePath = segments.join('/');
|
|
433
|
+
return relativePath.toLowerCase().endsWith('.md') ? relativePath : '';
|
|
434
|
+
}
|
|
435
|
+
|
|
285
436
|
function shouldIgnorePublicEntry(name) {
|
|
286
437
|
const basename = String(name || '');
|
|
287
438
|
const lowerName = basename.toLowerCase();
|
package/src/prebuild.js
CHANGED
|
@@ -6,6 +6,7 @@ import matter from 'gray-matter';
|
|
|
6
6
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
const rootDir = process.cwd();
|
|
8
8
|
const sourceDir = resolveEnvPath(['ZEROPRESS_BUILD_PAGES_SOURCE'], 'docs');
|
|
9
|
+
const publicDir = resolveEnvPath(['ZEROPRESS_BUILD_PAGES_PUBLIC_DIR'], sourceDir);
|
|
9
10
|
const defaultConfigPath = path.join(sourceDir, '.zeropress', 'config.json');
|
|
10
11
|
const configPath = resolveOptionalEnvPath(['ZEROPRESS_BUILD_PAGES_CONFIG'], defaultConfigPath);
|
|
11
12
|
const outDir = path.join(rootDir, '.zeropress');
|
|
@@ -22,6 +23,7 @@ const FRONT_MATTER_DATA_MAX_DEPTH = 4;
|
|
|
22
23
|
const FRONT_MATTER_DATA_MAX_KEYS = 64;
|
|
23
24
|
const FRONT_MATTER_DATA_MAX_ARRAY_LENGTH = 256;
|
|
24
25
|
const FRONT_MATTER_DISCOVERABILITY_VALUES = new Set(['default', 'noindex', 'delist']);
|
|
26
|
+
const markdownDiscoverExcludeRoots = buildMarkdownDiscoverExcludeRoots();
|
|
25
27
|
|
|
26
28
|
class PrebuildMarkdownError extends Error {
|
|
27
29
|
constructor(sourcePath, reason, expected = '', code = 'invalid_markdown') {
|
|
@@ -243,6 +245,7 @@ function buildSiteData(config, frontPage) {
|
|
|
243
245
|
},
|
|
244
246
|
disallow_comments: true,
|
|
245
247
|
expose_generator: configuredSite.expose_generator !== false,
|
|
248
|
+
search: configuredSite.search !== false,
|
|
246
249
|
indexing: configuredSite.indexing !== false,
|
|
247
250
|
};
|
|
248
251
|
|
|
@@ -278,12 +281,13 @@ function normalizeSiteConfig(value) {
|
|
|
278
281
|
}
|
|
279
282
|
|
|
280
283
|
const configuredSite = isPlainObject(value) ? value : {};
|
|
281
|
-
assertKnownConfigKeys(configuredSite, ['title', 'description', 'url', 'expose_generator', 'indexing', 'footer'], 'site');
|
|
284
|
+
assertKnownConfigKeys(configuredSite, ['title', 'description', 'url', 'expose_generator', 'search', 'indexing', 'footer'], 'site');
|
|
282
285
|
const site = {
|
|
283
286
|
title: readConfigString(configuredSite.title, 'Documentation'),
|
|
284
287
|
description: readConfigString(configuredSite.description, 'A documentation site.'),
|
|
285
288
|
url: readEnv('ZEROPRESS_SITE_URL', readConfigString(configuredSite.url, '')),
|
|
286
289
|
expose_generator: readConfigBoolean(configuredSite.expose_generator, true, 'site.expose_generator'),
|
|
290
|
+
search: readConfigBoolean(configuredSite.search, true, 'site.search'),
|
|
287
291
|
indexing: readConfigBoolean(configuredSite.indexing, true, 'site.indexing'),
|
|
288
292
|
};
|
|
289
293
|
|
|
@@ -760,6 +764,7 @@ function buildPrebuildReport({
|
|
|
760
764
|
return {
|
|
761
765
|
generated_at: new Date().toISOString(),
|
|
762
766
|
source_dir: formatSourcePath(sourceDir),
|
|
767
|
+
public_dir: formatSourcePath(publicDir),
|
|
763
768
|
config_path: formatSourcePath(configPath),
|
|
764
769
|
build_pages_config_path: formatSourcePath(buildPagesConfigPath),
|
|
765
770
|
preview_data_path: formatSourcePath(previewDataPath),
|
|
@@ -786,7 +791,8 @@ function buildPrebuildReport({
|
|
|
786
791
|
function printPrebuildSummary(report) {
|
|
787
792
|
const lines = [
|
|
788
793
|
'ZeroPress build report',
|
|
789
|
-
`-
|
|
794
|
+
`- Source root: ${report.source_dir}`,
|
|
795
|
+
`- Public root: ${report.public_dir}`,
|
|
790
796
|
`- Markdown discovered: ${report.markdown.discovered}`,
|
|
791
797
|
`- Markdown pages generated: ${report.markdown.generated_pages}`,
|
|
792
798
|
`- Markdown skipped: ${report.markdown.skipped}`,
|
|
@@ -1134,6 +1140,10 @@ async function listMarkdownFiles(dir) {
|
|
|
1134
1140
|
}
|
|
1135
1141
|
|
|
1136
1142
|
const entryPath = path.join(dir, entry.name);
|
|
1143
|
+
if (isMarkdownDiscoverExcluded(entryPath)) {
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1137
1147
|
if (entry.isDirectory()) {
|
|
1138
1148
|
files.push(...await listMarkdownFiles(entryPath));
|
|
1139
1149
|
continue;
|
|
@@ -1147,6 +1157,24 @@ async function listMarkdownFiles(dir) {
|
|
|
1147
1157
|
return files.sort((left, right) => left.localeCompare(right));
|
|
1148
1158
|
}
|
|
1149
1159
|
|
|
1160
|
+
function buildMarkdownDiscoverExcludeRoots() {
|
|
1161
|
+
if (samePath(sourceDir, publicDir) || !isPathInside(sourceDir, publicDir)) {
|
|
1162
|
+
return [];
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
return [publicDir];
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
function isMarkdownDiscoverExcluded(entryPath) {
|
|
1169
|
+
return markdownDiscoverExcludeRoots.some((excludeRoot) => (
|
|
1170
|
+
samePath(entryPath, excludeRoot) || isPathInside(excludeRoot, entryPath)
|
|
1171
|
+
));
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
function samePath(firstPath, secondPath) {
|
|
1175
|
+
return path.resolve(firstPath) === path.resolve(secondPath);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1150
1178
|
function shouldIgnoreMarkdownDiscoverEntry(name) {
|
|
1151
1179
|
const basename = String(name || '');
|
|
1152
1180
|
const lowerName = basename.toLowerCase();
|
|
@@ -12,6 +12,15 @@
|
|
|
12
12
|
--prose-ink: #344054;
|
|
13
13
|
--pre-bg: #101828;
|
|
14
14
|
--pre-ink: #f8fafc;
|
|
15
|
+
--syntax-comment: #98a2b3;
|
|
16
|
+
--syntax-keyword: #f472b6;
|
|
17
|
+
--syntax-title: #93c5fd;
|
|
18
|
+
--syntax-string: #86efac;
|
|
19
|
+
--syntax-number: #fbbf24;
|
|
20
|
+
--syntax-attr: #67e8f9;
|
|
21
|
+
--syntax-built-in: #c4b5fd;
|
|
22
|
+
--syntax-deletion: #fca5a5;
|
|
23
|
+
--syntax-addition: #bbf7d0;
|
|
15
24
|
--button-ink: #ffffff;
|
|
16
25
|
--alert-note: #2563eb;
|
|
17
26
|
--alert-tip: #059669;
|
|
@@ -99,12 +108,31 @@ a {
|
|
|
99
108
|
gap: 1.5rem;
|
|
100
109
|
}
|
|
101
110
|
|
|
111
|
+
.visually-hidden {
|
|
112
|
+
position: absolute;
|
|
113
|
+
width: 1px;
|
|
114
|
+
height: 1px;
|
|
115
|
+
padding: 0;
|
|
116
|
+
overflow: hidden;
|
|
117
|
+
clip: rect(0, 0, 0, 0);
|
|
118
|
+
white-space: nowrap;
|
|
119
|
+
border: 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
102
122
|
.brand {
|
|
103
123
|
color: var(--ink);
|
|
104
124
|
font-weight: 750;
|
|
105
125
|
text-decoration: none;
|
|
106
126
|
}
|
|
107
127
|
|
|
128
|
+
.site-header__actions {
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
justify-content: flex-end;
|
|
132
|
+
gap: 1rem;
|
|
133
|
+
min-width: 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
108
136
|
.site-nav ul {
|
|
109
137
|
list-style: none;
|
|
110
138
|
margin: 0;
|
|
@@ -129,6 +157,109 @@ a {
|
|
|
129
157
|
color: var(--accent);
|
|
130
158
|
}
|
|
131
159
|
|
|
160
|
+
.site-search {
|
|
161
|
+
position: relative;
|
|
162
|
+
width: min(22rem, 34vw);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.site-search__form {
|
|
166
|
+
display: flex;
|
|
167
|
+
align-items: center;
|
|
168
|
+
gap: 0.4rem;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.site-search__input {
|
|
172
|
+
min-width: 0;
|
|
173
|
+
width: 100%;
|
|
174
|
+
height: 2.35rem;
|
|
175
|
+
padding: 0 0.75rem;
|
|
176
|
+
border: 1px solid var(--line);
|
|
177
|
+
border-radius: 6px;
|
|
178
|
+
background: var(--surface);
|
|
179
|
+
color: var(--ink);
|
|
180
|
+
font: inherit;
|
|
181
|
+
font-size: 0.92rem;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.site-search__input:focus {
|
|
185
|
+
border-color: var(--accent);
|
|
186
|
+
outline: 2px solid color-mix(in srgb, var(--accent) 22%, transparent);
|
|
187
|
+
outline-offset: 1px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.site-search__button {
|
|
191
|
+
height: 2.35rem;
|
|
192
|
+
padding: 0 0.75rem;
|
|
193
|
+
border: 0;
|
|
194
|
+
border-radius: 6px;
|
|
195
|
+
background: var(--accent);
|
|
196
|
+
color: var(--button-ink);
|
|
197
|
+
font: inherit;
|
|
198
|
+
font-size: 0.88rem;
|
|
199
|
+
font-weight: 750;
|
|
200
|
+
cursor: pointer;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.site-search__panel {
|
|
204
|
+
position: absolute;
|
|
205
|
+
top: calc(100% + 0.55rem);
|
|
206
|
+
right: 0;
|
|
207
|
+
width: min(31rem, calc(100vw - 2rem));
|
|
208
|
+
max-height: min(31rem, calc(100vh - 6rem));
|
|
209
|
+
overflow: auto;
|
|
210
|
+
padding: 0.85rem;
|
|
211
|
+
border: 1px solid var(--line);
|
|
212
|
+
border-radius: var(--radius);
|
|
213
|
+
background: var(--surface);
|
|
214
|
+
box-shadow: 0 20px 45px rgb(15 23 42 / 18%);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.site-search__status {
|
|
218
|
+
margin: 0 0 0.75rem;
|
|
219
|
+
color: var(--muted);
|
|
220
|
+
font-size: 0.86rem;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.site-search__results {
|
|
224
|
+
list-style: none;
|
|
225
|
+
margin: 0;
|
|
226
|
+
padding: 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.site-search__results li + li {
|
|
230
|
+
margin-top: 0.65rem;
|
|
231
|
+
padding-top: 0.65rem;
|
|
232
|
+
border-top: 1px solid var(--line);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.site-search__results a {
|
|
236
|
+
display: inline-block;
|
|
237
|
+
color: var(--ink);
|
|
238
|
+
font-weight: 750;
|
|
239
|
+
text-decoration: none;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.site-search__results a:hover {
|
|
243
|
+
color: var(--accent);
|
|
244
|
+
text-decoration: underline;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.site-search__results span {
|
|
248
|
+
display: block;
|
|
249
|
+
margin-top: 0.1rem;
|
|
250
|
+
color: var(--accent);
|
|
251
|
+
font-size: 0.75rem;
|
|
252
|
+
font-weight: 750;
|
|
253
|
+
text-transform: uppercase;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.site-search__results p {
|
|
257
|
+
margin: 0.25rem 0 0;
|
|
258
|
+
color: var(--muted);
|
|
259
|
+
font-size: 0.88rem;
|
|
260
|
+
line-height: 1.45;
|
|
261
|
+
}
|
|
262
|
+
|
|
132
263
|
.hero {
|
|
133
264
|
background: var(--surface);
|
|
134
265
|
border-bottom: 1px solid var(--line);
|
|
@@ -372,6 +503,71 @@ h1 {
|
|
|
372
503
|
padding: 0;
|
|
373
504
|
}
|
|
374
505
|
|
|
506
|
+
.prose pre code.hljs {
|
|
507
|
+
color: var(--pre-ink);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.prose .hljs-comment,
|
|
511
|
+
.prose .hljs-quote {
|
|
512
|
+
color: var(--syntax-comment);
|
|
513
|
+
font-style: italic;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
.prose .hljs-keyword,
|
|
517
|
+
.prose .hljs-selector-tag,
|
|
518
|
+
.prose .hljs-subst {
|
|
519
|
+
color: var(--syntax-keyword);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.prose .hljs-title,
|
|
523
|
+
.prose .hljs-section,
|
|
524
|
+
.prose .hljs-name,
|
|
525
|
+
.prose .hljs-selector-id,
|
|
526
|
+
.prose .hljs-selector-class {
|
|
527
|
+
color: var(--syntax-title);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.prose .hljs-string,
|
|
531
|
+
.prose .hljs-regexp,
|
|
532
|
+
.prose .hljs-symbol,
|
|
533
|
+
.prose .hljs-bullet {
|
|
534
|
+
color: var(--syntax-string);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.prose .hljs-number,
|
|
538
|
+
.prose .hljs-literal {
|
|
539
|
+
color: var(--syntax-number);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.prose .hljs-attr,
|
|
543
|
+
.prose .hljs-attribute,
|
|
544
|
+
.prose .hljs-variable,
|
|
545
|
+
.prose .hljs-template-variable {
|
|
546
|
+
color: var(--syntax-attr);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
.prose .hljs-built_in,
|
|
550
|
+
.prose .hljs-type,
|
|
551
|
+
.prose .hljs-class .hljs-title {
|
|
552
|
+
color: var(--syntax-built-in);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.prose .hljs-deletion {
|
|
556
|
+
color: var(--syntax-deletion);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.prose .hljs-addition {
|
|
560
|
+
color: var(--syntax-addition);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
.prose .hljs-emphasis {
|
|
564
|
+
font-style: italic;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.prose .hljs-strong {
|
|
568
|
+
font-weight: 800;
|
|
569
|
+
}
|
|
570
|
+
|
|
375
571
|
.prose table {
|
|
376
572
|
display: block;
|
|
377
573
|
width: 100%;
|
|
@@ -544,10 +740,26 @@ h1, h2, h3, h4, h5, h6 {
|
|
|
544
740
|
padding: 1rem 0;
|
|
545
741
|
}
|
|
546
742
|
|
|
743
|
+
.site-header__actions {
|
|
744
|
+
width: 100%;
|
|
745
|
+
align-items: stretch;
|
|
746
|
+
flex-direction: column;
|
|
747
|
+
}
|
|
748
|
+
|
|
547
749
|
.site-nav ul {
|
|
548
750
|
justify-content: flex-start;
|
|
549
751
|
}
|
|
550
752
|
|
|
753
|
+
.site-search {
|
|
754
|
+
width: 100%;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
.site-search__panel {
|
|
758
|
+
left: 0;
|
|
759
|
+
right: auto;
|
|
760
|
+
width: 100%;
|
|
761
|
+
}
|
|
762
|
+
|
|
551
763
|
.docs-grid,
|
|
552
764
|
.npm-links,
|
|
553
765
|
.doc-layout,
|