feat: publish public website at furtka.org
Hugo static site with an intentionally minimal single-page copy — English default, German under /de/ — while the project stays pre-alpha. No CMS, no external theme, no webfonts, no external requests. System-UI sans on a paper-white / near-black palette with a deep crimson accent; a small wicket-gate SVG as the sole brand mark. Hosting: nginx on forge-runner-01 serves /var/www/furtka.org; the upstream openresty proxy terminates TLS so the VM itself only speaks plain HTTP. Deploy is ./website/deploy.sh (rsync + remote hugo --minify). One-time VM bootstrap in ops/nginx/setup-vm.sh.
This commit is contained in:
parent
7f15543f1c
commit
defd2eda06
20 changed files with 604 additions and 0 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -8,3 +8,8 @@ __pycache__/
|
||||||
# Real credentials must never be committed — use the .example files
|
# Real credentials must never be committed — use the .example files
|
||||||
archinstall/user_credentials.json
|
archinstall/user_credentials.json
|
||||||
iso/out/
|
iso/out/
|
||||||
|
|
||||||
|
# Hugo website
|
||||||
|
website/public/
|
||||||
|
website/resources/
|
||||||
|
website/.hugo_build.lock
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ This project uses calendar versioning: `YY.N-stage` (e.g. `26.0-alpha` = 2026, r
|
||||||
|
|
||||||
- **Forgejo Actions runner** live on Proxmox VM (`forge-runner-01`, Ubuntu 24.04) with DinD sidecar — CI green end-to-end. Setup scripts in `ops/forgejo-runner/`.
|
- **Forgejo Actions runner** live on Proxmox VM (`forge-runner-01`, Ubuntu 24.04) with DinD sidecar — CI green end-to-end. Setup scripts in `ops/forgejo-runner/`.
|
||||||
- **Walking-skeleton live ISO** (`iso/build.sh`). Overlays an Arch `releng` profile with Flask + the webinstaller, bakes a systemd unit that auto-starts the wizard on boot, produces a hybrid BIOS/UEFI ISO via `mkarchiso` in a privileged `archlinux:latest` container. Tested booting under OVMF in Proxmox — wizard screens 1–3 respond at `http://<vm-ip>:5000`.
|
- **Walking-skeleton live ISO** (`iso/build.sh`). Overlays an Arch `releng` profile with Flask + the webinstaller, bakes a systemd unit that auto-starts the wizard on boot, produces a hybrid BIOS/UEFI ISO via `mkarchiso` in a privileged `archlinux:latest` container. Tested booting under OVMF in Proxmox — wizard screens 1–3 respond at `http://<vm-ip>:5000`.
|
||||||
|
- **Public website at [furtka.org](https://furtka.org)** (`website/`). Hugo static site, English + German, served from `/var/www/furtka.org` on `forge-runner-01` via nginx. Upstream openresty proxy handles TLS. Intentionally minimal single-page copy while the project is pre-alpha. Deploy is `./website/deploy.sh` (rsync + remote Hugo build); one-time VM setup in `ops/nginx/setup-vm.sh`.
|
||||||
|
|
||||||
## [26.0-alpha] - 2026-04-13
|
## [26.0-alpha] - 2026-04-13
|
||||||
|
|
||||||
|
|
|
||||||
28
ops/nginx/furtka.org.conf
Normal file
28
ops/nginx/furtka.org.conf
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name furtka.org www.furtka.org;
|
||||||
|
|
||||||
|
root /var/www/furtka.org;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ $uri.html =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /favicon.svg {
|
||||||
|
access_log off;
|
||||||
|
log_not_found off;
|
||||||
|
expires 7d;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(css|js|svg|woff2?|png|jpg|jpeg|webp|avif)$ {
|
||||||
|
access_log off;
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 404 /404.html;
|
||||||
|
}
|
||||||
27
ops/nginx/setup-vm.sh
Executable file
27
ops/nginx/setup-vm.sh
Executable file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# One-time setup on forge-runner-01 for furtka.org.
|
||||||
|
# Idempotent — safe to re-run.
|
||||||
|
#
|
||||||
|
# Usage (on the VM, with sudo):
|
||||||
|
# sudo ops/nginx/setup-vm.sh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
OWNER="${SUDO_USER:-daniel}"
|
||||||
|
WEBROOT="/var/www/furtka.org"
|
||||||
|
SRCROOT="/srv/furtka-site"
|
||||||
|
SITE_CONF="/etc/nginx/sites-available/furtka.org"
|
||||||
|
SITE_LINK="/etc/nginx/sites-enabled/furtka.org"
|
||||||
|
|
||||||
|
install -d -o "$OWNER" -g "$OWNER" -m 0755 "$WEBROOT"
|
||||||
|
install -d -o "$OWNER" -g "$OWNER" -m 0755 "$SRCROOT"
|
||||||
|
|
||||||
|
cp "$(dirname "$0")/furtka.org.conf" "$SITE_CONF"
|
||||||
|
ln -sfn "$SITE_CONF" "$SITE_LINK"
|
||||||
|
|
||||||
|
# Drop the Ubuntu default site so it doesn't shadow us on :80.
|
||||||
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
|
||||||
|
nginx -t
|
||||||
|
systemctl reload nginx
|
||||||
|
|
||||||
|
echo "OK: furtka.org ready at $WEBROOT (owner $OWNER)"
|
||||||
61
website/README.md
Normal file
61
website/README.md
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
# website/ — furtka.org
|
||||||
|
|
||||||
|
Hugo source for [furtka.org](https://furtka.org). Intentionally minimal while
|
||||||
|
the project is pre-alpha: a single idea page in English and German, nothing more.
|
||||||
|
More pages will come back when there's something real to show.
|
||||||
|
|
||||||
|
## Local build
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd website
|
||||||
|
hugo server # http://localhost:1313
|
||||||
|
```
|
||||||
|
|
||||||
|
Requires Hugo **extended** ≥ 0.140.
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
Hosted on `forge-runner-01` (Proxmox VM, Ubuntu 24.04). Hugo runs on the VM;
|
||||||
|
nginx serves the built output from `/var/www/furtka.org`. TLS is terminated by
|
||||||
|
an upstream openresty reverse proxy — the VM itself only speaks plain HTTP.
|
||||||
|
|
||||||
|
First time only, on the VM:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ssh forge-runner
|
||||||
|
sudo /srv/furtka-site/ops/nginx/setup-vm.sh # or copy the script over first
|
||||||
|
```
|
||||||
|
|
||||||
|
From then on, deploy from your dev machine:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./website/deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script rsyncs `website/` to `/srv/furtka-site/` on the VM and runs
|
||||||
|
`hugo --minify` into `/var/www/furtka.org`.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
hugo.toml Hugo config (multilingual: en default, de)
|
||||||
|
content/ Markdown pages
|
||||||
|
_index.md Home (EN)
|
||||||
|
_index.de.md Home (DE)
|
||||||
|
layouts/ Custom inline theme — no external theme or framework
|
||||||
|
_default/ baseof, single, list
|
||||||
|
partials/ head, header, footer, gate SVG, lang switcher
|
||||||
|
index.html Home-only layout with editorial hero
|
||||||
|
assets/css/main.css Stylesheet (fingerprinted + minified on build)
|
||||||
|
static/favicon.svg Gate mark in crimson
|
||||||
|
deploy.sh Rsync + remote Hugo build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
Modern-minimal on paper-white light / near-black dark. System-UI sans
|
||||||
|
(no webfonts — zero external requests, matches the self-hosting ethos).
|
||||||
|
Deep crimson accent, `prefers-color-scheme` switch.
|
||||||
|
|
||||||
|
The gate SVG is the one brand mark — a small wicket-gate glyph repeated in the
|
||||||
|
header, footer, and favicon.
|
||||||
260
website/assets/css/main.css
Normal file
260
website/assets/css/main.css
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
:root {
|
||||||
|
--bg: #f7f6f3;
|
||||||
|
--bg-subtle: #efeee8;
|
||||||
|
--fg: #0e0e0f;
|
||||||
|
--fg-muted: #6b6b6f;
|
||||||
|
--accent: #c03a28;
|
||||||
|
--accent-hover: #a0301f;
|
||||||
|
--border: #e4e3dc;
|
||||||
|
--font-sans:
|
||||||
|
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
|
||||||
|
Arial, "Noto Sans", sans-serif;
|
||||||
|
--font-mono:
|
||||||
|
ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
||||||
|
--measure: 32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--bg: #0d0d0f;
|
||||||
|
--bg-subtle: #17171a;
|
||||||
|
--fg: #ececee;
|
||||||
|
--fg-muted: #8a8a90;
|
||||||
|
--accent: #ff6b56;
|
||||||
|
--accent-hover: #ff8b78;
|
||||||
|
--border: #232326;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
html { -webkit-text-size-adjust: 100%; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-size: 1.0625rem;
|
||||||
|
line-height: 1.65;
|
||||||
|
font-feature-settings: "kern", "cv11", "ss01";
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 52rem;
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-inline: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
main.container {
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
|
padding-block: 3rem 4.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gate-mark {
|
||||||
|
color: var(--accent);
|
||||||
|
vertical-align: -0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Kicker (shared small-caps style) ────────────────────────── */
|
||||||
|
|
||||||
|
.kicker {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
letter-spacing: 0.14em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--fg-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Site header ─────────────────────────────────────────────── */
|
||||||
|
|
||||||
|
.site-header {
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
padding-block: 1rem;
|
||||||
|
}
|
||||||
|
.site-header .container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
.site-title {
|
||||||
|
margin-right: auto;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
.site-title .gate-mark {
|
||||||
|
width: 1.15em;
|
||||||
|
height: 1.15em;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
}
|
||||||
|
.site-title .wordmark {
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.14em;
|
||||||
|
color: var(--fg);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
}
|
||||||
|
.site-title:hover .wordmark { color: var(--accent); }
|
||||||
|
|
||||||
|
/* ── Language switcher ───────────────────────────────────────── */
|
||||||
|
|
||||||
|
.lang-switcher {
|
||||||
|
display: flex;
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.lang-switcher li { display: flex; }
|
||||||
|
.lang-switcher a {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
letter-spacing: 0.14em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--fg-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.1rem 0.15rem;
|
||||||
|
border-bottom: 1.5px solid transparent;
|
||||||
|
}
|
||||||
|
.lang-switcher a:hover { color: var(--accent); }
|
||||||
|
.lang-switcher .is-active a {
|
||||||
|
color: var(--fg);
|
||||||
|
border-bottom-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Hero (home) ─────────────────────────────────────────────── */
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
padding-block: 3.5rem 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.45rem;
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
letter-spacing: 0.14em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--accent);
|
||||||
|
margin: 0 0 1.75rem;
|
||||||
|
}
|
||||||
|
.status-chip::before {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
width: 0.5rem;
|
||||||
|
height: 0.5rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--accent);
|
||||||
|
}
|
||||||
|
.status-chip .mono {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
text-transform: none;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home h1 {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: clamp(3.25rem, 10vw, 6.5rem);
|
||||||
|
line-height: 0.95;
|
||||||
|
letter-spacing: -0.035em;
|
||||||
|
margin: 0 0 1.5rem;
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.home .lede {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: clamp(1.15rem, 1.8vw, 1.375rem);
|
||||||
|
line-height: 1.4;
|
||||||
|
letter-spacing: -0.005em;
|
||||||
|
color: var(--fg-muted);
|
||||||
|
margin: 0;
|
||||||
|
max-width: 36rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Body prose ──────────────────────────────────────────────── */
|
||||||
|
|
||||||
|
.prose {
|
||||||
|
max-width: var(--measure);
|
||||||
|
}
|
||||||
|
.prose p {
|
||||||
|
margin: 0 0 1.2rem;
|
||||||
|
letter-spacing: -0.003em;
|
||||||
|
}
|
||||||
|
.prose p:last-child { margin-bottom: 0; }
|
||||||
|
|
||||||
|
.prose strong {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose a {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: color-mix(in srgb, var(--accent) 35%, transparent);
|
||||||
|
text-decoration-thickness: 1px;
|
||||||
|
text-underline-offset: 3px;
|
||||||
|
transition: color 120ms, text-decoration-color 120ms;
|
||||||
|
}
|
||||||
|
.prose a:hover {
|
||||||
|
color: var(--accent-hover);
|
||||||
|
text-decoration-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose em, .prose i { font-style: italic; }
|
||||||
|
|
||||||
|
/* ── Footer ──────────────────────────────────────────────────── */
|
||||||
|
|
||||||
|
.site-footer {
|
||||||
|
margin-top: auto;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
padding-block: 1.25rem;
|
||||||
|
}
|
||||||
|
.site-footer .container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.site-footer .kicker { margin: 0; }
|
||||||
|
.site-footer a {
|
||||||
|
color: var(--fg-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
transition: color 120ms, border-color 120ms;
|
||||||
|
}
|
||||||
|
.site-footer a:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
border-bottom-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Selection + focus ───────────────────────────────────────── */
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background: var(--accent);
|
||||||
|
color: var(--bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus-visible {
|
||||||
|
outline: 2px solid var(--accent);
|
||||||
|
outline-offset: 3px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
18
website/content/_index.de.md
Normal file
18
website/content/_index.de.md
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
title: "Furtka"
|
||||||
|
description: "Offenes Heimserver-Betriebssystem — einfach genug für alle."
|
||||||
|
status: "<span class=\"mono\">26.0-alpha</span> — in Arbeit"
|
||||||
|
---
|
||||||
|
|
||||||
|
**Furtka** ist ein offenes Heimserver-Betriebssystem.
|
||||||
|
USB-Stick einstecken, durch einen Assistenten klicken, und aus jedem
|
||||||
|
alten x86-PC wird eine private Cloud für den Haushalt — mit eigenen
|
||||||
|
Apps, eigener Domain, eigenen Daten.
|
||||||
|
|
||||||
|
Das Ziel ist einfach: **dein Vater soll das einrichten können.**
|
||||||
|
|
||||||
|
Wir sind zu zweit und bauen das öffentlich, abends und am Wochenende.
|
||||||
|
Es ist früh. Außer uns selbst sollte das noch niemand benutzen.
|
||||||
|
Sobald es etwas Echtes zu zeigen gibt, steht es hier.
|
||||||
|
|
||||||
|
Mitlesen? Schreib an <a href="mailto:hallo@furtka.org">hallo@furtka.org</a>.
|
||||||
18
website/content/_index.md
Normal file
18
website/content/_index.md
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
title: "Furtka"
|
||||||
|
description: "Open-source home server OS — simple enough for everyone."
|
||||||
|
status: "<span class=\"mono\">26.0-alpha</span> — work in progress"
|
||||||
|
---
|
||||||
|
|
||||||
|
**Furtka** is an open-source home server OS.
|
||||||
|
Boot from USB, click through a wizard, and any old x86 PC
|
||||||
|
turns into a private cloud for your household — with your own apps,
|
||||||
|
your own domain, your own data.
|
||||||
|
|
||||||
|
The goal is simple: **your dad should be able to set this up.**
|
||||||
|
|
||||||
|
We're two people building it in public on evenings and weekends,
|
||||||
|
and it's early. Nothing here is ready for other people yet.
|
||||||
|
When there's something real to show, this page will say so.
|
||||||
|
|
||||||
|
Want to follow along? Write to <a href="mailto:hallo@furtka.org">hallo@furtka.org</a>.
|
||||||
22
website/deploy.sh
Executable file
22
website/deploy.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Deploy furtka.org to forge-runner-01.
|
||||||
|
# Rsyncs the Hugo source up to the VM and builds it in-place.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
HOST="${FURTKA_HOST:-forge-runner}"
|
||||||
|
SRCROOT="/srv/furtka-site"
|
||||||
|
WEBROOT="/var/www/furtka.org"
|
||||||
|
|
||||||
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
|
||||||
|
echo "→ rsync website/ to $HOST:$SRCROOT"
|
||||||
|
rsync -az --delete \
|
||||||
|
--exclude='.hugo_build.lock' \
|
||||||
|
--exclude='public/' \
|
||||||
|
--exclude='resources/' \
|
||||||
|
"$HERE/" "$HOST:$SRCROOT/"
|
||||||
|
|
||||||
|
echo "→ build on $HOST"
|
||||||
|
ssh "$HOST" "cd $SRCROOT && hugo --minify --cleanDestinationDir -d $WEBROOT"
|
||||||
|
|
||||||
|
echo "OK: deployed to https://furtka.org/"
|
||||||
36
website/hugo.toml
Normal file
36
website/hugo.toml
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
baseURL = "https://furtka.org/"
|
||||||
|
title = "Furtka"
|
||||||
|
defaultContentLanguage = "en"
|
||||||
|
defaultContentLanguageInSubdir = false
|
||||||
|
enableRobotsTXT = true
|
||||||
|
|
||||||
|
[params]
|
||||||
|
description = "Open-source home server OS — simple enough for everyone."
|
||||||
|
version = "26.0-alpha"
|
||||||
|
contactEmail = "hallo@furtka.org"
|
||||||
|
|
||||||
|
[markup.goldmark.renderer]
|
||||||
|
unsafe = true
|
||||||
|
|
||||||
|
[languages]
|
||||||
|
[languages.en]
|
||||||
|
languageCode = "en-us"
|
||||||
|
languageName = "English"
|
||||||
|
title = "Furtka"
|
||||||
|
weight = 1
|
||||||
|
[languages.en.params]
|
||||||
|
description = "Open-source home server OS — simple enough for everyone."
|
||||||
|
|
||||||
|
[languages.de]
|
||||||
|
languageCode = "de-de"
|
||||||
|
languageName = "Deutsch"
|
||||||
|
title = "Furtka"
|
||||||
|
weight = 2
|
||||||
|
[languages.de.params]
|
||||||
|
description = "Offenes Heimserver-Betriebssystem — einfach genug für alle."
|
||||||
|
|
||||||
|
[build]
|
||||||
|
writeStats = true
|
||||||
|
|
||||||
|
[minify]
|
||||||
|
minifyOutput = true
|
||||||
13
website/layouts/_default/baseof.html
Normal file
13
website/layouts/_default/baseof.html
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ .Site.Language.Lang }}">
|
||||||
|
<head>
|
||||||
|
{{ partial "head.html" . }}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{ partial "header.html" . }}
|
||||||
|
<main class="container">
|
||||||
|
{{ block "main" . }}{{ end }}
|
||||||
|
</main>
|
||||||
|
{{ partial "footer.html" . }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
website/layouts/_default/list.html
Normal file
21
website/layouts/_default/list.html
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{{ define "main" }}
|
||||||
|
<article>
|
||||||
|
<header class="page-header">
|
||||||
|
<h1>{{ .Title }}</h1>
|
||||||
|
{{ with .Params.description }}<p class="lede">{{ . }}</p>{{ end }}
|
||||||
|
</header>
|
||||||
|
<div class="prose{{ if .Params.wide }} prose--wide{{ end }}">
|
||||||
|
{{ .Content }}
|
||||||
|
</div>
|
||||||
|
{{ with .Pages }}
|
||||||
|
<ul class="post-list">
|
||||||
|
{{ range . }}
|
||||||
|
<li>
|
||||||
|
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
|
||||||
|
{{ with .Date }}<time datetime="{{ .Format "2006-01-02" }}">{{ .Format "2006-01-02" }}</time>{{ end }}
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
|
{{ end }}
|
||||||
|
</article>
|
||||||
|
{{ end }}
|
||||||
11
website/layouts/_default/single.html
Normal file
11
website/layouts/_default/single.html
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{{ define "main" }}
|
||||||
|
<article>
|
||||||
|
<header class="page-header">
|
||||||
|
<h1>{{ .Title }}</h1>
|
||||||
|
{{ with .Params.description }}<p class="lede">{{ . }}</p>{{ end }}
|
||||||
|
</header>
|
||||||
|
<div class="prose{{ if .Params.wide }} prose--wide{{ end }}">
|
||||||
|
{{ .Content }}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{{ end }}
|
||||||
14
website/layouts/index.html
Normal file
14
website/layouts/index.html
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{{ define "main" }}
|
||||||
|
<article class="home">
|
||||||
|
<header class="hero">
|
||||||
|
{{ with .Params.status }}
|
||||||
|
<p class="status-chip">{{ . | safeHTML }}</p>
|
||||||
|
{{ end }}
|
||||||
|
<h1>{{ .Title }}</h1>
|
||||||
|
{{ with site.Params.description }}<p class="lede">{{ . }}</p>{{ end }}
|
||||||
|
</header>
|
||||||
|
<div class="prose">
|
||||||
|
{{ .Content }}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{{ end }}
|
||||||
9
website/layouts/partials/footer.html
Normal file
9
website/layouts/partials/footer.html
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<footer class="site-footer">
|
||||||
|
<div class="container">
|
||||||
|
<p class="kicker">
|
||||||
|
Furtka <span style="letter-spacing:0.04em">{{ site.Params.version }}</span>
|
||||||
|
· AGPL-3.0 ·
|
||||||
|
<a href="mailto:{{ site.Params.contactEmail }}">{{ site.Params.contactEmail }}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
6
website/layouts/partials/gate.html
Normal file
6
website/layouts/partials/gate.html
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg class="gate-mark" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
|
||||||
|
<path d="M4 20 V12 A9 9 0 0 1 20 12 V20"/>
|
||||||
|
<line x1="12" y1="5" x2="12" y2="20"/>
|
||||||
|
<line x1="3" y1="20" x2="21" y2="20"/>
|
||||||
|
<line x1="15" y1="12" x2="15" y2="14.5"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 384 B |
16
website/layouts/partials/head.html
Normal file
16
website/layouts/partials/head.html
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>{{ if .IsHome }}{{ site.Title }} — {{ site.Params.description }}{{ else }}{{ .Title }} · {{ site.Title }}{{ end }}</title>
|
||||||
|
<meta name="description" content="{{ with .Params.description }}{{ . }}{{ else }}{{ site.Params.description }}{{ end }}">
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||||
|
<meta property="og:site_name" content="{{ site.Title }}">
|
||||||
|
<meta property="og:title" content="{{ if .IsHome }}{{ site.Title }}{{ else }}{{ .Title }} · {{ site.Title }}{{ end }}">
|
||||||
|
<meta property="og:description" content="{{ with .Params.description }}{{ . }}{{ else }}{{ site.Params.description }}{{ end }}">
|
||||||
|
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}">
|
||||||
|
<meta property="og:url" content="{{ .Permalink }}">
|
||||||
|
{{ $parts := split .Site.Language.LanguageCode "-" }}<meta property="og:locale" content="{{ index $parts 0 }}{{ if gt (len $parts) 1 }}_{{ upper (index $parts 1) }}{{ end }}">
|
||||||
|
{{ range .AllTranslations }}
|
||||||
|
<link rel="alternate" hreflang="{{ .Lang }}" href="{{ .Permalink }}">
|
||||||
|
{{ end }}
|
||||||
|
{{ $css := resources.Get "css/main.css" | minify | fingerprint }}
|
||||||
|
<link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}">
|
||||||
9
website/layouts/partials/header.html
Normal file
9
website/layouts/partials/header.html
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="container">
|
||||||
|
<a href="{{ if eq .Site.Language.Lang "de" }}/de/{{ else }}/{{ end }}" class="site-title" aria-label="Furtka — home">
|
||||||
|
{{ partial "gate.html" . }}
|
||||||
|
<span class="wordmark">Furtka</span>
|
||||||
|
</a>
|
||||||
|
{{ partial "lang-switcher.html" . }}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
23
website/layouts/partials/lang-switcher.html
Normal file
23
website/layouts/partials/lang-switcher.html
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<ul class="lang-switcher" aria-label="Language">
|
||||||
|
{{ $current := .Site.Language.Lang }}
|
||||||
|
{{ range site.Languages }}
|
||||||
|
{{ $lang := . }}
|
||||||
|
{{ $link := "" }}
|
||||||
|
{{ if eq .Lang $current }}
|
||||||
|
{{ $link = $.Permalink }}
|
||||||
|
{{ else }}
|
||||||
|
{{ with (where $.AllTranslations "Lang" .Lang) }}
|
||||||
|
{{ $link = (index . 0).Permalink }}
|
||||||
|
{{ else }}
|
||||||
|
{{ if eq $lang.Lang "en" }}
|
||||||
|
{{ $link = "/" }}
|
||||||
|
{{ else }}
|
||||||
|
{{ $link = printf "/%s/" $lang.Lang }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
<li{{ if eq .Lang $current }} class="is-active"{{ end }}>
|
||||||
|
<a href="{{ $link }}" lang="{{ .Lang }}"{{ if eq .Lang $current }} aria-current="true"{{ end }}>{{ upper .Lang }}</a>
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
6
website/static/favicon.svg
Normal file
6
website/static/favicon.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#a33e2e" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M4 20 V12 A9 9 0 0 1 20 12 V20"/>
|
||||||
|
<line x1="12" y1="5" x2="12" y2="20"/>
|
||||||
|
<line x1="3" y1="20" x2="21" y2="20"/>
|
||||||
|
<line x1="15" y1="12" x2="15" y2="14.5"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 334 B |
Loading…
Add table
Reference in a new issue