From 67fdf7c55b2683aa8b78be40d3235f7cfbe72ca1 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 1 Aug 2026 22:42:14 -0400 Subject: [PATCH] refactor(ui): auth views migrate onto the shared buttons; two variants added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The five auth views each defined .btn-submit identically — full-width, filled, 0.6rem — and LoginView additionally defined .btn-oauth. Those rules are now gone entirely rather than tokenised: the template composes `btn-primary btn-block` and `btn-ghost btn-block`, and there is nothing left per-file to drift. That is the difference between this and the earlier chunks. Consolidating the core four moved geometry into one place but left every semantic name defining its own; this removes the definition. Two variants added, both earned rather than invented: - .btn-text — no fill, no border. The most common shape in the dense surfaces (dismiss, cancel-beside-confirm, clear-search) where a border would draw a box around something that should read as an action on the adjacent text. Distinct from ghost, which IS a box. - .btn-danger-outline — already existed independently in three views before this sheet, which is what makes it a variant and not a one-off. It is what a delete looks like when it must not shout. .btn-block composes with a variant rather than being one, because width is orthogonal to appearance. Also corrected the sheet's own header, which claimed "no template changes" — true when it was written, false as of this commit. It now states the actual model: a button is variant + size, composed in the template. Semantic per-view names are named as the thing that drifted, and why: a name says what a button is FOR and nothing about what it should look like, so two buttons doing the same job in two views had no reason to match, and didn't. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs --- frontend/src/assets/components.css | 68 +++++++++++++++++++++-- frontend/src/views/ForgotPasswordView.vue | 20 +------ frontend/src/views/LoginView.vue | 36 +----------- frontend/src/views/RegisterInviteView.vue | 20 +------ frontend/src/views/RegisterView.vue | 20 +------ frontend/src/views/ResetPasswordView.vue | 20 +------ 6 files changed, 68 insertions(+), 116 deletions(-) diff --git a/frontend/src/assets/components.css b/frontend/src/assets/components.css index e9632a2..2b9c148 100644 --- a/frontend/src/assets/components.css +++ b/frontend/src/assets/components.css @@ -9,9 +9,19 @@ * because a scoped duplicate is invisible to every tool — it isn't a rule * violation, isn't a broken reference, and isn't a recorded snippet. * - * GEOMETRY LIVES HERE; the class names are the app's existing ones so no - * template changes. Every value is a design-system token, so a palette or scale - * change moves the buttons rather than stranding a copy that no longer matches. + * GEOMETRY LIVES HERE. Every value is a design-system token, so a palette or + * scale change moves the buttons rather than stranding a copy that no longer + * matches. + * + * A button is `variant + size`, composed in the template: + * btn-primary a page action + * btn-primary btn-compact a row action + * btn-ghost btn-inline an affordance inside a card + * btn-primary btn-block a form's single submitting action + * Semantic per-view names (.btn-save, .btn-delete-task, …) were the thing that + * drifted, because a name says what a button is FOR and nothing about what it + * should look like — so two buttons doing the same job in two views had no + * reason to match, and didn't. * * MIGRATION NOTE — this file is deliberately safe to land ahead of the removals. * These are plain selectors (specificity 0,1,0); a Vue `