mirror of
				https://github.com/jaandrle/deka-dom-el
				synced 2025-11-04 07:09:15 +01:00 
			
		
		
		
	🔤 ⚡ Docs UI/UX
This commit is contained in:
		@@ -1,28 +1,174 @@
 | 
				
			|||||||
import { registerClientFile, styles } from "../ssr.js";
 | 
					import { registerClientFile, styles } from "../ssr.js";
 | 
				
			||||||
const host= "."+code.name;
 | 
					const host= "."+code.name;
 | 
				
			||||||
styles.css`
 | 
					styles.css`
 | 
				
			||||||
${host}{
 | 
					/* Code block styling */
 | 
				
			||||||
	--shiki-color-text: #e9eded;
 | 
					${host} {
 | 
				
			||||||
	--shiki-color-background: #212121;
 | 
						/* 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-constant: #82b1ff;
 | 
				
			||||||
	--shiki-token-string: #c3e88d;
 | 
						--shiki-token-string: #c3e88d;
 | 
				
			||||||
	--shiki-token-comment: #546e7a;
 | 
						--shiki-token-comment: #546e7a;
 | 
				
			||||||
	--shiki-token-keyword: #c792ea;
 | 
						--shiki-token-keyword: #c792ea;
 | 
				
			||||||
	--shiki-token-parameter: #AA0000;
 | 
						--shiki-token-parameter: #fd971f;
 | 
				
			||||||
	--shiki-token-function: #80cbae;
 | 
						--shiki-token-function: #80cbae;
 | 
				
			||||||
	--shiki-token-string-expression: #c3e88d;
 | 
						--shiki-token-string-expression: #c3e88d;
 | 
				
			||||||
	--shiki-token-punctuation: var(--code);
 | 
						--shiki-token-punctuation: #89ddff;
 | 
				
			||||||
	--shiki-token-link: #EE0000;
 | 
						--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;
 | 
						white-space: pre;
 | 
				
			||||||
	tab-size: 2; /* TODO: allow custom tab size?! */
 | 
						tab-size: 2;
 | 
				
			||||||
	overflow: scroll;
 | 
						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: 1px solid var(--border);
 | 
				
			||||||
	border-radius: var(--standard-border-radius);
 | 
						border-radius: var(--border-radius);
 | 
				
			||||||
	margin-bottom: 1rem;
 | 
						margin-bottom: 1.5rem;
 | 
				
			||||||
	margin-top: 18.4px; /* to fix shift when → dataJS=done */
 | 
						margin-top: 1rem;
 | 
				
			||||||
	padding: 1rem 1.4rem;
 | 
						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";
 | 
					import { el } from "deka-dom-el";
 | 
				
			||||||
@@ -52,12 +198,46 @@ let is_registered= {};
 | 
				
			|||||||
function registerClientPart(page_id){
 | 
					function registerClientPart(page_id){
 | 
				
			||||||
	if(is_registered[page_id]) return;
 | 
						if(is_registered[page_id]) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Add Shiki with a more reliable loading method
 | 
				
			||||||
	document.head.append(
 | 
						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(
 | 
						registerClientFile(
 | 
				
			||||||
		new URL("./code.js.js", import.meta.url),
 | 
							new URL("./code.js.js", import.meta.url),
 | 
				
			||||||
		el("script", { type: "module" })
 | 
							scriptElement
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	is_registered[page_id]= true;
 | 
						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",
 | 
							theme: "css-variables",
 | 
				
			||||||
	langs: ["js", "ts", "css", "html", "shell"],
 | 
							langs: ["javascript", "typescript", "css", "html", "shell"],
 | 
				
			||||||
});
 | 
						});
 | 
				
			||||||
const codeBlocks= document.querySelectorAll('code[class*="language-"]');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
codeBlocks.forEach((block)=> {
 | 
						// Find all code blocks that need highlighting
 | 
				
			||||||
	const lang= block.className.replace("language-", "");
 | 
						const codeBlocks = document.querySelectorAll('div[data-js="todo"] code[class*="language-"]');
 | 
				
			||||||
	block.parentElement.dataset.js= "done";
 | 
					
 | 
				
			||||||
	const html= highlighter.codeToHtml(block.textContent, { lang });
 | 
						// Process each code block
 | 
				
			||||||
	block.innerHTML= html;
 | 
						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";
 | 
					import { styles } from "../ssr.js";
 | 
				
			||||||
const host= "."+example.name;
 | 
					const host= "."+example.name;
 | 
				
			||||||
styles.css`
 | 
					styles.css`
 | 
				
			||||||
${host}{
 | 
					${host} {
 | 
				
			||||||
	grid-column: full-main;
 | 
						grid-column: full-main;
 | 
				
			||||||
	width: 100%;
 | 
						width: 100%;
 | 
				
			||||||
	max-width: calc(9/5 * var(--body-max-width));
 | 
						max-width: calc(9/5 * var(--body-max-width));
 | 
				
			||||||
	height: calc(3/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 {
 | 
					.CodeMirror, .CodeMirror-gutters {
 | 
				
			||||||
	background: #212121 !important;
 | 
						background: var(--code-bg) !important;
 | 
				
			||||||
	border: 1px solid white;
 | 
						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";
 | 
					import { pages, styles } from "../ssr.js";
 | 
				
			||||||
const host= "."+prevNext.name;
 | 
					const host= "."+prevNext.name;
 | 
				
			||||||
styles.css`
 | 
					styles.css`
 | 
				
			||||||
${host}{
 | 
					/* Previous/Next navigation */
 | 
				
			||||||
	display: grid;
 | 
					${host} {
 | 
				
			||||||
	grid-template-columns: 1fr 2fr 1fr;
 | 
						display: flex;
 | 
				
			||||||
	margin-top: 1rem;
 | 
						justify-content: space-between;
 | 
				
			||||||
 | 
						margin-top: 3rem;
 | 
				
			||||||
 | 
						padding-top: 1.5rem;
 | 
				
			||||||
	border-top: 1px solid var(--border);
 | 
						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;
 | 
					${host} a:hover {
 | 
				
			||||||
	text-align: right;
 | 
						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";
 | 
					import { el } from "../../index.js";
 | 
				
			||||||
@@ -23,9 +72,16 @@ import { el } from "../../index.js";
 | 
				
			|||||||
 * */
 | 
					 * */
 | 
				
			||||||
export function h3({ textContent, id }){
 | 
					export function h3({ textContent, id }){
 | 
				
			||||||
		if(!id) id= "h-"+textContent.toLowerCase().replaceAll(/\s/g, "-").replaceAll(/[^a-z-]/g, "");
 | 
							if(!id) id= "h-"+textContent.toLowerCase().replaceAll(/\s/g, "-").replaceAll(/[^a-z-]/g, "");
 | 
				
			||||||
	return el("h3", { id }).append(
 | 
							return el("h3", { id, className: "section-heading" }).append(
 | 
				
			||||||
		el("a", { textContent: "#", href: "#"+id, tabIndex: -1 }),
 | 
									el("a", {
 | 
				
			||||||
		" ", textContent
 | 
											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 }){
 | 
					function pageLink({ rel, page }){
 | 
				
			||||||
		if(!page) return el();
 | 
							if(!page) return el();
 | 
				
			||||||
		let { href, title, description }= page;
 | 
							let { href, title, description }= page;
 | 
				
			||||||
	return el("a", { rel, href, title: description }).append(
 | 
					
 | 
				
			||||||
		rel==="next" ?"(next) " : "",
 | 
							// Find the page index to show numbering
 | 
				
			||||||
		title,
 | 
							const pageIndex = pages.findIndex(p => p === page);
 | 
				
			||||||
		rel==="prev" ? " (previous)" : "",
 | 
							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";
 | 
					import { styles } from "./ssr.js";
 | 
				
			||||||
styles.css`
 | 
					styles.css`
 | 
				
			||||||
@import url(https://cdn.simplecss.org/simple.min.css);
 | 
					/* Modern custom styling with reddish color scheme and high contrast */
 | 
				
			||||||
:root{
 | 
					:root {
 | 
				
			||||||
	--body-max-width: 45rem;
 | 
						/* Color variables - reddish theme with increased contrast */
 | 
				
			||||||
	--marked: #fb3779;
 | 
						--primary: #b71c1c;       /* Darker red for better contrast on white */
 | 
				
			||||||
	--code: #0d47a1;
 | 
						--primary-light: #f05545; /* Lighter but still contrasting red */
 | 
				
			||||||
	--accent: #d81b60;
 | 
						--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 {
 | 
						:root {
 | 
				
			||||||
		--accent: #f06292;
 | 
							--bg: #121212;           /* Pure dark background */
 | 
				
			||||||
		--code: #62c1f0;
 | 
							--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%;
 | 
					/* Base styling */
 | 
				
			||||||
	grid-template-areas: "header" "sidebar" "content";
 | 
					* {
 | 
				
			||||||
}
 | 
						box-sizing: border-box;
 | 
				
			||||||
@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;
 | 
					 | 
				
			||||||
	margin: 0;
 | 
						margin: 0;
 | 
				
			||||||
	padding: 0;
 | 
						padding: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
body > nav ol li,
 | 
					
 | 
				
			||||||
body > nav ul li {
 | 
					html {
 | 
				
			||||||
	display:inline-block
 | 
						scroll-behavior: smooth;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
body > nav a,
 | 
					
 | 
				
			||||||
body > nav a:visited {
 | 
					/* Accessibility improvements */
 | 
				
			||||||
	margin: 0 .5rem 1rem .5rem;
 | 
					:focus {
 | 
				
			||||||
	border: 1px solid currentColor;
 | 
						outline: 3px solid rgba(63, 81, 181, 0.5);
 | 
				
			||||||
	border-radius: var(--standard-border-radius);
 | 
						outline-offset: 2px;
 | 
				
			||||||
	color: var(--text-light);
 | 
					}
 | 
				
			||||||
	display: inline-block;
 | 
					
 | 
				
			||||||
	padding: .1rem 1rem;
 | 
					: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;
 | 
						text-decoration: none;
 | 
				
			||||||
	cursor: pointer;
 | 
						transition: transform 0.3s ease-in-out;
 | 
				
			||||||
	transition: all .15s;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
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);
 | 
						background-color: var(--bg);
 | 
				
			||||||
	color: var(--text);
 | 
						color: var(--text);
 | 
				
			||||||
}
 | 
						line-height: 1.6;
 | 
				
			||||||
body > nav a:hover{
 | 
						font-size: 1rem;
 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
	display: grid;
 | 
						display: grid;
 | 
				
			||||||
	grid-template-columns:
 | 
						grid-template-columns: 100%;
 | 
				
			||||||
	[full-main-start] 1fr
 | 
						grid-template-areas:
 | 
				
			||||||
	[main-start] min(var(--body-max-width), 90%) [main-end]
 | 
							"header"
 | 
				
			||||||
	1fr [full-main-end];
 | 
							"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 {
 | 
					.icon {
 | 
				
			||||||
	vertical-align: sub;
 | 
					 | 
				
			||||||
	padding-right: .25rem;
 | 
					 | 
				
			||||||
	display: inline-block;
 | 
						display: inline-block;
 | 
				
			||||||
	width: 1em;
 | 
						width: 1em;
 | 
				
			||||||
	height: 1.3em;
 | 
						height: 1em;
 | 
				
			||||||
	margin-right: 0.2rem;
 | 
						margin-right: 0.5rem;
 | 
				
			||||||
 | 
						vertical-align: -0.125em;
 | 
				
			||||||
	stroke-width: 0;
 | 
						stroke-width: 0;
 | 
				
			||||||
	stroke: currentColor;
 | 
						stroke: currentColor;
 | 
				
			||||||
	fill: currentColor;
 | 
						fill: currentColor;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.note{
 | 
					
 | 
				
			||||||
	font-size: .9rem;
 | 
					/* Information blocks */
 | 
				
			||||||
	font-style: italic;
 | 
					.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 { 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 {object} def
 | 
				
			||||||
 * @param {import("../types.d.ts").Info} def.info
 | 
					 * @param {import("../types.d.ts").Info} def.info
 | 
				
			||||||
 * @param {import("../types.d.ts").Pkg} def.pkg Package information.
 | 
					 * @param {import("../types.d.ts").Pkg} def.pkg Package information.
 | 
				
			||||||
 * */
 | 
					 * */
 | 
				
			||||||
export function header({ info: { href, title, description }, pkg }){
 | 
					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(
 | 
						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(
 | 
						return el().append(
 | 
				
			||||||
		el("header").append(
 | 
							// Header section with accessibility support
 | 
				
			||||||
			el("h1", title),
 | 
							el("header", { role: "banner", className: header.name }).append(
 | 
				
			||||||
			el("p", description)
 | 
								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("p", description),
 | 
				
			||||||
			el("a", { href: pkg.homepage }).append(
 | 
								el("a", {
 | 
				
			||||||
 | 
									href: pkg.homepage,
 | 
				
			||||||
 | 
									className: "github-link",
 | 
				
			||||||
 | 
									"aria-label": "View on GitHub",
 | 
				
			||||||
 | 
									target: "_blank",
 | 
				
			||||||
 | 
									rel: "noopener noreferrer"
 | 
				
			||||||
 | 
								}).append(
 | 
				
			||||||
				el(iconGitHub),
 | 
									el(iconGitHub),
 | 
				
			||||||
				"GitHub"
 | 
									"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 }){
 | 
					function head({ title, description, pkg }){
 | 
				
			||||||
	return el().append(
 | 
						return el().append(
 | 
				
			||||||
		el("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
 | 
							el("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
 | 
				
			||||||
		el("meta", { name: "description", content: description }),
 | 
							el("meta", { name: "description", content: description }),
 | 
				
			||||||
 | 
							el("meta", { name: "theme-color", content: "#b71c1c" }),
 | 
				
			||||||
		el("title", title),
 | 
							el("title", title),
 | 
				
			||||||
		el(metaAuthor),
 | 
							el(metaAuthor),
 | 
				
			||||||
		el(metaTwitter, pkg),
 | 
							el(metaTwitter, pkg),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,9 +7,25 @@ import { prevNext } from "../components/pageUtils.html.js";
 | 
				
			|||||||
/** @param {Pick<import("../types.d.ts").PageAttrs, "pkg" | "info">} attrs */
 | 
					/** @param {Pick<import("../types.d.ts").PageAttrs, "pkg" | "info">} attrs */
 | 
				
			||||||
export function simplePage({ pkg, info }){
 | 
					export function simplePage({ pkg, info }){
 | 
				
			||||||
	return simulateSlots(el().append(
 | 
						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(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"),
 | 
								el("slot"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Navigation between pages
 | 
				
			||||||
			el(prevNext, info)
 | 
								el(prevNext, info)
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
	));
 | 
						));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import { T, t } from "./utils/index.js";
 | 
					import { T, t } from "./utils/index.js";
 | 
				
			||||||
export const info= {
 | 
					export const info= {
 | 
				
			||||||
	title: t`Signals and reactivity`,
 | 
						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";
 | 
					import { el } from "deka-dom-el";
 | 
				
			||||||
@@ -100,10 +100,10 @@ export function page({ pkg, info }){
 | 
				
			|||||||
		`),
 | 
							`),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		el(h3, t`Reactive DOM attributes and elements`),
 | 
							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("ol").append(
 | 
				
			||||||
			el("li", t`to change some attribute(s) of existing element(s)`),
 | 
								el("li", t`Reactive attributes: Update properties, attributes, and styles of existing elements`),
 | 
				
			||||||
			el("li", t`to generate elements itself dynamically – this covers conditions and loops`)
 | 
								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(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }),
 | 
				
			||||||
		el("p").append(...T`
 | 
							el("p").append(...T`
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user