pyr0ball created pull request Circuit-Forge/avocet#1

pyr0ball
Wed, 04 Mar 2026 09:24:08 -0800

1#feat: Vue 3 label tab — complete card-stack UI with ASMR bucket UX#

Summary

Full implementation of the Avocet Vue 3 label tab, replacing the previous Streamlit UI with a purpose-built card-stack labeling interface.

Backend

FastAPI skeleton with JSONL helpers (_read_jsonl, _write_jsonl, _append_jsonl)

GET /api/queue — paginated batch fetch from staging JSONL

POST /api/label, /api/skip, /api/discard — write results + undo support

GET /api/config/labels — dynamic label config from label_tool.yaml

SPA serving with Cache-Control: no-cache on / (prevents stale index.html after rebuild)

Bind to 0.0.0.0 for LAN access

Email body HTML stripping via stdlib HTMLParser (no deps)

Frontend (Vue 3 + Pinia + UnoCSS + VueUse)

EmailCard — subject, from/date, body preview with expand/collapse

EmailCardStack — swipe gestures (VueUse useSwipe), depth shadows, dismiss/skip animations

LabelBucketGrid — numpad layout; picks up a card → buttons transform into drop buckets (the ASMR payoff); spring expansion + glow on hover/drop

UndoToast — 5-second countdown, undo button, accessible

useLabelKeyboard — 1-9 hotkeys, h to skip, S/D/U shortcuts, ? for help

useMotion — rich-animation toggle (localStorage cf-avocet-rich-motion)

useHaptics — navigator.vibrate() wrapper with in-app toggle

useEasterEgg — Konami code → hacker mode (terminal green), hired confetti, century mark, clean sweep, midnight labeler, cursor trail

Pinia store — queue buffer, totalRemaining, lastAction for undo, easter egg counters

CircuitForge base theme + Avocet Slate Teal / Russet brand colors; dark mode; self-hosted fonts

Bug Fixes

Queue drain: handleSkip/handleDiscard now call fetchBatch() when buffer drops below 3

Label schema synced across API, _LABEL_META, Vue UI, and classifier_adapters.py (10 labels: new_lead + hired replacing unrelated)

Queue schema normalized after IMAP fetch format changed

start-api polls port readiness instead of blind sleep

manage.sh

start-api — build Vue SPA + start FastAPI on port 8503

stop-api / open-api

Test Plan

./manage.sh start-api — SPA builds, server starts on 8503

Cards render and swipe correctly

Bucket expansion fires when card is picked up

Labels POST correctly, queue drains and refills

Undo recovers last action

Keyboard shortcuts trigger labels

Konami code activates hacker mode

Hired confetti fires on hired label

./manage.sh test — all pytest tests pass