feat: initial mono-repo with 30 vanity domain sites

Scaffold complete repo structure:
- 28 static sites extracted from running containers on mlake
- 2 dynamic sites (dasbes.de, dumusst.com) marked for separate handling
- Template system with 6 templates (person-dark/light, product-dark, editorial, fun, minimal)
- Shared CSS (variables, responsive, animations, noise overlay)
- nginx config generator with multi-domain alias support
- Build script with Docker-based nginx validation
- add-site.sh helper for scaffolding new domains
- Dockerfile for single nginx:alpine container

Sites: clemensplassmann.de, danosi.de, deinesei.de, derkaiseristnackt.de,
elefantenhor.de, fragina.de, frenchkis.de, ichbinaufbali.de, ichbinaufbarley.de,
insain.de, julietensity.de, kainco.de (+keinco.de), kainstress.de, keinefreun.de,
knzlmgmt.de, kopffrai.de, legalais.de, machesdocheinfach.de, mai-otto.de
(+otto.flexsiebels.de, ottomatisch.de, ichbinotto.de), martinsiebels.de,
matthiasbreier.de, osterai.de, paragraphenraiter.de, schulfrai.de, smartin3.de,
sorgenfrai.de, vonschraitter.de, wartebitte.de

Refs: otto#341
This commit is contained in:
mAi
2026-03-29 13:20:27 +02:00
parent ec3e1e42f3
commit 6f5de542ab
78 changed files with 13471 additions and 1 deletions

190
render.sh Executable file
View File

@@ -0,0 +1,190 @@
#!/bin/bash
# Render a site from site.yaml + template
# Usage: ./render.sh sites/example.de/site.yaml templates/person-dark.html
# Outputs rendered HTML to stdout
set -euo pipefail
SITE_YAML="$1"
TEMPLATE_FILE="$2"
SITE_DIR=$(dirname "$SITE_YAML")
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
# Check dependencies
if ! command -v yq &>/dev/null; then
echo "ERROR: yq is required. Install: https://github.com/mikefarah/yq" >&2
exit 1
fi
# Read site config
domain=$(yq -r '.domain' "$SITE_YAML")
title=$(yq -r '.title // .domain' "$SITE_YAML")
description=$(yq -r '.description // ""' "$SITE_YAML")
lang=$(yq -r '.lang // "de"' "$SITE_YAML")
favicon=$(yq -r '.vars.favicon // ""' "$SITE_YAML")
name=$(yq -r '.vars.name // .title // ""' "$SITE_YAML")
role=$(yq -r '.vars.role // ""' "$SITE_YAML")
initials=$(yq -r '.vars.initials // ""' "$SITE_YAML")
tagline=$(yq -r '.vars.tagline // ""' "$SITE_YAML")
accent=$(yq -r '.vars.accent // "#c9a84c"' "$SITE_YAML")
accent_light=$(yq -r '.vars.accent_light // "rgba(201, 168, 76, 0.1)"' "$SITE_YAML")
font_primary=$(yq -r '.vars.font_primary // "Inter"' "$SITE_YAML")
font_secondary=$(yq -r '.vars.font_secondary // "Inter"' "$SITE_YAML")
emoji=$(yq -r '.vars.emoji // ""' "$SITE_YAML")
cta_text=$(yq -r '.vars.cta.text // ""' "$SITE_YAML")
cta_href=$(yq -r '.vars.cta.href // "#"' "$SITE_YAML")
year=$(date +%Y)
# Build tags HTML
tags_html=""
tag_count=$(yq -r '.vars.tags | length' "$SITE_YAML" 2>/dev/null || echo "0")
if [ "$tag_count" -gt 0 ]; then
for i in $(seq 0 $((tag_count - 1))); do
tag=$(yq -r ".vars.tags[$i]" "$SITE_YAML")
tags_html="${tags_html} <span class=\"tag\">${tag}</span>\n"
done
fi
# Build sections HTML
sections_html=""
section_count=$(yq -r '.vars.sections | length' "$SITE_YAML" 2>/dev/null || echo "0")
if [ "$section_count" -gt 0 ]; then
for i in $(seq 0 $((section_count - 1))); do
sec_type=$(yq -r ".vars.sections[$i].type" "$SITE_YAML")
sec_title=$(yq -r ".vars.sections[$i].title // \"\"" "$SITE_YAML")
if [ "$sec_type" = "features" ]; then
sections_html="${sections_html} <div class=\"section fade-in stagger-$((i+2))\">\n"
[ -n "$sec_title" ] && sections_html="${sections_html} <h2>${sec_title}</h2>\n"
sections_html="${sections_html} <div class=\"grid\">\n"
item_count=$(yq -r ".vars.sections[$i].items | length" "$SITE_YAML" 2>/dev/null || echo "0")
for j in $(seq 0 $((item_count - 1))); do
item_title=$(yq -r ".vars.sections[$i].items[$j].title" "$SITE_YAML")
item_desc=$(yq -r ".vars.sections[$i].items[$j].desc // \"\"" "$SITE_YAML")
sections_html="${sections_html} <div class=\"card\">\n"
sections_html="${sections_html} <h3>${item_title}</h3>\n"
[ -n "$item_desc" ] && sections_html="${sections_html} <p>${item_desc}</p>\n"
sections_html="${sections_html} </div>\n"
done
sections_html="${sections_html} </div>\n </div>\n"
elif [ "$sec_type" = "profile" ]; then
bio=$(yq -r ".vars.sections[$i].bio // \"\"" "$SITE_YAML")
sections_html="${sections_html} <div class=\"section fade-in stagger-$((i+2))\">\n"
[ -n "$sec_title" ] && sections_html="${sections_html} <h2>${sec_title}</h2>\n"
sections_html="${sections_html} <p class=\"bio\">${bio}</p>\n"
sections_html="${sections_html} </div>\n"
fi
done
fi
# Build content HTML (for editorial template)
content_html=""
content=$(yq -r '.vars.content // ""' "$SITE_YAML")
if [ -n "$content" ] && [ "$content" != "null" ]; then
# Convert newlines to paragraphs
content_html=$(echo "$content" | sed 's/^$/<\/p><p>/g' | sed '1s/^/<p>/' | sed '$s/$/<\/p>/')
fi
# Read template file and extract CSS/body sections
template_content=$(cat "$TEMPLATE_FILE")
# Extract template CSS (between markers)
template_css=$(echo "$template_content" | sed -n '/{{template_css_start}}/,/{{template_css_end}}/p' | sed '1d;$d')
# Extract template body (between markers)
template_body=$(echo "$template_content" | sed -n '/{{template_body_start}}/,/{{template_body_end}}/p' | sed '1d;$d')
# Read base template
base=$(cat "$SCRIPT_DIR/templates/base.html")
# Read shared CSS
css_variables=$(cat "$SCRIPT_DIR/shared/css/variables.css")
css_responsive=$(cat "$SCRIPT_DIR/shared/css/responsive.css")
css_animations=$(cat "$SCRIPT_DIR/shared/css/animations.css")
css_noise=$(cat "$SCRIPT_DIR/shared/css/noise.css")
fonts=$(cat "$SCRIPT_DIR/shared/fonts.html")
# Additional font links if non-Inter fonts are used
extra_fonts=""
if [ "$font_primary" != "Inter" ]; then
font_url=$(echo "$font_primary" | tr ' ' '+')
extra_fonts="${extra_fonts} <link href=\"https://fonts.googleapis.com/css2?family=${font_url}:wght@300;400;500;600;700&display=swap\" rel=\"stylesheet\">\n"
fi
if [ "$font_secondary" != "Inter" ] && [ "$font_secondary" != "$font_primary" ]; then
font_url=$(echo "$font_secondary" | tr ' ' '+')
extra_fonts="${extra_fonts} <link href=\"https://fonts.googleapis.com/css2?family=${font_url}:wght@400;500;700&display=swap\" rel=\"stylesheet\">\n"
fi
fonts="${fonts}${extra_fonts}"
# Assemble: substitute into base template
output="$base"
# Replace shared includes
output=$(echo "$output" | sed "s|{{fonts}}|$(echo "$fonts" | sed 's/[&/\]/\\&/g; s/$/\\/' | sed '$ s/\\$//')|")
# For CSS blocks, use temp files to handle multiline
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
echo "$css_variables" > "$tmpdir/css_variables"
echo "$css_responsive" > "$tmpdir/css_responsive"
echo "$css_animations" > "$tmpdir/css_animations"
echo "$css_noise" > "$tmpdir/css_noise"
echo "$template_css" > "$tmpdir/template_css"
printf '%b' "$template_body" > "$tmpdir/template_body"
# Use awk for reliable multiline substitution
awk -v vars="$tmpdir/css_variables" \
-v resp="$tmpdir/css_responsive" \
-v anim="$tmpdir/css_animations" \
-v noise="$tmpdir/css_noise" \
-v tcss="$tmpdir/template_css" \
-v tbody="$tmpdir/template_body" \
-v fonts_file=<(echo "$fonts") \
'
function read_file(path, line, content) {
content = ""
while ((getline line < path) > 0) content = content line "\n"
close(path)
return content
}
BEGIN {
cv = read_file(vars)
cr = read_file(resp)
ca = read_file(anim)
cn = read_file(noise)
tc = read_file(tcss)
tb = read_file(tbody)
}
{
gsub(/\{\{css_variables\}\}/, cv)
gsub(/\{\{css_responsive\}\}/, cr)
gsub(/\{\{css_animations\}\}/, ca)
gsub(/\{\{css_noise\}\}/, cn)
gsub(/\{\{template_css\}\}/, tc)
gsub(/\{\{body\}\}/, tb)
print
}
' <<< "$output" | sed \
-e "s|{{title}}|${title}|g" \
-e "s|{{description}}|${description}|g" \
-e "s|{{lang}}|${lang}|g" \
-e "s|{{favicon}}|${favicon}|g" \
-e "s|{{name}}|${name}|g" \
-e "s|{{role}}|${role}|g" \
-e "s|{{initials}}|${initials}|g" \
-e "s|{{tagline}}|${tagline}|g" \
-e "s|{{accent}}|${accent}|g" \
-e "s|{{accent_light}}|${accent_light}|g" \
-e "s|{{font_primary}}|${font_primary}|g" \
-e "s|{{font_secondary}}|${font_secondary}|g" \
-e "s|{{emoji}}|${emoji}|g" \
-e "s|{{cta_text}}|${cta_text}|g" \
-e "s|{{cta_href}}|${cta_href}|g" \
-e "s|{{year}}|${year}|g" \
-e "s|{{domain}}|${domain}|g" | \
sed "s|{{tags_html}}|$(printf '%b' "$tags_html" | sed 's/[&/\]/\\&/g; s/$/\\/' | sed '$ s/\\$//')|g" | \
sed "s|{{sections_html}}|$(printf '%b' "$sections_html" | sed 's/[&/\]/\\&/g; s/$/\\/' | sed '$ s/\\$//')|g" | \
sed "s|{{content_html}}|$(printf '%b' "$content_html" | sed 's/[&/\]/\\&/g; s/$/\\/' | sed '$ s/\\$//')|g"