diff --git a/.envrc b/.envrc deleted file mode 100644 index a5dbbcb..0000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use flake . diff --git a/.gitignore b/.gitignore index e69de29..567609b 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/LICENSE.md b/LICENSE.md index 1ff0209..a536416 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -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: diff --git a/Makefile b/Makefile deleted file mode 100644 index 1bb2250..0000000 --- a/Makefile +++ /dev/null @@ -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 diff --git a/README.md b/README.md deleted file mode 100644 index 96ecaed..0000000 --- a/README.md +++ /dev/null @@ -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) diff --git a/convert.sh b/convert.sh new file mode 100755 index 0000000..c3e98d2 --- /dev/null +++ b/convert.sh @@ -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 $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 \ No newline at end of file diff --git a/demo/template.html b/demo/template.html deleted file mode 100644 index ce10579..0000000 --- a/demo/template.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - -$for(author-meta)$ - -$endfor$ -$if(date-meta)$ - -$endif$ -$if(keywords)$ - -$endif$ -$if(description-meta)$ - -$endif$ - $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ -$for(css)$ - -$endfor$ -$for(header-includes)$ - $header-includes$ -$endfor$ -$if(math)$ - $math$ -$endif$ - - -$for(include-before)$ -$include-before$ -$endfor$ - - - - - - - - - - - - - - - - -
-

$title$

- $subtitle$ -
Version$version$
Updated
Author$author$LicenseMIT
- -$if(abstract)$ -
-
$abstract-title$
-$abstract$ -
-$endif$ -$if(toc)$ - -$endif$ -$body$ -$for(include-after)$ -$include-after$ -$endfor$ -
- - - diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 76dc8f3..0000000 --- a/flake.lock +++ /dev/null @@ -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 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index eb57a8f..0000000 --- a/flake.nix +++ /dev/null @@ -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 - ]; - }; - } - ); - }; -} diff --git a/index.html b/index.html deleted file mode 100644 index 123ff6e..0000000 --- a/index.html +++ /dev/null @@ -1,324 +0,0 @@ - - - - - - - - The Monospace Web - - - - - - - - - - - - - - - - - - - - -
-

The Monospace Web

- A minimalist design exploration -
Versionv0.1.5
Updated
AuthorOskar -WickströmLicenseMIT
- - -

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.

-

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.

-

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.

-

The Basics

-

This document uses a few extra classes here and there, but mostly -it’s just markup. This, for instance, is a regular paragraph.

-

Look at this horizontal break:

-
-

Lovely. We can hide stuff in the <details> -element:

-
- -A short summary of the contents - -

-Hidden gems. -

-
-

Lists

-

This is a plain old bulleted list:

- -

Ordered lists look pretty much as you’d expect:

-
    -
  1. Goals
  2. -
  3. Motivations -
      -
    1. Intrinsic
    2. -
    3. Extrinsic
    4. -
  4. -
  5. Second-order effects
  6. -
-

It’s nice to visualize trees. This is a regular unordered list with a -tree class:

- -

Tables

-

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

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

Note that only one column is allowed to grow.

-

Forms

-

Here are some buttons:

- -

And inputs:

-
- - -
-

And radio buttons:

-
- - - -
-

Grids

-

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

-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-

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

-
- -
-

ASCII Drawings

-

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

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

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

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

Let’s go wild and draw a chart!

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

Media

-

Media objects are supported, like images and video:

-
-A room in an old French castle (2024) - -
-
- - -
-

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

-

Discussion

-

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.

-

The full source code is here: github.com/owickstrom/the-monospace-web

-

Finally, a massive shout-out to U.S. Graphics Company for all the -inspiration.

-
- - - diff --git a/package.json b/package.json deleted file mode 100644 index 6552c68..0000000 --- a/package.json +++ /dev/null @@ -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" - ] -} diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..16f79d4 --- /dev/null +++ b/readme.txt @@ -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 \ No newline at end of file diff --git a/src/blog/index.md b/src/blog/index.md new file mode 100644 index 0000000..eb7428e --- /dev/null +++ b/src/blog/index.md @@ -0,0 +1,16 @@ +--- +title: Blog +subtitle: Random musings. +author: John Doe +lang: en +toc: false +--- + + +## Highligted + +None. + +## Other + +- [Lorem ipsum](lorem-ipsum.html) diff --git a/src/blog/lorem-ipsum.md b/src/blog/lorem-ipsum.md new file mode 100644 index 0000000..03cdce4 --- /dev/null +++ b/src/blog/lorem-ipsum.md @@ -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. \ No newline at end of file diff --git a/src/index.css b/src/files/css/index.css similarity index 50% rename from src/index.css rename to src/files/css/index.css index ac7a8fe..0a0bb54 100644 --- a/src/index.css +++ b/src/files/css/index.css @@ -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))) - ; + 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 > * { + +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); +} \ No newline at end of file diff --git a/src/reset.css b/src/files/css/reset.css similarity index 100% rename from src/reset.css rename to src/files/css/reset.css diff --git a/src/files/img/Nicaragua1_1913.jpg b/src/files/img/Nicaragua1_1913.jpg new file mode 100644 index 0000000..af482ae Binary files /dev/null and b/src/files/img/Nicaragua1_1913.jpg differ diff --git a/demo/castle.jpg b/src/files/img/castle.jpg similarity index 100% rename from demo/castle.jpg rename to src/files/img/castle.jpg diff --git a/src/index.js b/src/files/js/index.js similarity index 100% rename from src/index.js rename to src/files/js/index.js diff --git a/demo/index.md b/src/index.md similarity index 54% rename from demo/index.md rename to src/index.md index 13d7021..6c1ab9e 100644 --- a/demo/index.md +++ b/src/index.md @@ -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. +
-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. + +
+ +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) + +
+ +## 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 subscript. + +## Horizontal Rules + +Default horizontal rule:
-Lovely. We can hide stuff in the ` element: +Thin variant: -
-A short summary of the contents -

Hidden gems.

-
+
## 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: + ## Tables We can use regular tables that automatically adjust to the monospace grid. @@ -126,18 +145,17 @@ Here are some buttons: And inputs: -
- - - + + + +
-And radio buttons: - +### Radio & Checkboxes
- - - + + +
## Grids @@ -157,7 +175,42 @@ If we want one cell to fill the remainder, we set `flex-grow: 1;` for that parti
-## 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 + +
+Click to expand +

Hidden content goes here

+

Can contain any other elements

+
+ + +## ASCII Art & Diagrams We can draw in `
` 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
 
-## Media -Media objects are supported, like images and video: +## Product Cards -![A room in an old French castle (2024)](castle.jpg) +Product cards are useful for displaying items with images, descriptions, and actions: -![[The Center of the Web (1914), Wikimedia](https://en.wikisource.org/wiki/Page:The_Center_of_the_Web_(1914).webm/11)](https://upload.wikimedia.org/wikipedia/commons/e/e0/The_Center_of_the_Web_%281914%29.webm) +
+ Product image +

Product Title

+

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

+ + + + + + + + + +
Price$99.99
Rating★★★★☆
+ +
+ +## Media with Captions + +Media objects are supported, like images and video with captions: + +![A sample image with caption (2024)](./files/img/castle.jpg) 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). + -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): + +
+This image inverts in dark mode + +This image stays the same in both modes + +This image adjusts contrast in dark mode +
+ + +[^1]: Pandoc understands an extended and slightly revised version of John Gruber’s Markdown syntax. See [Pandoc’s Markdown](https://pandoc.org/chunkedhtml-demo/8-pandocs-markdown.html) for details. diff --git a/template.html b/template.html new file mode 100644 index 0000000..1786175 --- /dev/null +++ b/template.html @@ -0,0 +1,114 @@ + + + + + + +$for(author-meta)$ + +$endfor$ +$if(date-meta)$ + +$endif$ +$if(keywords)$ + +$endif$ +$if(description-meta)$ + +$endif$ + + $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ +$for(css)$ + +$endfor$ +$for(header-includes)$ + $header-includes$ +$endfor$ +$if(math)$ + $math$ +$endif$ + + +$for(include-before)$ +$include-before$ +$endfor$ + + + + + + + + + + +
+

$title$

+ $subtitle$ +
Version$version$
Updated
+$if(abstract)$ +
+
$abstract-title$
+$abstract$ +
+$endif$ +$if(toc)$ + +$endif$ +$body$ +$for(include-after)$ +$include-after$ +$endfor$ + + + + + +
+ Home • + Blog • + ©Copyright $year$ • + + + + + +
+ + + +