commit 7e4964b4ef37b3260e218bce6ccc01cd40108627 Author: tkucar Date: Tue Feb 25 18:19:09 2025 +0100 hardcode loc diff --git a/blog/index.html b/blog/index.html new file mode 100644 index 0000000..a1949f1 --- /dev/null +++ b/blog/index.html @@ -0,0 +1,81 @@ + + + + + + + + + Blog + + + + + + + + + + + + + + +
+

Blog

+ Random musings. +
Versionv1740503848
Updated
+

Highligted

+

None.

+

Other

+ + + + + + +
+ Home • + Blog • + ©Copyright 2025 • + + + + + +
+ + + + diff --git a/blog/lorem-ipsum.html b/blog/lorem-ipsum.html new file mode 100644 index 0000000..f6340f5 --- /dev/null +++ b/blog/lorem-ipsum.html @@ -0,0 +1,121 @@ + + + + + + + + + Lorem ipsum + + + + + + + + + + + + + + +
+

Lorem ipsum

+ Lorem ipsum dolor sit amet, consectetur +adipiscing elit. +
Versionv1740503848
Updated
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque quis +sagittis diam. Nunc nec nisi venenatis, varius ipsum sed, interdum ex. +Nullam lacinia ex at sapien maximus mattis. Donec felis leo, viverra sit +amet augue at, convallis laoreet ex. Cras luctus lacinia mi vitae +tincidunt. Duis pellentesque consequat sapien a gravida. Donec tincidunt +diam turpis, nec imperdiet est faucibus at. Vestibulum ante ipsum primis +in faucibus orci luctus et ultrices posuere cubilia curae;

+

Phasellus posuere, magna ut vulputate tincidunt, ipsum libero euismod +mi, sit amet tincidunt risus sem in tellus. Quisque vestibulum sem sed +orci rutrum euismod euismod sit amet velit. Phasellus pharetra dui eget +metus pellentesque, vitae blandit leo tempus. Pellentesque commodo a +magna vitae maximus. Aliquam hendrerit justo quis metus sollicitudin, ut +tempus sapien tincidunt. Nam vitae mollis nunc, non iaculis neque. Cras +ornare velit nec eros faucibus rhoncus. Praesent porttitor lectus +lectus, nec luctus lectus sagittis sit amet. Fusce ultrices tincidunt +commodo.

+

Fusce pulvinar sit amet neque sit amet ultrices. Sed facilisis non +dui a consectetur. Cras vitae sem nisi. Nunc at tortor eu leo facilisis +ultrices et eget lorem. Sed et odio nunc. Quisque mattis congue porta. +Integer aliquet eleifend urna, eget molestie justo fermentum a. +Phasellus ut efficitur tellus. Nulla posuere nisi vitae nisl dapibus +mollis.

+

Integer condimentum libero ut ligula tempus dictum. Pellentesque +dignissim mauris eget sapien consequat bibendum. Integer interdum risus +nec quam egestas, id consequat arcu rutrum. Quisque viverra arcu ex, ut +varius neque volutpat ut. Quisque et mattis nulla. Suspendisse congue +orci id velit tincidunt rhoncus. Sed luctus odio nec augue vulputate, +sit amet hendrerit lacus commodo. Duis auctor nisi orci, ut suscipit +ipsum aliquet id. Etiam elementum orci sed augue iaculis, vitae +condimentum justo pellentesque. Morbi eget tortor ullamcorper, eleifend +tellus non, iaculis sapien. Aenean pellentesque laoreet ante, eu +suscipit nisi imperdiet sit amet. Ut non dapibus tellus, posuere +dignissim lacus. Aliquam aliquet malesuada porttitor. Maecenas tincidunt +id ante at ultricies.

+

Fusce id libero vel diam faucibus congue. Cras sed molestie leo. Cras +lobortis blandit orci dignissim pulvinar. Morbi ut fermentum erat. +Suspendisse varius est lacinia mauris lacinia pellentesque. Duis non +purus suscipit, dapibus ante ut, finibus metus. Nam dictum placerat +suscipit. Suspendisse sapien ex, rutrum ut efficitur sed, suscipit ut +justo. Donec venenatis libero vitae lobortis tristique. Aliquam +ultricies mi consequat lectus rhoncus vestibulum. Curabitur consectetur +in sem id tempor. Fusce eget ex mauris. Nunc porta porta arcu, vitae +viverra ante gravida ut. Maecenas luctus condimentum nisi a cursus. +Aenean blandit dolor vel velit rhoncus, vitae consectetur sem tincidunt. +In ac tortor sit amet justo eleifend tincidunt eget quis justo.

+ + + + + +
+ Home • + Blog • + ©Copyright 2025 • + + + + + +
+ + + + diff --git a/files/css/index.css b/files/css/index.css new file mode 100644 index 0000000..0a0bb54 --- /dev/null +++ b/files/css/index.css @@ -0,0 +1,728 @@ +/* ========================================================================== + Base & Variables + ========================================================================== */ + +@import url('https://fonts.cdnfonts.com/css/jetbrains-mono-2'); + +:root { + --font-family: "JetBrains Mono", "Cascadia Code", "Fira Code", "Source Code Pro", + Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --line-height: 1.20rem; + --border-thickness: 2px; + --text-color: #000; + --text-color-alt: #666; + --background-color: #fff; + --background-color-alt: #eee; + + --font-weight-normal: 500; + --font-weight-medium: 600; + --font-weight-bold: 800; + + font-family: var(--font-family); + font-optical-sizing: auto; + font-weight: var(--font-weight-normal); + font-style: normal; + font-variant-numeric: tabular-nums lining-nums; + font-size: 16px; +} + +@media (prefers-color-scheme: dark) { + :root { + --text-color: #fff; + --text-color-alt: #aaa; + --background-color: #111; + --background-color-alt: #222; + } +} + +[data-theme="dark"] { + --text-color: #fff; + --text-color-alt: #aaa; + --background-color: #111; + --background-color-alt: #222; +} + +[data-theme="light"] { + --text-color: #000; + --text-color-alt: #666; + --background-color: #fff; + --background-color-alt: #eee; +} + +* { + box-sizing: border-box; +} + +*+* { + margin-top: var(--line-height); +} + +.theme-toggle { + cursor: pointer; + display: inline-flex; + align-items: center; + vertical-align: middle; + width: 1.5ch; + height: 1.5ch; + margin: 0 0 0 0; +} + +.theme-toggle svg { + width: 100%; + height: 100%; + fill: var(--text-color); +} + +.theme-toggle:hover svg { + fill: var(--text-color-alt); +} + +/* ========================================================================== + Layout & Grid + ========================================================================== */ + +html { + display: flex; + width: 100%; + margin: 0; + padding: 0; + flex-direction: column; + align-items: center; + background: var(--background-color); + color: var(--text-color); +} + +body { + position: relative; + width: 100%; + margin: 0; + padding: var(--line-height) 2ch; + max-width: calc(min(80ch, round(down, 100%, 1ch))); + line-height: var(--line-height); + overflow-x: hidden; +} + +@media screen and (max-width: 480px) { + :root { + font-size: 14px; + } + + body { + padding: var(--line-height) 1ch; + } +} + +@media print { + .page, .page-break { break-after: page; } +} + +/* Override universal margins for grid */ +.grid { + margin-top: 0; +} + +.grid>* { + margin-top: 0; +} + +/* Fix grid spacing */ +.grid { + --grid-cells: 0; + display: flex; + gap: 1ch; + width: calc(round(down, 100%, (1ch * var(--grid-cells)) - (1ch * var(--grid-cells) - 1))); + margin-bottom: var(--line-height); +} + +.grid>*, +.grid>input { + flex: 0 0 calc(round(down, (100% - (1ch * (var(--grid-cells) - 1))) / var(--grid-cells), 1ch)); +} + +.grid:has(> :last-child:nth-child(1)) { + --grid-cells: 1; +} + +.grid:has(> :last-child:nth-child(2)) { + --grid-cells: 2; +} + +.grid:has(> :last-child:nth-child(3)) { + --grid-cells: 3; +} + +.grid:has(> :last-child:nth-child(4)) { + --grid-cells: 4; +} + +.grid:has(> :last-child:nth-child(5)) { + --grid-cells: 5; +} + +.grid:has(> :last-child:nth-child(6)) { + --grid-cells: 6; +} + +.grid:has(> :last-child:nth-child(7)) { + --grid-cells: 7; +} + +.grid:has(> :last-child:nth-child(8)) { + --grid-cells: 8; +} + +.grid:has(> :last-child:nth-child(9)) { + --grid-cells: 9; +} + +/* ========================================================================== + Typography + ========================================================================== */ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: var(--font-weight-bold); + margin: calc(var(--line-height) * 2) 0 var(--line-height); + line-height: var(--line-height); +} + +h1 { + font-size: 2rem; + line-height: calc(2 * var(--line-height)); + margin-bottom: calc(var(--line-height) * 2); + text-transform: uppercase; +} + +h2 { + font-size: 1rem; + text-transform: uppercase; +} + +.header-anchor { + opacity: 0; + text-decoration: none; + margin-left: 1ch; + font-weight: normal; +} + +h1:hover .header-anchor, +h2:hover .header-anchor, +h3:hover .header-anchor, +h4:hover .header-anchor, +h5:hover .header-anchor, +h6:hover .header-anchor { + opacity: 1; +} + +hr { + position: relative; + display: block; + height: var(--line-height); + margin: calc(var(--line-height) * 1.5) 0; + border: none; + color: var(--text-color); +} + +hr:after { + display: block; + content: ""; + position: absolute; + top: calc(var(--line-height) / 2 - var(--border-thickness)); + left: 0; + width: 100%; + border-top: calc(var(--border-thickness) * 3) double var(--text-color); + height: 0; +} + +hr.thin { + position: relative; + height: var(--line-height); + margin: var(--line-height) 0; +} + +hr.thin:after { + display: block; + content: ""; + position: absolute; + top: calc(var(--line-height) / 2); + left: 0; + width: 100%; + border-top: var(--border-thickness) solid var(--text-color-alt); + height: 0; +} + +p { + word-break: break-word; + word-wrap: break-word; + hyphens: auto; + margin-bottom: var(--line-height); +} + +strong { + font-weight: var(--font-weight-bold); +} + +em { + font-style: italic; +} + +a { + text-decoration-thickness: var(--border-thickness); +} + +a:link, +a:visited { + color: var(--text-color); +} + +sub { + position: relative; + display: inline-block; + margin: 0; + vertical-align: sub; + line-height: 0; + width: calc(1ch / 0.75); + font-size: .75rem; +} + +/* ========================================================================== + Components + ========================================================================== */ + + +/* Tables */ +table { + position: relative; + top: calc(var(--line-height) / 2); + width: calc(round(down, 100%, 1ch)); + border-collapse: collapse; + margin: 0 0 calc(var(--line-height) * 2); +} + +th, +td { + border: var(--border-thickness) solid var(--text-color); + padding: + calc((var(--line-height) / 2)) calc(1ch - var(--border-thickness) / 2) calc((var(--line-height) / 2) - (var(--border-thickness))); + line-height: var(--line-height); + vertical-align: top; + text-align: left; +} + +table tbody tr:first-child>* { + padding-top: calc((var(--line-height) / 2) - var(--border-thickness)); +} + +th { + font-weight: var(--font-weight-bold); +} + +/* Forms */ +input, +button, +textarea { + border: var(--border-thickness) solid var(--text-color); + padding: calc(var(--line-height) / 2 - var(--border-thickness)) calc(1ch - var(--border-thickness)); + margin: 0; + font: inherit; + font-weight: inherit; + height: calc(var(--line-height) * 2); + width: auto; + overflow: visible; + background: var(--background-color); + color: var(--text-color); + line-height: normal; + -webkit-font-smoothing: inherit; + -moz-osx-font-smoothing: inherit; + -webkit-appearance: none; +} + +input[type=checkbox], +input[type=radio] { + display: inline-grid; + place-content: center; + vertical-align: top; + width: 2ch; + height: var(--line-height); + cursor: pointer; +} + +input[type=checkbox]:checked:before, +input[type=radio]:checked:before { + content: ""; + width: 1ch; + height: calc(var(--line-height) / 2); + background: var(--text-color); +} + +input[type=radio], +input[type=radio]:before { + border-radius: 100%; +} + +button:focus, +input:focus { + --border-thickness: 3px; + outline: none; +} + +input { + width: calc(round(down, 100%, 1ch)); +} + +::placeholder { + color: var(--text-color-alt); + opacity: 1; +} + +::-ms-input-placeholder { + color: var(--text-color-alt); +} + +button::-moz-focus-inner { + padding: 0; + border: 0; +} + +button { + text-transform: uppercase; + font-weight: var(--font-weight-medium); + cursor: pointer; +} + +button:hover { + background: var(--background-color-alt); +} + +button:active { + transform: translate(2px, 2px); +} + +/* Code Blocks */ +pre { + white-space: pre; + overflow-x: auto; + margin: var(--line-height) 0; + overflow-y: hidden; +} + +pre, +code { + font-family: var(--font-family); +} + +code { + font-weight: var(--font-weight-medium); +} + +code:not(pre code) { + background: var(--background-color-alt); + padding: 0 0.5ch; + border-radius: 2px; + font-size: 0.95em; + white-space: nowrap; +} + +pre code { + display: block; + padding: calc(var(--line-height) / 2) 2ch; + background: var(--background-color-alt); + border-radius: 2px; + overflow-x: auto; + line-height: var(--line-height); + margin: 0; +} + +pre code::-webkit-scrollbar { + height: calc(var(--line-height) / 2); +} + +pre code::-webkit-scrollbar-thumb { + background: var(--text-color-alt); + border-radius: 2px; +} + +pre code::-webkit-scrollbar-track { + background: transparent; +} + +/* Lists */ +ul, +ol { + padding: 0; + margin: 0 0 var(--line-height); +} + +ul { + list-style-type: square; + padding: 0 0 0 2ch; +} + +ol { + list-style-type: none; + counter-reset: item; + padding: 0; +} + +ol ul, +ol ol, +ul ol, +ul ul { + padding: 0 0 0 3ch; + margin: 0; +} + +ol li:before { + content: counters(item, ".") ". "; + counter-increment: item; + font-weight: var(--font-weight-medium); +} + +li { + margin: 0; + padding: 0; +} + +li::marker { + line-height: 0; +} + +/* Blockquotes */ +blockquote { + margin: var(--line-height) 3ch; + padding-left: 2ch; + border-left: var(--border-thickness) solid var(--text-color); + color: var(--text-color-alt); +} + +blockquote p { + margin: 0; +} + +blockquote+blockquote { + margin-top: 0; +} + +/* Details */ +details { + border: var(--border-thickness) solid var(--text-color); + padding: calc(var(--line-height) - var(--border-thickness)) 1ch; + margin-bottom: var(--line-height); +} + +summary { + font-weight: var(--font-weight-medium); + cursor: pointer; +} + +details[open] summary { + margin-bottom: var(--line-height); +} + +details ::marker { + display: inline-block; + content: '▶'; + margin: 0; +} + +details[open] ::marker { + content: '▼'; +} + +details :last-child { + margin-bottom: 0; +} + +/* Media */ +img, +video { + display: block; + width: 100%; + object-fit: contain; + overflow: hidden; +} + +img { + font-style: italic; + color: var(--text-color-alt); +} + +figure { + margin: calc(var(--line-height) * 2) 3ch; + overflow-x: auto; + overflow-y: hidden; +} + +figcaption { + display: block; + font-style: italic; + margin-top: var(--line-height); +} + +/* ========================================================================== + Utilities + ========================================================================== */ + +.width-min { + width: 0%; +} + +.width-auto { + width: 100%; +} + +.header { + margin-bottom: calc(var(--line-height) * 2); +} + +.header h1 { + margin: 0; +} + +.header tr td:last-child { + text-align: right; +} + + +/* ========================================================================== + Debug + ========================================================================== */ + +.debug .debug-grid { + --color: color-mix(in srgb, var(--text-color) 10%, var(--background-color) 90%); + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + background-image: + repeating-linear-gradient(var(--color) 0 1px, transparent 1px 100%), + repeating-linear-gradient(90deg, var(--color) 0 1px, transparent 1px 100%); + background-size: 1ch var(--line-height); + margin: 0; +} + +.debug .off-grid { + background: rgba(255, 0, 0, 0.1); +} + +.debug-toggle-label { + text-align: right; +} + + +/* ========================================================================== + Miscellaneous + ========================================================================== */ + +/* Product Cards */ +.product-card { + display: flex; + flex-direction: column; +} + +.product-card > *:not(nav) { + flex: 1 0 auto; +} + +.product-card nav { + display: flex; + gap: 1ch; + align-items: stretch; + margin-top: auto; +} + +.product-card nav a { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + padding: calc(var(--line-height) / 4) 0; + background: var(--background-color-alt); + text-decoration: none; + min-height: calc(var(--line-height) * 1.5); + margin-top: 0; +} + +.product-card nav a:hover { + background: var(--text-color); + color: var(--background-color); +} + +.product-card { + border: var(--border-thickness) solid var(--text-color); + padding: calc(var(--line-height) - var(--border-thickness)) 1ch; + width: 100%; + margin-top: var(--line-height); +} + +.product-card img, .product-card video { + margin: 0 -1ch; + width: calc(100% + 2ch); + max-height: calc(var(--line-height) * 8); + object-fit: cover; +} + +.product-card h3 { + margin-top: var(--line-height); + margin-bottom: 0; + font-weight: var(--font-weight-bold); +} + +.product-card p { + color: var(--text-color-alt); + margin-bottom: var(--line-height); +} + +.product-card table { + font-size: 0.9em; + margin-bottom: var(--line-height); +} + +/* Override the universal margin for nav elements and their children */ +nav, +nav + *, +nav > *, +nav > * + * { + margin-top: 0; +} + +/* Also override for nav when it's inside a product-card */ +.product-card nav { + margin-top: auto; /* This pushes the nav to the bottom while removing the default margin */ +} + +/* Ensure nav children (links/buttons) don't have top margin */ +.product-card nav > * { + margin-top: 0; +} + + +/* Transformations */ +.rotate-90 { + transform: rotate(90deg); + transform-origin: center center; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +/* theme-aware images */ +.theme-aware-image { + filter: none; +} + +[data-theme="dark"] .theme-aware-image:not(.no-invert) { + filter: invert(1) hue-rotate(180deg); +} + +/* Optional: Add specific adjustments for certain images if needed */ +[data-theme="dark"] .theme-aware-image.adjust-contrast { + filter: invert(1) hue-rotate(180deg) contrast(0.8); +} \ No newline at end of file diff --git a/files/css/reset.css b/files/css/reset.css new file mode 100644 index 0000000..aabd759 --- /dev/null +++ b/files/css/reset.css @@ -0,0 +1,48 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + /*margin: 0;*/ + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/files/img/Nicaragua1_1913.jpg b/files/img/Nicaragua1_1913.jpg new file mode 100644 index 0000000..af482ae Binary files /dev/null and b/files/img/Nicaragua1_1913.jpg differ diff --git a/files/img/castle.jpg b/files/img/castle.jpg new file mode 100644 index 0000000..a4addc9 Binary files /dev/null and b/files/img/castle.jpg differ diff --git a/files/js/index.js b/files/js/index.js new file mode 100644 index 0000000..4379fc2 --- /dev/null +++ b/files/js/index.js @@ -0,0 +1,120 @@ +function gridCellDimensions() { + const element = document.createElement("div"); + element.style.position = "fixed"; + element.style.height = "var(--line-height)"; + element.style.width = "1ch"; + document.body.appendChild(element); + const rect = element.getBoundingClientRect(); + document.body.removeChild(element); + return { width: rect.width, height: rect.height }; +} + +// Add padding to each media to maintain grid. +function adjustMediaPadding() { + const cell = gridCellDimensions(); + + function setHeightFromRatio(media, ratio) { + const rect = media.getBoundingClientRect(); + const realHeight = rect.width / ratio; + const diff = cell.height - (realHeight % cell.height); + media.style.setProperty("padding-bottom", `${diff}px`); + } + + function setFallbackHeight(media) { + const rect = media.getBoundingClientRect(); + const height = Math.round((rect.width / 2) / cell.height) * cell.height; + media.style.setProperty("height", `${height}px`); + } + + function onMediaLoaded(media) { + var width, height; + switch (media.tagName) { + case "IMG": + width = media.naturalWidth; + height = media.naturalHeight; + break; + case "VIDEO": + width = media.videoWidth; + height = media.videoHeight; + break; + } + if (width > 0 && height > 0) { + setHeightFromRatio(media, width / height); + } else { + setFallbackHeight(media); + } + } + + const medias = document.querySelectorAll("img, video"); + for (media of medias) { + switch (media.tagName) { + case "IMG": + if (media.complete) { + onMediaLoaded(media); + } else { + media.addEventListener("load", () => onMediaLoaded(media)); + media.addEventListener("error", function() { + setFallbackHeight(media); + }); + } + break; + case "VIDEO": + switch (media.readyState) { + case HTMLMediaElement.HAVE_CURRENT_DATA: + case HTMLMediaElement.HAVE_FUTURE_DATA: + case HTMLMediaElement.HAVE_ENOUGH_DATA: + onMediaLoaded(media); + break; + default: + media.addEventListener("loadeddata", () => onMediaLoaded(media)); + media.addEventListener("error", function() { + setFallbackHeight(media); + }); + break; + } + break; + } + } +} + +adjustMediaPadding(); +window.addEventListener("load", adjustMediaPadding); +window.addEventListener("resize", adjustMediaPadding); + +function checkOffsets() { + const ignoredTagNames = new Set([ + "THEAD", + "TBODY", + "TFOOT", + "TR", + "TD", + "TH", + ]); + const cell = gridCellDimensions(); + const elements = document.querySelectorAll("body :not(.debug-grid, .debug-toggle)"); + for (const element of elements) { + if (ignoredTagNames.has(element.tagName)) { + continue; + } + const rect = element.getBoundingClientRect(); + if (rect.width === 0 && rect.height === 0) { + continue; + } + const top = rect.top + window.scrollY; + const left = rect.left + window.scrollX; + const offset = top % (cell.height / 2); + if(offset > 0) { + element.classList.add("off-grid"); + console.error("Incorrect vertical offset for", element, "with remainder", top % cell.height, "when expecting divisible by", cell.height / 2); + } else { + element.classList.remove("off-grid"); + } + } +} + +const debugToggle = document.querySelector(".debug-toggle"); +function onDebugToggle() { + document.body.classList.toggle("debug", debugToggle.checked); +} +debugToggle.addEventListener("change", onDebugToggle); +onDebugToggle(); diff --git a/index.html b/index.html new file mode 100644 index 0000000..aedcb1a --- /dev/null +++ b/index.html @@ -0,0 +1,462 @@ + + + + + + + + + CSS Features Demo + + + + + + + + + + + + + + +
+

CSS Features Demo

+ Showcasing all available styles +
Versionv1740503848
Updated
+ +


+

Pandoc Monospace Web

+

This is a simple Pandoc based Static Site Generator based on the +Monospace Web project by Oskar Wickström.

+
    +
  1. Install pandoc
  2. +
  3. Drop Markdown files in the src directory
  4. +
  5. Execute the convert.sh script
  6. +
  7. Deploy the build directory to your static site host
  8. +
+

Given that the site generator consits of a single bash script, single +html template and a css file, it’s easy to customize.

+

All changes to the original project are unlicensed (C0). The +Monospace Web is licensed under the MIT license.

+
+

This is a demo page showcasing all the available styles for the +Pandoc Monospace Web. All standard Pandoc markdown features are +supported 1.

+

See the footer for “blog” implementation idea.

+ +
+

Typography

+

H1 Heading (Uppercase)

+

H2 Heading (Uppercase)

+

H3 Heading

+

H4 Heading

+
H5 Heading
+
H6 Heading
+

Regular paragraph with bold text, italic +text, and inline code. Here’s a link to somewhere.

+

Text with a subscript.

+

Horizontal Rules

+

Default horizontal rule:

+
+

Thin variant:

+
+

Lists

+

Unordered list:

+ +

Ordered list:

+
    +
  1. First item
  2. +
  3. Second item +
      +
    1. Nested numbered
    2. +
    3. Another nested
    4. +
  4. +
  5. Third item
  6. +
+

Tree view:

+ +

Tables

+

We can use regular tables that automatically adjust to the monospace +grid. They’re responsive.

+ + + + + + + + + + + + + + + + + + + + +
+Name + +Dimensions + +Position +
+Boboli Obelisk + +1.41m × 1.41m × 4.87m + +43°45’50.78”N 11°15’3.34”E +
+Pyramid of Khafre + +215.25m × 215.25m × 136.4m + +29°58’34”N 31°07’51”E +
+

Note that only one column is allowed to grow.

+

Forms

+

Here are some buttons:

+ +

And inputs:

+
+ +
+

Radio & Checkboxes

+
+ + + +
+

Grids

+

Add the grid class to a container to divide up the +horizontal space evenly for the cells. Note that it maintains the +monospace, so the total width might not be 100%. Here are six grids with +increasing cell count:

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+

If we want one cell to fill the remainder, we set +flex-grow: 1; for that particular cell.

+
+ +
+

Code Blocks

+

Inline code: const example = "hello world";

+

Fenced code block:

+
function demo() {
+  return {
+    hello: "world",
+    number: 42
+  };
+}
+

Blockquotes

+
+

This is a blockquote It can span multiple lines And can contain +formatted text

+
+
+

Nested blockquotes > Are also possible >> And can go +deeper

+
+

Details/Summary

+
+ +Click to expand + +

+Hidden content goes here +

+

+Can contain any other elements +

+
+

ASCII Art & Diagrams

+

We can draw in <pre> tags using box-drawing +characters:

+
╭─────────────────╮
+│ MONOSPACE ROCKS │
+╰─────────────────╯
+

To have it stand out a bit more, we can wrap it in a +<figure> tag, and why not also add a +<figcaption>.

+
+
+┌───────┐ ┌───────┐ ┌───────┐
+│Actor 1│ │Actor 2│ │Actor 3│
+└───┬───┘ └───┬───┘ └───┬───┘
+    │         │         │    
+    │         │  msg 1  │    
+    │         │────────►│    
+    │         │         │    
+    │  msg 2  │         │    
+    │────────►│         │    
+┌───┴───┐ ┌───┴───┐ ┌───┴───┐
+│Actor 1│ │Actor 2│ │Actor 3│
+└───────┘ └───────┘ └───────┘
+
+Example: Message passing. +
+
+

Let’s go wild and draw a chart!

+
+
+                      Things I Have
+                                              
+    │                                     ████ Usable
+15  │
+    │                                     ░░░░ Broken
+    │
+12  │             ░            
+    │             ░            
+    │   ░         ░              
+ 9  │   ░         ░              
+    │   ░         ░              
+    │   ░         ░                    ░
+ 6  │   █         ░         ░          ░
+    │   █         ░         ░          ░
+    │   █         ░         █          ░
+ 3  │   █         █         █          ░
+    │   █         █         █          ░
+    │   █         █         █          ░
+ 0  └───▀─────────▀─────────▀──────────▀─────────────
+      Socks     Jeans     Shirts   USB Drives
+
+
+

Product Cards

+

Product cards are useful for displaying items with images, +descriptions, and actions:

+
+Product image +

+Product Title +

+

+This is a description of the product with all its amazing features. +

+ + + + + + + + + +
+Price + +$99.99 +
+Rating + +★★★★☆ +
+ +
+

Media with Captions

+

Media objects are supported, like images and video with captions:

+
+ + +
+

They extend to the width of the page, and add appropriate padding in +the bottom to maintain the monospace grid.

+
+Example image alt text + +
+ +

Theme-Aware Images

+

Images can adapt to light and dark themes (convert theme using +lightbulb icon in the footer or system settings):

+
+

This image inverts in dark mode

+

This image stays the same in both modes

+

This image adjusts contrast in dark mode

+
+
+
+
    +
  1. Pandoc understands an extended and +slightly revised version of John Gruber’s Markdown syntax. See Pandoc’s +Markdown for details.↩︎

  2. +
+
+ + + + + +
+ Home • + Blog • + ©Copyright 2025 • + + + + + +
+ + + +