website: add diagram Prism language, CodeBlock showLineNumbers prop, brighter dark mode links

- Custom 'diagram' Prism language: box-drawing chars get neutral color,
  text labels get a saturated blue so they pop against the structure
- CodeBlock gains showLineNumbers prop (default true) and skips Prism
  highlighting when lang is empty
- Diagram block in index page uses lang='diagram' with line numbers off
- Dark mode --link-accent bumped from #58a6ff to #79bbff for better
  visibility against dark backgrounds
This commit is contained in:
Tommy D. Rossi
2026-02-24 14:44:08 +01:00
parent c23eced495
commit 1a9c6ddcd0
4 changed files with 65 additions and 24 deletions
+34 -22
View File
@@ -12,6 +12,14 @@ import 'prismjs/components/prism-jsx'
import 'prismjs/components/prism-tsx' import 'prismjs/components/prism-tsx'
import 'prismjs/components/prism-bash' import 'prismjs/components/prism-bash'
/* Custom "diagram" language for ASCII/Unicode box-drawing diagrams.
Tokenizes box-drawing chars as neutral structure, text as highlighted labels. */
Prism.languages.diagram = {
'box-drawing': /[┌┐└┘├┤┬┴┼─│═║╔╗╚╝╠╣╦╩╬╭╮╯╰┊┈╌┄╶╴╵╷]+/,
'line-char': /[-_|<>]+/,
'label': /[^\s┌┐└┘├┤┬┴┼─│═║╔╗╚╝╠╣╦╩╬╭╮╯╰┊┈╌┄╶╴╵╷\-_|<>]+/,
}
/* ========================================================================= /* =========================================================================
TOC sidebar (fixed left) TOC sidebar (fixed left)
========================================================================= */ ========================================================================= */
@@ -342,19 +350,21 @@ export function CodeBlock({
children, children,
lang = 'jsx', lang = 'jsx',
lineHeight = '1.85', lineHeight = '1.85',
showLineNumbers = true,
}: { }: {
children: string children: string
lang?: string lang?: string
lineHeight?: string lineHeight?: string
showLineNumbers?: boolean
}) { }) {
const codeRef = useRef<HTMLElement>(null) const codeRef = useRef<HTMLElement>(null)
const lines = children.split('\n') const lines = children.split('\n')
useEffect(() => { useEffect(() => {
if (codeRef.current) { if (codeRef.current && lang) {
Prism.highlightElement(codeRef.current) Prism.highlightElement(codeRef.current)
} }
}, [children]) }, [children, lang])
return ( return (
<figure className='m-0 bleed'> <figure className='m-0 bleed'>
@@ -381,28 +391,30 @@ export function CodeBlock({
tabSize: 2, tabSize: 2,
}} }}
> >
<span {showLineNumbers && (
className='select-none shrink-0' <span
aria-hidden='true' className='select-none shrink-0'
style={{ aria-hidden='true'
color: 'var(--code-line-nr)', style={{
textAlign: 'right', color: 'var(--code-line-nr)',
paddingRight: '20px', textAlign: 'right',
width: '36px', paddingRight: '20px',
userSelect: 'none', width: '36px',
}} userSelect: 'none',
> }}
{lines.map((_, i) => { >
return ( {lines.map((_, i) => {
<span key={i} className='block'> return (
{i + 1} <span key={i} className='block'>
</span> {i + 1}
) </span>
})} )
</span> })}
</span>
)}
<code <code
ref={codeRef} ref={codeRef}
className={`language-${lang}`} className={lang ? `language-${lang}` : undefined}
style={{ whiteSpace: 'pre', background: 'none', padding: 0, lineHeight }} style={{ whiteSpace: 'pre', background: 'none', padding: 0, lineHeight }}
> >
{children} {children}
+1 -1
View File
@@ -146,7 +146,7 @@ export default function IndexPage() {
Chrome restart, no flags, no special setup. Chrome restart, no flags, no special setup.
</P> </P>
<CodeBlock lang='bash' lineHeight='1.3'>{dedent` <CodeBlock lang='diagram' lineHeight='1.3' showLineNumbers={false}>{dedent`
┌─────────────────────┐ ┌──────────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ BROWSER │ │ LOCALHOST │ │ CLIENT │ │ BROWSER │ │ LOCALHOST │ │ CLIENT │
│ │ │ │ │ │ │ │ │ │ │ │
+29
View File
@@ -130,6 +130,20 @@ pre[class*='language-'] {
color: #2563eb; color: #2563eb;
} }
/* Diagram language: neutral box-drawing, colored text labels */
.language-diagram .token.box-drawing {
color: #c0c0c0;
}
.language-diagram .token.line-char {
color: #c0c0c0;
}
.language-diagram .token.label {
color: #0550ae;
font-weight: 600;
}
/* No text shadow on any token */ /* No text shadow on any token */
.token { .token {
text-shadow: none; text-shadow: none;
@@ -159,6 +173,8 @@ pre[class*='language-'] {
--prism-spread: #ff7b72; --prism-spread: #ff7b72;
--prism-regex: #a5d6ff; --prism-regex: #a5d6ff;
--prism-bash-fn: #79c0ff; --prism-bash-fn: #79c0ff;
--prism-diagram-structure: #555;
--prism-diagram-label: #79bbff;
} }
} }
@@ -284,3 +300,16 @@ pre[class*='language-'] {
color: var(--prism-bash-fn); color: var(--prism-bash-fn);
} }
} }
.language-diagram .token.box-drawing,
.language-diagram .token.line-char {
@variant dark {
color: var(--prism-diagram-structure);
}
}
.language-diagram .token.label {
@variant dark {
color: var(--prism-diagram-label);
}
}
+1 -1
View File
@@ -174,7 +174,7 @@
rgba(255, 255, 255, 0.05) 0px 2px 8px, rgba(255, 255, 255, 0.02) 0px 4px 16px, rgba(255, 255, 255, 0.05) 0px 2px 8px, rgba(255, 255, 255, 0.02) 0px 4px 16px,
rgba(255, 255, 255, 0.06) 0px 0px 0px 1px inset; rgba(255, 255, 255, 0.06) 0px 0px 0px 1px inset;
--link-accent: #58a6ff; --link-accent: #79bbff;
--brand-primary: #60a5fa; --brand-primary: #60a5fa;
--brand-secondary: #f5a623; --brand-secondary: #f5a623;