hardcode loc

This commit is contained in:
tkucar
2025-02-25 18:19:09 +01:00
commit 7e4964b4ef
8 changed files with 1560 additions and 0 deletions

81
blog/index.html Normal file
View File

@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc-monospace-v1.0.1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="author" content="John Doe" />
<link rel="shortcut icon" href="/files/img/favicon.ico">
<title>Blog</title>
<link rel="stylesheet" href="../files/css/reset.css" />
<link rel="stylesheet" href="../files/css/index.css" />
</head>
<body>
<table class="header">
<tr>
<td colspan="2" rowspan="2" class="width-auto">
<h1 class="title">Blog</h1>
<span class="subtitle">Random musings.</span>
</td>
<th>Version</th>
<td class="width-min">v1740503848</td>
</tr>
<tr>
<th>Updated</th>
<td class="width-min"><time style="white-space: pre;">2025-02-25</time></td>
</tr>
</table>
<h2 id="highligted">Highligted</h2>
<p>None.</p>
<h2 id="other">Other</h2>
<ul class="incremental">
<li><a href="lorem-ipsum.html">Lorem ipsum</a></li>
</ul>
<table>
<tr>
<td class="width-auto">
<a style="text-decoration: none;" href="">Home</a>
<a style="text-decoration: none;" href="/blog/index.html">Blog</a>
<a style="text-decoration: none;" href="">©Copyright 2025</a>
<span onclick="toggleTheme()" class="theme-toggle" title="Toggle theme">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sun" viewBox="0 0 16 16">
<path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6m0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8M8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0m0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13m8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5M3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8m10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0m-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0m9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707M4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708"/>
</svg>
</span>
</td>
</tr>
</table>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Check for saved theme preference, otherwise use system preference
const theme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
// Apply theme
document.documentElement.setAttribute('data-theme', theme);
// Add anchor links to headers
document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(heading => {
if (heading.id) {
const anchor = document.createElement('a');
anchor.href = '#' + heading.id;
anchor.className = 'header-anchor';
anchor.textContent = '#';
const headingText = heading.textContent || '';
anchor.setAttribute('aria-label', 'Link to header' + headingText);
heading.appendChild(anchor);
}
});
});
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
}
</script>
</body>
</html>

121
blog/lorem-ipsum.html Normal file
View File

@@ -0,0 +1,121 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc-monospace-v1.0.1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="author" content="John Doe" />
<link rel="shortcut icon" href="/files/img/favicon.ico">
<title>Lorem ipsum</title>
<link rel="stylesheet" href="../files/css/reset.css" />
<link rel="stylesheet" href="../files/css/index.css" />
</head>
<body>
<table class="header">
<tr>
<td colspan="2" rowspan="2" class="width-auto">
<h1 class="title">Lorem ipsum</h1>
<span class="subtitle">Lorem ipsum dolor sit amet, consectetur
adipiscing elit.</span>
</td>
<th>Version</th>
<td class="width-min">v1740503848</td>
</tr>
<tr>
<th>Updated</th>
<td class="width-min"><time style="white-space: pre;">2025-02-25</time></td>
</tr>
</table>
<p>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;</p>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<table>
<tr>
<td class="width-auto">
<a style="text-decoration: none;" href="">Home</a>
<a style="text-decoration: none;" href="/blog/index.html">Blog</a>
<a style="text-decoration: none;" href="">©Copyright 2025</a>
<span onclick="toggleTheme()" class="theme-toggle" title="Toggle theme">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sun" viewBox="0 0 16 16">
<path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6m0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8M8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0m0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13m8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5M3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8m10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0m-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0m9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707M4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708"/>
</svg>
</span>
</td>
</tr>
</table>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Check for saved theme preference, otherwise use system preference
const theme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
// Apply theme
document.documentElement.setAttribute('data-theme', theme);
// Add anchor links to headers
document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(heading => {
if (heading.id) {
const anchor = document.createElement('a');
anchor.href = '#' + heading.id;
anchor.className = 'header-anchor';
anchor.textContent = '#';
const headingText = heading.textContent || '';
anchor.setAttribute('aria-label', 'Link to header' + headingText);
heading.appendChild(anchor);
}
});
});
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
}
</script>
</body>
</html>

728
files/css/index.css Normal file
View File

@@ -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);
}

48
files/css/reset.css Normal file
View File

@@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

BIN
files/img/castle.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

120
files/js/index.js Normal file
View File

@@ -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();

462
index.html Normal file
View File

@@ -0,0 +1,462 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc-monospace-v1.0.1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="author" content="Demo Author" />
<link rel="shortcut icon" href="/files/img/favicon.ico">
<title>CSS Features Demo</title>
<link rel="stylesheet" href="files/css/reset.css" />
<link rel="stylesheet" href="files/css/index.css" />
</head>
<body>
<table class="header">
<tr>
<td colspan="2" rowspan="2" class="width-auto">
<h1 class="title">CSS Features Demo</h1>
<span class="subtitle">Showcasing all available styles</span>
</td>
<th>Version</th>
<td class="width-min">v1740503848</td>
</tr>
<tr>
<th>Updated</th>
<td class="width-min"><time style="white-space: pre;">2025-02-25</time></td>
</tr>
</table>
<nav id="TOC" role="doc-toc">
<h2 id="toc-title">Contents</h2>
<ul class="incremental">
<li><a href="#pandoc-monospace-web">Pandoc Monospace Web</a>
<ul class="incremental">
<li><a href="#typography">Typography</a></li>
</ul></li>
<li><a href="#h1-heading-uppercase">H1 Heading (Uppercase)</a>
<ul class="incremental">
<li><a href="#h2-heading-uppercase">H2 Heading (Uppercase)</a>
<ul class="incremental">
<li><a href="#h3-heading">H3 Heading</a></li>
</ul></li>
<li><a href="#horizontal-rules">Horizontal Rules</a></li>
<li><a href="#lists">Lists</a></li>
<li><a href="#tables">Tables</a></li>
<li><a href="#forms">Forms</a>
<ul class="incremental">
<li><a href="#radio-checkboxes">Radio &amp; Checkboxes</a></li>
</ul></li>
<li><a href="#grids">Grids</a></li>
<li><a href="#code-blocks">Code Blocks</a></li>
<li><a href="#blockquotes">Blockquotes</a></li>
<li><a href="#detailssummary">Details/Summary</a></li>
<li><a href="#ascii-art-diagrams">ASCII Art &amp; Diagrams</a></li>
<li><a href="#product-cards">Product Cards</a></li>
<li><a href="#media-with-captions">Media with Captions</a>
<ul class="incremental">
<li><a href="#theme-aware-images">Theme-Aware Images</a></li>
</ul></li>
</ul></li>
</ul>
</nav>
<p><br></p>
<h1 id="pandoc-monospace-web">Pandoc Monospace Web</h1>
<p>This is a simple Pandoc based Static Site Generator based on the
Monospace Web project by Oskar Wickström.</p>
<ol class="incremental" type="1">
<li>Install pandoc</li>
<li>Drop Markdown files in the src directory</li>
<li>Execute the convert.sh script</li>
<li>Deploy the build directory to your static site host</li>
</ol>
<p>Given that the site generator consits of a single bash script, single
html template and a css file, its easy to customize.</p>
<p>All changes to the original project are unlicensed (C0). The
Monospace Web is licensed under the MIT license.</p>
<hr class="thin">
<p>This is a demo page showcasing all the available styles for the
Pandoc Monospace Web. All standard Pandoc markdown features are
supported <a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>.</p>
<p>See the footer for “blog” implementation idea.</p>
<ul class="incremental">
<li>Github repository: <a
href="https://github.com/frainfreeze/the-monospace-web-pandoc">frainfreeze/the-monospace-web-pandoc</a></li>
<li>Original author GitHub: <a
href="https://github.com/owickstrom/the-monospace-web">owickstrom/the-monospace-web</a></li>
</ul>
<hr class="thin">
<h2 id="typography">Typography</h2>
<h1 id="h1-heading-uppercase">H1 Heading (Uppercase)</h1>
<h2 id="h2-heading-uppercase">H2 Heading (Uppercase)</h2>
<h3 id="h3-heading">H3 Heading</h3>
<h4 id="h4-heading">H4 Heading</h4>
<h5 id="h5-heading">H5 Heading</h5>
<h6 id="h6-heading">H6 Heading</h6>
<p>Regular paragraph with <strong>bold text</strong>, <em>italic
text</em>, and <code>inline code</code>. Heres a <a
href="https://example.com">link to somewhere</a>.</p>
<p>Text with a sub<sub>script</sub>.</p>
<h2 id="horizontal-rules">Horizontal Rules</h2>
<p>Default horizontal rule:</p>
<hr>
<p>Thin variant:</p>
<hr class="thin">
<h2 id="lists">Lists</h2>
<p>Unordered list:</p>
<ul class="incremental">
<li>Item one</li>
<li>Item two</li>
<li>Item three
<ul class="incremental">
<li>Nested item</li>
<li>Another nested item</li>
</ul></li>
</ul>
<p>Ordered list:</p>
<ol class="incremental" type="1">
<li>First item</li>
<li>Second item
<ol class="incremental" type="1">
<li>Nested numbered</li>
<li>Another nested</li>
</ol></li>
<li>Third item</li>
</ol>
<p>Tree view:</p>
<ul class="tree">
<li>
<p style="margin: 0;">
<strong>/dev/nvme0n1p2</strong>
</p>
<ul class="incremental">
<li>usr
<ul class="incremental">
<li>local<br />
</li>
<li>share<br />
</li>
<li>libexec<br />
</li>
<li>include<br />
</li>
<li>sbin<br />
</li>
<li>src<br />
</li>
<li>lib64<br />
</li>
<li>lib<br />
</li>
<li>bin<br />
</li>
<li>games
<ul class="incremental">
<li>solitaire</li>
<li>snake</li>
<li>tic-tac-toe</li>
</ul></li>
<li>media<br />
</li>
</ul></li>
<li>media<br />
</li>
<li>run<br />
</li>
<li>tmp</li>
</ul>
</li>
</ul>
<h2 id="tables">Tables</h2>
<p>We can use regular tables that automatically adjust to the monospace
grid. Theyre responsive.</p>
<table>
<thead>
<tr>
<th class="width-min">
Name
</th>
<th class="width-auto">
Dimensions
</th>
<th class="width-min">
Position
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
Boboli Obelisk
</td>
<td>
1.41m × 1.41m × 4.87m
</td>
<td>
43°4550.78”N 11°153.34”E
</td>
</tr>
<tr>
<td>
Pyramid of Khafre
</td>
<td>
215.25m × 215.25m × 136.4m
</td>
<td>
29°5834”N 31°0751”E
</td>
</tr>
</tbody>
</table>
<p>Note that only one column is allowed to grow.</p>
<h2 id="forms">Forms</h2>
<p>Here are some buttons:</p>
<nav>
<button>
Reset
</button>
<button>
Save
</button>
</nav>
<p>And inputs:</p>
<form>
<label>First name
<input type="text" placeholder="Placeholder..." /></label> <label>Age
<input type="text" value="30" /></label> <label>Disabled Input
<input type="text" disabled value="Can't edit" /></label>
</form>
<h3 id="radio-checkboxes">Radio &amp; Checkboxes</h3>
<form class="grid">
<label><input type="checkbox" /> Checkbox Option</label>
<label><input type="radio" name="group1" /> Radio 1</label>
<label><input type="radio" name="group1" /> Radio 2</label>
</form>
<h2 id="grids">Grids</h2>
<p>Add the <code>grid</code> 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:</p>
<div class="grid">
<input readonly value="1" />
</div>
<div class="grid">
<input readonly value="1" /><input readonly value="2" />
</div>
<div class="grid">
<input readonly value="1" /><input readonly value="2" /><input readonly value="3" />
</div>
<div class="grid">
<input readonly value="1" /><input readonly value="2" /><input readonly value="3" /><input readonly value="4" />
</div>
<div class="grid">
<input readonly value="1" /><input readonly value="2" /><input readonly value="3" /><input readonly value="4" /><input readonly value="5" />
</div>
<div class="grid">
<input readonly value="1" /><input readonly value="2" /><input readonly value="3" /><input readonly value="4" /><input readonly value="5" /><input readonly value="6" />
</div>
<p>If we want one cell to fill the remainder, we set
<code>flex-grow: 1;</code> for that particular cell.</p>
<div class="grid">
<input readonly value="1" /><input readonly value="2" /><input readonly value="3!" style="flex-grow: 1;" /><input readonly value="4" /><input readonly value="5" /><input readonly value="6" />
</div>
<h2 id="code-blocks">Code Blocks</h2>
<p>Inline code: <code>const example = "hello world";</code></p>
<p>Fenced code block:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span> <span class="fu">demo</span>() {</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> {</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">hello</span><span class="op">:</span> <span class="st">&quot;world&quot;</span><span class="op">,</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">number</span><span class="op">:</span> <span class="dv">42</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> }<span class="op">;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<h2 id="blockquotes">Blockquotes</h2>
<blockquote>
<p>This is a blockquote It can span multiple lines And can contain
<em>formatted</em> <strong>text</strong></p>
</blockquote>
<blockquote>
<p>Nested blockquotes &gt; Are also possible &gt;&gt; And can go
deeper</p>
</blockquote>
<h2 id="detailssummary">Details/Summary</h2>
<details>
<summary>
Click to expand
</summary>
<p>
Hidden content goes here
</p>
<p>
Can contain any other elements
</p>
</details>
<h2 id="ascii-art-diagrams">ASCII Art &amp; Diagrams</h2>
<p>We can draw in <code>&lt;pre&gt;</code> tags using <a
href="https://en.wikipedia.org/wiki/Box-drawing_characters">box-drawing
characters</a>:</p>
<pre><code>╭─────────────────╮
│ MONOSPACE ROCKS │
╰─────────────────╯</code></pre>
<p>To have it stand out a bit more, we can wrap it in a
<code>&lt;figure&gt;</code> tag, and why not also add a
<code>&lt;figcaption&gt;</code>.</p>
<figure>
<pre>
┌───────┐ ┌───────┐ ┌───────┐
│Actor 1│ │Actor 2│ │Actor 3│
└───┬───┘ └───┬───┘ └───┬───┘
│ │ │
│ │ msg 1 │
│ │────────►│
│ │ │
│ msg 2 │ │
│────────►│ │
┌───┴───┐ ┌───┴───┐ ┌───┴───┐
│Actor 1│ │Actor 2│ │Actor 3│
└───────┘ └───────┘ └───────┘</pre>
<figcaption>
Example: Message passing.
</figcaption>
</figure>
<p>Lets go wild and draw a chart!</p>
<figure>
<pre>
Things I Have
│ ████ Usable
15 │
│ ░░░░ Broken
12 │ ░
│ ░
│ ░ ░
9 │ ░ ░
│ ░ ░
│ ░ ░ ░
6 │ █ ░ ░ ░
│ █ ░ ░ ░
│ █ ░ █ ░
3 │ █ █ █ ░
│ █ █ █ ░
│ █ █ █ ░
0 └───▀─────────▀─────────▀──────────▀─────────────
Socks Jeans Shirts USB Drives
</pre>
</figure>
<h2 id="product-cards">Product Cards</h2>
<p>Product cards are useful for displaying items with images,
descriptions, and actions:</p>
<div class="product-card">
<img src="./files/images/example.jpg" alt="Product image">
<h3>
Product Title
</h3>
<p>
This is a description of the product with all its amazing features.
</p>
<table>
<tr>
<th>
Price
</th>
<td>
$99.99
</td>
</tr>
<tr>
<th>
Rating
</th>
<td>
★★★★☆
</td>
</tr>
</table>
<nav>
<a href="#">Details</a> <a href="#">Buy Now</a>
</nav>
</div>
<h2 id="media-with-captions">Media with Captions</h2>
<p>Media objects are supported, like images and video with captions:</p>
<figure>
<img src="./files/img/castle.jpg"
alt="A sample image with caption (2024)" />
<figcaption aria-hidden="true">A sample image with caption
(2024)</figcaption>
</figure>
<p>They extend to the width of the page, and add appropriate padding in
the bottom to maintain the monospace grid.</p>
<figure>
<img src="" alt="Example image alt text" />
<figcaption aria-hidden="true">Example image alt text</figcaption>
</figure>
<video src="https://upload.wikimedia.org/wikipedia/commons/e/e0/The_Center_of_the_Web_%281914%29.webm" controls>
</video>
<h3 id="theme-aware-images">Theme-Aware Images</h3>
<p>Images can adapt to light and dark themes (convert theme using
lightbulb icon in the footer or system settings):</p>
<div class="grid">
<p><img height="150px" class="theme-aware-image" src="./files/img/Nicaragua1_1913.jpg" alt="This image inverts in dark mode"></p>
<p><img height="150px" class="theme-aware-image no-invert" src="./files/img/Nicaragua1_1913.jpg" alt="This image stays the same in both modes"></p>
<p><img height="150px" class="theme-aware-image adjust-contrast" src="./files/img/Nicaragua1_1913.jpg" alt="This image adjusts contrast in dark mode"></p>
</div>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>Pandoc understands an extended and
slightly revised version of John Grubers Markdown syntax. See <a
href="https://pandoc.org/chunkedhtml-demo/8-pandocs-markdown.html">Pandocs
Markdown</a> for details.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
<table>
<tr>
<td class="width-auto">
<a style="text-decoration: none;" href="https://frainfreeze.github.io/the-monospace-web-pandoc/">Home</a>
<a style="text-decoration: none;" href="https://frainfreeze.github.io/the-monospace-web-pandoc/blog/index.html">Blog</a>
<a style="text-decoration: none;" href="">©Copyright 2025</a>
<span onclick="toggleTheme()" class="theme-toggle" title="Toggle theme">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sun" viewBox="0 0 16 16">
<path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6m0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8M8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0m0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13m8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5M3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8m10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0m-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0m9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707M4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708"/>
</svg>
</span>
</td>
</tr>
</table>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Check for saved theme preference, otherwise use system preference
const theme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
// Apply theme
document.documentElement.setAttribute('data-theme', theme);
// Add anchor links to headers
document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(heading => {
if (heading.id) {
const anchor = document.createElement('a');
anchor.href = '#' + heading.id;
anchor.className = 'header-anchor';
anchor.textContent = '#';
const headingText = heading.textContent || '';
anchor.setAttribute('aria-label', 'Link to header' + headingText);
heading.appendChild(anchor);
}
});
});
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
}
</script>
</body>
</html>