mirror of
				https://github.com/jaandrle/deka-dom-el
				synced 2025-11-03 22:59:16 +01:00 
			
		
		
		
	🔤 ⚡ Docs UI/UX
This commit is contained in:
		@@ -1,28 +1,174 @@
 | 
			
		||||
import { registerClientFile, styles } from "../ssr.js";
 | 
			
		||||
const host= "."+code.name;
 | 
			
		||||
styles.css`
 | 
			
		||||
${host}{
 | 
			
		||||
	--shiki-color-text: #e9eded;
 | 
			
		||||
	--shiki-color-background: #212121;
 | 
			
		||||
/* Code block styling */
 | 
			
		||||
${host} {
 | 
			
		||||
	/* Theme for dark mode - matches Flems/CodeMirror dark theme */
 | 
			
		||||
	--shiki-color-text: #f8f8f2;
 | 
			
		||||
	--shiki-color-background: var(--code-bg);
 | 
			
		||||
	--shiki-token-constant: #82b1ff;
 | 
			
		||||
	--shiki-token-string: #c3e88d;
 | 
			
		||||
	--shiki-token-comment: #546e7a;
 | 
			
		||||
	--shiki-token-keyword: #c792ea;
 | 
			
		||||
	--shiki-token-parameter: #AA0000;
 | 
			
		||||
	--shiki-token-parameter: #fd971f;
 | 
			
		||||
	--shiki-token-function: #80cbae;
 | 
			
		||||
	--shiki-token-string-expression: #c3e88d;
 | 
			
		||||
	--shiki-token-punctuation: var(--code);
 | 
			
		||||
	--shiki-token-link: #EE0000;
 | 
			
		||||
	--shiki-token-punctuation: #89ddff;
 | 
			
		||||
	--shiki-token-link: #82aaff;
 | 
			
		||||
	--shiki-token-variable: #f8f8f2;
 | 
			
		||||
	--shiki-token-number: #f78c6c;
 | 
			
		||||
	--shiki-token-boolean: #82b1ff;
 | 
			
		||||
	--shiki-token-tag: #f07178;
 | 
			
		||||
	--shiki-token-attribute: #ffcb6b;
 | 
			
		||||
	--shiki-token-property: #82b1ff;
 | 
			
		||||
	--shiki-token-operator: #89ddff;
 | 
			
		||||
	--shiki-token-regex: #c3e88d;
 | 
			
		||||
	--shiki-token-class: #ffcb6b;
 | 
			
		||||
 | 
			
		||||
	/* Basic styling */
 | 
			
		||||
	white-space: pre;
 | 
			
		||||
	tab-size: 2; /* TODO: allow custom tab size?! */
 | 
			
		||||
	overflow: scroll;
 | 
			
		||||
	tab-size: 2;
 | 
			
		||||
	overflow: auto;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	font-family: var(--font-mono);
 | 
			
		||||
	font-size: 0.9rem;
 | 
			
		||||
	line-height: 1.5;
 | 
			
		||||
	position: relative;
 | 
			
		||||
}
 | 
			
		||||
${host}[data-js=todo]{
 | 
			
		||||
 | 
			
		||||
/* Light mode overrides to match GitHub-like theme */
 | 
			
		||||
@media (prefers-color-scheme: light) {
 | 
			
		||||
	${host} {
 | 
			
		||||
		--shiki-color-text: #24292e;
 | 
			
		||||
		--shiki-color-background: var(--code-bg);
 | 
			
		||||
		--shiki-token-constant: #005cc5;
 | 
			
		||||
		--shiki-token-string: #22863a;
 | 
			
		||||
		--shiki-token-comment: #6a737d;
 | 
			
		||||
		--shiki-token-keyword: #d73a49;
 | 
			
		||||
		--shiki-token-parameter: #e36209;
 | 
			
		||||
		--shiki-token-function: #6f42c1;
 | 
			
		||||
		--shiki-token-string-expression: #22863a;
 | 
			
		||||
		--shiki-token-punctuation: #24292e;
 | 
			
		||||
		--shiki-token-link: #0366d6;
 | 
			
		||||
		--shiki-token-variable: #24292e;
 | 
			
		||||
		--shiki-token-number: #005cc5;
 | 
			
		||||
		--shiki-token-boolean: #005cc5;
 | 
			
		||||
		--shiki-token-tag: #22863a;
 | 
			
		||||
		--shiki-token-attribute: #005cc5;
 | 
			
		||||
		--shiki-token-property: #005cc5;
 | 
			
		||||
		--shiki-token-operator: #d73a49;
 | 
			
		||||
		--shiki-token-regex: #032f62;
 | 
			
		||||
		--shiki-token-class: #6f42c1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Support for theme toggles */
 | 
			
		||||
html[data-theme="light"] ${host} {
 | 
			
		||||
	--shiki-color-text: #24292e;
 | 
			
		||||
	--shiki-color-background: var(--code-bg);
 | 
			
		||||
	--shiki-token-constant: #005cc5;
 | 
			
		||||
	--shiki-token-string: #22863a;
 | 
			
		||||
	--shiki-token-comment: #6a737d;
 | 
			
		||||
	--shiki-token-keyword: #d73a49;
 | 
			
		||||
	--shiki-token-parameter: #e36209;
 | 
			
		||||
	--shiki-token-function: #6f42c1;
 | 
			
		||||
	--shiki-token-string-expression: #22863a;
 | 
			
		||||
	--shiki-token-punctuation: #24292e;
 | 
			
		||||
	--shiki-token-link: #0366d6;
 | 
			
		||||
	--shiki-token-variable: #24292e;
 | 
			
		||||
	--shiki-token-number: #005cc5;
 | 
			
		||||
	--shiki-token-boolean: #005cc5;
 | 
			
		||||
	--shiki-token-tag: #22863a;
 | 
			
		||||
	--shiki-token-attribute: #005cc5;
 | 
			
		||||
	--shiki-token-property: #005cc5;
 | 
			
		||||
	--shiki-token-operator: #d73a49;
 | 
			
		||||
	--shiki-token-regex: #032f62;
 | 
			
		||||
	--shiki-token-class: #6f42c1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
html[data-theme="dark"] ${host} {
 | 
			
		||||
	--shiki-color-text: #f8f8f2;
 | 
			
		||||
	--shiki-color-background: var(--code-bg);
 | 
			
		||||
	--shiki-token-constant: #82b1ff;
 | 
			
		||||
	--shiki-token-string: #c3e88d;
 | 
			
		||||
	--shiki-token-comment: #546e7a;
 | 
			
		||||
	--shiki-token-keyword: #c792ea;
 | 
			
		||||
	--shiki-token-parameter: #fd971f;
 | 
			
		||||
	--shiki-token-function: #80cbae;
 | 
			
		||||
	--shiki-token-string-expression: #c3e88d;
 | 
			
		||||
	--shiki-token-punctuation: #89ddff;
 | 
			
		||||
	--shiki-token-link: #82aaff;
 | 
			
		||||
	--shiki-token-variable: #f8f8f2;
 | 
			
		||||
	--shiki-token-number: #f78c6c;
 | 
			
		||||
	--shiki-token-boolean: #82b1ff;
 | 
			
		||||
	--shiki-token-tag: #f07178;
 | 
			
		||||
	--shiki-token-attribute: #ffcb6b;
 | 
			
		||||
	--shiki-token-property: #82b1ff;
 | 
			
		||||
	--shiki-token-operator: #89ddff;
 | 
			
		||||
	--shiki-token-regex: #c3e88d;
 | 
			
		||||
	--shiki-token-class: #ffcb6b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Code block with syntax highlighting waiting for JS */
 | 
			
		||||
${host}[data-js=todo] {
 | 
			
		||||
	border: 1px solid var(--border);
 | 
			
		||||
	border-radius: var(--standard-border-radius);
 | 
			
		||||
	margin-bottom: 1rem;
 | 
			
		||||
	margin-top: 18.4px; /* to fix shift when → dataJS=done */
 | 
			
		||||
	padding: 1rem 1.4rem;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	margin-bottom: 1.5rem;
 | 
			
		||||
	margin-top: 1rem;
 | 
			
		||||
	padding: 1rem;
 | 
			
		||||
	background-color: var(--code-bg);
 | 
			
		||||
	position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Add a subtle loading indicator */
 | 
			
		||||
${host}[data-js=todo]::before {
 | 
			
		||||
	content: "Loading syntax highlighting...";
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	top: 0.5rem;
 | 
			
		||||
	right: 0.5rem;
 | 
			
		||||
	font-size: 0.75rem;
 | 
			
		||||
	color: var(--text-light);
 | 
			
		||||
	background-color: var(--bg);
 | 
			
		||||
	padding: 0.25rem 0.5rem;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	opacity: 0.7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* All code blocks should have consistent font and sizing */
 | 
			
		||||
${host} code {
 | 
			
		||||
	font-family: var(--font-mono);
 | 
			
		||||
	font-size: 0.9rem;
 | 
			
		||||
	line-height: 1.5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Ensure line numbers (if added) are styled appropriately */
 | 
			
		||||
${host} .line-number {
 | 
			
		||||
	user-select: none;
 | 
			
		||||
	opacity: 0.5;
 | 
			
		||||
	margin-right: 1rem;
 | 
			
		||||
	min-width: 1.5rem;
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	text-align: right;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* If there's a copy button, style it */
 | 
			
		||||
${host} .copy-button {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	top: 0.5rem;
 | 
			
		||||
	right: 0.5rem;
 | 
			
		||||
	background-color: var(--bg);
 | 
			
		||||
	color: var(--text);
 | 
			
		||||
	border: 1px solid var(--border);
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	padding: 0.25rem 0.5rem;
 | 
			
		||||
	font-size: 0.75rem;
 | 
			
		||||
	cursor: pointer;
 | 
			
		||||
	opacity: 0;
 | 
			
		||||
	transition: opacity 0.2s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host}:hover .copy-button {
 | 
			
		||||
	opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
`;
 | 
			
		||||
import { el } from "deka-dom-el";
 | 
			
		||||
@@ -52,12 +198,46 @@ let is_registered= {};
 | 
			
		||||
function registerClientPart(page_id){
 | 
			
		||||
	if(is_registered[page_id]) return;
 | 
			
		||||
 | 
			
		||||
	// Add Shiki with a more reliable loading method
 | 
			
		||||
	document.head.append(
 | 
			
		||||
		el("script", { src: "https://cdn.jsdelivr.net/npm/shiki@0.9", defer: true }),
 | 
			
		||||
		// Use a newer version of Shiki with better performance
 | 
			
		||||
		el("script", { src: "https://cdn.jsdelivr.net/npm/shiki@0.14.3/dist/index.unpkg.iife.js", defer: true }),
 | 
			
		||||
		// Make sure we can match Flems styling in dark/light mode
 | 
			
		||||
		el("style", `
 | 
			
		||||
			/* Ensure CodeMirror and Shiki use the same font */
 | 
			
		||||
			.CodeMirror *, .shiki * {
 | 
			
		||||
				font-family: var(--font-mono) !important;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Style Shiki's output to match our theme */
 | 
			
		||||
			.shiki {
 | 
			
		||||
				background-color: var(--shiki-color-background) !important;
 | 
			
		||||
				color: var(--shiki-color-text) !important;
 | 
			
		||||
				padding: 1rem;
 | 
			
		||||
				border-radius: var(--border-radius);
 | 
			
		||||
				tab-size: 2;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Ensure Shiki code tokens use our CSS variables */
 | 
			
		||||
			.shiki .keyword { color: var(--shiki-token-keyword) !important; }
 | 
			
		||||
			.shiki .constant { color: var(--shiki-token-constant) !important; }
 | 
			
		||||
			.shiki .string { color: var(--shiki-token-string) !important; }
 | 
			
		||||
			.shiki .comment { color: var(--shiki-token-comment) !important; }
 | 
			
		||||
			.shiki .function { color: var(--shiki-token-function) !important; }
 | 
			
		||||
			.shiki .operator, .shiki .punctuation { color: var(--shiki-token-punctuation) !important; }
 | 
			
		||||
			.shiki .parameter { color: var(--shiki-token-parameter) !important; }
 | 
			
		||||
			.shiki .variable { color: var(--shiki-token-variable) !important; }
 | 
			
		||||
			.shiki .property { color: var(--shiki-token-property) !important; }
 | 
			
		||||
		`),
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	// Register our highlighting script to run after Shiki loads
 | 
			
		||||
	const scriptElement = el("script", { type: "module" });
 | 
			
		||||
 | 
			
		||||
	registerClientFile(
 | 
			
		||||
		new URL("./code.js.js", import.meta.url),
 | 
			
		||||
		el("script", { type: "module" })
 | 
			
		||||
		scriptElement
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	is_registered[page_id]= true;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,61 @@
 | 
			
		||||
const highlighter= await globalThis.shiki.getHighlighter({
 | 
			
		||||
try {
 | 
			
		||||
	// Initialize Shiki with our custom theme
 | 
			
		||||
	const highlighter = await globalThis.shiki.getHighlighter({
 | 
			
		||||
		theme: "css-variables",
 | 
			
		||||
	langs: ["js", "ts", "css", "html", "shell"],
 | 
			
		||||
});
 | 
			
		||||
const codeBlocks= document.querySelectorAll('code[class*="language-"]');
 | 
			
		||||
		langs: ["javascript", "typescript", "css", "html", "shell"],
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
codeBlocks.forEach((block)=> {
 | 
			
		||||
	const lang= block.className.replace("language-", "");
 | 
			
		||||
	block.parentElement.dataset.js= "done";
 | 
			
		||||
	const html= highlighter.codeToHtml(block.textContent, { lang });
 | 
			
		||||
	block.innerHTML= html;
 | 
			
		||||
});
 | 
			
		||||
	// Find all code blocks that need highlighting
 | 
			
		||||
	const codeBlocks = document.querySelectorAll('div[data-js="todo"] code[class*="language-"]');
 | 
			
		||||
 | 
			
		||||
	// Process each code block
 | 
			
		||||
	codeBlocks.forEach((block) => {
 | 
			
		||||
		try {
 | 
			
		||||
			// Get the language from the class
 | 
			
		||||
			const langClass = block.className.match(/language-(\w+)/);
 | 
			
		||||
 | 
			
		||||
			// Map the language to Shiki format
 | 
			
		||||
			let lang = langClass ? langClass[1] : 'javascript';
 | 
			
		||||
			if (lang === 'js') lang = 'javascript';
 | 
			
		||||
			if (lang === 'ts') lang = 'typescript';
 | 
			
		||||
 | 
			
		||||
			// Mark the container as processed
 | 
			
		||||
			block.parentElement.dataset.js = "done";
 | 
			
		||||
 | 
			
		||||
			// Highlight the code
 | 
			
		||||
			const code = block.textContent;
 | 
			
		||||
			const html = highlighter.codeToHtml(code, { lang });
 | 
			
		||||
 | 
			
		||||
			// Insert the highlighted HTML
 | 
			
		||||
			block.innerHTML = html;
 | 
			
		||||
 | 
			
		||||
			// Add copy button functionality
 | 
			
		||||
			const copyBtn = document.createElement('button');
 | 
			
		||||
			copyBtn.className = 'copy-button';
 | 
			
		||||
			copyBtn.textContent = 'Copy';
 | 
			
		||||
			copyBtn.setAttribute('aria-label', 'Copy code to clipboard');
 | 
			
		||||
			copyBtn.addEventListener('click', () => {
 | 
			
		||||
				navigator.clipboard.writeText(code).then(() => {
 | 
			
		||||
					copyBtn.textContent = 'Copied!';
 | 
			
		||||
					setTimeout(() => {
 | 
			
		||||
						copyBtn.textContent = 'Copy';
 | 
			
		||||
					}, 2000);
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// Add the copy button to the code block container
 | 
			
		||||
			block.parentElement.appendChild(copyBtn);
 | 
			
		||||
		} catch (err) {
 | 
			
		||||
			console.error('Error highlighting code block:', err);
 | 
			
		||||
			// Make sure we don't leave the block in a pending state
 | 
			
		||||
			block.parentElement.dataset.js = "error";
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
} catch (err) {
 | 
			
		||||
	console.error('Failed to initialize Shiki:', err);
 | 
			
		||||
 | 
			
		||||
	// Fallback: at least mark blocks as processed so they don't show loading indicator
 | 
			
		||||
	document.querySelectorAll('div[data-js="todo"]').forEach(block => {
 | 
			
		||||
		block.dataset.js = "error";
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,103 @@
 | 
			
		||||
import { styles } from "../ssr.js";
 | 
			
		||||
const host= "."+example.name;
 | 
			
		||||
styles.css`
 | 
			
		||||
${host}{
 | 
			
		||||
${host} {
 | 
			
		||||
	grid-column: full-main;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	max-width: calc(9/5 * var(--body-max-width));
 | 
			
		||||
	height: calc(3/5 * var(--body-max-width));
 | 
			
		||||
	margin-inline: auto;
 | 
			
		||||
	margin: 2rem auto;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	box-shadow: var(--shadow);
 | 
			
		||||
	border: 1px solid var(--border);
 | 
			
		||||
}
 | 
			
		||||
${host} .runtime {
 | 
			
		||||
	background-color: whitesmoke;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* CodeMirror styling to match our theme */
 | 
			
		||||
.CodeMirror {
 | 
			
		||||
	height: 100% !important;
 | 
			
		||||
	font-family: var(--font-mono) !important;
 | 
			
		||||
	font-size: 0.95rem !important;
 | 
			
		||||
	line-height: 1.5 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Dark mode styles for CodeMirror */
 | 
			
		||||
.CodeMirror, .CodeMirror-gutters {
 | 
			
		||||
	background: #212121 !important;
 | 
			
		||||
	border: 1px solid white;
 | 
			
		||||
	background: var(--code-bg) !important;
 | 
			
		||||
	border: 1px solid var(--border) !important;
 | 
			
		||||
	color: var(--text) !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Light mode adjustments for CodeMirror - using CSS variables */
 | 
			
		||||
@media (prefers-color-scheme: light) {
 | 
			
		||||
	/* Core syntax elements */
 | 
			
		||||
	.cm-s-material .cm-keyword { color: var(--shiki-token-keyword, #d73a49) !important; }
 | 
			
		||||
	.cm-s-material .cm-atom { color: var(--shiki-token-constant, #005cc5) !important; }
 | 
			
		||||
	.cm-s-material .cm-number { color: var(--shiki-token-number, #005cc5) !important; }
 | 
			
		||||
	.cm-s-material .cm-def { color: var(--shiki-token-function, #6f42c1) !important; }
 | 
			
		||||
	.cm-s-material .cm-variable { color: var(--shiki-token-variable, #24292e) !important; }
 | 
			
		||||
	.cm-s-material .cm-variable-2 { color: var(--shiki-token-variable, #24292e) !important; }
 | 
			
		||||
	.cm-s-material .cm-variable-3 { color: var(--shiki-token-variable, #24292e) !important; }
 | 
			
		||||
	.cm-s-material .cm-property { color: var(--shiki-token-property, #005cc5) !important; }
 | 
			
		||||
	.cm-s-material .cm-operator { color: var(--shiki-token-operator, #d73a49) !important; }
 | 
			
		||||
	.cm-s-material .cm-comment { color: var(--shiki-token-comment, #6a737d) !important; }
 | 
			
		||||
	.cm-s-material .cm-string { color: var(--shiki-token-string, #22863a) !important; }
 | 
			
		||||
	.cm-s-material .cm-string-2 { color: var(--shiki-token-string, #22863a) !important; }
 | 
			
		||||
	.cm-s-material .cm-tag { color: var(--shiki-token-tag, #22863a) !important; }
 | 
			
		||||
	.cm-s-material .cm-attribute { color: var(--shiki-token-attribute, #005cc5) !important; }
 | 
			
		||||
	.cm-s-material .cm-bracket { color: var(--shiki-token-punctuation, #24292e) !important; }
 | 
			
		||||
	.cm-s-material .cm-punctuation { color: var(--shiki-token-punctuation, #24292e) !important; }
 | 
			
		||||
	.cm-s-material .cm-link { color: var(--shiki-token-link, #0366d6) !important; }
 | 
			
		||||
	.cm-s-material .cm-error { color: #f44336 !important; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Handle theme toggle */
 | 
			
		||||
html[data-theme="light"] .CodeMirror {
 | 
			
		||||
	background: #f5f7fa !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
html[data-theme="light"] .CodeMirror-gutters {
 | 
			
		||||
	background: #f5f7fa !important;
 | 
			
		||||
	border-right: 1px solid #e5e7eb !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Also apply the same styles to CodeMirror with data-theme */
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-keyword { color: var(--shiki-token-keyword, #d73a49) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-atom { color: var(--shiki-token-constant, #005cc5) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-number { color: var(--shiki-token-number, #005cc5) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-def { color: var(--shiki-token-function, #6f42c1) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-variable { color: var(--shiki-token-variable, #24292e) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-variable-2 { color: var(--shiki-token-variable, #24292e) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-variable-3 { color: var(--shiki-token-variable, #24292e) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-property { color: var(--shiki-token-property, #005cc5) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-operator { color: var(--shiki-token-operator, #d73a49) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-comment { color: var(--shiki-token-comment, #6a737d) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-string { color: var(--shiki-token-string, #22863a) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-string-2 { color: var(--shiki-token-string, #22863a) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-tag { color: var(--shiki-token-tag, #22863a) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-attribute { color: var(--shiki-token-attribute, #005cc5) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-bracket { color: var(--shiki-token-punctuation, #24292e) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-punctuation { color: var(--shiki-token-punctuation, #24292e) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-link { color: var(--shiki-token-link, #0366d6) !important; }
 | 
			
		||||
html[data-theme="light"] .cm-s-material .cm-error { color: #f44336 !important; }
 | 
			
		||||
 | 
			
		||||
/* Mobile adjustments */
 | 
			
		||||
@media (max-width: 767px) {
 | 
			
		||||
	${host} {
 | 
			
		||||
		height: 50vh;
 | 
			
		||||
		max-width: 100%;
 | 
			
		||||
	}
 | 
			
		||||
	${host} main {
 | 
			
		||||
		flex-grow: 1;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		flex-direction: column;
 | 
			
		||||
	}
 | 
			
		||||
	${host} main > * {
 | 
			
		||||
		width: 100%;
 | 
			
		||||
		max-width: 100% !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,67 @@
 | 
			
		||||
import { pages, styles } from "../ssr.js";
 | 
			
		||||
const host= "."+prevNext.name;
 | 
			
		||||
styles.css`
 | 
			
		||||
${host}{
 | 
			
		||||
	display: grid;
 | 
			
		||||
	grid-template-columns: 1fr 2fr 1fr;
 | 
			
		||||
	margin-top: 1rem;
 | 
			
		||||
/* Previous/Next navigation */
 | 
			
		||||
${host} {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	justify-content: space-between;
 | 
			
		||||
	margin-top: 3rem;
 | 
			
		||||
	padding-top: 1.5rem;
 | 
			
		||||
	border-top: 1px solid var(--border);
 | 
			
		||||
	gap: 1rem;
 | 
			
		||||
}
 | 
			
		||||
${host} [rel=prev]{
 | 
			
		||||
	grid-column: 1;
 | 
			
		||||
 | 
			
		||||
${host} a {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	padding: 0.75rem 1.25rem;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	background-color: var(--primary-dark); /* Darker background for better contrast */
 | 
			
		||||
	color: white;
 | 
			
		||||
	font-weight: 600; /* Bolder text for better readability */
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
	transition: background-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
 | 
			
		||||
	max-width: 45%;
 | 
			
		||||
	box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); /* Subtle shadow for better visibility */
 | 
			
		||||
}
 | 
			
		||||
${host} [rel=next]{
 | 
			
		||||
	grid-column: 3;
 | 
			
		||||
	text-align: right;
 | 
			
		||||
 | 
			
		||||
${host} a:hover {
 | 
			
		||||
	background-color: var(--primary);
 | 
			
		||||
	transform: translateY(-2px);
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
	box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* Enhanced shadow on hover */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} [rel=prev] {
 | 
			
		||||
	margin-right: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} [rel=next] {
 | 
			
		||||
	margin-left: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} [rel=prev]::before {
 | 
			
		||||
	content: "←";
 | 
			
		||||
	margin-right: 0.75rem;
 | 
			
		||||
	font-size: 1.2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} [rel=next]::after {
 | 
			
		||||
	content: "→";
 | 
			
		||||
	margin-left: 0.75rem;
 | 
			
		||||
	font-size: 1.2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* If there's no previous/next, ensure the spacing still works */
 | 
			
		||||
${host} a:only-child {
 | 
			
		||||
	margin-left: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (max-width: 640px) {
 | 
			
		||||
	${host} a {
 | 
			
		||||
		padding: 0.5rem 0.75rem;
 | 
			
		||||
		font-size: 0.9rem;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
`;
 | 
			
		||||
import { el } from "../../index.js";
 | 
			
		||||
@@ -23,9 +72,16 @@ import { el } from "../../index.js";
 | 
			
		||||
 * */
 | 
			
		||||
export function h3({ textContent, id }){
 | 
			
		||||
		if(!id) id= "h-"+textContent.toLowerCase().replaceAll(/\s/g, "-").replaceAll(/[^a-z-]/g, "");
 | 
			
		||||
	return el("h3", { id }).append(
 | 
			
		||||
		el("a", { textContent: "#", href: "#"+id, tabIndex: -1 }),
 | 
			
		||||
		" ", textContent
 | 
			
		||||
		return el("h3", { id, className: "section-heading" }).append(
 | 
			
		||||
				el("a", {
 | 
			
		||||
						className: "heading-anchor",
 | 
			
		||||
						href: "#"+id,
 | 
			
		||||
						textContent: "#",
 | 
			
		||||
						title: `Link to this section: ${textContent}`,
 | 
			
		||||
						"aria-label": `Link to section ${textContent}`
 | 
			
		||||
				}),
 | 
			
		||||
				" ",
 | 
			
		||||
				textContent,
 | 
			
		||||
		);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
@@ -46,9 +102,20 @@ export function prevNext(page){
 | 
			
		||||
function pageLink({ rel, page }){
 | 
			
		||||
		if(!page) return el();
 | 
			
		||||
		let { href, title, description }= page;
 | 
			
		||||
	return el("a", { rel, href, title: description }).append(
 | 
			
		||||
		rel==="next" ?"(next) " : "",
 | 
			
		||||
		title,
 | 
			
		||||
		rel==="prev" ? " (previous)" : "",
 | 
			
		||||
 | 
			
		||||
		// Find the page index to show numbering
 | 
			
		||||
		const pageIndex = pages.findIndex(p => p === page);
 | 
			
		||||
		const pageNumber = pageIndex + 1;
 | 
			
		||||
 | 
			
		||||
		const linkTitle = rel === "prev"
 | 
			
		||||
				? `Previous: ${pageNumber}. ${title}`
 | 
			
		||||
				: `Next: ${pageNumber}. ${title}`;
 | 
			
		||||
 | 
			
		||||
		return el("a", {
 | 
			
		||||
				rel,
 | 
			
		||||
				href,
 | 
			
		||||
				title: description || linkTitle
 | 
			
		||||
		}).append(
 | 
			
		||||
				title
 | 
			
		||||
		);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,124 +1,438 @@
 | 
			
		||||
import { styles } from "./ssr.js";
 | 
			
		||||
styles.css`
 | 
			
		||||
@import url(https://cdn.simplecss.org/simple.min.css);
 | 
			
		||||
:root{
 | 
			
		||||
	--body-max-width: 45rem;
 | 
			
		||||
	--marked: #fb3779;
 | 
			
		||||
	--code: #0d47a1;
 | 
			
		||||
	--accent: #d81b60;
 | 
			
		||||
/* Modern custom styling with reddish color scheme and high contrast */
 | 
			
		||||
:root {
 | 
			
		||||
	/* Color variables - reddish theme with increased contrast */
 | 
			
		||||
	--primary: #b71c1c;       /* Darker red for better contrast on white */
 | 
			
		||||
	--primary-light: #f05545; /* Lighter but still contrasting red */
 | 
			
		||||
	--primary-dark: #7f0000;  /* Very dark red for maximum contrast */
 | 
			
		||||
	--primary-rgb: 183, 28, 28; /* RGB values for rgba operations */
 | 
			
		||||
	--secondary: #700037;     /* Darker purple for better contrast */
 | 
			
		||||
	--secondary-light: #ae1357; /* More saturated magenta for visibility */
 | 
			
		||||
	--secondary-dark: #4a0027;  /* Very dark purple */
 | 
			
		||||
	--secondary-rgb: 112, 0, 55; /* RGB values for rgba operations */
 | 
			
		||||
 | 
			
		||||
	/* Typography */
 | 
			
		||||
	--font-main: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
 | 
			
		||||
	--font-mono: 'Fira Code', 'JetBrains Mono', 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
 | 
			
		||||
 | 
			
		||||
	/* Layout */
 | 
			
		||||
	--body-max-width: 50rem;
 | 
			
		||||
	--sidebar-width: 16rem;
 | 
			
		||||
	--header-height: 4rem;
 | 
			
		||||
	--border-radius: 0.375rem;
 | 
			
		||||
 | 
			
		||||
	/* Colors light mode - enhanced contrast */
 | 
			
		||||
	--bg: #ffffff;
 | 
			
		||||
	--bg-sidebar: #fff5f5;
 | 
			
		||||
	--text: #1a1313;          /* Near-black text for high contrast */
 | 
			
		||||
	--text-light: #555050;    /* Darker gray text that meets contrast requirements */
 | 
			
		||||
	--code-bg: #f9f2f2;
 | 
			
		||||
	--code-text: #9a0000;     /* Darker red for code text */
 | 
			
		||||
	--border: #d8c0c0;
 | 
			
		||||
	--selection: rgba(183, 28, 28, 0.15);
 | 
			
		||||
	--marked: #b71c1c;
 | 
			
		||||
	--accent: var(--secondary);
 | 
			
		||||
	--shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
 | 
			
		||||
 | 
			
		||||
	/* Contrast improvements for components */
 | 
			
		||||
	--link-color: #9a0000;
 | 
			
		||||
	--link-hover: #7f0000;
 | 
			
		||||
	--button-text: #ffffff;
 | 
			
		||||
}
 | 
			
		||||
@media (prefers-color-scheme:dark) {
 | 
			
		||||
 | 
			
		||||
@media (prefers-color-scheme: dark) {
 | 
			
		||||
	:root {
 | 
			
		||||
		--accent: #f06292;
 | 
			
		||||
		--code: #62c1f0;
 | 
			
		||||
		--bg: #121212;           /* Pure dark background */
 | 
			
		||||
		--bg-sidebar: #1a1212;   /* Slightly lighter sidebar */
 | 
			
		||||
		--text: #ffffff;         /* Pure white text for highest contrast */
 | 
			
		||||
		--text-light: #cccccc;   /* Light gray that still meets contrast requirements */
 | 
			
		||||
		--code-bg: #2c2020;
 | 
			
		||||
		--code-text: #ff9e80;    /* Slightly more orange for better visibility */
 | 
			
		||||
		--border: #4d3939;
 | 
			
		||||
		--selection: rgba(255, 99, 71, 0.25);
 | 
			
		||||
		--primary: #b74141;      /* Brighter red for better visibility on dark */
 | 
			
		||||
		--primary-light: #ff867f; /* Even brighter highlight red */
 | 
			
		||||
		--primary-dark: #c62828; /* Darker red that still has good contrast */
 | 
			
		||||
		--secondary: #f02b47;    /* Brighter magenta for better visibility */
 | 
			
		||||
		--secondary-light: #ff6090; /* Bright pink with good contrast */
 | 
			
		||||
		--secondary-dark: #b0003a; /* Darker but still visible pink */
 | 
			
		||||
		--accent: var(--secondary);
 | 
			
		||||
 | 
			
		||||
		/* Contrast improvements for dark mode components */
 | 
			
		||||
		--link-color: #ff5252;
 | 
			
		||||
		--link-hover: #ff867f;
 | 
			
		||||
		--button-text: #ffffff;
 | 
			
		||||
 | 
			
		||||
		/* Navigation current page - darker for better contrast */
 | 
			
		||||
		--nav-current-bg: #aa2222;
 | 
			
		||||
		--nav-current-text: #ffffff;
 | 
			
		||||
 | 
			
		||||
		/* RGB values for rgba operations in dark mode */
 | 
			
		||||
		--primary-rgb: 255, 82, 82;
 | 
			
		||||
		--secondary-rgb: 233, 30, 99;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
body {
 | 
			
		||||
	grid-template-columns: 100%;
 | 
			
		||||
	grid-template-areas: "header" "sidebar" "content";
 | 
			
		||||
}
 | 
			
		||||
@media (min-width:768px) {
 | 
			
		||||
	body{
 | 
			
		||||
		grid-template-rows: auto auto;
 | 
			
		||||
		grid-template-columns: calc(10 * var(--body-max-width) / 27) auto;
 | 
			
		||||
		grid-template-areas:
 | 
			
		||||
			"header header"
 | 
			
		||||
			"sidebar content"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
body > *{
 | 
			
		||||
	grid-column: unset;
 | 
			
		||||
}
 | 
			
		||||
body > header{
 | 
			
		||||
	grid-area: header;
 | 
			
		||||
	padding: 0;
 | 
			
		||||
}
 | 
			
		||||
body > nav{
 | 
			
		||||
	grid-area: sidebar;
 | 
			
		||||
	background-color: var(--accent-bg);
 | 
			
		||||
	display: flex;
 | 
			
		||||
	flex-flow: column nowrap;
 | 
			
		||||
}
 | 
			
		||||
body > nav {
 | 
			
		||||
	font-size: 1rem;
 | 
			
		||||
	line-height: 2;
 | 
			
		||||
	padding: 1rem 0 0 0;
 | 
			
		||||
}
 | 
			
		||||
body > nav ol,
 | 
			
		||||
body > nav ul {
 | 
			
		||||
	align-content: space-around;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	flex-direction: row;
 | 
			
		||||
	flex-wrap: wrap;
 | 
			
		||||
	justify-content: center;
 | 
			
		||||
	list-style-type: none;
 | 
			
		||||
 | 
			
		||||
/* Base styling */
 | 
			
		||||
* {
 | 
			
		||||
	box-sizing: border-box;
 | 
			
		||||
	margin: 0;
 | 
			
		||||
	padding: 0;
 | 
			
		||||
}
 | 
			
		||||
body > nav ol li,
 | 
			
		||||
body > nav ul li {
 | 
			
		||||
	display:inline-block
 | 
			
		||||
 | 
			
		||||
html {
 | 
			
		||||
	scroll-behavior: smooth;
 | 
			
		||||
}
 | 
			
		||||
body > nav a,
 | 
			
		||||
body > nav a:visited {
 | 
			
		||||
	margin: 0 .5rem 1rem .5rem;
 | 
			
		||||
	border: 1px solid currentColor;
 | 
			
		||||
	border-radius: var(--standard-border-radius);
 | 
			
		||||
	color: var(--text-light);
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	padding: .1rem 1rem;
 | 
			
		||||
 | 
			
		||||
/* Accessibility improvements */
 | 
			
		||||
:focus {
 | 
			
		||||
	outline: 3px solid rgba(63, 81, 181, 0.5);
 | 
			
		||||
	outline-offset: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:focus:not(:focus-visible) {
 | 
			
		||||
	outline: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:focus-visible {
 | 
			
		||||
	outline: 3px solid rgba(63, 81, 181, 0.5);
 | 
			
		||||
	outline-offset: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Ensure reduced motion preferences are respected */
 | 
			
		||||
@media (prefers-reduced-motion: reduce) {
 | 
			
		||||
	html {
 | 
			
		||||
		scroll-behavior: auto;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*, *::before, *::after {
 | 
			
		||||
		animation-duration: 0.01ms !important;
 | 
			
		||||
		animation-iteration-count: 1 !important;
 | 
			
		||||
		transition-duration: 0.01ms !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Skip link for better keyboard navigation */
 | 
			
		||||
.skip-link {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	top: 0;
 | 
			
		||||
	left: 0;
 | 
			
		||||
	transform: translateX(-100%);
 | 
			
		||||
	z-index: 9999;
 | 
			
		||||
	background-color: var(--primary);
 | 
			
		||||
	color: white;
 | 
			
		||||
	padding: 0.5rem 1rem;
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
	cursor: pointer;
 | 
			
		||||
	transition: all .15s;
 | 
			
		||||
	transition: transform 0.3s ease-in-out;
 | 
			
		||||
}
 | 
			
		||||
body > nav a.current,
 | 
			
		||||
body > nav a[aria-current=page] {
 | 
			
		||||
 | 
			
		||||
.skip-link:focus {
 | 
			
		||||
	transform: translateX(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (prefers-reduced-motion: reduce) {
 | 
			
		||||
	*, *::before, *::after {
 | 
			
		||||
		animation-duration: 0.01ms !important;
 | 
			
		||||
		animation-iteration-count: 1 !important;
 | 
			
		||||
		transition-duration: 0.01ms !important;
 | 
			
		||||
		scroll-behavior: auto !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
	font-family: var(--font-main);
 | 
			
		||||
	background-color: var(--bg);
 | 
			
		||||
	color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
body > nav a:hover{
 | 
			
		||||
	background-color: var(--bg);
 | 
			
		||||
	color: var(--accent);
 | 
			
		||||
}
 | 
			
		||||
@media only screen and (max-width:720px) {
 | 
			
		||||
	body > nav{
 | 
			
		||||
		flex-flow: row wrap;
 | 
			
		||||
		padding-block: .5rem;
 | 
			
		||||
	}
 | 
			
		||||
	body > nav a {
 | 
			
		||||
		border:none;
 | 
			
		||||
		text-decoration:underline;
 | 
			
		||||
		margin-block: .1rem;
 | 
			
		||||
		padding-block:.1rem;
 | 
			
		||||
		line-height: 1rem;
 | 
			
		||||
		font-size: .9rem;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
main{
 | 
			
		||||
	grid-area: content;
 | 
			
		||||
	line-height: 1.6;
 | 
			
		||||
	font-size: 1rem;
 | 
			
		||||
	display: grid;
 | 
			
		||||
	grid-template-columns:
 | 
			
		||||
	[full-main-start] 1fr
 | 
			
		||||
	[main-start] min(var(--body-max-width), 90%) [main-end]
 | 
			
		||||
	1fr [full-main-end];
 | 
			
		||||
	grid-template-columns: 100%;
 | 
			
		||||
	grid-template-areas:
 | 
			
		||||
		"header"
 | 
			
		||||
		"sidebar"
 | 
			
		||||
		"content";
 | 
			
		||||
	min-height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
main > *, main slot > *{
 | 
			
		||||
	grid-column: main;
 | 
			
		||||
 | 
			
		||||
::selection {
 | 
			
		||||
	background-color: var(--selection);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Typography */
 | 
			
		||||
h1, h2, h3, h4, h5, h6 {
 | 
			
		||||
	margin-bottom: 1rem;
 | 
			
		||||
	margin-top: 2rem;
 | 
			
		||||
	font-weight: 700; /* Bolder for better contrast */
 | 
			
		||||
	line-height: 1.25;
 | 
			
		||||
	color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1 {
 | 
			
		||||
	font-size: 2.25rem; /* Slightly larger for better hierarchy */
 | 
			
		||||
	margin-top: 0;
 | 
			
		||||
	color: var(--primary-dark); /* Distinctive color for main headings */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h2 {
 | 
			
		||||
	font-size: 1.5rem;
 | 
			
		||||
	border-bottom: 2px solid var(--border); /* Thicker border for better visibility */
 | 
			
		||||
	padding-bottom: 0.5rem;
 | 
			
		||||
	color: var(--primary); /* Color for better hierarchy */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h3 {
 | 
			
		||||
	font-size: 1.25rem;
 | 
			
		||||
	color: var(--secondary); /* Different color for tertiary headings */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p {
 | 
			
		||||
	margin-bottom: 1.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a {
 | 
			
		||||
	color: var(--link-color, var(--primary));
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
	transition: color 0.2s ease;
 | 
			
		||||
	font-weight: 500; /* Slightly bolder for better contrast */
 | 
			
		||||
	text-decoration: underline;
 | 
			
		||||
	text-underline-offset: 3px;
 | 
			
		||||
	transition: color 0.2s ease, text-underline-offset 0.2s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Ensure visited links maintain high contrast */
 | 
			
		||||
a:visited {
 | 
			
		||||
	color: var(--secondary, #700037);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a:hover {
 | 
			
		||||
	color: var(--link-hover, var(--primary-light));
 | 
			
		||||
	text-underline-offset: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
code, pre {
 | 
			
		||||
	font-family: var(--font-mono);
 | 
			
		||||
	font-size: 0.9em;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
code {
 | 
			
		||||
	background-color: var(--code-bg);
 | 
			
		||||
	color: var(--code-text);
 | 
			
		||||
	padding: 0.2em 0.4em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pre {
 | 
			
		||||
	background-color: var(--code-bg);
 | 
			
		||||
	padding: 1rem;
 | 
			
		||||
	overflow-x: auto;
 | 
			
		||||
	margin-bottom: 1.5rem;
 | 
			
		||||
	border: 1px solid var(--border);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pre code {
 | 
			
		||||
	background-color: transparent;
 | 
			
		||||
	padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Layout */
 | 
			
		||||
@media (min-width: 768px) {
 | 
			
		||||
	body {
 | 
			
		||||
		grid-template-rows: var(--header-height) 1fr;
 | 
			
		||||
		grid-template-columns: var(--sidebar-width) 1fr;
 | 
			
		||||
		grid-template-areas:
 | 
			
		||||
			"header header"
 | 
			
		||||
			"sidebar content";
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Main content */
 | 
			
		||||
body > main {
 | 
			
		||||
	grid-area: content;
 | 
			
		||||
	padding: 2rem;
 | 
			
		||||
	max-width: 100%;
 | 
			
		||||
	overflow-x: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body > main > *, body > main slot > * {
 | 
			
		||||
	max-width: calc(var(--body-max-width) - var(--sidebar-width));
 | 
			
		||||
	margin-left: auto;
 | 
			
		||||
	margin-right: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Page title with ID anchor for skip link */
 | 
			
		||||
body > main .page-title {
 | 
			
		||||
	margin-top: 0;
 | 
			
		||||
	border-bottom: 1px solid var(--border);
 | 
			
		||||
	padding-bottom: 0.75rem;
 | 
			
		||||
	margin-bottom: 1.5rem;
 | 
			
		||||
	color: var(--primary);
 | 
			
		||||
	position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Section headings with better visual hierarchy */
 | 
			
		||||
body > main h2, body > main h3 {
 | 
			
		||||
	scroll-margin-top: calc(var(--header-height) + 1rem);
 | 
			
		||||
	position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body > main h3 {
 | 
			
		||||
	border-left: 3px solid var(--primary);
 | 
			
		||||
	padding-left: 0.75rem;
 | 
			
		||||
	margin-left: -0.75rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Make clickable heading links for better navigation */
 | 
			
		||||
body > main h2 .heading-anchor,
 | 
			
		||||
body > main h3 .heading-anchor {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	color: var(--text-light);
 | 
			
		||||
	left: -1rem;
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
	font-weight: normal;
 | 
			
		||||
	opacity: 0;
 | 
			
		||||
	transition: opacity 0.2s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body > main h2:hover .heading-anchor,
 | 
			
		||||
body > main h3:hover .heading-anchor {
 | 
			
		||||
	opacity: 0.8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (max-width: 767px) {
 | 
			
		||||
	body > main {
 | 
			
		||||
		padding: 1.5rem 1rem;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body > main > *, body > main slot > * {
 | 
			
		||||
		max-width: 100%;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Example boxes */
 | 
			
		||||
.example {
 | 
			
		||||
	border: 1px solid var(--border);
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	margin: 2rem 0;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	box-shadow: var(--shadow-sm);
 | 
			
		||||
	transition: box-shadow 0.2s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.example:hover {
 | 
			
		||||
	box-shadow: var(--shadow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.example-header {
 | 
			
		||||
	background-color: var(--bg-sidebar);
 | 
			
		||||
	padding: 0.75rem 1rem;
 | 
			
		||||
	border-bottom: 1px solid var(--border);
 | 
			
		||||
	font-weight: 600;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	justify-content: space-between;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.example-content {
 | 
			
		||||
	padding: 1.25rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Icon styling */
 | 
			
		||||
.icon {
 | 
			
		||||
	vertical-align: sub;
 | 
			
		||||
	padding-right: .25rem;
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	width: 1em;
 | 
			
		||||
	height: 1.3em;
 | 
			
		||||
	margin-right: 0.2rem;
 | 
			
		||||
	height: 1em;
 | 
			
		||||
	margin-right: 0.5rem;
 | 
			
		||||
	vertical-align: -0.125em;
 | 
			
		||||
	stroke-width: 0;
 | 
			
		||||
	stroke: currentColor;
 | 
			
		||||
	fill: currentColor;
 | 
			
		||||
}
 | 
			
		||||
.note{
 | 
			
		||||
	font-size: .9rem;
 | 
			
		||||
	font-style: italic;
 | 
			
		||||
 | 
			
		||||
/* Information blocks */
 | 
			
		||||
.note, .tip, .warning {
 | 
			
		||||
	padding: 1rem 1.25rem;
 | 
			
		||||
	margin: 1.5rem 0;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	position: relative;
 | 
			
		||||
	font-size: 0.95rem;
 | 
			
		||||
	line-height: 1.5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.note {
 | 
			
		||||
	background-color: rgba(63, 81, 181, 0.08);
 | 
			
		||||
	border-left: 4px solid var(--primary);
 | 
			
		||||
	border-radius: 0 var(--border-radius) var(--border-radius) 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tip {
 | 
			
		||||
	background-color: rgba(46, 204, 113, 0.08);
 | 
			
		||||
	border-left: 4px solid #2ecc71;
 | 
			
		||||
	border-radius: 0 var(--border-radius) var(--border-radius) 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.warning {
 | 
			
		||||
	background-color: rgba(241, 196, 15, 0.08);
 | 
			
		||||
	border-left: 4px solid #f1c40f;
 | 
			
		||||
	border-radius: 0 var(--border-radius) var(--border-radius) 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.note::before, .tip::before, .warning::before {
 | 
			
		||||
	font-weight: 600;
 | 
			
		||||
	display: block;
 | 
			
		||||
	margin-bottom: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.note::before {
 | 
			
		||||
	content: "Note";
 | 
			
		||||
	color: var(--primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tip::before {
 | 
			
		||||
	content: "Tip";
 | 
			
		||||
	color: #2ecc71;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.warning::before {
 | 
			
		||||
	content: "Warning";
 | 
			
		||||
	color: #f1c40f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Prev/Next buttons */
 | 
			
		||||
.prev-next {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	justify-content: space-between;
 | 
			
		||||
	margin-top: 3rem;
 | 
			
		||||
	padding-top: 1.5rem;
 | 
			
		||||
	border-top: 1px solid var(--border);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.prev-next a {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	padding: 0.5rem 1rem;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	background-color: var(--primary);
 | 
			
		||||
	color: white;
 | 
			
		||||
	transition: background-color 0.2s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.prev-next a:hover {
 | 
			
		||||
	background-color: var(--primary-dark);
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.prev-next a:empty {
 | 
			
		||||
	display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.prev-next a[rel="prev"]::before {
 | 
			
		||||
	content: "←";
 | 
			
		||||
	margin-right: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.prev-next a[rel="next"]::after {
 | 
			
		||||
	content: "→";
 | 
			
		||||
	margin-left: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
`;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,38 +1,245 @@
 | 
			
		||||
import { el, elNS } from "deka-dom-el";
 | 
			
		||||
import { pages } from "../ssr.js";
 | 
			
		||||
import { pages, styles } from "../ssr.js";
 | 
			
		||||
const host= "."+header.name;
 | 
			
		||||
const host_nav= "."+nav.name;
 | 
			
		||||
styles.css`
 | 
			
		||||
/* Header */
 | 
			
		||||
${host} {
 | 
			
		||||
	grid-area: header;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	flex-wrap: wrap;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	justify-content: space-between;
 | 
			
		||||
	padding: 0.75rem 1.5rem;
 | 
			
		||||
	background-color: var(--primary);
 | 
			
		||||
	color: white;
 | 
			
		||||
	box-shadow: var(--shadow);
 | 
			
		||||
	min-height: var(--header-height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} .header-title {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	gap: 0.75rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} h1 {
 | 
			
		||||
	font-size: 1.25rem;
 | 
			
		||||
	margin: 0;
 | 
			
		||||
	white-space: nowrap;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	text-overflow: ellipsis;
 | 
			
		||||
	color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} .version-badge {
 | 
			
		||||
	font-size: 0.75rem;
 | 
			
		||||
	background-color: rgba(150, 150, 150, 0.2);
 | 
			
		||||
	padding: 0.25rem 0.5rem;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} p {
 | 
			
		||||
	display: none;
 | 
			
		||||
	margin: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} .github-link {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	gap: 0.5rem;
 | 
			
		||||
	color: white;
 | 
			
		||||
	font-size: 0.875rem;
 | 
			
		||||
	padding: 0.375rem 0.75rem;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	background-color: rgba(0, 0, 0, 0.2);
 | 
			
		||||
	margin-left: 1rem;
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
	transition: background-color 0.2s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host} .github-link:hover {
 | 
			
		||||
	background-color: rgba(0, 0, 0, 0.3);
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (min-width: 768px) {
 | 
			
		||||
	${host} p {
 | 
			
		||||
		display: block;
 | 
			
		||||
		font-size: 0.875rem;
 | 
			
		||||
		opacity: 0.9;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Navigation */
 | 
			
		||||
${host_nav} {
 | 
			
		||||
	grid-area: sidebar;
 | 
			
		||||
	background-color: var(--bg-sidebar);
 | 
			
		||||
	border-right: 1px solid var(--border);
 | 
			
		||||
	padding: 1.5rem 1rem;
 | 
			
		||||
	overflow-y: auto;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	flex-direction: column;
 | 
			
		||||
	gap: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host_nav} a {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	padding: 0.625rem 0.75rem;
 | 
			
		||||
	border-radius: var(--border-radius);
 | 
			
		||||
	color: var(--text);
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
	transition: background-color 0.2s ease, color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
 | 
			
		||||
	line-height: 1.2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host_nav} a:hover {
 | 
			
		||||
	background-color: rgba(var(--primary-rgb), 0.08); /* Using CSS variables for better theming */
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
	transform: translateY(-1px);
 | 
			
		||||
	color: var(--primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host_nav} a.current,
 | 
			
		||||
${host_nav} a[aria-current=page] {
 | 
			
		||||
	background-color: var(--nav-current-bg, var(--primary-dark));
 | 
			
		||||
	color: var(--nav-current-text, white);
 | 
			
		||||
	font-weight: 600;
 | 
			
		||||
	box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host_nav} a.current:hover,
 | 
			
		||||
${host_nav} a[aria-current=page]:hover {
 | 
			
		||||
	background-color: var(--primary);
 | 
			
		||||
	color: white;
 | 
			
		||||
	transform: translateY(-1px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host_nav} a .nav-number {
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	width: 1.5rem;
 | 
			
		||||
	text-align: right;
 | 
			
		||||
	margin-right: 0.5rem;
 | 
			
		||||
	opacity: 0.7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
${host_nav} a:first-child {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	font-weight: 600;
 | 
			
		||||
	margin-bottom: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Mobile navigation */
 | 
			
		||||
@media (max-width: 767px) {
 | 
			
		||||
	${host_nav} {
 | 
			
		||||
		padding: 0.75rem;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		flex-direction: row;
 | 
			
		||||
		flex-wrap: wrap;
 | 
			
		||||
		gap: 0.5rem;
 | 
			
		||||
		border-bottom: 1px solid var(--border);
 | 
			
		||||
		border-right: none;
 | 
			
		||||
		justify-content: center;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	${host_nav} a {
 | 
			
		||||
		font-size: 0.875rem;
 | 
			
		||||
		padding: 0.375rem 0.75rem;
 | 
			
		||||
		white-space: nowrap;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	${host_nav} a .nav-number {
 | 
			
		||||
		width: auto;
 | 
			
		||||
		margin-right: 0.25rem;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	${host_nav} a:first-child {
 | 
			
		||||
		margin-bottom: 0;
 | 
			
		||||
		margin-right: 0.5rem;
 | 
			
		||||
		min-width: 100%;
 | 
			
		||||
		justify-content: center;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
`;
 | 
			
		||||
/**
 | 
			
		||||
 * @param {object} def
 | 
			
		||||
 * @param {import("../types.d.ts").Info} def.info
 | 
			
		||||
 * @param {import("../types.d.ts").Pkg} def.pkg Package information.
 | 
			
		||||
 * */
 | 
			
		||||
export function header({ info: { href, title, description }, pkg }){
 | 
			
		||||
	title= `\`${pkg.name}\` — ${title}`;
 | 
			
		||||
	const pageTitle = `${pkg.name} — ${title}`;
 | 
			
		||||
 | 
			
		||||
	// Add meta elements to the head
 | 
			
		||||
	document.head.append(
 | 
			
		||||
		head({ title, description, pkg })
 | 
			
		||||
		head({ title: pageTitle, description, pkg })
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	// Add theme color meta tag
 | 
			
		||||
	document.head.append(
 | 
			
		||||
		el("meta", { name: "theme-color", content: "#3f51b5" })
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	return el().append(
 | 
			
		||||
		el("header").append(
 | 
			
		||||
			el("h1", title),
 | 
			
		||||
			el("p", description)
 | 
			
		||||
		// Header section with accessibility support
 | 
			
		||||
		el("header", { role: "banner", className: header.name }).append(
 | 
			
		||||
			el("div", { className: "header-title" }).append(
 | 
			
		||||
				el("h1", pkg.name),
 | 
			
		||||
				el("span", {
 | 
			
		||||
					className: "version-badge",
 | 
			
		||||
					"aria-label": "Version",
 | 
			
		||||
					textContent: pkg.version || ""
 | 
			
		||||
				})
 | 
			
		||||
			),
 | 
			
		||||
		el("nav").append(
 | 
			
		||||
			el("a", { href: pkg.homepage }).append(
 | 
			
		||||
			el("p", description),
 | 
			
		||||
			el("a", {
 | 
			
		||||
				href: pkg.homepage,
 | 
			
		||||
				className: "github-link",
 | 
			
		||||
				"aria-label": "View on GitHub",
 | 
			
		||||
				target: "_blank",
 | 
			
		||||
				rel: "noopener noreferrer"
 | 
			
		||||
			}).append(
 | 
			
		||||
				el(iconGitHub),
 | 
			
		||||
				"GitHub"
 | 
			
		||||
			),
 | 
			
		||||
			...pages.map((p, i)=> el("a", {
 | 
			
		||||
				href: p.href==="index" ? "./" : p.href,
 | 
			
		||||
				textContent: (i+1) + ". " + p.title,
 | 
			
		||||
				title: p.description,
 | 
			
		||||
				classList: { current: p.href===href }
 | 
			
		||||
			}))
 | 
			
		||||
			)
 | 
			
		||||
		),
 | 
			
		||||
 | 
			
		||||
		// Navigation between pages
 | 
			
		||||
		nav({ href })
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
function nav({ href }){
 | 
			
		||||
	return el("nav", {
 | 
			
		||||
		role: "navigation",
 | 
			
		||||
		"aria-label": "Main navigation",
 | 
			
		||||
		className: nav.name
 | 
			
		||||
	}).append(
 | 
			
		||||
		...pages.map((p, i) => {
 | 
			
		||||
			const isIndex = p.href === "index";
 | 
			
		||||
			const isCurrent = p.href === href;
 | 
			
		||||
 | 
			
		||||
			return el("a", {
 | 
			
		||||
				href: isIndex ? "./" : p.href,
 | 
			
		||||
				title: p.description || `Go to ${p.title}`,
 | 
			
		||||
				"aria-current": isCurrent ? "page" : null,
 | 
			
		||||
				classList: { current: isCurrent }
 | 
			
		||||
			}).append(
 | 
			
		||||
				el("span", {
 | 
			
		||||
					className: "nav-number",
 | 
			
		||||
					"aria-hidden": "true",
 | 
			
		||||
					textContent: `${i+1}.`
 | 
			
		||||
				}),
 | 
			
		||||
				p.title
 | 
			
		||||
			);
 | 
			
		||||
		})
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
function head({ title, description, pkg }){
 | 
			
		||||
	return el().append(
 | 
			
		||||
		el("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
 | 
			
		||||
		el("meta", { name: "description", content: description }),
 | 
			
		||||
		el("meta", { name: "theme-color", content: "#b71c1c" }),
 | 
			
		||||
		el("title", title),
 | 
			
		||||
		el(metaAuthor),
 | 
			
		||||
		el(metaTwitter, pkg),
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,25 @@ import { prevNext } from "../components/pageUtils.html.js";
 | 
			
		||||
/** @param {Pick<import("../types.d.ts").PageAttrs, "pkg" | "info">} attrs */
 | 
			
		||||
export function simplePage({ pkg, info }){
 | 
			
		||||
	return simulateSlots(el().append(
 | 
			
		||||
		// Skip link for keyboard navigation
 | 
			
		||||
		el("a", {
 | 
			
		||||
			href: "#main-content",
 | 
			
		||||
			className: "skip-link",
 | 
			
		||||
			textContent: "Skip to main content"
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
		// Header with site information
 | 
			
		||||
		el(header, { info, pkg }),
 | 
			
		||||
		el("main").append(
 | 
			
		||||
 | 
			
		||||
		// Main content area
 | 
			
		||||
		el("main", { id: "main-content", role: "main" }).append(
 | 
			
		||||
			// Page title as an h1
 | 
			
		||||
			el("h1", { className: "page-title", textContent: info.title }),
 | 
			
		||||
 | 
			
		||||
			// Main content from child elements
 | 
			
		||||
			el("slot"),
 | 
			
		||||
 | 
			
		||||
			// Navigation between pages
 | 
			
		||||
			el(prevNext, info)
 | 
			
		||||
		)
 | 
			
		||||
	));
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import { T, t } from "./utils/index.js";
 | 
			
		||||
export const info= {
 | 
			
		||||
	title: t`Signals and reactivity`,
 | 
			
		||||
	description: t`Handling reactivity in UI via signals.`,
 | 
			
		||||
	description: t`Managing reactive UI state with signals.`,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
import { el } from "deka-dom-el";
 | 
			
		||||
@@ -100,10 +100,10 @@ export function page({ pkg, info }){
 | 
			
		||||
		`),
 | 
			
		||||
 | 
			
		||||
		el(h3, t`Reactive DOM attributes and elements`),
 | 
			
		||||
		el("p", t`There are on basic level two distinc situation to mirror dynamic value into the DOM/UI`),
 | 
			
		||||
		el("p", t`There are two fundamental ways to make your DOM reactive with signals:`),
 | 
			
		||||
		el("ol").append(
 | 
			
		||||
			el("li", t`to change some attribute(s) of existing element(s)`),
 | 
			
		||||
			el("li", t`to generate elements itself dynamically – this covers conditions and loops`)
 | 
			
		||||
			el("li", t`Reactive attributes: Update properties, attributes, and styles of existing elements`),
 | 
			
		||||
			el("li", t`Reactive elements: Dynamically create or update DOM elements based on data changes (for conditions and loops)`)
 | 
			
		||||
		),
 | 
			
		||||
		el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }),
 | 
			
		||||
		el("p").append(...T`
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user