@ox-content/vite-plugin 3.0.0-alpha.13 → 3.0.0-alpha.15
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/dist/index.cjs +200 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -15
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +93 -15
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +199 -20
- package/dist/index.mjs.map +1 -1
- package/dist/markdown-tables.cjs.map +1 -1
- package/dist/markdown-tables.mjs.map +1 -1
- package/dist/styles/core.css +16 -16
- package/dist/styles/markdown-tables.css +3 -1
- package/dist/styles/social.css +68 -15
- package/dist/styles/tabs.css +15 -15
- package/dist/styles/twitter-full.css +71 -0
- package/dist/theme-tokens.cjs +95 -0
- package/dist/theme-tokens.cjs.map +1 -0
- package/dist/theme-tokens.d.cts +75 -0
- package/dist/theme-tokens.d.cts.map +1 -0
- package/dist/theme-tokens.d.mts +75 -0
- package/dist/theme-tokens.d.mts.map +1 -0
- package/dist/theme-tokens.mjs +91 -0
- package/dist/theme-tokens.mjs.map +1 -0
- package/dist/vitepress.cjs +2 -31
- package/dist/vitepress.cjs.map +1 -1
- package/dist/vitepress.mjs +2 -31
- package/dist/vitepress.mjs.map +1 -1
- package/package.json +13 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-tables.cjs","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"markdown-tables.cjs","sourceRoot":"","sources":["../../../../home/runner/work/ox-content/ox-content/npm/vite-plugin-ox-content/src/markdown-tables.ts"],"names":[],"mappings":"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","sourcesContent":["export interface MarkdownTableEnhancementOptions {\n /**\n * Tables to enhance. Defaults to Markdown content tables styled by\n * `@ox-content/vite-plugin/styles/core.css`.\n */\n selector?: string;\n /**\n * Accessible name applied only when an overflowing table has no existing\n * `aria-label` or `aria-labelledby`.\n */\n label?: string;\n}\n\nconst TABINDEX_FLAG = \"oxTableScrollTabindex\";\nconst LABEL_FLAG = \"oxTableScrollLabel\";\nconst SCROLLABLE_ATTR = \"data-ox-table-scrollable\";\n\nexport function markdownTableScrollLabel(locale?: string): string {\n const language = locale?.split(\"-\")[0]?.toLowerCase();\n if (language === \"ja\") {\n return \"横スクロールできる表\";\n }\n return \"Scrollable table\";\n}\n\n/**\n * Makes overflowing Markdown tables keyboard-scrollable without wrapping or\n * replacing the native `<table>` element.\n *\n * Run this after rendering Markdown and again after layout-changing updates.\n * Narrow tables stay out of the tab order when overflow can be measured.\n */\nexport function enhanceMarkdownTables(\n root?: ParentNode,\n options: MarkdownTableEnhancementOptions = {},\n): number {\n const target = root ?? globalThis.document;\n if (!target?.querySelectorAll) {\n return 0;\n }\n\n const selector = options.selector ?? \".content table\";\n const locale = ownerDocument(target)?.documentElement.lang;\n const label = options.label ?? markdownTableScrollLabel(locale);\n let scrollableCount = 0;\n\n for (const table of target.querySelectorAll(selector)) {\n if (typeof HTMLElement === \"undefined\" || !(table instanceof HTMLElement)) {\n continue;\n }\n if (table.tagName !== \"TABLE\") {\n continue;\n }\n\n const scrollable = table.scrollWidth > table.clientWidth + 1;\n table.toggleAttribute(SCROLLABLE_ATTR, scrollable);\n if (scrollable) {\n scrollableCount++;\n if (!table.hasAttribute(\"tabindex\")) {\n table.tabIndex = 0;\n table.dataset[TABINDEX_FLAG] = \"true\";\n }\n if (!table.hasAttribute(\"aria-label\") && !table.hasAttribute(\"aria-labelledby\")) {\n table.setAttribute(\"aria-label\", label);\n table.dataset[LABEL_FLAG] = \"true\";\n }\n } else {\n if (table.dataset[TABINDEX_FLAG] === \"true\") {\n table.removeAttribute(\"tabindex\");\n delete table.dataset[TABINDEX_FLAG];\n }\n if (table.dataset[LABEL_FLAG] === \"true\") {\n table.removeAttribute(\"aria-label\");\n delete table.dataset[LABEL_FLAG];\n }\n }\n }\n\n return scrollableCount;\n}\n\nfunction ownerDocument(root: ParentNode): Document | undefined {\n if (typeof Document !== \"undefined\" && root instanceof Document) {\n return root;\n }\n return root.ownerDocument ?? globalThis.document;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-tables.mjs","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"markdown-tables.mjs","sourceRoot":"","sources":["../../../../home/runner/work/ox-content/ox-content/npm/vite-plugin-ox-content/src/markdown-tables.ts"],"names":[],"mappings":"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","sourcesContent":["export interface MarkdownTableEnhancementOptions {\n /**\n * Tables to enhance. Defaults to Markdown content tables styled by\n * `@ox-content/vite-plugin/styles/core.css`.\n */\n selector?: string;\n /**\n * Accessible name applied only when an overflowing table has no existing\n * `aria-label` or `aria-labelledby`.\n */\n label?: string;\n}\n\nconst TABINDEX_FLAG = \"oxTableScrollTabindex\";\nconst LABEL_FLAG = \"oxTableScrollLabel\";\nconst SCROLLABLE_ATTR = \"data-ox-table-scrollable\";\n\nexport function markdownTableScrollLabel(locale?: string): string {\n const language = locale?.split(\"-\")[0]?.toLowerCase();\n if (language === \"ja\") {\n return \"横スクロールできる表\";\n }\n return \"Scrollable table\";\n}\n\n/**\n * Makes overflowing Markdown tables keyboard-scrollable without wrapping or\n * replacing the native `<table>` element.\n *\n * Run this after rendering Markdown and again after layout-changing updates.\n * Narrow tables stay out of the tab order when overflow can be measured.\n */\nexport function enhanceMarkdownTables(\n root?: ParentNode,\n options: MarkdownTableEnhancementOptions = {},\n): number {\n const target = root ?? globalThis.document;\n if (!target?.querySelectorAll) {\n return 0;\n }\n\n const selector = options.selector ?? \".content table\";\n const locale = ownerDocument(target)?.documentElement.lang;\n const label = options.label ?? markdownTableScrollLabel(locale);\n let scrollableCount = 0;\n\n for (const table of target.querySelectorAll(selector)) {\n if (typeof HTMLElement === \"undefined\" || !(table instanceof HTMLElement)) {\n continue;\n }\n if (table.tagName !== \"TABLE\") {\n continue;\n }\n\n const scrollable = table.scrollWidth > table.clientWidth + 1;\n table.toggleAttribute(SCROLLABLE_ATTR, scrollable);\n if (scrollable) {\n scrollableCount++;\n if (!table.hasAttribute(\"tabindex\")) {\n table.tabIndex = 0;\n table.dataset[TABINDEX_FLAG] = \"true\";\n }\n if (!table.hasAttribute(\"aria-label\") && !table.hasAttribute(\"aria-labelledby\")) {\n table.setAttribute(\"aria-label\", label);\n table.dataset[LABEL_FLAG] = \"true\";\n }\n } else {\n if (table.dataset[TABINDEX_FLAG] === \"true\") {\n table.removeAttribute(\"tabindex\");\n delete table.dataset[TABINDEX_FLAG];\n }\n if (table.dataset[LABEL_FLAG] === \"true\") {\n table.removeAttribute(\"aria-label\");\n delete table.dataset[LABEL_FLAG];\n }\n }\n }\n\n return scrollableCount;\n}\n\nfunction ownerDocument(root: ParentNode): Document | undefined {\n if (typeof Document !== \"undefined\" && root instanceof Document) {\n return root;\n }\n return root.ownerDocument ?? globalThis.document;\n}\n"]}
|
package/dist/styles/core.css
CHANGED
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
--octc-focus-offset: 2px;
|
|
60
60
|
--octc-motion-base: 150ms;
|
|
61
61
|
--octc-motion-ease: ease;
|
|
62
|
-
--octc-code-pad-block:
|
|
63
|
-
--octc-code-pad-inline:
|
|
62
|
+
--octc-code-pad-block: 1.05rem;
|
|
63
|
+
--octc-code-pad-inline: 1rem;
|
|
64
64
|
--octc-code-title-pad-block: 0.75rem;
|
|
65
65
|
--octc-code-title-gap: 0.875rem;
|
|
66
66
|
--octc-table-cell-pad-block: 0.75rem;
|
|
@@ -1013,11 +1013,11 @@ a:hover {
|
|
|
1013
1013
|
margin-bottom: 0;
|
|
1014
1014
|
}
|
|
1015
1015
|
.content .ox-steps {
|
|
1016
|
-
margin: 1.
|
|
1017
|
-
padding:
|
|
1016
|
+
margin: 1.25rem 0 1.5rem;
|
|
1017
|
+
padding: 0.85rem 0.9rem;
|
|
1018
1018
|
border: 1px solid var(--octc-color-border);
|
|
1019
|
-
border-radius:
|
|
1020
|
-
background: color-mix(in srgb, var(--octc-color-bg-alt)
|
|
1019
|
+
border-radius: 6px;
|
|
1020
|
+
background: color-mix(in srgb, var(--octc-color-bg-alt) 34%, transparent);
|
|
1021
1021
|
}
|
|
1022
1022
|
.content .ox-steps__list {
|
|
1023
1023
|
list-style: none;
|
|
@@ -1027,20 +1027,20 @@ a:hover {
|
|
|
1027
1027
|
}
|
|
1028
1028
|
.content .ox-steps__item {
|
|
1029
1029
|
position: relative;
|
|
1030
|
-
margin: 0 0
|
|
1031
|
-
padding-left: 2.
|
|
1030
|
+
margin: 0 0 0.85rem;
|
|
1031
|
+
padding-left: 2.2rem;
|
|
1032
1032
|
counter-increment: ox-steps;
|
|
1033
1033
|
}
|
|
1034
1034
|
.content .ox-steps__item::before {
|
|
1035
1035
|
content: counter(ox-steps);
|
|
1036
1036
|
position: absolute;
|
|
1037
1037
|
left: 0;
|
|
1038
|
-
top: 0.
|
|
1038
|
+
top: 0.12rem;
|
|
1039
1039
|
display: flex;
|
|
1040
1040
|
align-items: center;
|
|
1041
1041
|
justify-content: center;
|
|
1042
|
-
width: 1.
|
|
1043
|
-
height: 1.
|
|
1042
|
+
width: 1.45rem;
|
|
1043
|
+
height: 1.45rem;
|
|
1044
1044
|
border-radius: 999px;
|
|
1045
1045
|
background: var(--octc-color-primary);
|
|
1046
1046
|
color: var(--octc-color-bg);
|
|
@@ -1196,13 +1196,13 @@ a:hover {
|
|
|
1196
1196
|
position: relative;
|
|
1197
1197
|
}
|
|
1198
1198
|
.content pre.ox-code-block.line-numbers-mode .line {
|
|
1199
|
-
padding-left:
|
|
1199
|
+
padding-left: 3rem;
|
|
1200
1200
|
}
|
|
1201
1201
|
.content pre.ox-code-block.line-numbers-mode .line::before {
|
|
1202
1202
|
content: attr(data-line-number);
|
|
1203
1203
|
position: absolute;
|
|
1204
1204
|
left: var(--octc-code-pad-inline);
|
|
1205
|
-
width:
|
|
1205
|
+
width: 1.65rem;
|
|
1206
1206
|
text-align: right;
|
|
1207
1207
|
color: var(--octc-color-code-line-number);
|
|
1208
1208
|
user-select: none;
|
|
@@ -1264,7 +1264,7 @@ a:hover {
|
|
|
1264
1264
|
margin: 1.25rem 0;
|
|
1265
1265
|
font-size: 0.875rem;
|
|
1266
1266
|
}
|
|
1267
|
-
.content table[data-ox-table-scrollable
|
|
1267
|
+
.content table[data-ox-table-scrollable]:focus-visible {
|
|
1268
1268
|
outline: var(--octc-focus-ring);
|
|
1269
1269
|
outline-offset: var(--octc-focus-offset);
|
|
1270
1270
|
}
|
|
@@ -2104,10 +2104,10 @@ a:hover {
|
|
|
2104
2104
|
font-size: 0.82rem !important;
|
|
2105
2105
|
}
|
|
2106
2106
|
.content pre.ox-code-block.line-numbers-mode .line {
|
|
2107
|
-
padding-left:
|
|
2107
|
+
padding-left: 2.85rem;
|
|
2108
2108
|
}
|
|
2109
2109
|
.content pre.ox-code-block.line-numbers-mode .line::before {
|
|
2110
|
-
width: 1.
|
|
2110
|
+
width: 1.65rem;
|
|
2111
2111
|
}
|
|
2112
2112
|
.content table {
|
|
2113
2113
|
margin: 1rem 0;
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
-webkit-overflow-scrolling: touch;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/* `enhanceMarkdownTables()` marks overflow with `toggleAttribute()`, so the
|
|
12
|
+
attribute is present with an empty value. Match on presence, never a value. */
|
|
13
|
+
.content table[data-ox-table-scrollable]:focus-visible {
|
|
12
14
|
outline: var(--octc-focus-ring, 2px solid Highlight);
|
|
13
15
|
outline-offset: var(--octc-focus-offset, 2px);
|
|
14
16
|
}
|
package/dist/styles/social.css
CHANGED
|
@@ -17,6 +17,13 @@
|
|
|
17
17
|
color: var(--octc-color-text);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/* A fetched tweet renders `<figure><header>…` rather than wrapping its body in
|
|
21
|
+
one anchor, so the rule above never matches it. Pad the card itself to keep
|
|
22
|
+
it level with the Bluesky card. */
|
|
23
|
+
.ox-tweet--fetched {
|
|
24
|
+
padding: 1rem 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
.ox-tweet > a:hover,
|
|
21
28
|
.ox-bluesky > a:hover {
|
|
22
29
|
text-decoration: none;
|
|
@@ -292,13 +299,13 @@
|
|
|
292
299
|
.ox-tweet__quote .ox-tweet__media {
|
|
293
300
|
margin-bottom: 0;
|
|
294
301
|
}
|
|
295
|
-
|
|
296
302
|
/* WebContainer lazy placeholder */
|
|
297
303
|
.ox-webcontainer {
|
|
298
304
|
margin: 1.5rem 0;
|
|
299
305
|
border: 1px solid color-mix(in srgb, var(--octc-color-border) 74%, transparent);
|
|
300
306
|
border-radius: 8px;
|
|
301
307
|
overflow: hidden;
|
|
308
|
+
background: var(--octc-color-bg);
|
|
302
309
|
}
|
|
303
310
|
|
|
304
311
|
.ox-webcontainer__header {
|
|
@@ -306,40 +313,79 @@
|
|
|
306
313
|
align-items: center;
|
|
307
314
|
justify-content: space-between;
|
|
308
315
|
gap: 0.75rem;
|
|
309
|
-
padding: 0.
|
|
316
|
+
padding: 0.65rem 0.85rem;
|
|
310
317
|
border-bottom: 1px solid color-mix(in srgb, var(--octc-color-border) 74%, transparent);
|
|
311
318
|
background: var(--octc-color-bg-alt);
|
|
312
319
|
}
|
|
313
320
|
|
|
314
|
-
.ox-
|
|
321
|
+
.ox-webcontainer__title {
|
|
322
|
+
display: inline-flex;
|
|
323
|
+
align-items: center;
|
|
324
|
+
min-width: 0;
|
|
325
|
+
gap: 0.55rem;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.ox-webcontainer__title strong {
|
|
315
329
|
font-size: 0.875rem;
|
|
316
330
|
color: var(--octc-color-text);
|
|
317
331
|
}
|
|
318
332
|
|
|
319
|
-
.ox-
|
|
333
|
+
.ox-webcontainer__title code {
|
|
334
|
+
color: var(--octc-color-text-muted);
|
|
335
|
+
overflow: hidden;
|
|
336
|
+
text-overflow: ellipsis;
|
|
337
|
+
white-space: nowrap;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.ox-webcontainer__status,
|
|
341
|
+
.ox-webcontainer__meta {
|
|
320
342
|
font-size: 0.75rem;
|
|
321
343
|
color: var(--octc-color-text-muted);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.ox-webcontainer__status {
|
|
347
|
+
padding: 0.16rem 0.5rem;
|
|
348
|
+
border: 1px solid color-mix(in srgb, var(--octc-color-primary) 26%, transparent);
|
|
349
|
+
border-radius: 999px;
|
|
350
|
+
background: color-mix(in srgb, var(--octc-color-primary) 8%, transparent);
|
|
351
|
+
color: var(--octc-color-primary);
|
|
322
352
|
white-space: nowrap;
|
|
323
353
|
}
|
|
324
354
|
|
|
355
|
+
.ox-webcontainer__preview {
|
|
356
|
+
background: var(--octc-color-code-bg);
|
|
357
|
+
}
|
|
358
|
+
|
|
325
359
|
.ox-webcontainer pre {
|
|
326
360
|
margin: 0;
|
|
327
361
|
border: 0;
|
|
328
362
|
border-radius: 0;
|
|
329
363
|
}
|
|
364
|
+
|
|
365
|
+
.ox-webcontainer__meta {
|
|
366
|
+
display: flex;
|
|
367
|
+
flex-wrap: wrap;
|
|
368
|
+
gap: 0.45rem 0.85rem;
|
|
369
|
+
padding: 0.6rem 0.85rem;
|
|
370
|
+
border-top: 1px solid color-mix(in srgb, var(--octc-color-border) 74%, transparent);
|
|
371
|
+
background: color-mix(in srgb, var(--octc-color-bg-alt) 54%, transparent);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.ox-webcontainer__meta code {
|
|
375
|
+
color: var(--octc-color-text);
|
|
376
|
+
}
|
|
330
377
|
/* Provider cards for static article, place, community, and social embeds */
|
|
331
378
|
.ox-provider-card {
|
|
332
379
|
display: block;
|
|
333
|
-
margin:
|
|
380
|
+
margin: 1rem 0;
|
|
334
381
|
border: 1px solid color-mix(in srgb, var(--octc-color-border) 74%, transparent);
|
|
335
|
-
border-radius:
|
|
382
|
+
border-radius: 6px;
|
|
336
383
|
overflow: hidden;
|
|
337
384
|
background: var(--octc-color-bg);
|
|
338
385
|
}
|
|
339
386
|
|
|
340
387
|
.ox-provider-card__main {
|
|
341
|
-
display:
|
|
342
|
-
padding: 1rem;
|
|
388
|
+
display: grid;
|
|
343
389
|
color: var(--octc-color-text);
|
|
344
390
|
text-decoration: none;
|
|
345
391
|
}
|
|
@@ -358,7 +404,10 @@
|
|
|
358
404
|
}
|
|
359
405
|
|
|
360
406
|
.ox-provider-card__header {
|
|
361
|
-
|
|
407
|
+
min-height: 2.1rem;
|
|
408
|
+
padding: 0.45rem 0.8rem;
|
|
409
|
+
border-bottom: 1px solid color-mix(in srgb, var(--octc-color-border) 68%, transparent);
|
|
410
|
+
background: color-mix(in srgb, var(--octc-color-bg-alt) 60%, transparent);
|
|
362
411
|
font-size: 0.75rem;
|
|
363
412
|
}
|
|
364
413
|
|
|
@@ -378,6 +427,7 @@
|
|
|
378
427
|
align-items: flex-start;
|
|
379
428
|
gap: 0.75rem;
|
|
380
429
|
min-width: 0;
|
|
430
|
+
padding: 0.8rem;
|
|
381
431
|
}
|
|
382
432
|
|
|
383
433
|
.ox-provider-card__avatar {
|
|
@@ -393,7 +443,7 @@
|
|
|
393
443
|
min-width: 0;
|
|
394
444
|
}
|
|
395
445
|
|
|
396
|
-
.ox-provider-card__title {
|
|
446
|
+
.ox-provider-card .ox-provider-card__title {
|
|
397
447
|
margin: 0;
|
|
398
448
|
font-size: 1rem;
|
|
399
449
|
line-height: 1.35;
|
|
@@ -404,8 +454,8 @@
|
|
|
404
454
|
text-decoration: underline;
|
|
405
455
|
}
|
|
406
456
|
|
|
407
|
-
.ox-provider-card__excerpt {
|
|
408
|
-
margin: 0.
|
|
457
|
+
.ox-provider-card .ox-provider-card__excerpt {
|
|
458
|
+
margin: 0.35rem 0 0;
|
|
409
459
|
font-size: 0.875rem;
|
|
410
460
|
line-height: 1.55;
|
|
411
461
|
color: var(--octc-color-text-muted);
|
|
@@ -417,15 +467,18 @@
|
|
|
417
467
|
width: 100%;
|
|
418
468
|
height: auto;
|
|
419
469
|
max-height: 420px;
|
|
420
|
-
margin-top: 0.875rem;
|
|
421
470
|
border: 1px solid color-mix(in srgb, var(--octc-color-border) 74%, transparent);
|
|
422
|
-
border-
|
|
471
|
+
border-width: 1px 0 0;
|
|
472
|
+
border-radius: 0;
|
|
423
473
|
object-fit: cover;
|
|
424
474
|
background: var(--octc-color-bg-alt);
|
|
425
475
|
}
|
|
426
476
|
|
|
427
477
|
.ox-provider-card__meta {
|
|
428
|
-
|
|
478
|
+
min-height: 2.15rem;
|
|
479
|
+
padding: 0.45rem 0.8rem;
|
|
480
|
+
border-top: 1px solid color-mix(in srgb, var(--octc-color-border) 68%, transparent);
|
|
481
|
+
background: color-mix(in srgb, var(--octc-color-bg-alt) 48%, transparent);
|
|
429
482
|
font-size: 0.75rem;
|
|
430
483
|
}
|
|
431
484
|
|
package/dist/styles/tabs.css
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/* ox-content Tabs Plugin - Pure CSS, No JS */
|
|
2
2
|
|
|
3
3
|
.ox-tabs {
|
|
4
|
-
margin: 1.
|
|
4
|
+
margin: 1.25rem 0;
|
|
5
5
|
border: 1px solid var(--octc-color-border);
|
|
6
|
-
border-radius:
|
|
6
|
+
border-radius: 6px;
|
|
7
7
|
overflow: hidden;
|
|
8
8
|
background: var(--octc-color-bg);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
.ox-tabs-header {
|
|
12
12
|
display: flex;
|
|
13
|
-
align-items:
|
|
14
|
-
gap: 0.
|
|
15
|
-
padding: 0.35rem
|
|
13
|
+
align-items: center;
|
|
14
|
+
gap: 0.2rem;
|
|
15
|
+
padding: 0.35rem;
|
|
16
16
|
background: var(--octc-color-bg-alt);
|
|
17
17
|
border-bottom: 1px solid var(--octc-color-border);
|
|
18
18
|
overflow-x: auto;
|
|
@@ -42,17 +42,17 @@
|
|
|
42
42
|
display: inline-flex;
|
|
43
43
|
align-items: center;
|
|
44
44
|
justify-content: center;
|
|
45
|
-
flex:
|
|
46
|
-
min-width:
|
|
47
|
-
|
|
45
|
+
flex: 0 0 auto;
|
|
46
|
+
min-width: 0;
|
|
47
|
+
min-height: 2.1rem;
|
|
48
|
+
padding: 0.42rem 0.7rem;
|
|
48
49
|
cursor: pointer;
|
|
49
|
-
font-size: 0.
|
|
50
|
-
font-weight:
|
|
50
|
+
font-size: 0.8125rem;
|
|
51
|
+
font-weight: 600;
|
|
51
52
|
color: var(--octc-color-text-muted);
|
|
52
53
|
border: 1px solid transparent;
|
|
53
54
|
border-bottom: 2px solid transparent;
|
|
54
|
-
|
|
55
|
-
border-radius: 4px 4px 0 0;
|
|
55
|
+
border-radius: 5px;
|
|
56
56
|
white-space: nowrap;
|
|
57
57
|
transition:
|
|
58
58
|
background-color 0.2s ease,
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
/* Tab content panels */
|
|
83
83
|
.ox-tab-panel {
|
|
84
84
|
display: none;
|
|
85
|
-
padding:
|
|
85
|
+
padding: 0.85rem 0.9rem;
|
|
86
86
|
background: var(--octc-color-bg);
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
.ox-tabs-fallback summary {
|
|
172
|
-
padding: 0.75rem
|
|
172
|
+
padding: 0.55rem 0.75rem;
|
|
173
173
|
cursor: pointer;
|
|
174
174
|
font-weight: 500;
|
|
175
175
|
background: var(--octc-color-bg-alt);
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
.ox-tabs-fallback .ox-tabs-fallback-content {
|
|
201
|
-
padding:
|
|
201
|
+
padding: 0.85rem 0.9rem;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
/* The disclosure marker still turns, it just turns instantly. */
|
|
@@ -1,3 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Host-prose isolation for full-fidelity Tweet cards.
|
|
3
|
+
*
|
|
4
|
+
* The full card replaces native elements — a `<figure>` root, `<img>`
|
|
5
|
+
* avatars and media, a `<blockquote>` for the quoted post — and an article
|
|
6
|
+
* stylesheet such as `@tailwindcss/typography` styles those by element. The
|
|
7
|
+
* component rules below the isolation block win wherever they set a
|
|
8
|
+
* property; this file covers the properties they never set, which is how a
|
|
9
|
+
* `.prose` article was adding image margins to avatars and quotation
|
|
10
|
+
* typography to the quoted post.
|
|
11
|
+
*
|
|
12
|
+
* Every selector doubles the root class (`.ox-tweet.ox-tweet--full`) so it
|
|
13
|
+
* outranks `.prose <element>` regardless of which stylesheet the host
|
|
14
|
+
* imports last. Generated quotes need a longer chain still: Tailwind writes
|
|
15
|
+
* them at `.prose blockquote p:first-of-type::before`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* The card root is a `<figure>`, and the component sets its margin at one
|
|
20
|
+
* class of specificity — which `.prose figure` outranks. Restate it here
|
|
21
|
+
* through the same custom property, so a host that overrides the property
|
|
22
|
+
* still gets what it asked for.
|
|
23
|
+
*/
|
|
24
|
+
.ox-tweet.ox-tweet--full {
|
|
25
|
+
margin: var(--ox-tweet-container-margin);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.ox-tweet.ox-tweet--full :where(img, video, figure, picture, svg) {
|
|
29
|
+
margin: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.ox-tweet.ox-tweet--full :where(p, ul, ol, li, dl, dd, dt, hr, h1, h2, h3, h4, h5, h6) {
|
|
33
|
+
margin: 0;
|
|
34
|
+
padding: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.ox-tweet.ox-tweet--full :where(ul, ol) {
|
|
38
|
+
list-style: none;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.ox-tweet.ox-tweet--full :where(a) {
|
|
42
|
+
font-weight: inherit;
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.ox-tweet.ox-tweet--full :where(code, pre, kbd, samp) {
|
|
47
|
+
padding: 0;
|
|
48
|
+
font-size: inherit;
|
|
49
|
+
font-family: inherit;
|
|
50
|
+
background: none;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.ox-tweet.ox-tweet--full :where(code)::before,
|
|
54
|
+
.ox-tweet.ox-tweet--full :where(code)::after {
|
|
55
|
+
content: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* The quoted post is a `<blockquote>`, which prose styles the hardest. */
|
|
59
|
+
.ox-tweet.ox-tweet--full .ox-tweet__quote {
|
|
60
|
+
font-style: normal;
|
|
61
|
+
font-weight: 400;
|
|
62
|
+
color: inherit;
|
|
63
|
+
quotes: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.ox-tweet.ox-tweet--full .ox-tweet__quote :where(p)::before,
|
|
67
|
+
.ox-tweet.ox-tweet--full .ox-tweet__quote :where(p)::after,
|
|
68
|
+
.ox-tweet.ox-tweet--full .ox-tweet__quote :where(p):first-of-type::before,
|
|
69
|
+
.ox-tweet.ox-tweet--full .ox-tweet__quote :where(p):last-of-type::after {
|
|
70
|
+
content: none;
|
|
71
|
+
}
|
|
1
72
|
/*
|
|
2
73
|
* Opt-in full-card chrome for Twitter/X embeds.
|
|
3
74
|
* Loaded only when a page has .ox-tweet--full.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderThemeTokenCss = renderThemeTokenCss;
|
|
4
|
+
exports.tokensToCss = tokensToCss;
|
|
5
|
+
const TOKEN_PREFIX = "--octc-";
|
|
6
|
+
const TOKEN_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
7
|
+
/**
|
|
8
|
+
* Renders a theme's `--octc-*` tokens as a standalone stylesheet.
|
|
9
|
+
*
|
|
10
|
+
* The built-in SSG emits these declarations itself, but `ssg.bare: true` and
|
|
11
|
+
* custom hosts render their own document — this is how they get the same
|
|
12
|
+
* tokens. The built-in highlighter emits `var(--octc-syntax-*)` references, so
|
|
13
|
+
* a bare host that wants only the highlighter palette can ask for it:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { renderThemeTokenCss } from "@ox-content/vite-plugin/theme-tokens";
|
|
17
|
+
* import { kanagawa } from "@ox-content/theme-color-kanagawa";
|
|
18
|
+
*
|
|
19
|
+
* const css = renderThemeTokenCss(kanagawa, {
|
|
20
|
+
* include: (name) => name.startsWith("syntax-"),
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Layers compose left to right and each layer's `extends` chain is flattened
|
|
25
|
+
* base-first, matching how `resolveTheme()` stacks a skin and a color scheme.
|
|
26
|
+
*/
|
|
27
|
+
function renderThemeTokenCss(theme, options = {}) {
|
|
28
|
+
const layers = (Array.isArray(theme) ? theme : [theme]).flatMap(expandExtendsChain);
|
|
29
|
+
return tokensToCss(mergeTokens(layers, "tokens", options.include), mergeTokens(layers, "darkTokens", options.include));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Renders light and dark token records as the three selectors the SSG runtime
|
|
33
|
+
* switches between: an explicit `[data-theme="dark"]` opt-in, the OS
|
|
34
|
+
* `prefers-color-scheme` fallback, and the `:root` base.
|
|
35
|
+
*
|
|
36
|
+
* Emitted after the typed color variables and before the theme's own `css`, so
|
|
37
|
+
* a token can override a typed color and raw `css` can override a token.
|
|
38
|
+
*/
|
|
39
|
+
function tokensToCss(light, dark) {
|
|
40
|
+
const lightBody = declarations(light, " ");
|
|
41
|
+
const darkBody = declarations(dark, " ");
|
|
42
|
+
const blocks = [];
|
|
43
|
+
if (lightBody) {
|
|
44
|
+
blocks.push(`:root {\n${lightBody}\n}`);
|
|
45
|
+
}
|
|
46
|
+
if (darkBody) {
|
|
47
|
+
blocks.push(`[data-theme="dark"] {\n${darkBody}\n}`);
|
|
48
|
+
blocks.push(`@media (prefers-color-scheme: dark) {\n :root:not([data-theme="light"]) {\n${declarations(dark, " ")}\n }\n}`);
|
|
49
|
+
}
|
|
50
|
+
return blocks.join("\n");
|
|
51
|
+
}
|
|
52
|
+
function declarations(tokens, indent) {
|
|
53
|
+
return Object.entries(tokens)
|
|
54
|
+
.filter(([, value]) => value !== undefined && value !== "")
|
|
55
|
+
.map(([name, value]) => `${indent}${TOKEN_PREFIX}${assertTokenName(name)}: ${value};`)
|
|
56
|
+
.join("\n");
|
|
57
|
+
}
|
|
58
|
+
function assertTokenName(name) {
|
|
59
|
+
// Token names land verbatim inside a declaration block, so a stray `:` or `}`
|
|
60
|
+
// would silently break every rule after it. Fail the build with the offending
|
|
61
|
+
// key instead of shipping a corrupt stylesheet.
|
|
62
|
+
if (!TOKEN_NAME_PATTERN.test(name)) {
|
|
63
|
+
throw new Error(`Invalid theme token name: ${JSON.stringify(name)}. ` +
|
|
64
|
+
`Token names are lowercase kebab-case without the "${TOKEN_PREFIX}" prefix (e.g. "surface-glass").`);
|
|
65
|
+
}
|
|
66
|
+
return name;
|
|
67
|
+
}
|
|
68
|
+
function mergeTokens(layers, field, include) {
|
|
69
|
+
const merged = {};
|
|
70
|
+
for (const layer of layers) {
|
|
71
|
+
for (const [name, value] of Object.entries(layer[field] ?? {})) {
|
|
72
|
+
if (!include || include(name)) {
|
|
73
|
+
merged[name] = value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return merged;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Flattens one layer's `extends` chain into base-first order, mirroring the
|
|
81
|
+
* SSG's own resolution. The `seen` guard keeps a theme that extends itself (or
|
|
82
|
+
* forms a cycle across two packages) from hanging the caller.
|
|
83
|
+
*/
|
|
84
|
+
function expandExtendsChain(theme) {
|
|
85
|
+
const chain = [];
|
|
86
|
+
const seen = new Set();
|
|
87
|
+
let current = theme;
|
|
88
|
+
while (current && !seen.has(current)) {
|
|
89
|
+
seen.add(current);
|
|
90
|
+
chain.unshift(current);
|
|
91
|
+
current = current.extends;
|
|
92
|
+
}
|
|
93
|
+
return chain;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=theme-tokens.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-tokens.cjs","sourceRoot":"","sources":["../../../../home/runner/work/ox-content/ox-content/npm/vite-plugin-ox-content/src/theme-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Free-form `--octc-*` custom properties for themes that need more than the\n * typed `colors` / `fonts` / `layout` fields.\n *\n * Keys are written **without** the `--octc-` prefix, so `\"surface-glass\"`\n * becomes `--octc-surface-glass`. This is the seam that keeps the two theme\n * axes independent: a color package can restyle code-block line markers, brand\n * accents, and surface textures purely through tokens, while a skin package\n * lays out geometry against those same tokens without knowing any color.\n */\nexport type ThemeTokens = Record<string, string>;\n\nconst TOKEN_PREFIX = \"--octc-\";\nconst TOKEN_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * The token-bearing shape of a theme.\n *\n * Declared structurally instead of importing `ThemeConfig` so this module keeps\n * an empty import graph: `@ox-content/vite-plugin/theme-tokens` has to be\n * loadable by a bare (`ssg.bare: true`) or custom host that never pulls in the\n * Vite plugin, the SSG, the native binding, or a filesystem API. Every\n * `ThemeConfig` — including the published `@ox-content/theme-color-*` and\n * `@ox-content/theme-*` packages — satisfies it.\n */\nexport interface ThemeTokenSource {\n tokens?: ThemeTokens;\n darkTokens?: ThemeTokens;\n extends?: ThemeTokenSource;\n}\n\n/**\n * Options for {@link renderThemeTokenCss}.\n */\nexport interface RenderThemeTokenCssOptions {\n /**\n * Keeps only the tokens whose name passes the predicate. Names arrive without\n * the `--octc-` prefix, so `(name) => name.startsWith(\"syntax-\")` reuses a\n * color scheme's highlighter palette without adopting its page colors,\n * typography, or layout policy.\n *\n * Filtering runs per layer, before merging, so a token a later layer would\n * have overridden is dropped along with the override.\n */\n include?: (name: string) => boolean;\n}\n\n/**\n * Renders a theme's `--octc-*` tokens as a standalone stylesheet.\n *\n * The built-in SSG emits these declarations itself, but `ssg.bare: true` and\n * custom hosts render their own document — this is how they get the same\n * tokens. The built-in highlighter emits `var(--octc-syntax-*)` references, so\n * a bare host that wants only the highlighter palette can ask for it:\n *\n * ```ts\n * import { renderThemeTokenCss } from \"@ox-content/vite-plugin/theme-tokens\";\n * import { kanagawa } from \"@ox-content/theme-color-kanagawa\";\n *\n * const css = renderThemeTokenCss(kanagawa, {\n * include: (name) => name.startsWith(\"syntax-\"),\n * });\n * ```\n *\n * Layers compose left to right and each layer's `extends` chain is flattened\n * base-first, matching how `resolveTheme()` stacks a skin and a color scheme.\n */\nexport function renderThemeTokenCss(\n theme: ThemeTokenSource | ThemeTokenSource[],\n options: RenderThemeTokenCssOptions = {},\n): string {\n const layers = (Array.isArray(theme) ? theme : [theme]).flatMap(expandExtendsChain);\n return tokensToCss(\n mergeTokens(layers, \"tokens\", options.include),\n mergeTokens(layers, \"darkTokens\", options.include),\n );\n}\n\n/**\n * Renders light and dark token records as the three selectors the SSG runtime\n * switches between: an explicit `[data-theme=\"dark\"]` opt-in, the OS\n * `prefers-color-scheme` fallback, and the `:root` base.\n *\n * Emitted after the typed color variables and before the theme's own `css`, so\n * a token can override a typed color and raw `css` can override a token.\n */\nexport function tokensToCss(light: ThemeTokens, dark: ThemeTokens): string {\n const lightBody = declarations(light, \" \");\n const darkBody = declarations(dark, \" \");\n const blocks: string[] = [];\n\n if (lightBody) {\n blocks.push(`:root {\\n${lightBody}\\n}`);\n }\n if (darkBody) {\n blocks.push(`[data-theme=\"dark\"] {\\n${darkBody}\\n}`);\n blocks.push(\n `@media (prefers-color-scheme: dark) {\\n :root:not([data-theme=\"light\"]) {\\n${declarations(dark, \" \")}\\n }\\n}`,\n );\n }\n\n return blocks.join(\"\\n\");\n}\n\nfunction declarations(tokens: ThemeTokens, indent: string): string {\n return Object.entries(tokens)\n .filter(([, value]) => value !== undefined && value !== \"\")\n .map(([name, value]) => `${indent}${TOKEN_PREFIX}${assertTokenName(name)}: ${value};`)\n .join(\"\\n\");\n}\n\nfunction assertTokenName(name: string): string {\n // Token names land verbatim inside a declaration block, so a stray `:` or `}`\n // would silently break every rule after it. Fail the build with the offending\n // key instead of shipping a corrupt stylesheet.\n if (!TOKEN_NAME_PATTERN.test(name)) {\n throw new Error(\n `Invalid theme token name: ${JSON.stringify(name)}. ` +\n `Token names are lowercase kebab-case without the \"${TOKEN_PREFIX}\" prefix (e.g. \"surface-glass\").`,\n );\n }\n return name;\n}\n\nfunction mergeTokens(\n layers: ThemeTokenSource[],\n field: \"tokens\" | \"darkTokens\",\n include?: (name: string) => boolean,\n): ThemeTokens {\n const merged: ThemeTokens = {};\n\n for (const layer of layers) {\n for (const [name, value] of Object.entries(layer[field] ?? {})) {\n if (!include || include(name)) {\n merged[name] = value;\n }\n }\n }\n\n return merged;\n}\n\n/**\n * Flattens one layer's `extends` chain into base-first order, mirroring the\n * SSG's own resolution. The `seen` guard keeps a theme that extends itself (or\n * forms a cycle across two packages) from hanging the caller.\n */\nfunction expandExtendsChain(theme: ThemeTokenSource): ThemeTokenSource[] {\n const chain: ThemeTokenSource[] = [];\n const seen = new Set<ThemeTokenSource>();\n let current: ThemeTokenSource | undefined = theme;\n\n while (current && !seen.has(current)) {\n seen.add(current);\n chain.unshift(current);\n current = current.extends;\n }\n\n return chain;\n}\n"]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//#region src/theme-tokens.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Free-form `--octc-*` custom properties for themes that need more than the
|
|
4
|
+
* typed `colors` / `fonts` / `layout` fields.
|
|
5
|
+
*
|
|
6
|
+
* Keys are written **without** the `--octc-` prefix, so `"surface-glass"`
|
|
7
|
+
* becomes `--octc-surface-glass`. This is the seam that keeps the two theme
|
|
8
|
+
* axes independent: a color package can restyle code-block line markers, brand
|
|
9
|
+
* accents, and surface textures purely through tokens, while a skin package
|
|
10
|
+
* lays out geometry against those same tokens without knowing any color.
|
|
11
|
+
*/
|
|
12
|
+
type ThemeTokens = Record<string, string>;
|
|
13
|
+
/**
|
|
14
|
+
* The token-bearing shape of a theme.
|
|
15
|
+
*
|
|
16
|
+
* Declared structurally instead of importing `ThemeConfig` so this module keeps
|
|
17
|
+
* an empty import graph: `@ox-content/vite-plugin/theme-tokens` has to be
|
|
18
|
+
* loadable by a bare (`ssg.bare: true`) or custom host that never pulls in the
|
|
19
|
+
* Vite plugin, the SSG, the native binding, or a filesystem API. Every
|
|
20
|
+
* `ThemeConfig` — including the published `@ox-content/theme-color-*` and
|
|
21
|
+
* `@ox-content/theme-*` packages — satisfies it.
|
|
22
|
+
*/
|
|
23
|
+
interface ThemeTokenSource {
|
|
24
|
+
tokens?: ThemeTokens;
|
|
25
|
+
darkTokens?: ThemeTokens;
|
|
26
|
+
extends?: ThemeTokenSource;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for {@link renderThemeTokenCss}.
|
|
30
|
+
*/
|
|
31
|
+
interface RenderThemeTokenCssOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Keeps only the tokens whose name passes the predicate. Names arrive without
|
|
34
|
+
* the `--octc-` prefix, so `(name) => name.startsWith("syntax-")` reuses a
|
|
35
|
+
* color scheme's highlighter palette without adopting its page colors,
|
|
36
|
+
* typography, or layout policy.
|
|
37
|
+
*
|
|
38
|
+
* Filtering runs per layer, before merging, so a token a later layer would
|
|
39
|
+
* have overridden is dropped along with the override.
|
|
40
|
+
*/
|
|
41
|
+
include?: (name: string) => boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Renders a theme's `--octc-*` tokens as a standalone stylesheet.
|
|
45
|
+
*
|
|
46
|
+
* The built-in SSG emits these declarations itself, but `ssg.bare: true` and
|
|
47
|
+
* custom hosts render their own document — this is how they get the same
|
|
48
|
+
* tokens. The built-in highlighter emits `var(--octc-syntax-*)` references, so
|
|
49
|
+
* a bare host that wants only the highlighter palette can ask for it:
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { renderThemeTokenCss } from "@ox-content/vite-plugin/theme-tokens";
|
|
53
|
+
* import { kanagawa } from "@ox-content/theme-color-kanagawa";
|
|
54
|
+
*
|
|
55
|
+
* const css = renderThemeTokenCss(kanagawa, {
|
|
56
|
+
* include: (name) => name.startsWith("syntax-"),
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* Layers compose left to right and each layer's `extends` chain is flattened
|
|
61
|
+
* base-first, matching how `resolveTheme()` stacks a skin and a color scheme.
|
|
62
|
+
*/
|
|
63
|
+
declare function renderThemeTokenCss(theme: ThemeTokenSource | ThemeTokenSource[], options?: RenderThemeTokenCssOptions): string;
|
|
64
|
+
/**
|
|
65
|
+
* Renders light and dark token records as the three selectors the SSG runtime
|
|
66
|
+
* switches between: an explicit `[data-theme="dark"]` opt-in, the OS
|
|
67
|
+
* `prefers-color-scheme` fallback, and the `:root` base.
|
|
68
|
+
*
|
|
69
|
+
* Emitted after the typed color variables and before the theme's own `css`, so
|
|
70
|
+
* a token can override a typed color and raw `css` can override a token.
|
|
71
|
+
*/
|
|
72
|
+
declare function tokensToCss(light: ThemeTokens, dark: ThemeTokens): string;
|
|
73
|
+
//#endregion
|
|
74
|
+
export { RenderThemeTokenCssOptions, ThemeTokenSource, ThemeTokens, renderThemeTokenCss, tokensToCss };
|
|
75
|
+
//# sourceMappingURL=theme-tokens.d.cts.map
|