@jianwen-lang/parser 0.1.2 → 0.1.3

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 CHANGED
@@ -100,6 +100,34 @@ const { ast, errors } = parseJianwenWithErrors(source, {
100
100
  - `renderJianwenToHtmlDocument(source, options?) => { html; ast; errors }`
101
101
  - `renderJianwenToHtmlDocumentWithBlockMap(source, options?) => { html; ast; errors; groups }`
102
102
  - `buildHtmlDocument(bodyHtml, options?) => string`
103
+ - `composeThemeCss(options?) => string`(`preset: 'default' | 'none'`,支持 `theme` token 对象与 `extraCss` 追加覆盖)
104
+ - `renderThemeTokenCss(theme) => string`
105
+ - `JIANWEN_THEME_TOKEN_KEYS` / `JianwenThemeConfig` / `JianwenThemeTokenValues`
106
+
107
+ ## 主题对象(Token)注入
108
+
109
+ `JianwenThemeConfig` 支持局部覆盖:`light` / `dark` 可只写需要改动的 token,未提供项自动回退到默认主题。
110
+
111
+ ```ts
112
+ import {
113
+ composeThemeCss,
114
+ } from '@jianwen-lang/parser';
115
+
116
+ const css = composeThemeCss({
117
+ preset: 'default',
118
+ theme: {
119
+ light: { '--jw-strong-color': '#0b766e' },
120
+ dark: { '--jw-strong-color': '#79e9dc' },
121
+ includeAutoDark: true,
122
+ },
123
+ });
124
+ ```
125
+
126
+ CLI 也支持通过 `--theme-file` 注入 JSON 文件(同样支持局部覆盖):
127
+
128
+ ```bash
129
+ jw-render input.jw --out out.html --theme-file ./theme.json
130
+ ```
103
131
 
104
132
  ## 规范与扩展
105
133
 
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.runRenderCli = runRenderCli;
37
37
  const fs = __importStar(require("fs"));
38
38
  const path = __importStar(require("path"));
39
+ const theme_1 = require("../html/theme/theme");
39
40
  const convert_1 = require("../html/convert");
40
41
  const TAB_WIDTH = 4;
41
42
  function isCombiningCodePoint(code) {
@@ -89,6 +90,7 @@ function parseCliArgs(argv) {
89
90
  let format = false;
90
91
  let includeCss = true;
91
92
  let cssHref;
93
+ let themeFilePath;
92
94
  let includeRuntime = false;
93
95
  let runtimeSrc;
94
96
  let includeComments = false;
@@ -128,6 +130,14 @@ function parseCliArgs(argv) {
128
130
  includeCss = true;
129
131
  continue;
130
132
  }
133
+ if (arg === '--theme-file') {
134
+ const value = args.shift();
135
+ if (!value)
136
+ throw new Error('Missing value for --theme-file');
137
+ themeFilePath = value;
138
+ includeCss = true;
139
+ continue;
140
+ }
131
141
  if (arg === '--runtime') {
132
142
  includeRuntime = true;
133
143
  continue;
@@ -157,6 +167,7 @@ Options:
157
167
  --format Beautify output HTML
158
168
  --no-css Do not inline CSS
159
169
  --css-href <href> Link CSS instead of inlining
170
+ --theme-file <path> Load Jianwen theme token JSON for CSS generation
160
171
  --runtime Append runtime <script> tag (default src: ${convert_1.DEFAULT_RUNTIME_SRC})
161
172
  --runtime-src <src> Override runtime <script src=...>
162
173
  --comments Include comment nodes
@@ -173,12 +184,72 @@ Options:
173
184
  format,
174
185
  includeCss,
175
186
  cssHref,
187
+ themeFilePath,
176
188
  includeRuntime,
177
189
  runtimeSrc,
178
190
  includeComments,
179
191
  includeMeta,
180
192
  };
181
193
  }
194
+ function validateThemeTokenMap(filePath, section, candidate) {
195
+ if (candidate === undefined) {
196
+ return undefined;
197
+ }
198
+ if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
199
+ throw new Error(`Theme file ${filePath} has invalid "${section}" section (expected object).`);
200
+ }
201
+ const expectedKeys = new Set(theme_1.JIANWEN_THEME_TOKEN_KEYS);
202
+ const tokenMap = candidate;
203
+ const actualKeys = Object.keys(tokenMap);
204
+ const unknownKeys = actualKeys.filter((key) => !expectedKeys.has(key));
205
+ if (unknownKeys.length > 0) {
206
+ throw new Error(`Theme file ${filePath} has unknown ${section} token(s): ${unknownKeys.join(', ')}`);
207
+ }
208
+ for (const key of actualKeys) {
209
+ if (typeof tokenMap[key] !== 'string') {
210
+ throw new Error(`Theme file ${filePath} token ${section}.${key} must be a string.`);
211
+ }
212
+ }
213
+ return tokenMap;
214
+ }
215
+ function loadThemeFromFile(themeFilePath) {
216
+ const absoluteThemePath = path.resolve(process.cwd(), themeFilePath);
217
+ if (!fs.existsSync(absoluteThemePath)) {
218
+ throw new Error(`Theme file not found: ${absoluteThemePath}`);
219
+ }
220
+ let raw;
221
+ try {
222
+ raw = JSON.parse(fs.readFileSync(absoluteThemePath, 'utf-8'));
223
+ }
224
+ catch (error) {
225
+ const message = error instanceof Error ? error.message : String(error);
226
+ throw new Error(`Invalid theme JSON file ${absoluteThemePath}: ${message}`);
227
+ }
228
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
229
+ throw new Error(`Theme file ${absoluteThemePath} must contain an object.`);
230
+ }
231
+ const parsed = raw;
232
+ const knownRootKeys = new Set(['light', 'dark', 'includeAutoDark']);
233
+ const unknownRootKeys = Object.keys(parsed).filter((key) => !knownRootKeys.has(key));
234
+ if (unknownRootKeys.length > 0) {
235
+ throw new Error(`Theme file ${absoluteThemePath} has unknown root field(s): ${unknownRootKeys.join(', ')}`);
236
+ }
237
+ const lightCandidate = parsed.light;
238
+ const darkCandidate = parsed.dark;
239
+ const lightOverrides = validateThemeTokenMap(absoluteThemePath, 'light', lightCandidate);
240
+ const darkOverrides = validateThemeTokenMap(absoluteThemePath, 'dark', darkCandidate);
241
+ if (parsed.includeAutoDark !== undefined && typeof parsed.includeAutoDark !== 'boolean') {
242
+ throw new Error(`Theme file ${absoluteThemePath} field includeAutoDark must be a boolean.`);
243
+ }
244
+ if (!lightOverrides && !darkOverrides) {
245
+ throw new Error(`Theme file ${absoluteThemePath} must provide at least one of "light" or "dark" token overrides.`);
246
+ }
247
+ return {
248
+ light: lightOverrides,
249
+ dark: darkOverrides,
250
+ includeAutoDark: parsed.includeAutoDark,
251
+ };
252
+ }
182
253
  function runRenderCli(argv) {
183
254
  const options = parseCliArgs(argv);
184
255
  const absoluteInput = path.resolve(process.cwd(), options.inputFilePath);
@@ -188,6 +259,9 @@ function runRenderCli(argv) {
188
259
  }
189
260
  const baseDir = path.dirname(absoluteInput);
190
261
  const source = fs.readFileSync(absoluteInput, 'utf-8');
262
+ const themeConfig = options.includeCss && options.themeFilePath
263
+ ? loadThemeFromFile(options.themeFilePath)
264
+ : undefined;
191
265
  const sourceLines = source.split(/\r?\n/);
192
266
  const includeLineCache = new Map();
193
267
  const getIncludeLines = (target) => {
@@ -249,6 +323,7 @@ function runRenderCli(argv) {
249
323
  const documentOptions = {
250
324
  includeCss: options.includeCss,
251
325
  cssHref: options.cssHref,
326
+ theme: themeConfig,
252
327
  includeRuntime: options.includeRuntime,
253
328
  runtimeSrc: options.runtimeSrc,
254
329
  format: options.format,
@@ -9,6 +9,7 @@ function createBlockParseRuntime() {
9
9
  return {
10
10
  pending: {
11
11
  attrs: undefined,
12
+ anchorLocation: undefined,
12
13
  foldNext: false,
13
14
  tagName: undefined,
14
15
  isComment: false,
@@ -41,6 +42,7 @@ function buildBlockAttrs(runtime, tabCount) {
41
42
  }
42
43
  function resetPending(pending) {
43
44
  pending.attrs = undefined;
45
+ pending.anchorLocation = undefined;
44
46
  pending.foldNext = false;
45
47
  pending.tagName = undefined;
46
48
  pending.isComment = false;
@@ -50,10 +52,17 @@ function resetPending(pending) {
50
52
  }
51
53
  function commitParsedBlock(params) {
52
54
  const { runtime, blocks, block, blockAttrs, lineInfo, lineLocation, options } = params;
55
+ const existingLocation = (0, location_1.getNodeLocation)(block);
56
+ const shouldReanchor = existingLocation?.line !== lineLocation.line ||
57
+ existingLocation?.column !== lineLocation.column;
58
+ const blockToCommit = shouldReanchor ? { ...block } : block;
59
+ if (!existingLocation || shouldReanchor) {
60
+ (0, location_1.setNodeLocation)(blockToCommit, lineLocation);
61
+ }
53
62
  const allowTag = options?.allowTag !== false;
54
63
  const taggedOrOriginal = allowTag
55
- ? wrapTaggedIfNeeded(block, runtime.pending, blockAttrs, lineLocation)
56
- : block;
64
+ ? wrapTaggedIfNeeded(blockToCommit, runtime.pending, blockAttrs, lineLocation)
65
+ : blockToCommit;
57
66
  const finalBlock = wrapCommentIfNeeded(taggedOrOriginal, runtime.pending, lineLocation);
58
67
  blocks.push(finalBlock);
59
68
  runtime.lastBlockPosition = resolveNextPosition(getBlockAttributes(finalBlock), lineInfo.tabCount, runtime.lastBlockPosition);
@@ -1,6 +1,8 @@
1
1
  import { BlockAttributes } from '../ast';
2
+ import { SourceLocation } from '../location';
2
3
  export interface PendingBlockContext {
3
4
  attrs?: BlockAttributes;
5
+ anchorLocation?: SourceLocation;
4
6
  foldNext: boolean;
5
7
  tagName?: string;
6
8
  isComment: boolean;
@@ -61,13 +61,14 @@ function parseBlocks(source, errors) {
61
61
  continue;
62
62
  }
63
63
  const commitBlock = (block, blockAttrs, options) => {
64
+ const commitLocation = runtime.pending.anchorLocation ?? lineLocation;
64
65
  (0, runtime_1.commitParsedBlock)({
65
66
  runtime,
66
67
  blocks,
67
68
  block,
68
69
  blockAttrs,
69
70
  lineInfo,
70
- lineLocation,
71
+ lineLocation: commitLocation,
71
72
  options,
72
73
  });
73
74
  };
@@ -112,6 +113,9 @@ function parseBlocks(source, errors) {
112
113
  tabCount: lineInfo.tabCount,
113
114
  });
114
115
  if (consumed) {
116
+ if (!runtime.pending.anchorLocation) {
117
+ runtime.pending.anchorLocation = lineLocation;
118
+ }
115
119
  i += 1;
116
120
  continue;
117
121
  }
@@ -73,7 +73,7 @@ function parseInitializationTemplate(source) {
73
73
  applyMetaKey(meta, key, value);
74
74
  }
75
75
  }
76
- const bodyLines = lines.slice(0, start).concat(lines.slice(end + 1));
76
+ const bodyLines = lines.map((line, index) => index >= start && index <= end ? '' : (line ?? ''));
77
77
  const body = bodyLines.join('\n');
78
78
  if (isMetaEmpty(meta)) {
79
79
  return { body };
@@ -3,6 +3,7 @@ import { JianwenDocument } from '../core/ast';
3
3
  import { ParseError } from '../core/errors';
4
4
  import { RenderedBlockGroup } from './render/html';
5
5
  import { RenderHtmlOptions } from './render/utils';
6
+ import { JianwenThemeConfig } from './theme/theme';
6
7
  export declare const DEFAULT_RUNTIME_SRC = "dist/html/theme/runtime.js";
7
8
  export interface HtmlDocumentOptions {
8
9
  title?: string;
@@ -12,6 +13,7 @@ export interface HtmlDocumentOptions {
12
13
  includeCss?: boolean;
13
14
  cssText?: string;
14
15
  cssHref?: string;
16
+ theme?: JianwenThemeConfig;
15
17
  includeRuntime?: boolean;
16
18
  runtimeSrc?: string;
17
19
  format?: boolean;
@@ -23,7 +23,7 @@ function buildHtmlDocument(bodyHtml, options = {}) {
23
23
  headParts.push(`<link rel="stylesheet" href="${(0, utils_1.escapeAttr)(options.cssHref)}">`);
24
24
  }
25
25
  else {
26
- const cssText = options.cssText ?? theme_1.DEFAULT_CSS;
26
+ const cssText = options.cssText ?? (0, theme_1.composeThemeCss)({ preset: 'default', theme: options.theme });
27
27
  headParts.push(`<style>${cssText}</style>`);
28
28
  }
29
29
  }
@@ -6,6 +6,15 @@ exports.renderBlockToHtml = renderBlockToHtml;
6
6
  const utils_1 = require("./utils");
7
7
  const inlines_1 = require("./inlines");
8
8
  const location_1 = require("../../core/location");
9
+ function nestedRenderOptions(options) {
10
+ if (!options.emitBlockMeta) {
11
+ return options;
12
+ }
13
+ return {
14
+ ...options,
15
+ emitBlockMeta: false,
16
+ };
17
+ }
9
18
  function renderBlocksToHtml(blocks, options = {}) {
10
19
  return renderBlocksToHtmlWithGroups(blocks, options).html;
11
20
  }
@@ -99,6 +108,7 @@ function renderBlocksToHtmlWithGroups(blocks, options = {}) {
99
108
  if (!prevAttrs?.sameLine) {
100
109
  rowStartIndex = i - 1;
101
110
  result.pop();
111
+ groups.pop();
102
112
  }
103
113
  }
104
114
  }
@@ -214,7 +224,7 @@ function renderContentTitleBlock(block, options) {
214
224
  return `<div class="jw-content-title">${inner}</div>${spacer}`;
215
225
  }
216
226
  function renderQuoteBlock(block, options) {
217
- const inner = renderBlocksToHtml(block.children, options);
227
+ const inner = renderBlocksToHtml(block.children, nestedRenderOptions(options));
218
228
  const attrs = (0, utils_1.buildBlockAttributes)(block.blockAttrs, {
219
229
  extraData: { 'data-jw-level': String(block.level) },
220
230
  });
@@ -253,20 +263,20 @@ function renderListItemBlock(block, options) {
253
263
  prefix += `<span class="jw-list-task-marker" data-jw-task-status="${(0, utils_1.escapeAttr)(block.taskStatus)}"></span>`;
254
264
  }
255
265
  const inner = renderBlocksToHtml(block.children, {
256
- ...options,
266
+ ...nestedRenderOptions(options),
257
267
  suppressBlockWrapper: true,
258
268
  });
259
269
  if (block.kind === 'foldable') {
260
270
  const firstChild = block.children[0];
261
271
  if (firstChild && firstChild.type === 'paragraph') {
262
272
  const summaryContent = renderBlockToHtml(firstChild, {
263
- ...options,
273
+ ...nestedRenderOptions(options),
264
274
  suppressBlockWrapper: true,
265
275
  });
266
276
  const remainingChildren = block.children.slice(1);
267
277
  const detailsContent = remainingChildren.length > 0
268
278
  ? renderBlocksToHtml(remainingChildren, {
269
- ...options,
279
+ ...nestedRenderOptions(options),
270
280
  suppressBlockWrapper: true,
271
281
  })
272
282
  : '';
@@ -427,14 +437,14 @@ function renderFootnotesBlock(block, options) {
427
437
  return `<section class="jw-footnotes"${attrs}><ol class="jw-footnote-list">${items}</ol></section>`;
428
438
  }
429
439
  function renderFootnoteDefBlock(block, options) {
430
- const inner = renderBlocksToHtml(block.children, options);
440
+ const inner = renderBlocksToHtml(block.children, nestedRenderOptions(options));
431
441
  const attrs = (0, utils_1.buildBlockAttributes)(block.blockAttrs, {
432
442
  extraData: { 'data-jw-footnote-id': block.id },
433
443
  });
434
444
  return `<li class="jw-footnote-def"${attrs}>${inner}</li>`;
435
445
  }
436
446
  function renderCommentBlock(block, options) {
437
- const inner = renderBlocksToHtml(block.children, options);
447
+ const inner = renderBlocksToHtml(block.children, nestedRenderOptions(options));
438
448
  const attrs = (0, utils_1.buildBlockAttributes)(block.blockAttrs, {
439
449
  extraData: { 'data-jw-comment': 'true' },
440
450
  });
@@ -467,7 +477,7 @@ function renderTaggedBlock(block, options) {
467
477
  extraData: { 'data-jw-tag': block.name },
468
478
  rawAttrs: [`id="${(0, utils_1.escapeAttr)(id)}"`],
469
479
  });
470
- const inner = renderBlockToHtml(block.child, options);
480
+ const inner = renderBlockToHtml(block.child, nestedRenderOptions(options));
471
481
  return `<div class="jw-tagged-block"${attrs}>${inner}</div>`;
472
482
  }
473
483
  function renderRawBlock(block, _options) {
@@ -69,13 +69,18 @@ function renderDocumentToHtml(doc, options = {}) {
69
69
  function finalizeGroups(groups, sourceLineCount) {
70
70
  return groups.map((group, index) => {
71
71
  const next = groups[index + 1];
72
- let endLine = sourceLineCount;
73
- if (next?.startLine !== undefined) {
74
- endLine = Math.max(1, next.startLine - 1);
72
+ let endLine;
73
+ if (group.startLine !== undefined) {
74
+ if (next?.startLine !== undefined) {
75
+ endLine = Math.max(group.startLine, 1, next.startLine - 1);
76
+ }
77
+ else if (sourceLineCount !== undefined) {
78
+ endLine = Math.max(group.startLine, 1, sourceLineCount);
79
+ }
75
80
  }
76
81
  return {
77
82
  ...group,
78
- endLine: group.startLine !== undefined ? endLine : undefined,
83
+ endLine,
79
84
  };
80
85
  });
81
86
  }
@@ -1,2 +1,2 @@
1
1
  export = BASE_CSS;
2
- declare const BASE_CSS: "\nhtml,\nbody {\n margin: 0;\n padding: 0;\n}\n.jw-root {\n background-color: var(--jw-bg-color, transparent);\n color: var(--jw-text-color, inherit);\n display: flow-root;\n min-height: 100vh;\n}\n.jw-root > .jw-block + .jw-block { margin-top: var(--jw-block-spacing); }\n.jw-root > .jw-block { margin: 0; }\n.jw-table { border-collapse: collapse; }\n.jw-table-cell { border: 1px solid var(--jw-border-color); padding: 0.5em; }\n.jw-link { text-decoration: none; color: var(--jw-link-color, currentColor); }\n.jw-link:visited { color: var(--jw-link-color, currentColor); }\n.jw-link:hover { text-decoration: underline; }\n.jw-underline { text-decoration: underline; }\n.jw-strike { text-decoration: line-through; }\n.jw-wave { text-decoration: underline; text-decoration-style: wavy; }\n.jw-heading { font-weight: bold; margin: 0; }\n.jw-heading.level-1 { font-size: 2.5em; }\n.jw-heading.level-2 { font-size: 2em; }\n.jw-heading.level-3 { font-size: 1.75em; }\n.jw-heading.level-4 { font-size: 1.5em; }\n.jw-heading.level-5 { font-size: 1.25em; }\n.jw-foldable-section { margin: 1em 0; }\n.jw-foldable-section > summary {\n cursor: pointer;\n user-select: none;\n list-style: none;\n display: flex;\n align-items: center;\n}\n.jw-foldable-section > summary::-webkit-details-marker {\n display: none;\n}\n.jw-foldable-section > summary::before {\n content: '';\n display: block;\n width: 0.5em;\n height: 0.5em;\n margin-right: 0.4em;\n flex: 0 0 auto;\n background: currentColor;\n clip-path: polygon(0 0, 100% 50%, 0 100%);\n transform: rotate(0deg);\n opacity: 0.74;\n transition: transform 0.2s ease, opacity 0.2s ease;\n}\n.jw-foldable-section[open] > summary::before {\n transform: rotate(90deg);\n opacity: 0.85;\n}\n.jw-foldable-section > summary .jw-heading {\n display: inline;\n margin: 0;\n min-width: 0;\n}\n\n.jw-content-title {\n margin-top: 0.1em;\n margin-bottom: 0;\n font-size: 0.85em;\n color: var(--jw-text-muted);\n}\n.jw-content-title-gap {\n display: block;\n height: 0.8em;\n min-height: 8px;\n}\n.jw-quote {\n margin: 0;\n border-left: 4px solid var(--jw-quote-border-color);\n padding: 0 1em;\n background: var(--jw-quote-background);\n color: var(--jw-quote-text);\n}\n.jw-quote > .jw-paragraph { margin: var(--jw-quote-gap) 0; }\n.jw-quote > .jw-quote { margin: var(--jw-quote-gap) 0; }\n[data-jw-level=\"2\"].jw-quote { border-left-color: var(--jw-quote-border-color-2); }\n[data-jw-level=\"3\"].jw-quote { border-left-color: var(--jw-quote-border-color-3); }\n.jw-paragraph { white-space: pre-wrap; line-height: var(--jw-line-height-base); }\n.jw-paragraph-block { white-space: normal; }\n.jw-list { padding-left: 1.25em; }\n.jw-list[data-jw-list-kind=\"bullet\"] { list-style-type: disc; }\n.jw-hr { border: none; border-top: 1px solid currentColor; color: var(--jw-border-color); height: 0; background: none; padding: 0; margin: 0; }\n.jw-hr[data-jw-position=\"L\"] { width: 100%; }\n.jw-hr[data-jw-position=\"C\"] { width: 66.67%; }\n.jw-hr[data-jw-position=\"R\"] { width: 33.34%; }\n.jw-hr[data-jw-hr-style=\"dashed\"] { border-top-style: dashed; }\n.jw-hr[data-jw-hr-style=\"bold\"] { border-top-width: 4px; }\n.jw-hr[data-jw-hr-style=\"wavy\"] {\n border: none;\n height: 8px;\n color: var(--jw-border-color);\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 8' preserveAspectRatio='none'%3E%3Cpath d='M0 4 Q 8 0 16 4 T 32 4' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E\");\n background-size: 32px 8px;\n background-repeat: repeat-x;\n background-position: center bottom;\n background-color: transparent;\n}\n.jw-highlight-marker { background-color: var(--jw-highlight-marker); padding: 0; }\n.jw-highlight-frame { border: 1px solid var(--jw-border-color); padding: 0; border-radius: 3px; }\n.jw-highlight-block {\n display: block;\n padding: 0.75em 1em;\n white-space: normal;\n}\n.jw-list[data-jw-list-kind=\"task\"] { list-style: none; padding-left: 0; }\n.jw-list-item[data-jw-list-kind=\"task\"] { list-style: none; }\n.jw-list-item[data-jw-list-kind=\"task\"][data-jw-task-status] {\n position: relative;\n padding-left: 0;\n margin: 0.25em 0;\n}\n.jw-list-item {\n display: flex;\n flex-flow: row wrap;\n align-items: flex-start;\n}\n.jw-list-item[data-jw-list-kind=\"bullet\"] {\n display: list-item;\n}\n.jw-list-ordinal {\n margin-right: 0.5em;\n line-height: var(--jw-line-height-base);\n flex-shrink: 0;\n color: var(--jw-text-strong);\n font-variant-numeric: tabular-nums;\n}\n.jw-list-task-marker {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25em;\n height: 1.25em;\n border: 1px solid var(--jw-border-color-strong);\n background: var(--jw-surface-task);\n border-radius: 2px;\n font-size: 0.85em;\n color: transparent;\n transition: all 0.2s ease;\n box-sizing: border-box;\n margin-right: 0.5em;\n flex-shrink: 0;\n margin-top: 0.375em;\n position: relative;\n line-height: 1;\n}\n.jw-list-task-marker::before,\n.jw-list-task-marker::after {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n content: '';\n}\n.jw-list-task-marker[data-jw-task-status=\"done\"] {\n content: '\u2714';\n}\n.jw-list-task-marker[data-jw-task-status=\"done\"]::before {\n content: '\u2714';\n color: var(--jw-task-done-text);\n}\n.jw-list-task-marker[data-jw-task-status=\"done\"] {\n background: var(--jw-task-done-bg);\n border-color: var(--jw-task-done-bg);\n}\n.jw-list-task-marker[data-jw-task-status=\"not_done\"]::before,\n.jw-list-task-marker[data-jw-task-status=\"not_done\"]::after {\n width: 0.85em;\n height: 0.12em;\n background: var(--jw-task-not-done-cross);\n border-radius: 999px;\n}\n.jw-list-task-marker[data-jw-task-status=\"not_done\"]::before {\n transform: translate(-50%, -50%) rotate(45deg);\n}\n.jw-list-task-marker[data-jw-task-status=\"not_done\"]::after {\n transform: translate(-50%, -50%) rotate(-45deg);\n}\n.jw-list-task-marker[data-jw-task-status=\"not_done\"] {\n background: var(--jw-border-color-strong);\n border-color: var(--jw-border-color-strong);\n}\n.jw-list-task-marker[data-jw-task-status=\"in_progress\"]::before {\n width: 0.7em;\n height: 0.7em;\n border: 0.12em solid var(--jw-task-in-progress);\n border-radius: 50%;\n}\n.jw-list-task-marker[data-jw-task-status=\"unknown\"] {\n /* Empty box */\n}\n.jw-list-item > .jw-paragraph {\n flex: 1 1 auto;\n margin: 0;\n min-width: 0;\n line-height: var(--jw-line-height-base);\n}\n.jw-list-item > .jw-list {\n flex-basis: 100%;\n width: 100%;\n padding-left: 2em;\n margin: var(--jw-nested-list-gap) 0 0 0;\n}\n.jw-list-item + .jw-list-item {\n margin-top: var(--jw-nested-list-gap);\n}\n.jw-list-item > .jw-code-block {\n flex-basis: 100%;\n width: 100%;\n margin-top: var(--jw-nested-list-gap);\n}\n.jw-list-item[data-jw-task-status=\"done\"] > .jw-paragraph {\n text-decoration: line-through;\n color: var(--jw-text-faint);\n}\n.jw-list-item[data-jw-list-kind=\"ordered\"] {\n list-style: none;\n}\n.jw-list-item[data-jw-list-kind=\"ordered\"]::marker {\n content: none;\n}\n\n.jw-list-item[data-jw-list-kind=\"foldable\"] { list-style: none; }\n.jw-foldable-list-item {\n display: block;\n}\n.jw-foldable-list-item > summary {\n cursor: pointer;\n user-select: none;\n list-style: none;\n position: relative;\n padding-left: 1.2em;\n}\n.jw-foldable-list-item > summary::-webkit-details-marker {\n display: none;\n}\n.jw-foldable-list-item > summary::before {\n content: '';\n position: absolute;\n left: 0;\n top: 50%;\n width: 0.45em;\n height: 0.45em;\n background: currentColor;\n clip-path: polygon(0 0, 100% 50%, 0 100%);\n transform: translateY(-50%) rotate(0deg);\n opacity: 0.68;\n transition: transform 0.2s ease, opacity 0.2s ease;\n}\n.jw-foldable-list-item[open] > summary::before {\n transform: translateY(-50%) rotate(90deg);\n opacity: 0.85;\n}\n.jw-foldable-list-item > summary .jw-paragraph {\n display: inline;\n}\n\n.jw-image-figure { }\n.jw-image { max-width: 100%; max-height: 600px; width: auto; height: auto; object-fit: contain; }\n.jw-image-caption { margin-top: 0.5em; font-size: 0.9em; color: var(--jw-text-subtle); }\n.jw-image-figure[data-jw-shape=\"rounded\"] .jw-image { border-radius: 8px; }\n.jw-code-block {\n position: relative;\n display: flex;\n flex-direction: column;\n padding: 0;\n background: var(--jw-surface-code);\n border: 1px solid var(--jw-border-color-subtle);\n border-radius: 4px;\n font-family: \"JetBrains Mono\", \"Fira Code\", Consolas, Menlo, monospace;\n font-size: 0.9em;\n line-height: 1.5;\n margin: 0;\n}\n.jw-code-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.5em 0.75em;\n border-bottom: 1px solid var(--jw-border-color-subtle);\n background: var(--jw-surface-overlay-1);\n}\n.jw-code-lang {\n padding: 0.1em 0.4em;\n background: var(--jw-surface-overlay-2);\n color: var(--jw-text-subtle);\n font-size: 0.75em;\n border-radius: 3px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n.jw-code-copy {\n padding: 0.25em 0.5em;\n background: transparent;\n border: 1px solid var(--jw-border-color);\n border-radius: 3px;\n cursor: pointer;\n font-size: 0.75em;\n color: var(--jw-text-subtle);\n transition: background 0.2s, border-color 0.2s;\n}\n.jw-code-copy:hover {\n background: var(--jw-surface-overlay-2);\n border-color: var(--jw-border-color-strong);\n}\n.jw-code-copy:active {\n background: var(--jw-surface-overlay-3);\n}\n.jw-code-content {\n display: flex;\n padding: 1em 1em 1em 0;\n}\n.jw-line-numbers {\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n padding: 0 0.75em;\n border-right: 1px solid var(--jw-border-color-subtle);\n text-align: right;\n user-select: none;\n color: var(--jw-text-faint);\n font-variant-numeric: tabular-nums;\n}\n.jw-line-number {\n display: block;\n min-height: 1.5em;\n}\n.jw-code {\n flex: 1;\n display: block;\n overflow-x: auto;\n padding: 0 1em;\n background: transparent;\n font-family: inherit;\n white-space: pre;\n}\n.jw-code-line {\n display: block;\n white-space: pre;\n min-height: 1.5em;\n}\n.jw-disabled-block { font-family: inherit; white-space: pre-wrap; line-height: var(--jw-line-height-base); margin: 0; }\n[data-jw-position=\"C\"] { margin-left: 33.33%; }\n[data-jw-position=\"R\"] { margin-left: 66.66%; }\n[data-jw-truncate-left=\"true\"] { margin-left: 0; }\n[data-jw-truncate-right=\"true\"] { max-width: 33.33%; word-wrap: break-word; overflow-wrap: break-word; }\n[data-jw-position=\"C\"][data-jw-truncate-right=\"true\"] { max-width: 33.33%; }\n[data-jw-position=\"R\"][data-jw-truncate-right=\"true\"] { max-width: 33.33%; }\n.jw-hr[data-jw-truncate-right=\"true\"] { width: 33.33%; max-width: none; }\n[data-jw-align=\"center\"] { text-align: center; }\n[data-jw-align=\"right\"] { text-align: right; }\n.jw-same-line-row { display: flex; flex-wrap: nowrap; gap: 0; align-items: flex-start; max-width: 100%; overflow: hidden; }\n.jw-same-line-row > * { flex-shrink: 1; word-wrap: break-word; overflow-wrap: break-word; min-width: 0; }\n.jw-same-line-row > [data-jw-position=\"L\"]:not(:last-child),\n.jw-same-line-row > [data-jw-position=\"C\"]:not(:last-child),\n.jw-same-line-row > [data-jw-position=\"R\"]:not(:last-child) { flex-basis: 33.33%; max-width: 33.33%; }\n.jw-same-line-row > [data-jw-position=\"L\"]:last-child,\n.jw-same-line-row > [data-jw-position=\"C\"]:last-child,\n.jw-same-line-row > [data-jw-position=\"R\"]:last-child { flex-grow: 1; flex-basis: 0; }\n.jw-same-line-row > [data-jw-position] { margin-left: 0; }\n.jw-same-line-row > [data-jw-position=\"C\"]:first-child { margin-left: 33.33%; }\n.jw-same-line-row > [data-jw-position=\"R\"]:first-child { margin-left: 66.66%; }\n.jw-meta { margin: 0 0 var(--jw-block-spacing); }\n.jw-meta-time,\n.jw-meta-add-info,\n.jw-meta-tags,\n.jw-meta-author {\n color: var(--jw-quote-text);\n}\n.jw-meta-author-link { text-decoration: none; color: inherit; }\n.jw-meta-author-link:hover { text-decoration: underline; }\n.jw-comment-inline { display: none; }\n.jw-comment-block { display: none; }\n";
2
+ declare const BASE_CSS: "\n.jw-root {\n background-color: var(--jw-bg-color, transparent);\n color: var(--jw-text-color, inherit);\n display: flow-root;\n min-height: 100vh;\n}\n.jw-root > .jw-block + .jw-block { margin-top: var(--jw-block-spacing); }\n.jw-root > .jw-block { margin: 0; }\n.jw-table { border-collapse: collapse; width: 100%; }\n.jw-table-cell {\n border: 1px solid var(--jw-table-border-color, var(--jw-border-color));\n padding: 0.5em;\n}\n.jw-table thead .jw-table-cell {\n background: var(--jw-table-header-bg, var(--jw-surface-overlay-1));\n color: var(--jw-table-header-text, var(--jw-text-strong));\n font-weight: 600;\n}\n.jw-table tbody .jw-table-row:nth-child(odd) .jw-table-cell {\n background: var(--jw-table-row-bg, transparent);\n}\n.jw-table tbody .jw-table-row:nth-child(even) .jw-table-cell {\n background: var(--jw-table-row-alt-bg, transparent);\n}\n.jw-link { text-decoration: none; color: var(--jw-link-color, currentColor); }\n.jw-link:visited { color: var(--jw-link-color, currentColor); }\n.jw-link:hover { text-decoration: underline; }\n.jw-root strong {\n color: var(--jw-strong-color, currentColor);\n font-weight: var(--jw-strong-weight, 700);\n}\n.jw-underline {\n text-decoration: underline;\n text-decoration-color: var(--jw-underline-color, currentColor);\n text-decoration-thickness: var(--jw-underline-thickness, from-font);\n text-underline-offset: var(--jw-underline-offset, auto);\n}\n.jw-strike {\n text-decoration: line-through;\n text-decoration-color: var(--jw-strike-color, currentColor);\n}\n.jw-wave {\n text-decoration: underline;\n text-decoration-style: wavy;\n text-decoration-color: var(--jw-wave-color, currentColor);\n text-decoration-thickness: var(--jw-underline-thickness, from-font);\n text-underline-offset: var(--jw-underline-offset, auto);\n}\n.jw-heading { font-weight: bold; margin: 0; }\n.jw-heading.level-1 { font-size: 2.5em; }\n.jw-heading.level-2 { font-size: 2em; }\n.jw-heading.level-3 { font-size: 1.75em; }\n.jw-heading.level-4 { font-size: 1.5em; }\n.jw-heading.level-5 { font-size: 1.25em; }\n.jw-foldable-section { margin: 1em 0; }\n.jw-foldable-section > summary {\n cursor: pointer;\n user-select: none;\n list-style: none;\n display: flex;\n align-items: center;\n}\n.jw-foldable-section > summary::-webkit-details-marker {\n display: none;\n}\n.jw-foldable-section > summary::before {\n content: '';\n display: block;\n width: 0.5em;\n height: 0.5em;\n margin-right: 0.4em;\n flex: 0 0 auto;\n background: currentColor;\n clip-path: polygon(0 0, 100% 50%, 0 100%);\n transform: rotate(0deg);\n opacity: 0.74;\n transition: transform 0.2s ease, opacity 0.2s ease;\n}\n.jw-foldable-section[open] > summary::before {\n transform: rotate(90deg);\n opacity: 0.85;\n}\n.jw-foldable-section > summary .jw-heading {\n display: inline;\n margin: 0;\n min-width: 0;\n}\n\n.jw-content-title {\n margin-top: 0.1em;\n margin-bottom: 0;\n font-size: 0.85em;\n color: var(--jw-text-muted);\n}\n.jw-content-title-gap {\n display: block;\n height: 0.8em;\n min-height: 8px;\n}\n.jw-quote {\n margin: 0;\n border-left: 4px solid var(--jw-quote-border-color);\n padding: 0 1em;\n background: var(--jw-quote-background);\n color: var(--jw-quote-text);\n}\n.jw-quote > .jw-paragraph { margin: var(--jw-quote-gap) 0; }\n.jw-quote > .jw-quote { margin: var(--jw-quote-gap) 0; }\n[data-jw-level=\"2\"].jw-quote { border-left-color: var(--jw-quote-border-color-2); }\n[data-jw-level=\"3\"].jw-quote { border-left-color: var(--jw-quote-border-color-3); }\n.jw-paragraph { white-space: pre-wrap; line-height: var(--jw-line-height-base); }\n.jw-paragraph-block { white-space: normal; }\n.jw-list { padding-left: 1.25em; }\n.jw-list[data-jw-list-kind=\"bullet\"] { list-style-type: disc; }\n.jw-hr { border: none; border-top: 1px solid currentColor; color: var(--jw-border-color); height: 0; background: none; padding: 0; margin: 0; }\n.jw-hr[data-jw-position=\"L\"] { width: 100%; }\n.jw-hr[data-jw-position=\"C\"] { width: 66.67%; }\n.jw-hr[data-jw-position=\"R\"] { width: 33.34%; }\n.jw-hr[data-jw-hr-style=\"dashed\"] { border-top-style: dashed; }\n.jw-hr[data-jw-hr-style=\"bold\"] { border-top-width: 4px; }\n.jw-hr[data-jw-hr-style=\"wavy\"] {\n border: none;\n height: 8px;\n color: var(--jw-border-color);\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 8' preserveAspectRatio='none'%3E%3Cpath d='M0 4 Q 8 0 16 4 T 32 4' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E\");\n background-size: 32px 8px;\n background-repeat: repeat-x;\n background-position: center bottom;\n background-color: transparent;\n}\n.jw-highlight-marker { background-color: var(--jw-highlight-marker); padding: 0; }\n.jw-highlight-frame { border: 1px solid var(--jw-border-color); padding: 0; border-radius: 3px; }\n.jw-highlight-block {\n display: block;\n padding: 0.75em 1em;\n white-space: normal;\n}\n.jw-list[data-jw-list-kind=\"task\"] { list-style: none; padding-left: 0; }\n.jw-list-item[data-jw-list-kind=\"task\"] { list-style: none; }\n.jw-list-item[data-jw-list-kind=\"task\"][data-jw-task-status] {\n position: relative;\n padding-left: 0;\n margin: 0.25em 0;\n}\n.jw-list-item {\n display: flex;\n flex-flow: row wrap;\n align-items: flex-start;\n}\n.jw-list-item[data-jw-list-kind=\"bullet\"] {\n display: list-item;\n}\n.jw-list-ordinal {\n margin-right: 0.5em;\n line-height: var(--jw-line-height-base);\n flex-shrink: 0;\n color: var(--jw-text-strong);\n font-variant-numeric: tabular-nums;\n}\n.jw-list-task-marker {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25em;\n height: 1.25em;\n border: 1px solid var(--jw-border-color-strong);\n background: var(--jw-surface-task);\n border-radius: 2px;\n font-size: 0.85em;\n color: transparent;\n transition: all 0.2s ease;\n box-sizing: border-box;\n margin-right: 0.5em;\n flex-shrink: 0;\n margin-top: 0.375em;\n position: relative;\n line-height: 1;\n}\n.jw-list-task-marker::before,\n.jw-list-task-marker::after {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n content: '';\n}\n.jw-list-task-marker[data-jw-task-status=\"done\"] {\n content: '\u2714';\n}\n.jw-list-task-marker[data-jw-task-status=\"done\"]::before {\n content: '\u2714';\n color: var(--jw-task-done-text);\n}\n.jw-list-task-marker[data-jw-task-status=\"done\"] {\n background: var(--jw-task-done-bg);\n border-color: var(--jw-task-done-bg);\n}\n.jw-list-task-marker[data-jw-task-status=\"not_done\"]::before,\n.jw-list-task-marker[data-jw-task-status=\"not_done\"]::after {\n width: 0.85em;\n height: 0.12em;\n background: var(--jw-task-not-done-cross);\n border-radius: 999px;\n}\n.jw-list-task-marker[data-jw-task-status=\"not_done\"]::before {\n transform: translate(-50%, -50%) rotate(45deg);\n}\n.jw-list-task-marker[data-jw-task-status=\"not_done\"]::after {\n transform: translate(-50%, -50%) rotate(-45deg);\n}\n.jw-list-task-marker[data-jw-task-status=\"not_done\"] {\n background: var(--jw-border-color-strong);\n border-color: var(--jw-border-color-strong);\n}\n.jw-list-task-marker[data-jw-task-status=\"in_progress\"]::before {\n width: 0.7em;\n height: 0.7em;\n border: 0.12em solid var(--jw-task-in-progress);\n border-radius: 50%;\n}\n.jw-list-task-marker[data-jw-task-status=\"unknown\"] {\n /* Empty box */\n}\n.jw-list-item > .jw-paragraph {\n flex: 1 1 auto;\n margin: 0;\n min-width: 0;\n line-height: var(--jw-line-height-base);\n}\n.jw-list-item > .jw-list {\n flex-basis: 100%;\n width: 100%;\n padding-left: 2em;\n margin: var(--jw-nested-list-gap) 0 0 0;\n}\n.jw-list-item + .jw-list-item {\n margin-top: var(--jw-nested-list-gap);\n}\n.jw-list-item > .jw-code-block {\n flex-basis: 100%;\n width: 100%;\n margin-top: var(--jw-nested-list-gap);\n}\n.jw-list-item[data-jw-task-status=\"done\"] > .jw-paragraph {\n text-decoration: line-through;\n color: var(--jw-text-faint);\n}\n.jw-list-item[data-jw-list-kind=\"ordered\"] {\n list-style: none;\n}\n.jw-list-item[data-jw-list-kind=\"ordered\"]::marker {\n content: none;\n}\n\n.jw-list-item[data-jw-list-kind=\"foldable\"] { list-style: none; }\n.jw-foldable-list-item {\n display: block;\n}\n.jw-foldable-list-item > summary {\n cursor: pointer;\n user-select: none;\n list-style: none;\n position: relative;\n padding-left: 1.2em;\n}\n.jw-foldable-list-item > summary::-webkit-details-marker {\n display: none;\n}\n.jw-foldable-list-item > summary::before {\n content: '';\n position: absolute;\n left: 0;\n top: 50%;\n width: 0.45em;\n height: 0.45em;\n background: currentColor;\n clip-path: polygon(0 0, 100% 50%, 0 100%);\n transform: translateY(-50%) rotate(0deg);\n opacity: 0.68;\n transition: transform 0.2s ease, opacity 0.2s ease;\n}\n.jw-foldable-list-item[open] > summary::before {\n transform: translateY(-50%) rotate(90deg);\n opacity: 0.85;\n}\n.jw-foldable-list-item > summary .jw-paragraph {\n display: inline;\n}\n\n.jw-image-figure { }\n.jw-image { max-width: 100%; max-height: 600px; width: auto; height: auto; object-fit: contain; }\n.jw-image-caption { margin-top: 0.5em; font-size: 0.9em; color: var(--jw-text-subtle); }\n.jw-image-figure[data-jw-shape=\"rounded\"] .jw-image { border-radius: 8px; }\n.jw-code-block {\n position: relative;\n display: flex;\n flex-direction: column;\n padding: 0;\n background: var(--jw-code-block-bg, var(--jw-surface-code));\n border: 1px solid var(--jw-code-border-color, var(--jw-border-color-subtle));\n border-radius: 4px;\n font-family: \"JetBrains Mono\", \"Fira Code\", Consolas, Menlo, monospace;\n font-size: 0.9em;\n line-height: 1.5;\n margin: 0;\n}\n.jw-code-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.5em 0.75em;\n border-bottom: 1px solid var(--jw-code-border-color, var(--jw-border-color-subtle));\n background: var(--jw-code-header-bg, var(--jw-surface-overlay-1));\n color: var(--jw-code-header-text, var(--jw-text-subtle));\n}\n.jw-code-lang {\n padding: 0.1em 0.4em;\n background: var(--jw-code-lang-bg, var(--jw-surface-overlay-2));\n color: var(--jw-code-lang-text, var(--jw-text-subtle));\n font-size: 0.75em;\n border-radius: 3px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n.jw-code-copy {\n padding: 0.25em 0.5em;\n background: transparent;\n border: 1px solid var(--jw-code-copy-border, var(--jw-border-color));\n border-radius: 3px;\n cursor: pointer;\n font-size: 0.75em;\n color: var(--jw-code-header-text, var(--jw-text-subtle));\n transition: background 0.2s, border-color 0.2s;\n}\n.jw-code-copy:hover {\n background: var(--jw-code-copy-hover-bg, var(--jw-surface-overlay-2));\n border-color: var(--jw-code-copy-border, var(--jw-border-color-strong));\n}\n.jw-code-copy:active {\n background: var(--jw-surface-overlay-3);\n}\n.jw-code-content {\n display: flex;\n padding: 1em 1em 1em 0;\n}\n.jw-line-numbers {\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n padding: 0 0.75em;\n border-right: 1px solid var(--jw-code-border-color, var(--jw-border-color-subtle));\n text-align: right;\n user-select: none;\n color: var(--jw-code-line-number-color, var(--jw-text-faint));\n font-variant-numeric: tabular-nums;\n}\n.jw-line-number {\n display: block;\n min-height: 1.5em;\n}\n.jw-code {\n flex: 1;\n display: block;\n overflow-x: auto;\n padding: 0 1em;\n background: transparent;\n font-family: inherit;\n white-space: pre;\n}\n.jw-code-line {\n display: block;\n white-space: pre;\n min-height: 1.5em;\n}\n.jw-disabled-block { font-family: inherit; white-space: pre-wrap; line-height: var(--jw-line-height-base); margin: 0; }\n[data-jw-position=\"C\"] { margin-left: 33.33%; }\n[data-jw-position=\"R\"] { margin-left: 66.66%; }\n[data-jw-truncate-left=\"true\"] { margin-left: 0; }\n[data-jw-truncate-right=\"true\"] { max-width: 33.33%; word-wrap: break-word; overflow-wrap: break-word; }\n[data-jw-position=\"C\"][data-jw-truncate-right=\"true\"] { max-width: 33.33%; }\n[data-jw-position=\"R\"][data-jw-truncate-right=\"true\"] { max-width: 33.33%; }\n.jw-hr[data-jw-truncate-right=\"true\"] { width: 33.33%; max-width: none; }\n[data-jw-align=\"center\"] { text-align: center; }\n[data-jw-align=\"right\"] { text-align: right; }\n.jw-same-line-row { display: flex; flex-wrap: nowrap; gap: 0; align-items: flex-start; max-width: 100%; overflow: hidden; }\n.jw-same-line-row > * { flex-shrink: 1; word-wrap: break-word; overflow-wrap: break-word; min-width: 0; }\n.jw-same-line-row > [data-jw-position=\"L\"]:not(:last-child),\n.jw-same-line-row > [data-jw-position=\"C\"]:not(:last-child),\n.jw-same-line-row > [data-jw-position=\"R\"]:not(:last-child) { flex-basis: 33.33%; max-width: 33.33%; }\n.jw-same-line-row > [data-jw-position=\"L\"]:last-child,\n.jw-same-line-row > [data-jw-position=\"C\"]:last-child,\n.jw-same-line-row > [data-jw-position=\"R\"]:last-child { flex-grow: 1; flex-basis: 0; }\n.jw-same-line-row > [data-jw-position] { margin-left: 0; }\n.jw-same-line-row > [data-jw-position=\"C\"]:first-child { margin-left: 33.33%; }\n.jw-same-line-row > [data-jw-position=\"R\"]:first-child { margin-left: 66.66%; }\n.jw-meta { margin: 0 0 var(--jw-block-spacing); }\n.jw-meta-time,\n.jw-meta-add-info,\n.jw-meta-tags,\n.jw-meta-author {\n color: var(--jw-quote-text);\n}\n.jw-meta-author-link { text-decoration: none; color: inherit; }\n.jw-meta-author-link:hover { text-decoration: underline; }\n.jw-comment-inline { display: none; }\n.jw-comment-block { display: none; }\n";
@@ -1,10 +1,5 @@
1
1
  "use strict";
2
2
  const BASE_CSS = `
3
- html,
4
- body {
5
- margin: 0;
6
- padding: 0;
7
- }
8
3
  .jw-root {
9
4
  background-color: var(--jw-bg-color, transparent);
10
5
  color: var(--jw-text-color, inherit);
@@ -13,14 +8,46 @@ body {
13
8
  }
14
9
  .jw-root > .jw-block + .jw-block { margin-top: var(--jw-block-spacing); }
15
10
  .jw-root > .jw-block { margin: 0; }
16
- .jw-table { border-collapse: collapse; }
17
- .jw-table-cell { border: 1px solid var(--jw-border-color); padding: 0.5em; }
11
+ .jw-table { border-collapse: collapse; width: 100%; }
12
+ .jw-table-cell {
13
+ border: 1px solid var(--jw-table-border-color, var(--jw-border-color));
14
+ padding: 0.5em;
15
+ }
16
+ .jw-table thead .jw-table-cell {
17
+ background: var(--jw-table-header-bg, var(--jw-surface-overlay-1));
18
+ color: var(--jw-table-header-text, var(--jw-text-strong));
19
+ font-weight: 600;
20
+ }
21
+ .jw-table tbody .jw-table-row:nth-child(odd) .jw-table-cell {
22
+ background: var(--jw-table-row-bg, transparent);
23
+ }
24
+ .jw-table tbody .jw-table-row:nth-child(even) .jw-table-cell {
25
+ background: var(--jw-table-row-alt-bg, transparent);
26
+ }
18
27
  .jw-link { text-decoration: none; color: var(--jw-link-color, currentColor); }
19
28
  .jw-link:visited { color: var(--jw-link-color, currentColor); }
20
29
  .jw-link:hover { text-decoration: underline; }
21
- .jw-underline { text-decoration: underline; }
22
- .jw-strike { text-decoration: line-through; }
23
- .jw-wave { text-decoration: underline; text-decoration-style: wavy; }
30
+ .jw-root strong {
31
+ color: var(--jw-strong-color, currentColor);
32
+ font-weight: var(--jw-strong-weight, 700);
33
+ }
34
+ .jw-underline {
35
+ text-decoration: underline;
36
+ text-decoration-color: var(--jw-underline-color, currentColor);
37
+ text-decoration-thickness: var(--jw-underline-thickness, from-font);
38
+ text-underline-offset: var(--jw-underline-offset, auto);
39
+ }
40
+ .jw-strike {
41
+ text-decoration: line-through;
42
+ text-decoration-color: var(--jw-strike-color, currentColor);
43
+ }
44
+ .jw-wave {
45
+ text-decoration: underline;
46
+ text-decoration-style: wavy;
47
+ text-decoration-color: var(--jw-wave-color, currentColor);
48
+ text-decoration-thickness: var(--jw-underline-thickness, from-font);
49
+ text-underline-offset: var(--jw-underline-offset, auto);
50
+ }
24
51
  .jw-heading { font-weight: bold; margin: 0; }
25
52
  .jw-heading.level-1 { font-size: 2.5em; }
26
53
  .jw-heading.level-2 { font-size: 2em; }
@@ -271,8 +298,8 @@ body {
271
298
  display: flex;
272
299
  flex-direction: column;
273
300
  padding: 0;
274
- background: var(--jw-surface-code);
275
- border: 1px solid var(--jw-border-color-subtle);
301
+ background: var(--jw-code-block-bg, var(--jw-surface-code));
302
+ border: 1px solid var(--jw-code-border-color, var(--jw-border-color-subtle));
276
303
  border-radius: 4px;
277
304
  font-family: "JetBrains Mono", "Fira Code", Consolas, Menlo, monospace;
278
305
  font-size: 0.9em;
@@ -284,13 +311,14 @@ body {
284
311
  justify-content: space-between;
285
312
  align-items: center;
286
313
  padding: 0.5em 0.75em;
287
- border-bottom: 1px solid var(--jw-border-color-subtle);
288
- background: var(--jw-surface-overlay-1);
314
+ border-bottom: 1px solid var(--jw-code-border-color, var(--jw-border-color-subtle));
315
+ background: var(--jw-code-header-bg, var(--jw-surface-overlay-1));
316
+ color: var(--jw-code-header-text, var(--jw-text-subtle));
289
317
  }
290
318
  .jw-code-lang {
291
319
  padding: 0.1em 0.4em;
292
- background: var(--jw-surface-overlay-2);
293
- color: var(--jw-text-subtle);
320
+ background: var(--jw-code-lang-bg, var(--jw-surface-overlay-2));
321
+ color: var(--jw-code-lang-text, var(--jw-text-subtle));
294
322
  font-size: 0.75em;
295
323
  border-radius: 3px;
296
324
  font-weight: 500;
@@ -300,16 +328,16 @@ body {
300
328
  .jw-code-copy {
301
329
  padding: 0.25em 0.5em;
302
330
  background: transparent;
303
- border: 1px solid var(--jw-border-color);
331
+ border: 1px solid var(--jw-code-copy-border, var(--jw-border-color));
304
332
  border-radius: 3px;
305
333
  cursor: pointer;
306
334
  font-size: 0.75em;
307
- color: var(--jw-text-subtle);
335
+ color: var(--jw-code-header-text, var(--jw-text-subtle));
308
336
  transition: background 0.2s, border-color 0.2s;
309
337
  }
310
338
  .jw-code-copy:hover {
311
- background: var(--jw-surface-overlay-2);
312
- border-color: var(--jw-border-color-strong);
339
+ background: var(--jw-code-copy-hover-bg, var(--jw-surface-overlay-2));
340
+ border-color: var(--jw-code-copy-border, var(--jw-border-color-strong));
313
341
  }
314
342
  .jw-code-copy:active {
315
343
  background: var(--jw-surface-overlay-3);
@@ -323,10 +351,10 @@ body {
323
351
  display: flex;
324
352
  flex-direction: column;
325
353
  padding: 0 0.75em;
326
- border-right: 1px solid var(--jw-border-color-subtle);
354
+ border-right: 1px solid var(--jw-code-border-color, var(--jw-border-color-subtle));
327
355
  text-align: right;
328
356
  user-select: none;
329
- color: var(--jw-text-faint);
357
+ color: var(--jw-code-line-number-color, var(--jw-text-faint));
330
358
  font-variant-numeric: tabular-nums;
331
359
  }
332
360
  .jw-line-number {
@@ -40,6 +40,30 @@ const DARK_CSS = `
40
40
  --jw-task-not-done-cross: #eef1f7;
41
41
  --jw-task-in-progress: #b7bdca;
42
42
 
43
+ --jw-strong-color: #f3f5f8;
44
+ --jw-strong-weight: 700;
45
+ --jw-underline-color: #8ab4f8;
46
+ --jw-underline-thickness: 0.08em;
47
+ --jw-underline-offset: 0.12em;
48
+ --jw-wave-color: #8ab4f8;
49
+ --jw-strike-color: #98a2b3;
50
+
51
+ --jw-table-border-color: #374151;
52
+ --jw-table-header-bg: #1f2937;
53
+ --jw-table-header-text: #d1d5db;
54
+ --jw-table-row-bg: #141922;
55
+ --jw-table-row-alt-bg: #171d28;
56
+
57
+ --jw-code-block-bg: #1c1f26;
58
+ --jw-code-border-color: #313846;
59
+ --jw-code-header-bg: rgba(255, 255, 255, 0.05);
60
+ --jw-code-header-text: #b8c2d3;
61
+ --jw-code-lang-bg: rgba(255, 255, 255, 0.08);
62
+ --jw-code-lang-text: #d1d8e3;
63
+ --jw-code-copy-border: #4b5563;
64
+ --jw-code-copy-hover-bg: rgba(255, 255, 255, 0.12);
65
+ --jw-code-line-number-color: #8b95a7;
66
+
43
67
  --jw-color-red: ${PRESET_COLORS.red};
44
68
  --jw-color-orange: ${PRESET_COLORS.orange};
45
69
  --jw-color-yellow: ${PRESET_COLORS.yellow};
@@ -92,6 +116,30 @@ const DARK_CSS = `
92
116
  --jw-task-not-done-cross: #eef1f7;
93
117
  --jw-task-in-progress: #b7bdca;
94
118
 
119
+ --jw-strong-color: #f3f5f8;
120
+ --jw-strong-weight: 700;
121
+ --jw-underline-color: #8ab4f8;
122
+ --jw-underline-thickness: 0.08em;
123
+ --jw-underline-offset: 0.12em;
124
+ --jw-wave-color: #8ab4f8;
125
+ --jw-strike-color: #98a2b3;
126
+
127
+ --jw-table-border-color: #374151;
128
+ --jw-table-header-bg: #1f2937;
129
+ --jw-table-header-text: #d1d5db;
130
+ --jw-table-row-bg: #141922;
131
+ --jw-table-row-alt-bg: #171d28;
132
+
133
+ --jw-code-block-bg: #1c1f26;
134
+ --jw-code-border-color: #313846;
135
+ --jw-code-header-bg: rgba(255, 255, 255, 0.05);
136
+ --jw-code-header-text: #b8c2d3;
137
+ --jw-code-lang-bg: rgba(255, 255, 255, 0.08);
138
+ --jw-code-lang-text: #d1d8e3;
139
+ --jw-code-copy-border: #4b5563;
140
+ --jw-code-copy-hover-bg: rgba(255, 255, 255, 0.12);
141
+ --jw-code-line-number-color: #8b95a7;
142
+
95
143
  --jw-color-red: ${PRESET_COLORS.red};
96
144
  --jw-color-orange: ${PRESET_COLORS.orange};
97
145
  --jw-color-yellow: ${PRESET_COLORS.yellow};
@@ -40,6 +40,30 @@ const LIGHT_CSS = `
40
40
  --jw-task-not-done-cross: #ffffff;
41
41
  --jw-task-in-progress: #555555;
42
42
 
43
+ --jw-strong-color: #2b2f39;
44
+ --jw-strong-weight: 700;
45
+ --jw-underline-color: #1d4ed8;
46
+ --jw-underline-thickness: 0.08em;
47
+ --jw-underline-offset: 0.12em;
48
+ --jw-wave-color: #1d4ed8;
49
+ --jw-strike-color: #767676;
50
+
51
+ --jw-table-border-color: #d1d5db;
52
+ --jw-table-header-bg: #f0f3f6;
53
+ --jw-table-header-text: #3f4654;
54
+ --jw-table-row-bg: #ffffff;
55
+ --jw-table-row-alt-bg: #f9fafb;
56
+
57
+ --jw-code-block-bg: #f5f5f5;
58
+ --jw-code-border-color: #dddddd;
59
+ --jw-code-header-bg: rgba(0, 0, 0, 0.04);
60
+ --jw-code-header-text: #5f6672;
61
+ --jw-code-lang-bg: rgba(0, 0, 0, 0.06);
62
+ --jw-code-lang-text: #4b5563;
63
+ --jw-code-copy-border: #c9ced6;
64
+ --jw-code-copy-hover-bg: rgba(0, 0, 0, 0.08);
65
+ --jw-code-line-number-color: #9aa0ad;
66
+
43
67
  --jw-color-red: ${PRESET_COLORS.red};
44
68
  --jw-color-orange: ${PRESET_COLORS.orange};
45
69
  --jw-color-yellow: ${PRESET_COLORS.yellow};
@@ -1,9 +1,31 @@
1
1
  export type DocumentTheme = 'light' | 'dark' | 'auto';
2
+ export type ThemeCssPreset = 'default' | 'none';
3
+ type PresetColorName = 'red' | 'orange' | 'yellow' | 'green' | 'cyan' | 'blue' | 'purple' | 'black' | 'darkgray' | 'gray';
4
+ export declare const JIANWEN_THEME_TOKEN_KEYS: readonly ["--jw-line-height-base", "--jw-block-spacing", "--jw-nested-list-gap", "--jw-quote-gap", "--jw-bg-color", "--jw-text-color", "--jw-link-color", "--jw-quote-border-color", "--jw-quote-border-color-2", "--jw-quote-border-color-3", "--jw-quote-background", "--jw-quote-text", "--jw-border-color", "--jw-border-color-subtle", "--jw-border-color-strong", "--jw-text-muted", "--jw-text-subtle", "--jw-text-strong", "--jw-text-faint", "--jw-surface-code", "--jw-surface-task", "--jw-surface-overlay-1", "--jw-surface-overlay-2", "--jw-surface-overlay-3", "--jw-highlight-marker", "--jw-task-done-bg", "--jw-task-done-text", "--jw-task-not-done-cross", "--jw-task-in-progress", "--jw-color-red", "--jw-color-orange", "--jw-color-yellow", "--jw-color-green", "--jw-color-cyan", "--jw-color-blue", "--jw-color-purple", "--jw-color-black", "--jw-color-darkgray", "--jw-color-gray", "--jw-strong-color", "--jw-strong-weight", "--jw-underline-color", "--jw-underline-thickness", "--jw-underline-offset", "--jw-wave-color", "--jw-strike-color", "--jw-table-border-color", "--jw-table-header-bg", "--jw-table-header-text", "--jw-table-row-bg", "--jw-table-row-alt-bg", "--jw-code-block-bg", "--jw-code-border-color", "--jw-code-header-bg", "--jw-code-header-text", "--jw-code-lang-bg", "--jw-code-lang-text", "--jw-code-copy-border", "--jw-code-copy-hover-bg", "--jw-code-line-number-color"];
5
+ export type JianwenThemeTokenKey = (typeof JIANWEN_THEME_TOKEN_KEYS)[number];
6
+ export type JianwenThemeTokenValues = Record<JianwenThemeTokenKey, string>;
7
+ export type JianwenThemeTokenOverrides = Partial<JianwenThemeTokenValues>;
8
+ export interface JianwenThemeConfig {
9
+ light?: JianwenThemeTokenOverrides;
10
+ dark?: JianwenThemeTokenOverrides;
11
+ includeAutoDark?: boolean;
12
+ }
2
13
  export interface ThemeCssBundle {
3
14
  baseCss: string;
4
15
  lightCss: string;
5
16
  darkCss: string;
6
17
  }
18
+ export interface ComposeThemeCssOptions {
19
+ preset?: ThemeCssPreset;
20
+ theme?: JianwenThemeConfig;
21
+ extraCss?: string;
22
+ }
7
23
  export declare const DEFAULT_THEME: ThemeCssBundle;
24
+ export declare const PRESET_COLORS: Record<PresetColorName, string> & Record<string, string>;
25
+ export declare const DEFAULT_THEME_TOKENS_LIGHT: JianwenThemeTokenValues;
26
+ export declare const DEFAULT_THEME_TOKENS_DARK: JianwenThemeTokenValues;
27
+ export declare const DEFAULT_THEME_CONFIG: JianwenThemeConfig;
8
28
  export declare const DEFAULT_CSS: string;
9
- export declare const PRESET_COLORS: Record<string, string>;
29
+ export declare function renderThemeTokenCss(theme: JianwenThemeConfig): string;
30
+ export declare function composeThemeCss(options?: ComposeThemeCssOptions): string;
31
+ export {};
@@ -3,19 +3,259 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.PRESET_COLORS = exports.DEFAULT_CSS = exports.DEFAULT_THEME = void 0;
6
+ exports.DEFAULT_CSS = exports.DEFAULT_THEME_CONFIG = exports.DEFAULT_THEME_TOKENS_DARK = exports.DEFAULT_THEME_TOKENS_LIGHT = exports.PRESET_COLORS = exports.DEFAULT_THEME = exports.JIANWEN_THEME_TOKEN_KEYS = void 0;
7
+ exports.renderThemeTokenCss = renderThemeTokenCss;
8
+ exports.composeThemeCss = composeThemeCss;
7
9
  const css_1 = __importDefault(require("./base/css"));
8
10
  const css_2 = __importDefault(require("./dark/css"));
9
11
  const css_3 = __importDefault(require("./light/css"));
10
12
  const colors_1 = __importDefault(require("./preset/colors"));
13
+ exports.JIANWEN_THEME_TOKEN_KEYS = [
14
+ '--jw-line-height-base',
15
+ '--jw-block-spacing',
16
+ '--jw-nested-list-gap',
17
+ '--jw-quote-gap',
18
+ '--jw-bg-color',
19
+ '--jw-text-color',
20
+ '--jw-link-color',
21
+ '--jw-quote-border-color',
22
+ '--jw-quote-border-color-2',
23
+ '--jw-quote-border-color-3',
24
+ '--jw-quote-background',
25
+ '--jw-quote-text',
26
+ '--jw-border-color',
27
+ '--jw-border-color-subtle',
28
+ '--jw-border-color-strong',
29
+ '--jw-text-muted',
30
+ '--jw-text-subtle',
31
+ '--jw-text-strong',
32
+ '--jw-text-faint',
33
+ '--jw-surface-code',
34
+ '--jw-surface-task',
35
+ '--jw-surface-overlay-1',
36
+ '--jw-surface-overlay-2',
37
+ '--jw-surface-overlay-3',
38
+ '--jw-highlight-marker',
39
+ '--jw-task-done-bg',
40
+ '--jw-task-done-text',
41
+ '--jw-task-not-done-cross',
42
+ '--jw-task-in-progress',
43
+ '--jw-color-red',
44
+ '--jw-color-orange',
45
+ '--jw-color-yellow',
46
+ '--jw-color-green',
47
+ '--jw-color-cyan',
48
+ '--jw-color-blue',
49
+ '--jw-color-purple',
50
+ '--jw-color-black',
51
+ '--jw-color-darkgray',
52
+ '--jw-color-gray',
53
+ '--jw-strong-color',
54
+ '--jw-strong-weight',
55
+ '--jw-underline-color',
56
+ '--jw-underline-thickness',
57
+ '--jw-underline-offset',
58
+ '--jw-wave-color',
59
+ '--jw-strike-color',
60
+ '--jw-table-border-color',
61
+ '--jw-table-header-bg',
62
+ '--jw-table-header-text',
63
+ '--jw-table-row-bg',
64
+ '--jw-table-row-alt-bg',
65
+ '--jw-code-block-bg',
66
+ '--jw-code-border-color',
67
+ '--jw-code-header-bg',
68
+ '--jw-code-header-text',
69
+ '--jw-code-lang-bg',
70
+ '--jw-code-lang-text',
71
+ '--jw-code-copy-border',
72
+ '--jw-code-copy-hover-bg',
73
+ '--jw-code-line-number-color',
74
+ ];
11
75
  exports.DEFAULT_THEME = {
12
76
  baseCss: String(css_1.default),
13
77
  lightCss: String(css_3.default),
14
78
  darkCss: String(css_2.default),
15
79
  };
80
+ exports.PRESET_COLORS = colors_1.default;
81
+ exports.DEFAULT_THEME_TOKENS_LIGHT = {
82
+ '--jw-line-height-base': '1.7',
83
+ '--jw-block-spacing': '1em',
84
+ '--jw-nested-list-gap': '0.35em',
85
+ '--jw-quote-gap': '0.6em',
86
+ '--jw-bg-color': '#ffffff',
87
+ '--jw-text-color': '#222222',
88
+ '--jw-link-color': '#1d4ed8',
89
+ '--jw-quote-border-color': '#d0d0d0',
90
+ '--jw-quote-border-color-2': '#c5c5c5',
91
+ '--jw-quote-border-color-3': '#b8b8b8',
92
+ '--jw-quote-background': '#f8f8f8',
93
+ '--jw-quote-text': '#595959',
94
+ '--jw-border-color': '#cccccc',
95
+ '--jw-border-color-subtle': '#dddddd',
96
+ '--jw-border-color-strong': '#999999',
97
+ '--jw-text-muted': '#777777',
98
+ '--jw-text-subtle': '#666666',
99
+ '--jw-text-strong': '#555555',
100
+ '--jw-text-faint': '#999999',
101
+ '--jw-surface-code': '#f5f5f5',
102
+ '--jw-surface-task': '#eeeeee',
103
+ '--jw-surface-overlay-1': 'rgba(0, 0, 0, 0.02)',
104
+ '--jw-surface-overlay-2': 'rgba(0, 0, 0, 0.05)',
105
+ '--jw-surface-overlay-3': 'rgba(0, 0, 0, 0.1)',
106
+ '--jw-highlight-marker': '#FFEB3B',
107
+ '--jw-task-done-bg': '#333333',
108
+ '--jw-task-done-text': '#ffffff',
109
+ '--jw-task-not-done-cross': '#ffffff',
110
+ '--jw-task-in-progress': '#555555',
111
+ '--jw-color-red': exports.PRESET_COLORS.red,
112
+ '--jw-color-orange': exports.PRESET_COLORS.orange,
113
+ '--jw-color-yellow': exports.PRESET_COLORS.yellow,
114
+ '--jw-color-green': exports.PRESET_COLORS.green,
115
+ '--jw-color-cyan': exports.PRESET_COLORS.cyan,
116
+ '--jw-color-blue': exports.PRESET_COLORS.blue,
117
+ '--jw-color-purple': exports.PRESET_COLORS.purple,
118
+ '--jw-color-black': exports.PRESET_COLORS.black,
119
+ '--jw-color-darkgray': exports.PRESET_COLORS.darkgray,
120
+ '--jw-color-gray': exports.PRESET_COLORS.gray,
121
+ '--jw-strong-color': '#2b2f39',
122
+ '--jw-strong-weight': '700',
123
+ '--jw-underline-color': '#1d4ed8',
124
+ '--jw-underline-thickness': '0.08em',
125
+ '--jw-underline-offset': '0.12em',
126
+ '--jw-wave-color': '#1d4ed8',
127
+ '--jw-strike-color': '#767676',
128
+ '--jw-table-border-color': '#d1d5db',
129
+ '--jw-table-header-bg': '#f0f3f6',
130
+ '--jw-table-header-text': '#3f4654',
131
+ '--jw-table-row-bg': '#ffffff',
132
+ '--jw-table-row-alt-bg': '#f9fafb',
133
+ '--jw-code-block-bg': '#f5f5f5',
134
+ '--jw-code-border-color': '#dddddd',
135
+ '--jw-code-header-bg': 'rgba(0, 0, 0, 0.04)',
136
+ '--jw-code-header-text': '#5f6672',
137
+ '--jw-code-lang-bg': 'rgba(0, 0, 0, 0.06)',
138
+ '--jw-code-lang-text': '#4b5563',
139
+ '--jw-code-copy-border': '#c9ced6',
140
+ '--jw-code-copy-hover-bg': 'rgba(0, 0, 0, 0.08)',
141
+ '--jw-code-line-number-color': '#9aa0ad',
142
+ };
143
+ exports.DEFAULT_THEME_TOKENS_DARK = {
144
+ '--jw-line-height-base': '1.7',
145
+ '--jw-block-spacing': '1em',
146
+ '--jw-nested-list-gap': '0.35em',
147
+ '--jw-quote-gap': '0.6em',
148
+ '--jw-bg-color': '#15171c',
149
+ '--jw-text-color': '#e8e9ed',
150
+ '--jw-link-color': '#8ab4f8',
151
+ '--jw-quote-border-color': '#343843',
152
+ '--jw-quote-border-color-2': '#2c313a',
153
+ '--jw-quote-border-color-3': '#252a33',
154
+ '--jw-quote-background': '#1d2028',
155
+ '--jw-quote-text': '#c9ccd5',
156
+ '--jw-border-color': '#333844',
157
+ '--jw-border-color-subtle': '#282d38',
158
+ '--jw-border-color-strong': '#434958',
159
+ '--jw-text-muted': '#b3b7c2',
160
+ '--jw-text-subtle': '#9aa0ad',
161
+ '--jw-text-strong': '#d7d9e2',
162
+ '--jw-text-faint': '#7c8494',
163
+ '--jw-surface-code': '#1c1f26',
164
+ '--jw-surface-task': '#262b36',
165
+ '--jw-surface-overlay-1': 'rgba(255, 255, 255, 0.03)',
166
+ '--jw-surface-overlay-2': 'rgba(255, 255, 255, 0.06)',
167
+ '--jw-surface-overlay-3': 'rgba(255, 255, 255, 0.1)',
168
+ '--jw-highlight-marker': '#d2b21f',
169
+ '--jw-task-done-bg': '#cfd3dd',
170
+ '--jw-task-done-text': '#1c1f26',
171
+ '--jw-task-not-done-cross': '#eef1f7',
172
+ '--jw-task-in-progress': '#b7bdca',
173
+ '--jw-color-red': exports.PRESET_COLORS.red,
174
+ '--jw-color-orange': exports.PRESET_COLORS.orange,
175
+ '--jw-color-yellow': exports.PRESET_COLORS.yellow,
176
+ '--jw-color-green': exports.PRESET_COLORS.green,
177
+ '--jw-color-cyan': exports.PRESET_COLORS.cyan,
178
+ '--jw-color-blue': exports.PRESET_COLORS.blue,
179
+ '--jw-color-purple': exports.PRESET_COLORS.purple,
180
+ '--jw-color-black': exports.PRESET_COLORS.black,
181
+ '--jw-color-darkgray': exports.PRESET_COLORS.darkgray,
182
+ '--jw-color-gray': exports.PRESET_COLORS.gray,
183
+ '--jw-strong-color': '#f3f5f8',
184
+ '--jw-strong-weight': '700',
185
+ '--jw-underline-color': '#8ab4f8',
186
+ '--jw-underline-thickness': '0.08em',
187
+ '--jw-underline-offset': '0.12em',
188
+ '--jw-wave-color': '#8ab4f8',
189
+ '--jw-strike-color': '#98a2b3',
190
+ '--jw-table-border-color': '#374151',
191
+ '--jw-table-header-bg': '#1f2937',
192
+ '--jw-table-header-text': '#d1d5db',
193
+ '--jw-table-row-bg': '#141922',
194
+ '--jw-table-row-alt-bg': '#171d28',
195
+ '--jw-code-block-bg': '#1c1f26',
196
+ '--jw-code-border-color': '#313846',
197
+ '--jw-code-header-bg': 'rgba(255, 255, 255, 0.05)',
198
+ '--jw-code-header-text': '#b8c2d3',
199
+ '--jw-code-lang-bg': 'rgba(255, 255, 255, 0.08)',
200
+ '--jw-code-lang-text': '#d1d8e3',
201
+ '--jw-code-copy-border': '#4b5563',
202
+ '--jw-code-copy-hover-bg': 'rgba(255, 255, 255, 0.12)',
203
+ '--jw-code-line-number-color': '#8b95a7',
204
+ };
205
+ exports.DEFAULT_THEME_CONFIG = {
206
+ light: exports.DEFAULT_THEME_TOKENS_LIGHT,
207
+ dark: exports.DEFAULT_THEME_TOKENS_DARK,
208
+ includeAutoDark: true,
209
+ };
16
210
  exports.DEFAULT_CSS = [
17
211
  exports.DEFAULT_THEME.baseCss,
18
212
  exports.DEFAULT_THEME.lightCss,
19
213
  exports.DEFAULT_THEME.darkCss,
20
214
  ].join('\n');
21
- exports.PRESET_COLORS = colors_1.default;
215
+ function renderTokenDeclarations(tokens) {
216
+ return exports.JIANWEN_THEME_TOKEN_KEYS.map((key) => ` ${key}: ${tokens[key]};`).join('\n');
217
+ }
218
+ function renderTokenBlock(selector, tokens) {
219
+ return `${selector} {\n${renderTokenDeclarations(tokens)}\n}`;
220
+ }
221
+ function resolveThemeConfig(theme) {
222
+ return {
223
+ light: {
224
+ ...exports.DEFAULT_THEME_TOKENS_LIGHT,
225
+ ...(theme.light ?? {}),
226
+ },
227
+ dark: {
228
+ ...exports.DEFAULT_THEME_TOKENS_DARK,
229
+ ...(theme.dark ?? {}),
230
+ },
231
+ includeAutoDark: theme.includeAutoDark ?? true,
232
+ };
233
+ }
234
+ function renderThemeTokenCss(theme) {
235
+ const resolved = resolveThemeConfig(theme);
236
+ const parts = [
237
+ renderTokenBlock(':where(.jw-root)', resolved.light),
238
+ renderTokenBlock(':where(.jw-root)[data-jw-theme="dark"]', resolved.dark),
239
+ ];
240
+ if (resolved.includeAutoDark) {
241
+ parts.push(`@media (prefers-color-scheme: dark) {
242
+ ${renderTokenBlock(':where(.jw-root)[data-jw-theme="auto"]', resolved.dark)}
243
+ }`);
244
+ }
245
+ return parts.join('\n');
246
+ }
247
+ function composeThemeCss(options = {}) {
248
+ const preset = options.preset ?? 'default';
249
+ const extraCss = options.extraCss?.trim() ?? '';
250
+ const parts = [];
251
+ if (preset === 'default') {
252
+ parts.push(exports.DEFAULT_CSS);
253
+ }
254
+ if (options.theme) {
255
+ parts.push(renderThemeTokenCss(options.theme));
256
+ }
257
+ if (extraCss) {
258
+ parts.push(extraCss);
259
+ }
260
+ return parts.join('\n');
261
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jianwen-lang/parser",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "JianWen language parser implemented in TypeScript",
5
5
  "main": "dist/parser.js",
6
6
  "types": "dist/parser.d.ts",