mirror of
https://github.com/frainfreeze/the-monospace-web-pandoc
synced 2025-12-29 18:49:50 -08:00
pandoc-ed!
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -0,0 +1 @@
|
||||
build/
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
The Pandoc Monospace is a Static Site Generator based on The Monospace Web project by Oskar Wickström.
|
||||
All changes to the original project are unlicensed (C0).
|
||||
|
||||
|
||||
The Monospace Web is licensed under the MIT license.
|
||||
|
||||
Copyright 2024 Oskar Wickström
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
12
Makefile
12
Makefile
@@ -1,12 +0,0 @@
|
||||
VERSION=$(shell jq -r .version package.json)
|
||||
DATE=$(shell date +%F)
|
||||
|
||||
all: index.html
|
||||
|
||||
clean:
|
||||
rm -f index.html
|
||||
|
||||
index.html: demo/index.md demo/template.html Makefile
|
||||
pandoc --toc -s --css src/reset.css --css src/index.css -Vversion=v$(VERSION) -Vdate=$(DATE) -i $< -o $@ --template=demo/template.html
|
||||
|
||||
.PHONY: all clean
|
||||
16
README.md
16
README.md
@@ -1,16 +0,0 @@
|
||||
# The Monospace Web
|
||||
|
||||
Monospace fonts are dear to many of us. Some find them more readable, consistent, and beautiful, than their proportional alternatives. Maybe we’re just brainwashed from spending years in terminals? Or are we hopelessly nostalgic? I’m not sure. But I like them, and that’s why I started experimenting with all-monospace Web.
|
||||
|
||||
https://owickstrom.github.io/the-monospace-web/
|
||||
|
||||
## Build
|
||||
|
||||
```
|
||||
nix develop # or `direnv allow .`
|
||||
make
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE.md)
|
||||
308
convert.sh
Executable file
308
convert.sh
Executable file
@@ -0,0 +1,308 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Configuration
|
||||
VERSION="1.0.1"
|
||||
SOURCE_DIR="src"
|
||||
OUTPUT_DIR="build"
|
||||
TEMPLATE="template.html"
|
||||
CSS_FILES=(
|
||||
"files/css/reset.css"
|
||||
"files/css/index.css"
|
||||
)
|
||||
|
||||
# Add supported document formats
|
||||
SUPPORTED_FORMATS=(
|
||||
"*.md" # Markdown
|
||||
"*.markdown"
|
||||
"*.mdx"
|
||||
"*.org" # Org mode
|
||||
"*.rst" # reStructuredText
|
||||
"*.txt" # Plain text
|
||||
"*.tex" # LaTeX
|
||||
"*.wiki" # MediaWiki markup
|
||||
"*.dokuwiki" # DokuWiki markup
|
||||
"*.textile" # Textile
|
||||
"*.asciidoc" # AsciiDoc
|
||||
)
|
||||
|
||||
# Color definitions
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Add after VERSION declaration
|
||||
PDF_OUTPUT=false
|
||||
|
||||
|
||||
# Error handling function
|
||||
error() {
|
||||
echo -e "${RED}Error: $1${NC}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Warning function
|
||||
warning() {
|
||||
echo -e "${YELLOW}Warning: $1${NC}" >&2
|
||||
}
|
||||
|
||||
# Success function
|
||||
success() {
|
||||
echo -e "${GREEN}$1${NC}"
|
||||
}
|
||||
|
||||
# Info function
|
||||
info() {
|
||||
[ "$VERBOSE" = true ] && echo -e "${BLUE}$1${NC}"
|
||||
}
|
||||
|
||||
# Help function
|
||||
show_help() {
|
||||
cat << EOF
|
||||
$(basename "$0") v$VERSION
|
||||
Convert documents to HTML or PDF using pandoc.
|
||||
|
||||
Usage: $(basename "$0") [OPTIONS]
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message
|
||||
-v, --version Show version information
|
||||
-s, --source DIR Source directory (default: $SOURCE_DIR)
|
||||
-o, --output DIR Output directory (default: $OUTPUT_DIR)
|
||||
-t, --template FILE Template file (default: $TEMPLATE)
|
||||
-l, --list-formats List supported file formats
|
||||
--verbose Enable verbose output
|
||||
--clean Remove output directory before starting
|
||||
--pdf Generate PDF instead of HTML output
|
||||
|
||||
Examples:
|
||||
$(basename "$0") # Use default settings (HTML output)
|
||||
$(basename "$0") --pdf # Generate PDF output
|
||||
$(basename "$0") -s content -o dist # Use custom directories
|
||||
$(basename "$0") --clean # Clean build
|
||||
|
||||
Supported formats:
|
||||
${SUPPORTED_FORMATS[@]/#/ }
|
||||
|
||||
For more information, visit: https://pandoc.org/MANUAL.html
|
||||
EOF
|
||||
}
|
||||
|
||||
# Version function
|
||||
show_version() {
|
||||
echo "$(basename "$0") version $VERSION"
|
||||
}
|
||||
|
||||
# List supported formats
|
||||
list_formats() {
|
||||
echo "Supported input formats:"
|
||||
for format in "${SUPPORTED_FORMATS[@]}"; do
|
||||
echo " $format"
|
||||
done
|
||||
}
|
||||
|
||||
# Check if pandoc is installed before continuing
|
||||
if ! command -v pandoc >/dev/null 2>&1; then
|
||||
error "Pandoc is required but not installed. Please install pandoc."
|
||||
fi
|
||||
|
||||
# Function to create CSS arguments array
|
||||
create_css_args() {
|
||||
local source_file="$1"
|
||||
local source_dir="$2"
|
||||
|
||||
# Calculate relative path from the HTML file to the root
|
||||
local rel_path="${source_file#"$source_dir"/}"
|
||||
local dir_depth
|
||||
dir_depth=$(echo "$rel_path" | tr -cd '/' | wc -c)
|
||||
local path_prefix=""
|
||||
|
||||
# Add "../" for each directory level
|
||||
for ((i=0; i<dir_depth; i++)); do
|
||||
path_prefix="../$path_prefix"
|
||||
done
|
||||
|
||||
# Return array of CSS arguments
|
||||
local css_args=()
|
||||
for css in "${CSS_FILES[@]}"; do
|
||||
css_args+=("--css" "$path_prefix$css")
|
||||
done
|
||||
printf "%s\n" "${css_args[@]}"
|
||||
}
|
||||
|
||||
# Function to process a single file
|
||||
process_file() {
|
||||
local source_file="$1"
|
||||
local source_dir="$2"
|
||||
local target_dir="$3"
|
||||
local extension="${source_file##*.}"
|
||||
|
||||
info "Processing: $source_file"
|
||||
|
||||
# Get relative path from source directory
|
||||
local rel_path="${source_file#"$source_dir"/}"
|
||||
local dir_path
|
||||
dir_path=$(dirname "$rel_path")
|
||||
local filename
|
||||
filename=$(basename "$source_file")
|
||||
local output_filename
|
||||
output_filename="${filename%.*}.$([ "$PDF_OUTPUT" = true ] && echo "pdf" || echo "html")"
|
||||
|
||||
# Create target directory if it doesn't exist
|
||||
mkdir -p "$target_dir/$dir_path"
|
||||
|
||||
# Format-specific options
|
||||
local format_opts=""
|
||||
case "$extension" in
|
||||
"tex")
|
||||
format_opts="--mathjax"
|
||||
;;
|
||||
"org")
|
||||
format_opts="--shift-heading-level-by=1"
|
||||
;;
|
||||
"rst")
|
||||
format_opts="--section-divs"
|
||||
;;
|
||||
*)
|
||||
format_opts="--toc"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$PDF_OUTPUT" = true ]; then
|
||||
# Generate PDF file
|
||||
if ! pandoc --toc -s \
|
||||
$format_opts \
|
||||
--pdf-engine=xelatex \
|
||||
-Vversion="v$(date +%s)" \
|
||||
-Vdate="$(date +%F)" \
|
||||
-Vyear="$(date +%Y)" \
|
||||
-i "$source_file" \
|
||||
-o "$target_dir/$dir_path/$output_filename"; then
|
||||
error "Failed to convert $source_file to PDF"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# Generate HTML file
|
||||
if ! pandoc --toc -s \
|
||||
$format_opts \
|
||||
$(create_css_args "$source_file" "$source_dir") \
|
||||
-Vversion="v$(date +%s)" \
|
||||
-Vdate="$(date +%F)" \
|
||||
-Vyear="$(date +%Y)" \
|
||||
-i "$source_file" \
|
||||
-o "$target_dir/$dir_path/$output_filename" \
|
||||
--template="$TEMPLATE"; then
|
||||
error "Failed to convert $source_file to HTML"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
success "Converted: $source_file -> $target_dir/$dir_path/$output_filename"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
VERBOSE=false
|
||||
CLEAN=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-v|--version)
|
||||
show_version
|
||||
exit 0
|
||||
;;
|
||||
-s|--source)
|
||||
SOURCE_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-o|--output)
|
||||
OUTPUT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-t|--template)
|
||||
TEMPLATE="$2"
|
||||
shift 2
|
||||
;;
|
||||
-l|--list-formats)
|
||||
list_formats
|
||||
exit 0
|
||||
;;
|
||||
--verbose)
|
||||
VERBOSE=true
|
||||
shift
|
||||
;;
|
||||
--clean)
|
||||
CLEAN=true
|
||||
shift
|
||||
;;
|
||||
--pdf)
|
||||
PDF_OUTPUT=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
echo "Use --help for usage information"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Add after parsing arguments
|
||||
if [ "$PDF_OUTPUT" = true ]; then
|
||||
if ! command -v xelatex >/dev/null 2>&1; then
|
||||
error "PDF generation requires xelatex. Please install texlive-xelatex package."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create find command pattern for supported formats
|
||||
FIND_PATTERN=()
|
||||
for format in "${SUPPORTED_FORMATS[@]}"; do
|
||||
FIND_PATTERN+=(-o -name "$format")
|
||||
done
|
||||
# Remove the first -o since we don't need it for the first pattern
|
||||
FIND_PATTERN=("${FIND_PATTERN[@]:1}")
|
||||
|
||||
# Update error checks
|
||||
if [ "$PDF_OUTPUT" = false ] && [ ! -f "$TEMPLATE" ]; then
|
||||
error "Template file $TEMPLATE not found!"
|
||||
fi
|
||||
|
||||
if [ ! -d "$SOURCE_DIR" ]; then
|
||||
error "Source directory $SOURCE_DIR not found!"
|
||||
fi
|
||||
|
||||
# Clean up old build if requested
|
||||
if [ "$CLEAN" = true ]; then
|
||||
echo "Cleaning up old build directory..."
|
||||
rm -rf "$OUTPUT_DIR"
|
||||
fi
|
||||
|
||||
# Create output directory
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# Copy all files from source directory if it exists
|
||||
[ "$VERBOSE" = true ] && info "Copying assets..."
|
||||
if [ -d "$SOURCE_DIR/files" ]; then
|
||||
cp -r "$SOURCE_DIR/files" "$OUTPUT_DIR/"
|
||||
info "Copied files directory and its contents"
|
||||
else
|
||||
warning "files directory not found in source"
|
||||
fi
|
||||
|
||||
# Find and process all supported files
|
||||
[ "$VERBOSE" = true ] && info "Processing files..."
|
||||
if find "$SOURCE_DIR" -type f \( "${FIND_PATTERN[@]}" \) | while read -r file; do
|
||||
process_file "$file" "$SOURCE_DIR" "$OUTPUT_DIR" || exit 1
|
||||
done; then
|
||||
# Remove any hidden files (except .htaccess)
|
||||
find "$OUTPUT_DIR/" -type f -name '.*' ! -name ".htaccess" -delete
|
||||
success "Conversion complete! Output in $OUTPUT_DIR/"
|
||||
exit 0
|
||||
else
|
||||
error "Conversion failed!"
|
||||
fi
|
||||
@@ -1,76 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||
$for(author-meta)$
|
||||
<meta name="author" content="$author-meta$" />
|
||||
$endfor$
|
||||
$if(date-meta)$
|
||||
<meta name="dcterms.date" content="$date-meta$" />
|
||||
$endif$
|
||||
$if(keywords)$
|
||||
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
|
||||
$endif$
|
||||
$if(description-meta)$
|
||||
<meta name="description" content="$description-meta$" />
|
||||
$endif$
|
||||
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
|
||||
$for(css)$
|
||||
<link rel="stylesheet" href="$css$" />
|
||||
$endfor$
|
||||
$for(header-includes)$
|
||||
$header-includes$
|
||||
$endfor$
|
||||
$if(math)$
|
||||
$math$
|
||||
$endif$
|
||||
</head>
|
||||
<body>
|
||||
$for(include-before)$
|
||||
$include-before$
|
||||
$endfor$
|
||||
<table class="header">
|
||||
<tr>
|
||||
<td colspan="2" rowspan="2" class="width-auto">
|
||||
<h1 class="title">$title$</h1>
|
||||
<span class="subtitle">$subtitle$</span>
|
||||
</td>
|
||||
<th>Version</th>
|
||||
<td class="width-min">$version$</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Updated</th>
|
||||
<td class="width-min"><time style="white-space: pre;">$date$</time></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="width-min">Author</th>
|
||||
<td class="width-auto"><a href="$author-url$"><cite>$author$</cite></a></td>
|
||||
<th class="width-min">License</th>
|
||||
<td>MIT</td>
|
||||
</tr>
|
||||
</table>
|
||||
<label class="debug-toggle-label"><input type="checkbox" class="debug-toggle" /> Debug mode</label>
|
||||
$if(abstract)$
|
||||
<div class="abstract">
|
||||
<div class="abstract-title">$abstract-title$</div>
|
||||
$abstract$
|
||||
</div>
|
||||
$endif$
|
||||
$if(toc)$
|
||||
<nav id="$idprefix$TOC" role="doc-toc">
|
||||
$if(toc-title)$
|
||||
<h2 id="$idprefix$toc-title">$toc-title$</h2>
|
||||
$endif$
|
||||
$table-of-contents$
|
||||
</nav>
|
||||
$endif$
|
||||
$body$
|
||||
$for(include-after)$
|
||||
$include-after$
|
||||
$endfor$
|
||||
<div class="debug-grid"></div>
|
||||
<script src="src/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
43
flake.lock
generated
43
flake.lock
generated
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1723891200,
|
||||
"narHash": "sha256-uljX21+D/DZgb9uEFFG2dkkQbPZN+ig4Z6+UCLWFVAk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a0d6390cb3e82062a35d0288979c45756e481f60",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
36
flake.nix
36
flake.nix
@@ -1,36 +0,0 @@
|
||||
{
|
||||
description = "A very basic flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
systems.url = "github:nix-systems/default";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
systems,
|
||||
nixpkgs,
|
||||
}:
|
||||
let
|
||||
eachSystem = nixpkgs.lib.genAttrs (import systems);
|
||||
in
|
||||
{
|
||||
devShells = eachSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = (import nixpkgs { inherit system; });
|
||||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
live-server
|
||||
pandoc
|
||||
jq
|
||||
gnumake
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
324
index.html
324
index.html
@@ -1,324 +0,0 @@
|
||||
<!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" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||
<meta name="author" content="Oskar Wickström" />
|
||||
<title>The Monospace Web</title>
|
||||
<link rel="stylesheet" href="src/reset.css" />
|
||||
<link rel="stylesheet" href="src/index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<table class="header">
|
||||
<tr>
|
||||
<td colspan="2" rowspan="2" class="width-auto">
|
||||
<h1 class="title">The Monospace Web</h1>
|
||||
<span class="subtitle">A minimalist design exploration</span>
|
||||
</td>
|
||||
<th>Version</th>
|
||||
<td class="width-min">v0.1.5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Updated</th>
|
||||
<td class="width-min"><time style="white-space: pre;">2025-01-25</time></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="width-min">Author</th>
|
||||
<td class="width-auto"><a href="https://wickstrom.tech"><cite>Oskar
|
||||
Wickström</cite></a></td>
|
||||
<th class="width-min">License</th>
|
||||
<td>MIT</td>
|
||||
</tr>
|
||||
</table>
|
||||
<label class="debug-toggle-label"><input type="checkbox" class="debug-toggle" /> Debug mode</label>
|
||||
<nav id="TOC" role="doc-toc">
|
||||
<h2 id="toc-title">Contents</h2>
|
||||
<ul class="incremental">
|
||||
<li><a href="#introduction" id="toc-introduction">Introduction</a></li>
|
||||
<li><a href="#the-basics" id="toc-the-basics">The Basics</a></li>
|
||||
<li><a href="#lists" id="toc-lists">Lists</a></li>
|
||||
<li><a href="#tables" id="toc-tables">Tables</a></li>
|
||||
<li><a href="#forms" id="toc-forms">Forms</a></li>
|
||||
<li><a href="#grids" id="toc-grids">Grids</a></li>
|
||||
<li><a href="#ascii-drawings" id="toc-ascii-drawings">ASCII
|
||||
Drawings</a></li>
|
||||
<li><a href="#media" id="toc-media">Media</a></li>
|
||||
<li><a href="#discussion" id="toc-discussion">Discussion</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<h2 id="introduction">Introduction</h2>
|
||||
<p>Monospace fonts are dear to many of us. Some find them more readable,
|
||||
consistent, and beautiful, than their proportional alternatives. Maybe
|
||||
we’re just brainwashed from spending years in terminals? Or are we
|
||||
hopelessly nostalgic? I’m not sure. But I like them, and that’s why I
|
||||
started experimenting with all-monospace Web.</p>
|
||||
<p>On this page, I use a monospace grid to align text and draw diagrams.
|
||||
It’s generated from a simple Markdown document (using Pandoc), and the
|
||||
CSS and a tiny bit of Javascript renders it on the grid. The page is
|
||||
responsive, shrinking in character-sized steps. Standard elements should
|
||||
<em>just work</em>, at least that’s the goal. It’s semantic HTML,
|
||||
rendered as if we were back in the 70s.</p>
|
||||
<p>All right, but is this even a good idea? It’s a technical and
|
||||
creative challenge and I like the aestethic. If you’d like to use it,
|
||||
feel free to fork or copy the bits you need, respecting the license. I
|
||||
might update it over time with improvements and support for more
|
||||
standard elements.</p>
|
||||
<h2 id="the-basics">The Basics</h2>
|
||||
<p>This document uses a few extra classes here and there, but mostly
|
||||
it’s just markup. This, for instance, is a regular paragraph.</p>
|
||||
<p>Look at this horizontal break:</p>
|
||||
<hr>
|
||||
<p>Lovely. We can hide stuff in the <code><details</code>>
|
||||
element:</p>
|
||||
<details>
|
||||
<summary>
|
||||
A short summary of the contents
|
||||
</summary>
|
||||
<p>
|
||||
Hidden gems.
|
||||
</p>
|
||||
</details>
|
||||
<h2 id="lists">Lists</h2>
|
||||
<p>This is a plain old bulleted list:</p>
|
||||
<ul class="incremental">
|
||||
<li>Banana</li>
|
||||
<li>Paper boat</li>
|
||||
<li>Cucumber</li>
|
||||
<li>Rocket</li>
|
||||
</ul>
|
||||
<p>Ordered lists look pretty much as you’d expect:</p>
|
||||
<ol class="incremental" type="1">
|
||||
<li>Goals</li>
|
||||
<li>Motivations
|
||||
<ol class="incremental" type="1">
|
||||
<li>Intrinsic</li>
|
||||
<li>Extrinsic</li>
|
||||
</ol></li>
|
||||
<li>Second-order effects</li>
|
||||
</ol>
|
||||
<p>It’s nice to visualize trees. This is a regular unordered list with a
|
||||
<code>tree</code> class:</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. They’re 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°45’50.78”N 11°15’3.34”E
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Pyramid of Khafre
|
||||
</td>
|
||||
<td>
|
||||
215.25m × 215.25m × 136.4m
|
||||
</td>
|
||||
<td>
|
||||
29°58’34”N 31°07’51”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 class="grid">
|
||||
<label>First name
|
||||
<input type="text" placeholder="Placeholder..." /></label> <label>Last
|
||||
name <input type="text" placeholder="Text goes here..." /></label>
|
||||
<label>Age <input type="text" value="30" /></label>
|
||||
</form>
|
||||
<p>And radio buttons:</p>
|
||||
<form class="grid">
|
||||
<label><input name="radio" type="radio" /> Option #1</label>
|
||||
<label><input name="radio" type="radio" /> Option #2</label>
|
||||
<label><input name="radio" type="radio" /> Option #3</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="ascii-drawings">ASCII Drawings</h2>
|
||||
<p>We can draw in <code><pre></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><figure></code> tag, and why not also add a
|
||||
<code><figcaption></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>Let’s 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="media">Media</h2>
|
||||
<p>Media objects are supported, like images and video:</p>
|
||||
<figure>
|
||||
<img src="castle.jpg" alt="A room in an old French castle (2024)" />
|
||||
<figcaption aria-hidden="true">A room in an old French castle
|
||||
(2024)</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<video
|
||||
src="https://upload.wikimedia.org/wikipedia/commons/e/e0/The_Center_of_the_Web_%281914%29.webm"
|
||||
controls=""><a
|
||||
href="https://upload.wikimedia.org/wikipedia/commons/e/e0/The_Center_of_the_Web_%281914%29.webm">The
|
||||
Center of the Web (1914), Wikimedia</a></video>
|
||||
<figcaption aria-hidden="true"><a
|
||||
href="https://en.wikisource.org/wiki/Page:The_Center_of_the_Web_(1914).webm/11">The
|
||||
Center of the Web (1914), Wikimedia</a></figcaption>
|
||||
</figure>
|
||||
<p>They extend to the width of the page, and add appropriate padding in
|
||||
the bottom to maintain the monospace grid.</p>
|
||||
<h2 id="discussion">Discussion</h2>
|
||||
<p>That’s it for now. I’ve very much enjoyed making this, pushing my CSS
|
||||
chops and having a lot of fun with the design. If you like it or even
|
||||
decide to use it, please <a href="https://x.com/owickstrom">let me
|
||||
know</a>.</p>
|
||||
<p>The full source code is here: <a
|
||||
href="https://github.com/owickstrom/the-monospace-web">github.com/owickstrom/the-monospace-web</a></p>
|
||||
<p>Finally, a massive shout-out to <a
|
||||
href="https://x.com/usgraphics">U.S. Graphics Company</a> for all the
|
||||
inspiration.</p>
|
||||
<div class="debug-grid"></div>
|
||||
<script src="src/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
30
package.json
30
package.json
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "@owickstrom/the-monospace-web",
|
||||
"version": "0.1.5",
|
||||
"description": " A minimalist design exploration",
|
||||
"main": "src/index.css",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/owickstrom/the-monospace-web.git"
|
||||
},
|
||||
"keywords": [
|
||||
"css"
|
||||
],
|
||||
"author": "Oskar Wickström",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/owickstrom/the-monospace-web/issues"
|
||||
},
|
||||
"homepage": "https://github.com/owickstrom/the-monospace-web#readme",
|
||||
|
||||
"files": [
|
||||
"src/index.css",
|
||||
"src/reset.css",
|
||||
"src/index.js",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
22
readme.txt
Normal file
22
readme.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
▄▄▄· ▄▄▄· ▐ ▄ ·▄▄▄▄ ▄▄· • ▌ ▄ ·. ▐ ▄
|
||||
▐█ ▄█▐█ ▀█ •█▌▐███▪ ██ ▪ ▐█ ▌▪·██ ▐███▪▪ •█▌▐█▪
|
||||
██▀·▄█▀▀█ ▐█▐▐▌▐█· ▐█▌ ▄█▀▄ ██ ▄▄▐█ ▌▐▌▐█· ▄█▀▄ ▐█▐▐▌ ▄█▀▄
|
||||
▐█▪·•▐█ ▪▐▌██▐█▌██. ██ ▐█▌.▐▌▐███▌██ ██▌▐█▌▐█▌.▐▌██▐█▌▐█▌.▐▌
|
||||
.▀ ▀ ▀ ▀▀ █▪▀▀▀▀▀• ▀█▄▀▪·▀▀▀ ▀▀ █▪▀▀▀ ▀█▄▀▪▀▀ █▪ ▀█▄▀▪
|
||||
|
||||
|
||||
This is a simple Pandoc based Static Site Generator
|
||||
based on the Monospace Web project by Oskar Wickström.
|
||||
|
||||
1. Install pandoc
|
||||
2. Drop Markdown files in the src directory
|
||||
3. Execute the convert.sh script
|
||||
4. Deploy the build directory to your static site host
|
||||
|
||||
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.
|
||||
|
||||
- ff 2025
|
||||
16
src/blog/index.md
Normal file
16
src/blog/index.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: Blog
|
||||
subtitle: Random musings.
|
||||
author: John Doe
|
||||
lang: en
|
||||
toc: false
|
||||
---
|
||||
|
||||
|
||||
## Highligted
|
||||
|
||||
None.
|
||||
|
||||
## Other
|
||||
|
||||
- [Lorem ipsum](lorem-ipsum.html)
|
||||
20
src/blog/lorem-ipsum.md
Normal file
20
src/blog/lorem-ipsum.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
title: Lorem ipsum
|
||||
subtitle: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
author: John Doe
|
||||
lang: en
|
||||
toc: false
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
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.
|
||||
@@ -1,7 +1,12 @@
|
||||
/* ==========================================================================
|
||||
Base & Variables
|
||||
========================================================================== */
|
||||
|
||||
@import url('https://fonts.cdnfonts.com/css/jetbrains-mono-2');
|
||||
|
||||
:root {
|
||||
--font-family: "JetBrains Mono", monospace;
|
||||
--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;
|
||||
@@ -25,20 +30,57 @@
|
||||
:root {
|
||||
--text-color: #fff;
|
||||
--text-color-alt: #aaa;
|
||||
--background-color: #000;
|
||||
--background-color-alt: #111;
|
||||
--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%;
|
||||
@@ -64,12 +106,85 @@ body {
|
||||
:root {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: var(--line-height) 1ch;
|
||||
}
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
@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);
|
||||
@@ -81,11 +196,28 @@ h1 {
|
||||
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;
|
||||
@@ -94,6 +226,7 @@ hr {
|
||||
border: none;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
hr:after {
|
||||
display: block;
|
||||
content: "";
|
||||
@@ -105,25 +238,47 @@ hr:after {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration-thickness: var(--border-thickness);
|
||||
hr.thin {
|
||||
position: relative;
|
||||
height: var(--line-height);
|
||||
margin: var(--line-height) 0;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
color: var(--text-color);
|
||||
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;
|
||||
@@ -134,6 +289,12 @@ sub {
|
||||
font-size: .75rem;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Components
|
||||
========================================================================== */
|
||||
|
||||
|
||||
/* Tables */
|
||||
table {
|
||||
position: relative;
|
||||
top: calc(var(--line-height) / 2);
|
||||
@@ -142,161 +303,30 @@ table {
|
||||
margin: 0 0 calc(var(--line-height) * 2);
|
||||
}
|
||||
|
||||
th, td {
|
||||
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)))
|
||||
;
|
||||
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 > * {
|
||||
|
||||
table tbody tr:first-child>* {
|
||||
padding-top: calc((var(--line-height) / 2) - var(--border-thickness));
|
||||
}
|
||||
|
||||
|
||||
th {
|
||||
font-weight: 700;
|
||||
}
|
||||
.width-min {
|
||||
width: 0%;
|
||||
}
|
||||
.width-auto {
|
||||
width: 100%;
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: calc(var(--line-height) * 2);
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
}
|
||||
.header tr td:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
p {
|
||||
word-break: break-word;
|
||||
word-wrap: break-word;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
img, video {
|
||||
display: block;
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
overflow: hidden;
|
||||
}
|
||||
img {
|
||||
font-style: italic;
|
||||
color: var(--text-color-alt);
|
||||
}
|
||||
|
||||
details {
|
||||
/* Forms */
|
||||
input,
|
||||
button,
|
||||
textarea {
|
||||
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;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre;
|
||||
overflow-x: auto;
|
||||
margin: var(--line-height) 0;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
figure pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-family: var(--font-family);
|
||||
}
|
||||
|
||||
code {
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
height: var(--line-height);
|
||||
}
|
||||
|
||||
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));
|
||||
padding: calc(var(--line-height) / 2 - var(--border-thickness)) calc(1ch - var(--border-thickness));
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
font-weight: inherit;
|
||||
@@ -320,6 +350,7 @@ input[type=radio] {
|
||||
height: var(--line-height);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked:before,
|
||||
input[type=radio]:checked:before {
|
||||
content: "";
|
||||
@@ -327,12 +358,14 @@ input[type=radio]:checked:before {
|
||||
height: calc(var(--line-height) / 2);
|
||||
background: var(--text-color);
|
||||
}
|
||||
|
||||
input[type=radio],
|
||||
input[type=radio]:before {
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
button:focus, input:focus {
|
||||
button:focus,
|
||||
input:focus {
|
||||
--border-thickness: 3px;
|
||||
outline: none;
|
||||
}
|
||||
@@ -340,16 +373,19 @@ button:focus, input:focus {
|
||||
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
|
||||
border: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
@@ -361,83 +397,200 @@ button {
|
||||
button:hover {
|
||||
background: var(--background-color-alt);
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translate(2px, 2px);
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
width: calc(round(down, 100%, 1ch));
|
||||
height: auto;
|
||||
line-height: var(--line-height);
|
||||
/* 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);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
label input {
|
||||
width: 100%;
|
||||
code:not(pre code) {
|
||||
background: var(--background-color-alt);
|
||||
padding: 0 0.5ch;
|
||||
border-radius: 2px;
|
||||
font-size: 0.95em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tree, .tree ul {
|
||||
position: relative;
|
||||
padding-left: 0;
|
||||
list-style-type: none;
|
||||
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);
|
||||
}
|
||||
.tree ul {
|
||||
margin: 0;
|
||||
}
|
||||
.tree ul li {
|
||||
position: relative;
|
||||
padding-left: 1.5ch;
|
||||
margin-left: 1.5ch;
|
||||
border-left: var(--border-thickness) solid var(--text-color);
|
||||
}
|
||||
.tree ul li:before {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: calc(var(--line-height) / 2);
|
||||
left: 0;
|
||||
content: "";
|
||||
width: 1ch;
|
||||
border-bottom: var(--border-thickness) solid var(--text-color);
|
||||
}
|
||||
.tree ul li:last-child {
|
||||
border-left: none;
|
||||
}
|
||||
.tree ul li:last-child:after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 0;
|
||||
left: 0;
|
||||
content: "";
|
||||
|
||||
pre code::-webkit-scrollbar {
|
||||
height: calc(var(--line-height) / 2);
|
||||
border-left: var(--border-thickness) solid var(--text-color);
|
||||
}
|
||||
|
||||
.grid {
|
||||
--grid-cells: 0;
|
||||
display: flex;
|
||||
gap: 1ch;
|
||||
width: calc(round(down, 100%, (1ch * var(--grid-cells)) - (1ch * var(--grid-cells) - 1)));
|
||||
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);
|
||||
}
|
||||
|
||||
.grid > *,
|
||||
.grid > input {
|
||||
flex: 0 0 calc(round(down, (100% - (1ch * (var(--grid-cells) - 1))) / var(--grid-cells), 1ch));
|
||||
summary {
|
||||
font-weight: var(--font-weight-medium);
|
||||
cursor: pointer;
|
||||
}
|
||||
.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; }
|
||||
|
||||
/* DEBUG UTILITIES */
|
||||
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%);
|
||||
@@ -461,3 +614,115 @@ label input {
|
||||
.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);
|
||||
}
|
||||
BIN
src/files/img/Nicaragua1_1913.jpg
Normal file
BIN
src/files/img/Nicaragua1_1913.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 310 KiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.5 MiB |
@@ -1,67 +1,85 @@
|
||||
---
|
||||
title: The Monospace Web
|
||||
subtitle: A minimalist design exploration
|
||||
author: Oskar Wickström
|
||||
author-url: "https://wickstrom.tech"
|
||||
title: CSS Features Demo
|
||||
subtitle: Showcasing all available styles
|
||||
author: Demo Author
|
||||
author-url: "https://example.com"
|
||||
lang: en
|
||||
toc-title: Contents
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Monospace fonts are dear to many of us.
|
||||
Some find them more readable, consistent, and beautiful, than their proportional alternatives.
|
||||
Maybe we're just brainwashed from spending years in terminals?
|
||||
Or are we hopelessly nostalgic?
|
||||
I'm not sure.
|
||||
But I like them, and that's why I started experimenting with all-monospace Web.
|
||||
<br>
|
||||
|
||||
On this page, I use a monospace grid to align text and draw diagrams.
|
||||
It's generated from a simple Markdown document (using Pandoc), and the CSS and a tiny bit of Javascript renders it on the grid.
|
||||
The page is responsive, shrinking in character-sized steps.
|
||||
Standard elements should _just work_, at least that's the goal.
|
||||
It's semantic HTML, rendered as if we were back in the 70s.
|
||||
# Pandoc Monospace Web
|
||||
|
||||
All right, but is this even a good idea?
|
||||
It's a technical and creative challenge and I like the aestethic.
|
||||
If you'd like to use it, feel free to fork or copy the bits you need, respecting the license.
|
||||
I might update it over time with improvements and support for more standard elements.
|
||||
This is a simple Pandoc based Static Site Generator
|
||||
based on the Monospace Web project by Oskar Wickström.
|
||||
|
||||
## The Basics
|
||||
1. Install pandoc
|
||||
2. Drop Markdown files in the src directory
|
||||
3. Execute the convert.sh script
|
||||
4. Deploy the build directory to your static site host
|
||||
|
||||
This document uses a few extra classes here and there, but mostly it's just markup.
|
||||
This, for instance, is a regular paragraph.
|
||||
Given that the site generator consits of a single bash script,
|
||||
single html template and a css file, it's easy to customize.
|
||||
|
||||
Look at this horizontal break:
|
||||
All changes to the original project are unlicensed (C0).
|
||||
The Monospace Web is licensed under the MIT license.
|
||||
|
||||
<hr class="thin">
|
||||
|
||||
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.
|
||||
|
||||
- Github repository: [frainfreeze/the-monospace-web-pandoc](https://github.com/frainfreeze/the-monospace-web-pandoc)
|
||||
- Original author GitHub: [owickstrom/the-monospace-web](https://github.com/owickstrom/the-monospace-web)
|
||||
|
||||
<hr class="thin">
|
||||
|
||||
## 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](https://example.com).
|
||||
|
||||
Text with a sub<sub>script</sub>.
|
||||
|
||||
## Horizontal Rules
|
||||
|
||||
Default horizontal rule:
|
||||
|
||||
<hr>
|
||||
|
||||
Lovely. We can hide stuff in the `<details`> element:
|
||||
Thin variant:
|
||||
|
||||
<details>
|
||||
<summary>A short summary of the contents</summary>
|
||||
<p>Hidden gems.</p>
|
||||
</details>
|
||||
<hr class="thin">
|
||||
|
||||
## Lists
|
||||
|
||||
This is a plain old bulleted list:
|
||||
Unordered list:
|
||||
|
||||
* Banana
|
||||
* Paper boat
|
||||
* Cucumber
|
||||
* Rocket
|
||||
* Item one
|
||||
* Item two
|
||||
* Item three
|
||||
* Nested item
|
||||
* Another nested item
|
||||
|
||||
Ordered lists look pretty much as you'd expect:
|
||||
Ordered list:
|
||||
|
||||
1. Goals
|
||||
1. Motivations
|
||||
1. Intrinsic
|
||||
1. Extrinsic
|
||||
1. Second-order effects
|
||||
1. First item
|
||||
2. Second item
|
||||
1. Nested numbered
|
||||
2. Another nested
|
||||
3. Third item
|
||||
|
||||
It's nice to visualize trees.
|
||||
This is a regular unordered list with a `tree` class:
|
||||
Tree view:
|
||||
|
||||
<ul class="tree"><li><p style="margin: 0;"><strong>/dev/nvme0n1p2</strong></p>
|
||||
|
||||
@@ -86,6 +104,7 @@ This is a regular unordered list with a `tree` class:
|
||||
|
||||
</li></ul>
|
||||
|
||||
|
||||
## Tables
|
||||
|
||||
We can use regular tables that automatically adjust to the monospace grid.
|
||||
@@ -126,18 +145,17 @@ Here are some buttons:
|
||||
|
||||
And inputs:
|
||||
|
||||
<form class="grid">
|
||||
<label>First name <input type="text" placeholder="Placeholder..." /></label>
|
||||
<label>Last name <input type="text" placeholder="Text goes here..." /></label>
|
||||
<label>Age <input type="text" value="30" /></label>
|
||||
<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>
|
||||
|
||||
And radio buttons:
|
||||
|
||||
### Radio & Checkboxes
|
||||
<form class="grid">
|
||||
<label><input name="radio" type="radio" /> Option #1</label>
|
||||
<label><input name="radio" type="radio" /> Option #2</label>
|
||||
<label><input name="radio" type="radio" /> Option #3</label>
|
||||
<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>
|
||||
|
||||
## Grids
|
||||
@@ -157,7 +175,42 @@ If we want one cell to fill the remainder, we set `flex-grow: 1;` for that parti
|
||||
|
||||
<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>
|
||||
|
||||
## ASCII Drawings
|
||||
## Code Blocks
|
||||
|
||||
Inline code: `const example = "hello world";`
|
||||
|
||||
Fenced code block:
|
||||
|
||||
```javascript
|
||||
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
|
||||
|
||||
<details>
|
||||
<summary>Click to expand</summary>
|
||||
<p>Hidden content goes here</p>
|
||||
<p>Can contain any other elements</p>
|
||||
</details>
|
||||
|
||||
|
||||
## ASCII Art & Diagrams
|
||||
|
||||
We can draw in `<pre>` tags using [box-drawing characters](https://en.wikipedia.org/wiki/Box-drawing_characters):
|
||||
|
||||
@@ -211,22 +264,54 @@ Let's go wild and draw a chart!
|
||||
Socks Jeans Shirts USB Drives
|
||||
</pre></figure>
|
||||
|
||||
## Media
|
||||
|
||||
Media objects are supported, like images and video:
|
||||
## Product Cards
|
||||
|
||||

|
||||
Product cards are useful for displaying items with images, descriptions, and actions:
|
||||
|
||||
.webm/11)](https://upload.wikimedia.org/wikipedia/commons/e/e0/The_Center_of_the_Web_%281914%29.webm)
|
||||
<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>
|
||||
|
||||
## 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.
|
||||
|
||||
## Discussion
|
||||
![Example image alt text]()
|
||||
|
||||
That's it for now.
|
||||
I've very much enjoyed making this, pushing my CSS chops and having a lot of fun with the design.
|
||||
If you like it or even decide to use it, please [let me know](https://x.com/owickstrom).
|
||||
<video src="https://upload.wikimedia.org/wikipedia/commons/e/e0/The_Center_of_the_Web_%281914%29.webm" controls></video>
|
||||
|
||||
The full source code is here: [github.com/owickstrom/the-monospace-web](https://github.com/owickstrom/the-monospace-web)
|
||||
### Theme-Aware Images
|
||||
|
||||
Finally, a massive shout-out to [U.S. Graphics Company](https://x.com/usgraphics) for all the inspiration.
|
||||
Images can adapt to light and dark themes (convert theme using lightbulb icon in the footer or system settings):
|
||||
|
||||
<div class="grid">
|
||||
<img height="150px" class="theme-aware-image" src="./files/img/Nicaragua1_1913.jpg" alt="This image inverts in dark mode">
|
||||
|
||||
<img height="150px" class="theme-aware-image no-invert" src="./files/img/Nicaragua1_1913.jpg" alt="This image stays the same in both modes">
|
||||
|
||||
<img height="150px" class="theme-aware-image adjust-contrast" src="./files/img/Nicaragua1_1913.jpg" alt="This image adjusts contrast in dark mode">
|
||||
</div>
|
||||
|
||||
|
||||
[^1]: Pandoc understands an extended and slightly revised version of John Gruber’s Markdown syntax. See [Pandoc’s Markdown](https://pandoc.org/chunkedhtml-demo/8-pandocs-markdown.html) for details.
|
||||
114
template.html
Normal file
114
template.html
Normal file
@@ -0,0 +1,114 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
|
||||
<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" />
|
||||
$for(author-meta)$
|
||||
<meta name="author" content="$author-meta$" />
|
||||
$endfor$
|
||||
$if(date-meta)$
|
||||
<meta name="dcterms.date" content="$date-meta$" />
|
||||
$endif$
|
||||
$if(keywords)$
|
||||
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
|
||||
$endif$
|
||||
$if(description-meta)$
|
||||
<meta name="description" content="$description-meta$" />
|
||||
$endif$
|
||||
<link rel="shortcut icon" href="/files/img/favicon.ico">
|
||||
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
|
||||
$for(css)$
|
||||
<link rel="stylesheet" href="$css$" />
|
||||
$endfor$
|
||||
$for(header-includes)$
|
||||
$header-includes$
|
||||
$endfor$
|
||||
$if(math)$
|
||||
$math$
|
||||
$endif$
|
||||
</head>
|
||||
<body>
|
||||
$for(include-before)$
|
||||
$include-before$
|
||||
$endfor$
|
||||
<table class="header">
|
||||
<tr>
|
||||
<td colspan="2" rowspan="2" class="width-auto">
|
||||
<h1 class="title">$title$</h1>
|
||||
<span class="subtitle">$subtitle$</span>
|
||||
</td>
|
||||
<th>Version</th>
|
||||
<td class="width-min">$version$</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Updated</th>
|
||||
<td class="width-min"><time style="white-space: pre;">$date$</time></td>
|
||||
</tr>
|
||||
</table>
|
||||
$if(abstract)$
|
||||
<div class="abstract">
|
||||
<div class="abstract-title">$abstract-title$</div>
|
||||
$abstract$
|
||||
</div>
|
||||
$endif$
|
||||
$if(toc)$
|
||||
<nav id="$idprefix$TOC" role="doc-toc">
|
||||
$if(toc-title)$
|
||||
<h2 id="$idprefix$toc-title">$toc-title$</h2>
|
||||
$endif$
|
||||
$table-of-contents$
|
||||
</nav>
|
||||
$endif$
|
||||
$body$
|
||||
$for(include-after)$
|
||||
$include-after$
|
||||
$endfor$
|
||||
|
||||
<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 $year$</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>
|
||||
Reference in New Issue
Block a user