From 012caf567206b7b85fbda891cc8a0a6071337e65 Mon Sep 17 00:00:00 2001 From: Pit Friedrich Date: Sun, 9 Aug 2026 18:09:16 +0200 Subject: [PATCH] Build infra + CLAUDE.md --- .gitea/workflows/build.yml | 28 ++++++++++++++++++++ CLAUDE.md | 53 ++++++++++++++++++++++++++++++++++++++ go.mod | 8 +++++- go.sum | 6 +++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 .gitea/workflows/build.yml create mode 100644 CLAUDE.md diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..24edaa1 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,28 @@ +name: Build + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Generate dashboard_gsx.go from dashboard.gsx + run: go run github.com/grindlemire/go-tui/cmd/tui generate ./... + + - name: Build + run: go build -v ./... + + - name: Vet + run: go vet ./... diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..8cbdb3e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,53 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +A terminal dashboard (TUI) built with `github.com/grindlemire/go-tui`, showing simulated CPU/memory/disk gauges, network sparklines, and a scrolling event feed. Single binary, no external services. + +## Commands + +```sh +# Regenerate dashboard_gsx.go from dashboard.gsx (required before build if the .go file is missing/stale) +go run github.com/grindlemire/go-tui/cmd/tui generate ./... + +# Build +go build ./... + +# Vet +go vet ./... + +# Run the app +go run . +``` + +There are no test files in this repo yet. + +## Architecture + +### The .gsx → .go code generation step + +`dashboard.gsx` is the source of truth for the UI. It's written in `.gsx`, a JSX-like DSL (Tailwind-esque `class` strings, `{expr}` interpolation, `for`/`if` control flow, a `templ` method that compiles to `Render`) provided by the `go-tui` module. **`dashboard_gsx.go` is generated output — do not hand-edit it.** It's git-ignored and carries a `// Code generated by tui generate. DO NOT EDIT.` header. + +To change the UI: edit `dashboard.gsx`, then run `go run github.com/grindlemire/go-tui/cmd/tui generate ./...` to regenerate `dashboard_gsx.go`. Non-templ Go code (helper funcs, the `dashboardApp` struct, `produceEvents`, etc.) also lives in `dashboard.gsx` — the whole file is the source, not just the template block. + +The `tui` CLI is wired into `go.mod` as a Go 1.24+ `tool` dependency (`tool github.com/grindlemire/go-tui/cmd/tui`), which is why `go.sum` carries `golang.org/x/tools` etc. even though the app code doesn't import them directly. Don't `go mod tidy` this away — it strips the generator's transitive deps and breaks `go run .../cmd/tui generate`. + +CI (`.gitea/workflows/build.yml`) regenerates `dashboard_gsx.go` from scratch on every run before building, so the generated file never needs to be committed or kept in sync manually. + +### App structure (go-tui conventions) + +- `main.go` wires up `tui.NewApp(tui.WithRootComponent(Dashboard(eventCh)), tui.WithMouse())` and runs it. A background goroutine (`produceEvents`) pushes random events onto `eventCh`. +- `dashboardApp` (defined in `dashboard.gsx`) is the root component. It implements several go-tui interfaces, each independently optional and picked up via interface satisfaction (see the compile-time checks at the bottom of the generated file): + - `KeyMap() tui.KeyMap` — key bindings (`q`/Esc to quit, `j`/`k`/arrows to scroll). + - `HandleMouse(tui.MouseEvent) bool` — mouse wheel scroll support. + - `Watchers() []tui.Watcher` — background subscriptions: a 500ms timer (`updateMetrics`, simulates metric drift) and a channel watch (`addEvent`, consumes `eventCh`). + - `Render(*tui.App) *tui.Element` — the generated view tree (from the `templ` block). + - `BindApp(*tui.App)` — generated; wires every `*tui.State[T]` field to the app so state changes trigger re-renders. If you override `BindApp` yourself, call the generated `bindAppFields` helper rather than re-listing fields. +- All mutable UI state (`cpu`, `mem`, `sparkIn`, `events`, `scrollY`, ...) is `*tui.State[T]`, read via `.Get()` and mutated via `.Set()`. `eventsRef *tui.Ref` gives imperative access to the events panel element (used for `MaxScroll()`/auto-scroll-to-bottom in `addEvent`). +- Adding a new stateful field to `dashboardApp` means: add the `tui.State`/`tui.Ref` field, initialize it in `Dashboard(...)`, use it in the `templ` block — the generator regenerates `bindAppFields` and the compile-time interface checks automatically. + +### CI + +`.gitea/workflows/build.yml` runs on push/PR to `main`: checkout → setup-go (version from `go.mod`) → `tui generate` → `go build` → `go vet`. diff --git a/go.mod b/go.mod index 6395e0e..510a430 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,13 @@ module dashboard go 1.26.5 +require github.com/grindlemire/go-tui v0.19.0 + require ( - github.com/grindlemire/go-tui v0.19.0 // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.40.0 // indirect + golang.org/x/tools v0.41.0 // indirect ) + +tool github.com/grindlemire/go-tui/cmd/tui diff --git a/go.sum b/go.sum index dba9aa6..9ed177c 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,10 @@ github.com/grindlemire/go-tui v0.19.0 h1:4k4MRoYUFChUCfO5Lr4Z05SI3jlTSuH3W1H5/HKVH8s= github.com/grindlemire/go-tui v0.19.0/go.mod h1:95oaPy6Iu6MZpiByUqxYz2Wcbckzvaw3K0jgQeI4dD0= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=