@brillout/docpress 0.16.45 → 0.16.47-commit-cd5aa01

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/EditLink.tsx CHANGED
@@ -28,11 +28,11 @@ function EditLink({
28
28
  paddingBottom: 7,
29
29
  paddingLeft: 8,
30
30
  paddingRight: 7,
31
- border: '1px solid #e0e0e0',
31
+ border: '1px solid var(--color-border, #e0e0e0)',
32
32
  borderRadius: 7,
33
33
  fontSize: '0.91em',
34
- color: '#6c6c6c',
35
- background: '#f8f8f8',
34
+ color: 'var(--color-muted, #6c6c6c)',
35
+ background: 'var(--color-surface, #f8f8f8)',
36
36
  letterSpacing: 0.4,
37
37
  lineHeight: 0,
38
38
  ...style,
package/ExternalLinks.tsx CHANGED
@@ -46,10 +46,11 @@ function ExternalLinks(props: { style?: React.CSSProperties }) {
46
46
 
47
47
  function ChangelogButton() {
48
48
  const pageContext = usePageContext()
49
- const { version, github } = pageContext.globalContext.config.docpress
49
+ const { version, github, changelog } = pageContext.globalContext.config.docpress
50
+ const changeLogUrl = typeof changelog === 'string' ? changelog : `${github}/blob/main/CHANGELOG.md`
50
51
  return (
51
52
  <a
52
- href={`${github}/blob/main/CHANGELOG.md`}
53
+ href={changeLogUrl}
53
54
  className="colorize-on-hover"
54
55
  style={{
55
56
  display: 'flex',
@@ -62,7 +63,7 @@ function ChangelogButton() {
62
63
  className="button"
63
64
  style={{
64
65
  background: '#ffffff4f',
65
- fontFamily: 'monospace',
66
+ fontFamily: 'var(--font-mono, monospace)',
66
67
  letterSpacing: -1,
67
68
  display: 'flex',
68
69
  alignItems: 'center',
package/Layout.css CHANGED
@@ -1,4 +1,3 @@
1
1
  body {
2
2
  background: var(--color-bg-white);
3
- --color-bg-white: #fdfdfd;
4
3
  }
package/Layout.tsx CHANGED
@@ -82,7 +82,7 @@ function Layout({ children }: { children: React.ReactNode }) {
82
82
  return (
83
83
  <div
84
84
  style={{
85
- ['--color-bg-gray']: '#f5f5f5',
85
+ ['--color-bg-gray']: 'var(--color-surface, #f5f5f5)',
86
86
  ['--block-margin']: `${blockMargin}px`,
87
87
  // ['--nav-head-height']: `${isLandingPage ? 70 : 63}px`,
88
88
  ['--nav-head-height']: `63px`,
@@ -94,9 +94,12 @@ function Layout({ children }: { children: React.ReactNode }) {
94
94
  margin: 'auto',
95
95
  }}
96
96
  >
97
- <MenuModal isTopNav={isLandingPage} isNavLeftAlwaysHidden_={isNavLeftAlwaysHidden_} />
98
- <div className={isLandingPage ? '' : 'doc-page'} style={whitespaceBuster1}>
99
- <NavHead />
97
+ <div className={isLandingPage ? 'landing-page' : 'doc-page'} style={whitespaceBuster1}>
98
+ <div style={{ position: isLandingPage ? 'relative' : 'sticky', top: 0, zIndex: 100 }}>
99
+ <NavHead />
100
+ {/* <MenuModal> is inside here because `container-type` on the page wrapper traps `position: fixed` — https://github.com/brillout/docpress/pull/177 */}
101
+ <MenuModal isNavLeftAlwaysHidden_={isNavLeftAlwaysHidden_} />
102
+ </div>
100
103
  {content}
101
104
  </div>
102
105
  {/* Early toggling, to avoid layout jumps */}
@@ -220,10 +223,10 @@ function NavLeft() {
220
223
  <div
221
224
  style={{
222
225
  position: 'sticky',
223
- top: 0,
226
+ // Sit below the sticky top nav
227
+ top: 'var(--nav-head-height)',
224
228
  }}
225
229
  >
226
- <NavHead isNavLeft={true} />
227
230
  <div
228
231
  style={{
229
232
  backgroundColor: 'var(--color-bg-gray)',
@@ -296,29 +299,18 @@ const menuLinkStyle: React.CSSProperties = {
296
299
  justifyContent: 'center',
297
300
  }
298
301
 
299
- // Two <NavHead> instances are rendered:
300
- // - The left-side <NavHead> shown on documentation pages on desktop
301
- // - The top <NavHead> shown otherwise
302
- function NavHead({ isNavLeft }: { isNavLeft?: true }) {
302
+ function NavHead() {
303
303
  const pageContext = usePageContext()
304
304
  const { navMaxWidth, name, algolia } = pageContext.globalContext.config.docpress
305
305
  const hideNavHeadLogo = pageContext.resolved.isLandingPage && !navMaxWidth
306
306
 
307
307
  const navHeadSecondary = (
308
308
  <div
309
- className={cls(['nav-head-secondary', isNavLeft && 'show-on-nav-hover add-transition'])}
309
+ className="nav-head-secondary"
310
310
  style={{
311
311
  padding: 0,
312
312
  display: 'flex',
313
313
  height: '100%',
314
- ...(isNavLeft
315
- ? {
316
- position: 'absolute',
317
- left: '100%',
318
- top: 0,
319
- width: mainViewWidthMax, // guaranteed real estate
320
- }
321
- : {}),
322
314
  }}
323
315
  >
324
316
  {pageContext.globalContext.config.docpress.topNavigation}
@@ -336,35 +328,38 @@ function NavHead({ isNavLeft }: { isNavLeft?: true }) {
336
328
 
337
329
  return (
338
330
  <div
339
- className={cls(['nav-head link-hover-animation', isNavLeft && 'is-nav-left', !!navMaxWidth && 'has-max-width'])}
331
+ className={cls(['nav-head link-hover-animation', !!navMaxWidth && 'has-max-width'])}
340
332
  style={{
341
333
  backgroundColor: 'var(--color-bg-gray)',
342
- borderBottom: 'var(--block-margin) solid var(--color-bg-white)',
343
334
  position: 'relative',
335
+ boxShadow: `0 ${blockMargin}px 0 var(--color-bg-white)`,
344
336
  }}
345
337
  >
346
- {isNavLeft && <NavHeadLeftFullWidthBackground />}
347
338
  <div
348
339
  style={{
349
340
  // DON'T REMOVE this container: it's needed for the `cqw` values
350
341
  container: 'container-nav-head / inline-size',
351
342
  width: '100%',
343
+ // Cap the cqw context so nav-item spacing matches between landing and doc pages.
344
+ maxWidth: bodyMaxWidth,
345
+ margin: '0 auto',
352
346
  }}
353
347
  >
354
348
  <div
355
349
  className="nav-head-content"
356
350
  style={{
357
351
  width: '100%',
358
- maxWidth: navMaxWidth,
352
+ // Top nav spans the doc-page width so its logo lines up with the sidebar (same width on landing).
353
+ maxWidth: bodyMaxWidth,
359
354
  margin: 'auto',
360
355
  height: 'var(--nav-head-height)',
361
356
  fontSize: `min(14.2px, ${isProjectNameShort(name) ? '4.8cqw' : '4.5cqw'})`,
362
- color: '#666',
357
+ color: 'var(--color-muted, #666)',
363
358
  display: 'flex',
364
359
  justifyContent: 'center',
365
360
  }}
366
361
  >
367
- {!hideNavHeadLogo && <NavHeadLogo isNavLeft={isNavLeft} />}
362
+ {!hideNavHeadLogo && <NavHeadLogo />}
368
363
  <div className="desktop-grow" style={{ display: 'none' }} />
369
364
  {algolia && <SearchLink className="always-shown" style={menuLinkStyle} />}
370
365
  <MenuToggleMain className="always-shown nav-head-menu-toggle" style={menuLinkStyle} />
@@ -380,7 +375,7 @@ function getStyleLayout() {
380
375
  // Mobile
381
376
  style += css`
382
377
  @media(max-width: ${viewMobile}px) {
383
- .nav-head:not(.is-nav-left) {
378
+ .nav-head {
384
379
  .nav-head-menu-toggle {
385
380
  justify-content: flex-end !important;
386
381
  padding-right: var(--main-view-padding) !important;
@@ -397,7 +392,7 @@ function getStyleLayout() {
397
392
  // Mobile + tablet
398
393
  style += css`
399
394
  @media(max-width: ${viewTablet}px) {
400
- .nav-head:not(.is-nav-left) {
395
+ .nav-head {
401
396
  .nav-head-secondary {
402
397
  display: none !important;
403
398
  }
@@ -407,7 +402,7 @@ function getStyleLayout() {
407
402
  // Tablet
408
403
  style += css`
409
404
  @media(max-width: ${viewTablet}px) and (min-width: ${viewMobile + 1}px) {
410
- .nav-head:not(.is-nav-left) {
405
+ .nav-head {
411
406
  .nav-head-content {
412
407
  --icon-text-padding: 8px;
413
408
  --padding-side: 20px;
@@ -418,7 +413,7 @@ function getStyleLayout() {
418
413
  // Desktop small + desktop
419
414
  style += css`
420
415
  @media(min-width: ${viewTablet + 1}px) {
421
- .nav-head:not(.is-nav-left) {
416
+ .nav-head {
422
417
  .nav-head-content {
423
418
  --icon-text-padding: min(8px, 0.5cqw);
424
419
  --padding-side: min(20px, 1.2cqw);
@@ -442,39 +437,6 @@ function getStyleLayout() {
442
437
  // Desktop
443
438
  if (!isNavLeftAlwaysHidden()) {
444
439
  style += css`
445
- @container container-viewport (min-width: ${viewDesktop}px) {
446
- .nav-head:not(.is-nav-left) {
447
- display: none !important;
448
- }
449
- .nav-head.is-nav-left {
450
- .nav-head-content {
451
- --icon-text-padding: min(8px, 7 * (1cqw - 2.5px));
452
- & > :not(.always-shown) {
453
- --padding-side: min(24px, 27 * (1cqw - 2.5px));
454
- }
455
- & > * {
456
- flex-grow: 0.5;
457
- }
458
- & > .nav-head-menu-toggle {
459
- flex-grow: 1;
460
- }
461
- }
462
- }
463
- .show-on-nav-hover {
464
- opacity: 0;
465
- transition-property: opacity;
466
- pointer-events: none;
467
- }
468
- html:not(.unexpand-nav) {
469
- & .nav-head.is-nav-left:hover .show-on-nav-hover,
470
- &:has(.nav-head:hover) #menu-modal-wrapper.show-on-nav-hover,
471
- &.menu-modal-show .nav-head.is-nav-left .show-on-nav-hover,
472
- &.menu-modal-show #menu-modal-wrapper.show-on-nav-hover {
473
- opacity: 1;
474
- pointer-events: all;
475
- }
476
- }
477
- }
478
440
  @container container-viewport (max-width: ${viewDesktop - 1}px) {
479
441
  #nav-left, #nav-left-margin {
480
442
  display: none;
@@ -514,37 +476,7 @@ function unexpandNav() {
514
476
  }, 1000)
515
477
  }
516
478
 
517
- function NavHeadLeftFullWidthBackground() {
518
- return (
519
- <>
520
- <div
521
- className="nav-head-bg show-on-nav-hover add-transition"
522
- style={{
523
- height: '100%',
524
- zIndex: -1,
525
- background: 'var(--color-bg-gray)',
526
- position: 'absolute',
527
- left: 0,
528
- top: 0,
529
- boxSizing: 'content-box',
530
- borderBottom: 'var(--block-margin) solid var(--color-bg-white)',
531
- }}
532
- />
533
- <Style>{
534
- // (min-width: 0px) => trick to always apply => @container seems to always require a condition
535
- css`
536
- @container container-viewport (min-width: 0px) {
537
- .nav-head-bg {
538
- width: 100cqw;
539
- }
540
- }
541
- `
542
- }</Style>
543
- </>
544
- )
545
- }
546
-
547
- function NavHeadLogo({ isNavLeft }: { isNavLeft?: true }) {
479
+ function NavHeadLogo() {
548
480
  const pageContext = usePageContext()
549
481
 
550
482
  const { navLogo } = pageContext.globalContext.config.docpress
@@ -584,14 +516,8 @@ function NavHeadLogo({ isNavLeft }: { isNavLeft?: true }) {
584
516
  alignItems: 'center',
585
517
  height: '100%',
586
518
  color: 'inherit',
587
- ...(!isNavLeft
588
- ? {
589
- paddingLeft: 'var(--main-view-padding)',
590
- paddingRight: 'var(--padding-side)',
591
- }
592
- : {
593
- paddingLeft: 15,
594
- }),
519
+ paddingLeft: 'var(--main-view-padding)',
520
+ paddingRight: 'var(--padding-side)',
595
521
  }}
596
522
  href="/"
597
523
  onContextMenu={!navLogo ? undefined : onContextMenu}
@@ -670,7 +596,7 @@ function MenuToggle({ menuId, ...props }: PropsDiv & { menuId: number }) {
670
596
  width: 11,
671
597
  marginLeft: 'calc(var(--icon-text-padding) - 1px)',
672
598
  flexShrink: 0,
673
- color: '#888',
599
+ color: 'var(--color-muted, #888)',
674
600
  position: 'relative',
675
601
  top: 1,
676
602
  }}
@@ -138,7 +138,7 @@ function NavigationWithColumnLayout(props: { navItems: NavItem[] }) {
138
138
  ${/* Button style */ ''}
139
139
  .menu-toggle-${i} {
140
140
  html.menu-modal-show.menu-modal-show-${i} & {
141
- color: black !important;
141
+ color: var(--color-text, black) !important;
142
142
  [class^='decolorize-'],
143
143
  [class*=' decolorize-'] {
144
144
  filter: grayscale(0) opacity(1) !important;
package/MenuModal.tsx CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  } from './MenuModal/toggleMenuModal.js'
15
15
  import { EditLink } from './EditLink.js'
16
16
 
17
- function MenuModal({ isTopNav, isNavLeftAlwaysHidden_ }: { isTopNav: boolean; isNavLeftAlwaysHidden_: boolean }) {
17
+ function MenuModal({ isNavLeftAlwaysHidden_ }: { isNavLeftAlwaysHidden_: boolean }) {
18
18
  return (
19
19
  <>
20
20
  <Style>{getStyle()}</Style>
@@ -22,11 +22,12 @@ function MenuModal({ isTopNav, isNavLeftAlwaysHidden_ }: { isTopNav: boolean; is
22
22
  id="menu-modal-wrapper"
23
23
  className="link-hover-animation add-transition show-on-nav-hover"
24
24
  style={{
25
- position: isTopNav ? 'absolute' : 'fixed',
25
+ // Absolute inside the sticky header so the dropdown tracks the nav on scroll
26
+ position: 'absolute',
26
27
  width: '100%',
27
28
  top: 'var(--nav-head-height)',
28
29
  zIndex: 199, // maximum value, because docsearch's modal has `z-index: 200`
29
- background: '#ededef',
30
+ background: 'var(--color-surface, #ededef)',
30
31
  transitionProperty: 'opacity',
31
32
  transitionTimingFunction: 'ease',
32
33
  maxWidth: isNavLeftAlwaysHidden_ ? undefined : bodyMaxWidth,
@@ -169,8 +170,8 @@ function CloseButton({ className }: { className: string }) {
169
170
  cx="11.45"
170
171
  cy="11.45"
171
172
  r="10.607"
172
- fill="#ececec"
173
- stroke="#666"
173
+ fill="var(--color-surface, #ececec)"
174
+ stroke="var(--color-muted, #666)"
174
175
  strokeDashoffset="251.44"
175
176
  strokeLinecap="round"
176
177
  strokeLinejoin="round"
@@ -179,8 +180,8 @@ function CloseButton({ className }: { className: string }) {
179
180
  />
180
181
  <path
181
182
  d="m7.5904 6.2204 3.86 3.86 3.84-3.84a0.92 0.92 0 0 1 0.66-0.29 1 1 0 0 1 1 1 0.9 0.9 0 0 1-0.27 0.66l-3.89 3.84 3.89 3.89a0.9 0.9 0 0 1 0.27 0.61 1 1 0 0 1-1 1 0.92 0.92 0 0 1-0.69-0.27l-3.81-3.86-3.85 3.85a0.92 0.92 0 0 1-0.65 0.28 1 1 0 0 1-1-1 0.9 0.9 0 0 1 0.27-0.66l3.89-3.84-3.89-3.89a0.9 0.9 0 0 1-0.27-0.61 1 1 0 0 1 1-1c0.24 3e-3 0.47 0.1 0.64 0.27z"
182
- fill="#666"
183
- stroke="#666"
183
+ fill="var(--color-muted, #666)"
184
+ stroke="var(--color-muted, #666)"
184
185
  strokeWidth=".11719"
185
186
  />
186
187
  </svg>
@@ -13,7 +13,7 @@
13
13
  .nav-item-level-4 {
14
14
  padding-top: 14px;
15
15
  margin-bottom: -1px;
16
- color: #999;
16
+ color: var(--color-muted, #999);
17
17
  font-size: 12px;
18
18
  font-weight: 400;
19
19
  letter-spacing: 0.15ch;
@@ -82,7 +82,7 @@
82
82
  }
83
83
  .nav-item-level-3 {
84
84
  --shadow-size: 9px;
85
- --shadow-color: rgba(0, 0, 0, 0.11);
85
+ --shadow-color: var(--color-shadow, rgba(0, 0, 0, 0.11));
86
86
  --shadow-size-minus: calc(-1 * var(--shadow-size));
87
87
  --shadow-top: inset 0px var(--shadow-size) var(--shadow-size) var(--shadow-size-minus) var(--shadow-color);
88
88
  --shadow-bottom: inset 0px var(--shadow-size-minus) var(--shadow-size) var(--shadow-size-minus) var(--shadow-color);
@@ -5,6 +5,7 @@ pre > code {
5
5
  */
6
6
  background: rgba(0, 0, 0, 0.043137255);
7
7
  font-size: 1em;
8
+ font-family: var(--font-mono, monospace);
8
9
  }
9
10
 
10
11
  /* Copy button */
@@ -12,7 +12,7 @@ function HorizontalLine({ primary }: { primary?: true }) {
12
12
  margin: 0,
13
13
  border: 0,
14
14
  // Same as `.doc-page h2::after`
15
- borderTop: '1px solid rgba(0, 0, 0, 0.1)',
15
+ borderTop: '1px solid var(--color-border, rgba(0, 0, 0, 0.1))',
16
16
  maxWidth: 500,
17
17
  width: '80%',
18
18
  }}
package/css/code.css CHANGED
@@ -10,4 +10,5 @@ code {
10
10
  border-radius: 4px;
11
11
  background: rgba(0, 0, 0, 0.063137255);
12
12
  font-size: 1.1em;
13
+ font-family: var(--font-mono, monospace);
13
14
  }
@@ -51,7 +51,11 @@
51
51
  }
52
52
 
53
53
  body {
54
- --color-active-value: 0.03;
55
- --color-active: rgba(0, 0, 0, var(--color-active-value));
56
- --color-active-double: rgba(0, 0, 0, calc(2 * var(--color-active-value)));
54
+ /* Hover/active tint mixed from the text color so it tracks the active
55
+ appearance (light text -> light tint on dark). The `#000` fallback makes an
56
+ unthemed site identical to the original `rgba(0, 0, 0, value)`:
57
+ color-mix(in srgb, #000 3%, transparent) === rgba(0, 0, 0, 0.03). */
58
+ --color-active-value: 3%;
59
+ --color-active: color-mix(in srgb, var(--color-text, #000) var(--color-active-value), transparent);
60
+ --color-active-double: color-mix(in srgb, var(--color-text, #000) calc(2 * var(--color-active-value)), transparent);
57
61
  }
package/css/font.css CHANGED
@@ -1,13 +1,12 @@
1
1
  @import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
2
2
 
3
3
  body {
4
- font-family: 'Inter', sans-serif;
4
+ font-family: var(--font-sans, 'Inter', sans-serif);
5
5
  }
6
6
  button {
7
7
  font-family: inherit;
8
8
  }
9
9
  body {
10
- --color-text: #323d48;
11
- color: var(--color-text);
10
+ color: var(--color-text, #323d48);
12
11
  line-height: 1.5;
13
12
  }
package/css/heading.css CHANGED
@@ -13,6 +13,11 @@ h3 {
13
13
  margin-bottom: 20px;
14
14
  }
15
15
 
16
+ /* Offset headings below the sticky top nav. */
17
+ .doc-page :is(h1, h2, h3, h4, h5, h6) {
18
+ scroll-margin-top: calc(var(--nav-head-height) + 16px);
19
+ }
20
+
16
21
  .doc-page h2,
17
22
  .doc-page h3 {
18
23
  margin-bottom: 16px;
@@ -27,7 +32,7 @@ h3 {
27
32
  height: 1px;
28
33
  top: -45px;
29
34
  /* Same as <HorizontalLine> */
30
- background-color: rgba(0, 0, 0, 0.1);
35
+ background-color: var(--color-border, rgba(0, 0, 0, 0.1));
31
36
  --width: min(80%, 500px);
32
37
  width: var(--width);
33
38
  left: calc((100% - var(--width)) / 2);
@@ -54,7 +59,7 @@ h3 {
54
59
 
55
60
  .doc-page h5 {
56
61
  font-size: 0.94em;
57
- color: #777;
62
+ color: var(--color-muted, #777);
58
63
  margin-bottom: 10px;
59
64
  }
60
65
 
@@ -82,7 +87,7 @@ h3 {
82
87
  font-size: 23px;
83
88
  top: 1px;
84
89
  left: calc(-1 * (0.75em - var(--hash-offset)));
85
- color: #aaa;
90
+ color: var(--color-muted, #aaa);
86
91
  display: flex;
87
92
  align-items: center;
88
93
  }
package/css/index.css CHANGED
@@ -1,3 +1,4 @@
1
+ @import './tokens.css';
1
2
  @import './reset.css';
2
3
  @import './colorize-on-hover.css';
3
4
  @import './heading.css';
package/css/link.css CHANGED
@@ -2,5 +2,5 @@ a {
2
2
  text-decoration: none;
3
3
  }
4
4
  .doc-page a[href]:not(.nav-item) {
5
- color: #4747ff;
5
+ color: var(--color-primary, #4747ff);
6
6
  }
package/css/table.css CHANGED
@@ -1,5 +1,5 @@
1
1
  table th {
2
- background-color: #f7f7f7;
2
+ background-color: var(--color-surface, #f7f7f7);
3
3
  }
4
4
  table {
5
5
  border-collapse: collapse;
@@ -7,7 +7,7 @@ table {
7
7
  table td,
8
8
  table th {
9
9
  padding: 8px;
10
- border: 1px solid #ccc;
10
+ border: 1px solid var(--color-border, #ccc);
11
11
  }
12
12
  table th {
13
13
  text-align: left;
package/css/tokens.css ADDED
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Color tokens (opt-in, zero default change).
3
+ *
4
+ * No light palette is defined here on purpose: every consumer reads
5
+ * `var(--color-x, <literal>)` and falls back to its original literal, so an
6
+ * unthemed DocPress site renders exactly as before. A site re-themes by setting
7
+ * the `--color-*` variables (on :root or body), and turns on a dark appearance
8
+ * by adding the `dark` class or `[data-theme="dark"]`. There is no
9
+ * `prefers-color-scheme` switch, so the OS setting never changes a site that
10
+ * has not opted in.
11
+ */
12
+ :root {
13
+ /* --color-text has a single original value and pre-existing consumers that
14
+ read it bare (nav items, tabs), so it is defined here (was `body {}`). It
15
+ stays overridable (a `body`/`:root` override or the dark block below wins).
16
+ The ambiguous greys are intentionally NOT defined here: their consumers fall
17
+ back to their own original literal, so light rendering is unchanged. */
18
+ --color-text: #323d48;
19
+
20
+ /* Long-standing internal aliases, kept resolving to their original defaults. */
21
+ --color-bg-white: var(--color-bg, #fdfdfd);
22
+ --color-bg-gray: var(--color-surface, #f5f5f5);
23
+ }
24
+
25
+ :root.dark,
26
+ :root[data-theme='dark'] {
27
+ --color-bg: #0d0f14;
28
+ --color-surface: #161922;
29
+ --color-text: #d7dce5;
30
+ --color-muted: #8b95a5;
31
+ --color-border: #2b313c;
32
+ --color-primary: #8aa0ff;
33
+ --color-shadow: rgba(0, 0, 0, 0.45);
34
+ }
package/css/tooltip.css CHANGED
@@ -13,19 +13,19 @@
13
13
  opacity: 0;
14
14
  transition: opacity 0.3s ease-in-out;
15
15
  pointer-events: none;
16
- font-family: monospace;
16
+ font-family: var(--font-mono, monospace);
17
17
  font-size: 12px;
18
18
  content: attr(aria-label);
19
19
  position: absolute;
20
20
  left: 50%;
21
21
  transform: translate(-50%, 0);
22
- background: #fdfdfd;
22
+ background: var(--color-bg, #fdfdfd);
23
23
  padding: 3px 10px;
24
- box-shadow: rgb(0 0 0 / 8%) 2px 4px 7px 0px;
24
+ box-shadow: var(--color-shadow, rgb(0 0 0 / 8%)) 2px 4px 7px 0px;
25
25
  border-radius: 5px;
26
- color: #333;
26
+ color: var(--color-text, #333);
27
27
  letter-spacing: -0.02em;
28
- border: 1px solid #e3e3e3;
28
+ border: 1px solid var(--color-border, #e3e3e3);
29
29
  z-index: 1;
30
30
  /* Atlernative: https://stackoverflow.com/questions/30086913/css-positioned-absolute-element-automatic-width-outside-of-parents-bounds/57379329#57379329
31
31
  width: max-content;
@@ -8,7 +8,7 @@ function HorizontalLine({ primary }) {
8
8
  margin: 0,
9
9
  border: 0,
10
10
  // Same as `.doc-page h2::after`
11
- borderTop: '1px solid rgba(0, 0, 0, 0.1)',
11
+ borderTop: '1px solid var(--color-border, rgba(0, 0, 0, 0.1))',
12
12
  maxWidth: 500,
13
13
  width: '80%',
14
14
  } })));
@@ -13,12 +13,23 @@ type Config = {
13
13
  google: string;
14
14
  };
15
15
  banner?: string;
16
+ /**
17
+ * Raw HTML injected at the end of `<head>` on every page.
18
+ *
19
+ * Use for a small inline `<script>`/`<style>` that must run before first
20
+ * paint — e.g. a no-flash theme script that reads a cookie and applies the
21
+ * palette before the page renders (relevant for prerendered/static pages,
22
+ * where there is no request to read the cookie from at render time).
23
+ *
24
+ * Emitted verbatim (not escaped), so only pass trusted, self-authored markup.
25
+ */
26
+ headHtml?: string;
16
27
  github: string;
17
28
  discord?: string;
18
29
  twitter?: string;
19
30
  bluesky?: string;
20
31
  linkedin?: string;
21
- changelog?: boolean;
32
+ changelog?: boolean | string;
22
33
  headings: HeadingDefinition[];
23
34
  headingsDetached: HeadingDetachedDefinition[];
24
35
  categories?: Category[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brillout/docpress",
3
- "version": "0.16.45",
3
+ "version": "0.16.47-commit-cd5aa01",
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "@brillout/picocolors": "^1.0.10",
@@ -30,6 +30,7 @@ async function onRenderHtml(pageContext: PageContextServer): Promise<any> {
30
30
  <meta name="viewport" content="width=device-width,initial-scale=1">
31
31
  ${getOpenGraphTags(pageContext.urlPathname, documentTitle, pageContext.globalContext.config.docpress)}
32
32
  ${getAlgoliaTags(pageContext)}
33
+ ${getHeadHtml(pageContext.globalContext.config.docpress)}
33
34
  </head>
34
35
  <body>
35
36
  <div id="page-view">${dangerouslySkipEscape(pageHtml)}</div>
@@ -37,6 +38,10 @@ async function onRenderHtml(pageContext: PageContextServer): Promise<any> {
37
38
  </html>`
38
39
  }
39
40
 
41
+ function getHeadHtml(config: Config) {
42
+ return config.headHtml ? dangerouslySkipEscape(config.headHtml) : ''
43
+ }
44
+
40
45
  function getAlgoliaTags(pageContext: PageContextServer) {
41
46
  const activeCategory = getActiveCategory(pageContext)
42
47
  const categoryNameTag = escapeInject`<meta name="algolia:category" content="${activeCategory.name}">`
package/types/Config.ts CHANGED
@@ -18,12 +18,24 @@ type Config = {
18
18
  }
19
19
  banner?: string
20
20
 
21
+ /**
22
+ * Raw HTML injected at the end of `<head>` on every page.
23
+ *
24
+ * Use for a small inline `<script>`/`<style>` that must run before first
25
+ * paint — e.g. a no-flash theme script that reads a cookie and applies the
26
+ * palette before the page renders (relevant for prerendered/static pages,
27
+ * where there is no request to read the cookie from at render time).
28
+ *
29
+ * Emitted verbatim (not escaped), so only pass trusted, self-authored markup.
30
+ */
31
+ headHtml?: string
32
+
21
33
  github: string
22
34
  discord?: string
23
35
  twitter?: string
24
36
  bluesky?: string
25
37
  linkedin?: string
26
- changelog?: boolean
38
+ changelog?: boolean | string
27
39
 
28
40
  headings: HeadingDefinition[]
29
41
  headingsDetached: HeadingDetachedDefinition[]