diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..b5451c2 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,55 @@ +version: '3' + +vars: + REMOTE_MACHINE: bl@flo-homeserver + BINARY_DIR: ./bin + DEV_BINARY_DIR: ./local + BINARY: "{{.BINARY_DIR}}/zeitkort-web-poc" + DEV_BINARY: "{{.DEV_BINARY_DIR}}/" + +tasks: + + build: + desc: runs vet, fmt, and build + deps: [vet, fmt] + cmds: + - rm -rf {{.BINARY_DIR}}/* + - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o {{.BINARY}} . + + dev-build: + desc: runs vet, fmt, and builds dev binary + deps: [vet, fmt] + cmds: + - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o {{.DEV_BINARY}}/zeitkort-web-poc . + + deploy: + desc: build, stage binary, and deploy to remote server (preserves config.json) + deps: [build] + cmds: + - ssh {{.REMOTE_MACHINE}} "mkdir -p /tmp/zeitkort-web-poc-deploy" + - rsync -avz --delete {{.BINARY}} {{.REMOTE_MACHINE}}:/tmp/zeitkort-web-poc-deploy/ + + - ssh -t {{.REMOTE_MACHINE}} "sudo mkdir -p /opt/zeitkort-web-poc && sudo rsync -a /tmp/zeitkort-web-poc-deploy/zeitkort-web-poc /opt/zeitkort-web-poc/zeitkort-web-poc && sudo chown zeitkort-web-poc:zeitkort-web-poc /opt/zeitkort-web-poc/zeitkort-web-poc && sudo systemctl restart zeitkort-web-poc" + + - ssh {{.REMOTE_MACHINE}} "rm -rf /tmp/zeitkort-web-poc-deploy" + + dev-start: + desc: build dev binary, copy assets, and start locally + dir: "{{ .DEV_BINARY }}" + cmds: + - "rm -rf *" + - go tool task dev-build + - "cp ../config.json ." + - "./zeitkort-web-poc -config config.json" + + vet: + cmds: + - go vet ./... + + fmt: + cmds: + - go fmt ./... + + clean: + cmds: + - rm -f {{.BINARY}} diff --git a/static/app.css b/static/app.css index fdac443..de6cda8 100644 --- a/static/app.css +++ b/static/app.css @@ -1,33 +1,38 @@ @import url('https://fonts.googleapis.com/css2?family=Noto+Sans:wght@300;400;500;700&display=swap'); - - *, *::before, *::after { box-sizing: border-box; } :root, [data-theme="light"] { color-scheme: light; + --bg: #f4f1ec; + --bg-panel: rgba(255, 255, 255, 0.85); + --nav-bg: rgba(255, 253, 250, 0.92); + --fg: #1a1d22; --muted: #595f68; --dim: #9299a2; - --border: rgba(26, 29, 34, 0.12); + + --accent: #164f75; + --link: #0f527d; + --accent-bg: rgba(22, 79, 117, 0.07); + --accent-border: #164f75; + + --border: rgba(26, 29, 34, 0.1); --border-soft: rgba(26, 29, 34, 0.06); --dotted: rgba(26, 29, 34, 0.12); - --field-bg: rgba(26, 29, 34, 0.03); + + --field-bg: rgba(255, 253, 250, 0.6); --field-border: rgba(26, 29, 34, 0.18); + --btn-bg: rgba(26, 29, 34, 0.05); --btn-bg-hover: rgba(26, 29, 34, 0.09); --btn-border: rgba(26, 29, 34, 0.18); + --header-border: rgba(26, 29, 34, 0.12); --th-bg: rgba(26, 29, 34, 0.04); - --row-active: rgba(44, 90, 122, 0.06); - --link: #2c5a7a; - --accent: #2c5a7a; - --accent-bg: rgba(44, 90, 122, 0.07); - --accent-border: #2c5a7a; - --nav-bg: rgba(244, 241, 236, 0.6); - --bg-panel: rgba(255, 253, 250, 0.72); + --row-active: rgba(22, 79, 117, 0.06); --notice-fg: #2a6e2a; --notice-bg: rgba(42, 110, 42, 0.06); --notice-border: rgba(42, 110, 42, 0.25); --error-fg: #a03030; --error-bg: rgba(160, 48, 48, 0.06); --error-border: rgba(160, 48, 48, 0.25); @@ -38,53 +43,60 @@ --backdrop: rgba(0, 0, 0, 0.3); --shadow: rgba(0, 0, 0, 0.12); - /* Theme toggle pill */ - --toggle-bg: linear-gradient(135deg, #07070d 0%, #64dcff 100%); + --toggle-bg: linear-gradient(135deg, #24273a 0%, #8aadf4 100%); --toggle-border: rgba(26, 29, 34, 0.2); --toggle-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); } -[data-theme="tokyo"] { - color-scheme: dark; - --bg: #07070d; - --fg: #e8f4ff; - --muted: #a3b3cc; - --dim: #7886a0; - --border: rgba(100, 220, 255, 0.12); - --border-soft: rgba(100, 220, 255, 0.06); - --dotted: rgba(100, 220, 255, 0.1); - --field-bg: rgba(100, 220, 255, 0.04); - --field-border: rgba(100, 220, 255, 0.15); - --btn-bg: rgba(100, 220, 255, 0.06); - --btn-bg-hover: rgba(100, 220, 255, 0.1); - --btn-border: rgba(100, 220, 255, 0.18); - --header-border: rgba(100, 220, 255, 0.12); - --th-bg: rgba(100, 220, 255, 0.04); - --row-active: rgba(100, 220, 255, 0.06); - --link: #64dcff; - --accent: #64dcff; - --accent-bg: rgba(100, 220, 255, 0.06); - --accent-border: #64dcff; - --nav-bg: rgba(7, 7, 13, 0.65); - --bg-panel: rgba(15, 16, 28, 0.72); +[data-theme="macchiato"] { + color-scheme: dark; - --notice-fg: #8fe08f; --notice-bg: rgba(143, 224, 143, 0.06); --notice-border: rgba(143, 224, 143, 0.25); - --error-fg: #ff9b9b; --error-bg: rgba(255, 155, 155, 0.06); --error-border: rgba(255, 155, 155, 0.2); - --go-bg: rgba(80, 200, 80, 0.08); --go-border: rgba(80, 200, 80, 0.3); --go-bg-hover: rgba(80, 200, 80, 0.14); - --stop-bg: rgba(200, 80, 80, 0.08); --stop-border: rgba(200, 80, 80, 0.3); --stop-bg-hover: rgba(200, 80, 80, 0.14); - --card-bg: #0f1018; --card-border: rgba(200, 80, 80, 0.4); - --danger-btn-bg: rgba(200, 80, 80, 0.1); --danger-btn-bg-hover: rgba(200, 80, 80, 0.18); + --bg: #181926; + --bg-panel: #24273a; + --nav-bg: rgba(36, 39, 58, 0.65); + + --fg: #cad3f5; + --muted: #a5adcb; + --dim: #8087a2; + + --accent: #8aadf4; + --link: #8aadf4; + --accent-bg: rgba(138, 173, 244, 0.06); + --accent-border: #8aadf4; + + --border: rgba(165, 173, 203, 0.15); + --border-soft: rgba(165, 173, 203, 0.08); + --dotted: rgba(165, 173, 203, 0.12); + + --field-bg: rgba(138, 173, 244, 0.04); + --field-border: rgba(165, 173, 203, 0.18); + + --btn-bg: rgba(138, 173, 244, 0.06); + --btn-bg-hover: rgba(138, 173, 244, 0.1); + --btn-border: rgba(165, 173, 203, 0.18); + + --header-border: rgba(165, 173, 203, 0.15); + --th-bg: rgba(138, 173, 244, 0.04); + --row-active: rgba(138, 173, 244, 0.06); + + --notice-fg: #a6da95; --notice-bg: rgba(166, 218, 149, 0.06); --notice-border: rgba(166, 218, 149, 0.25); + --error-fg: #f38ba8; --error-bg: rgba(243, 139, 168, 0.06); --error-border: rgba(243, 139, 168, 0.2); + --go-bg: rgba(166, 218, 149, 0.08); --go-border: rgba(166, 218, 149, 0.3); --go-bg-hover: rgba(166, 218, 149, 0.14); + --stop-bg: rgba(243, 139, 168, 0.08); --stop-border: rgba(243, 139, 168, 0.3); --stop-bg-hover: rgba(243, 139, 168, 0.14); + --card-bg: #24273a; --card-border: rgba(243, 139, 168, 0.4); + --danger-btn-bg: rgba(243, 139, 168, 0.1); --danger-btn-bg-hover: rgba(243, 139, 168, 0.18); --backdrop: rgba(0, 0, 0, 0.55); --shadow: rgba(0, 0, 0, 0.5); - --toggle-bg: #f4f1ec; - --toggle-border: rgba(100, 220, 255, 0.4); - --toggle-shadow: 0 0 10px rgba(100, 220, 255, 0.5), 0 0 25px rgba(100, 220, 255, 0.3); + --toggle-bg: #24273a; + --toggle-border: rgba(138, 173, 244, 0.4); + --toggle-shadow: 0 0 10px rgba(138, 173, 244, 0.5), 0 0 25px rgba(138, 173, 244, 0.3); } -[data-theme="tokyo"] select, -[data-theme="tokyo"] option { - background: #0f1018; - color: #e8f4ff; + +[data-theme="macchiato"] select, +[data-theme="macchiato"] option { + background: #24273a; + color: #cad3f5; } html, body { max-width: 100%; overflow-x: hidden; } @@ -122,8 +134,8 @@ header { z-index: 20; transition: background 0.3s ease; } -.brand { justify-self: center; } -nav { justify-self: end; } +.brand { justify-self: center; } +nav { justify-self: end; } .back-link { font-family: 'Noto Sans', sans-serif; @@ -170,9 +182,9 @@ nav { justify-self: end; } color: var(--muted); } -[data-theme="tokyo"] .brand { - color: #e8f4ff; - text-shadow: 0 0 8px rgba(100, 220, 255, 0.3); +[data-theme="macchiato"] .brand { + color: #cad3f5; + text-shadow: 0 0 8px rgba(138, 173, 244, 0.25); } nav a { @@ -214,7 +226,7 @@ footer { } .footer-icon { - color: var(--ink-muted); + color: var(--muted); text-decoration: none; display: flex; align-items: center; @@ -234,8 +246,8 @@ h2 { letter-spacing: -0.02em; } -[data-theme="tokyo"] h2 { - text-shadow: 0 0 10px rgba(100, 220, 255, 0.2); +[data-theme="macchiato"] h2 { + text-shadow: 0 0 10px rgba(138, 173, 244, 0.2); } /* ---- Forms ---- */ @@ -312,10 +324,9 @@ fieldset > .inline { margin-top: 10px; } .clock { font-family: 'Noto Sans', sans-serif; font-size: 1.5rem; font-weight: 700; margin: 0; letter-spacing: -0.02em; } -/* Sticky bar shown only while a timer runs. */ .running-bar { position: sticky; - top: 52px; /* below the header */ + top: 52px; z-index: 15; display: flex; align-items: center; @@ -492,9 +503,28 @@ details.confirm[open]::before { } .theme-toggle:hover { transform: scale(1.08); } +[data-theme="macchiato"] .theme-toggle { + animation: neon-breathe-toggle 4s ease-in-out infinite; +} + +@keyframes neon-breathe-toggle { + 0%, 100% { + box-shadow: + 0 0 10px rgba(138, 173, 244, 0.5), + 0 0 25px rgba(138, 173, 244, 0.3), + 0 0 50px rgba(116, 150, 230, 0.2); + } + 50% { + box-shadow: + 0 0 15px rgba(138, 173, 244, 0.6), + 0 0 35px rgba(138, 173, 244, 0.4), + 0 0 70px rgba(116, 150, 230, 0.25); + } +} + /* ── Hamburger (hidden on desktop) ── */ .nav-hamburger { - display: none; /* shown only at ≤640px */ + display: none; flex-direction: column; gap: 4px; background: none; @@ -609,3 +639,4 @@ details.confirm[open]::before { .reset-note { display: none; } +} diff --git a/templates/page.html b/templates/page.html index 59c0f90..e2e647a 100644 --- a/templates/page.html +++ b/templates/page.html @@ -8,7 +8,8 @@ @@ -36,7 +37,7 @@