Compare commits

..

1 Commits

Author SHA1 Message Date
1c891cebe6 feat(tuie): drive roast meter from product roast_level field 2026-06-11 16:24:23 +02:00
23 changed files with 14 additions and 68 deletions

1
.gitignore vendored
View File

@@ -7,7 +7,6 @@
docs/sca-psd2-compliance.md
accept-a-payment/
codemap/
FULFILLMENT.md

View File

@@ -1,3 +0,0 @@
// Command api is the HTTP backend: it boots the router, bolts on all the
// middleware, and answers the requests the TUI throws at it.
package main

View File

@@ -1,3 +0,0 @@
// Package handlers is where the real work happens, one function per endpoint:
// carts, orders, products, addresses, cards, webhooks, and the rest.
package handlers

View File

@@ -1,4 +0,0 @@
// Package middleware holds the stuff that runs on every request before a
// handler ever sees it: auth, CORS, logging, rate limiting, metrics, and a
// recovery net for panics.
package middleware

View File

@@ -1,3 +0,0 @@
// Package routes is the switchboard: it maps every URL to the handler that
// knows what to do with it.
package routes

View File

@@ -1,3 +0,0 @@
// Command reconcile-cards hunts down saved cards that Stripe no longer knows
// about and detaches them. Run it with -dry-run first if you're nervous.
package main

View File

@@ -1,3 +0,0 @@
// Package api is the client side of the house: it talks to our HTTP backend
// so other Go code doesn't have to hand-roll requests.
package api

View File

@@ -1,3 +0,0 @@
// Package auth sorts out who you are: logging in with an SSH key and minting
// the JWT you carry around afterwards.
package auth

View File

@@ -1,3 +0,0 @@
// Package bring talks to Bring, the Norwegian postal service, for booking
// shipments and printing labels.
package bring

View File

@@ -1,3 +0,0 @@
// Package config reads everything out of the environment so secrets and
// settings stay out of the source code.
package config

View File

@@ -1,3 +0,0 @@
// Package database opens the SQLite connection, runs the migrations, and
// drops in some seed data so the shop isn't empty on a fresh boot.
package database

View File

@@ -1,3 +0,0 @@
// Package models is the shared vocabulary of the app: coffee, carts, orders,
// addresses, cards, users, and the other nouns everything passes around.
package models

View File

@@ -1,3 +0,0 @@
// Package observability sets up tracing and structured logs so that when
// something breaks at 3am you stand a chance of figuring out why.
package observability

View File

@@ -1,3 +0,0 @@
// Package shipping holds the plain shipping types that the rest of the app
// passes back and forth.
package shipping

View File

@@ -1,2 +0,0 @@
// Package shippo talks to the Shippo API for shipping rates and labels.
package shippo

View File

@@ -1,3 +0,0 @@
// Package stripeclient wires up the Stripe SDK once at startup (with tracing
// baked in) so everyone else can just make calls.
package stripeclient

View File

@@ -1,3 +0,0 @@
// Package tui is the terminal UI you see over SSH: the shop, the cart, your
// account, and the checkout flow, all drawn with Bubbletea.
package tui

View File

@@ -276,7 +276,9 @@ func (m Model) updatePaymentViewport() Model {
breadH := lipgloss.Height(m.BuildBreadcrumbs())
footerH := lipgloss.Height(m.BuildFooter())
availH := m.heightContainer - headerH - footerH - breadH
availH = max(availH, 1)
if availH < 1 {
availH = 1
}
if !m.payment.viewportReady {
m.payment.viewport = viewport.New(viewport.WithWidth(m.widthContent), viewport.WithHeight(availH))
m.payment.viewport.KeyMap = viewport.KeyMap{}
@@ -301,7 +303,7 @@ func (m Model) PaymentPageView() string {
m.widthContainer,
m.payment.viewport.Height(),
lipgloss.Center, lipgloss.Center,
m.renderPaymentHTTPSView(),
m.renderPaymentHttpsView(),
)
} else if m.payment.view == 0 && m.payment.form == nil {
content = m.RenderCardList()
@@ -372,7 +374,7 @@ func (m Model) RenderCardList() string {
return lipgloss.JoinVertical(lipgloss.Left, parts...)
}
func (m Model) renderPaymentHTTPSView() string {
func (m Model) renderPaymentHttpsView() string {
baseStyle := m.theme.TextLabel()
accentStyle := m.theme.TextHighlight()

View File

@@ -1,3 +0,0 @@
// Package qrfefe turns text into a QR code drawn with terminal block
// characters, handy for showing links you can scan right off the screen.
package qrfefe

View File

@@ -24,7 +24,9 @@ const (
// menu(menuW+4) + gap(1) + detail(detailW+4) = contentW = wideW + 4.
func (m Model) shopLayout() (contentW, menuW, detailW, wideW int) {
contentW = m.widthContent
contentW = min(contentW, 74)
if contentW > 74 {
contentW = 74
}
wideW = contentW - 4
if m.size < large {
// Stacked layout: both panels span the full content width.
@@ -64,7 +66,6 @@ func clampLines(s string, n int) string {
// roastMeter renders the strength dots, e.g. ● ● ● ○ ○
func roastMeter(n int) string {
n = max(0, min(n, 5))
on := lipgloss.NewStyle().Foreground(cGold).Render(strings.Repeat("● ", n))
off := pDim.Render(strings.Repeat("○ ", 5-n))
return strings.TrimRight(on+off, " ")
@@ -217,8 +218,12 @@ func (m Model) shopMoveSelected(previous bool) Model {
} else {
next++
}
next = max(next, 0)
next = min(next, len(m.Coffees)-1)
if next < 0 {
next = 0
}
if next >= len(m.Coffees) {
next = len(m.Coffees) - 1
}
m.shop.selected = next
return m
}

View File

@@ -1,3 +0,0 @@
// Package theme keeps the colors and styles in one spot so the whole UI
// looks like it was built by the same person.
package theme

View File

@@ -1,3 +0,0 @@
// Package utils is the catch-all drawer for tiny HTTP helpers that didn't
// earn a package of their own.
package utils

View File

@@ -1,3 +0,0 @@
// Package validate gives user input a once-over before the rest of the app
// trusts it.
package validate