No backend, no build step -- static HTML/CSS/JS, themed identically to flit/wisp (same CSS vars, same "> " title prefix, same dark/mono/green aesthetic). Snippets are real, shipped code pulled from six repos in this family (flit, wisp, keep, stash, delve-term, goonk) rather than generic pangrams. Stats: WPM = (correct chars / 5) / minutes elapsed, timing from first keystroke not page load. Accuracy = correct keystrokes / total keystrokes tracked at the keydown level (comparing the pressed key against the exact next expected character before it's inserted), so backspaced-over mistakes still count against it rather than only diffing the final text. Keys/sec updates live via a 200ms tick. Tabs in source are rendered as two spaces so players never need to press Tab -- sidesteps a browser default-Tab-moves-focus fight entirely rather than fighting it with preventDefault. Verified via simulated typing sessions (puppeteer), not just static review -- both an artificially fast pass (confirms the math is internally consistent: 308 correct/310 total keystrokes -> 99%, matches displayed) and a realistic ~60wpm-paced pass (confirms no unit-conversion bug that only a slow, deliberate typist would hit tests-at-lightspeed wouldn't surface). That process caught two real bugs before they'd have hit a real player: 1. A stray `tabindex="0"` on the code display let the browser's native click-to-focus behavior steal focus away from the hidden textarea before our own focus() call ran -- typing silently did nothing. Fixed by removing the tabindex and switching to a mousedown+preventDefault handler instead of click. 2. The help modal's CSS set `display: flex` unconditionally, which (author CSS always beats the UA stylesheet) overrode the `hidden` attribute's default `display: none` -- the modal was invisibly covering the entire viewport and intercepting every click, at all times, whether or not it had been opened. Fixed with an explicit `.modal-overlay:not([hidden])` rule. Also verified the actual Docker image builds and serves correctly (nginx, no build stage needed since there's nothing to compile). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
54 lines
1.7 KiB
YAML
54 lines
1.7 KiB
YAML
name: Docker
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
build-and-push:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Derive image name and tags
|
|
id: meta
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
SERVER_URL="${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-}}"
|
|
REPO="${GITHUB_REPOSITORY:-${GITEA_REPOSITORY:-}}"
|
|
SHA="${GITHUB_SHA:-${GITEA_SHA:-}}"
|
|
if [[ -z "${SERVER_URL}" || -z "${REPO}" || -z "${SHA}" ]]; then
|
|
echo "Missing SERVER_URL/REPO/SHA env vars." >&2; exit 1
|
|
fi
|
|
HOST=$(echo "${SERVER_URL}" | sed 's|https://||;s|http://||')
|
|
IMAGE=$(echo "${HOST}/${REPO}" | tr '[:upper:]' '[:lower:]')
|
|
SHORT_SHA=$(echo "${SHA}" | cut -c1-7)
|
|
echo "host=${HOST}" >> "$GITHUB_OUTPUT"
|
|
echo "image=${IMAGE}" >> "$GITHUB_OUTPUT"
|
|
echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Log in to Gitea container registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ steps.meta.outputs.host }}
|
|
username: ${{ github.actor }}
|
|
# Create a Gitea PAT with packages:write scope and add it as a
|
|
# repository secret named TKNTKN (Settings → Secrets)
|
|
password: ${{ secrets.TKNTKN }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Build and push
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
file: Dockerfile
|
|
push: true
|
|
tags: |
|
|
${{ steps.meta.outputs.image }}:latest
|
|
${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.short_sha }}
|