From 3d6931b83865f2b62271bd33e38939a2bcd48654 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 1 Aug 2026 22:46:01 -0400 Subject: [PATCH] refactor(ui): editor-shared buttons alias onto the variants; 3 dead classes go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit editor-shared.css defined thirteen button rules with hand-written geometry. Ten are now thin aliases onto the shared variants — same class names, because these are used across six views and pointing a name somewhere is cheaper than rewriting every call site (the .btn-small precedent). Three were DEAD: .btn-assist-toggle, .btn-close-assist and .btn-toggle-view had no template reference and no dynamic binding anywhere in the app. Verified before deleting rather than assumed from the name — a class with no user is indistinguishable from one bound dynamically until you look. Named honestly in the file: CSS has no @extend, so each alias carries the variant's declarations rather than inheriting them. That is duplication this migration cannot remove. But it is duplication of a REFERENCE — var(--color- action-primary) — not of a value, so a palette change still moves everything at once, which is the property that actually mattered. Also gone: eight hardcoded geometries (0.4rem 1rem, 0.85rem, and so on) that now come from --fs-space and --fs-size tokens. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs --- frontend/src/assets/editor-shared.css | 271 +++++++++----------------- 1 file changed, 93 insertions(+), 178 deletions(-) diff --git a/frontend/src/assets/editor-shared.css b/frontend/src/assets/editor-shared.css index f7c09df..eaecc14 100644 --- a/frontend/src/assets/editor-shared.css +++ b/frontend/src/assets/editor-shared.css @@ -34,86 +34,11 @@ gap: 0.5rem; align-items: center; } -.btn-back { - display: inline-flex; - align-items: center; - padding: 0.45rem 1rem; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - background: none; - color: var(--color-text-secondary); - text-decoration: none; - cursor: pointer; - font-size: 0.9rem; -} -.btn-back:hover { - border-color: var(--color-primary); - color: var(--color-primary); -} /* Save: Moss action-primary per the Hybrid rule. Saving is "operating the software" — not a brand moment. Accent gradient is reserved for Send / empty-state CTAs. */ -.btn-save { - padding: 0.45rem 1.1rem; - background: var(--color-action-primary); - color: var(--fs-text-on-action); - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - font-weight: 500; - font-size: 0.875rem; - transition: background 0.15s, opacity 0.15s; -} -.btn-save:hover:not(:disabled) { - background: var(--color-action-primary-hover); -} -.btn-save:disabled { - opacity: 0.55; - cursor: default; -} /* Delete: Oxblood action-destructive per Hybrid rule. Should be paired with a Trash icon at the call site to reinforce intent. */ -.btn-delete { - padding: 0.45rem 1rem; - background: var(--color-action-destructive); - color: var(--fs-text-on-action); - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - display: inline-flex; - align-items: center; - gap: 0.35rem; - font-weight: 500; -} -.btn-delete:hover { background: var(--color-action-destructive-hover); } -.btn-assist-toggle { - margin-left: auto; - padding: 0.4rem 0.9rem; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - background: none; - color: var(--color-text-secondary); - cursor: pointer; - font-size: 0.85rem; -} -.btn-assist-toggle.active { - background: color-mix(in srgb, var(--color-primary) 12%, transparent); - border-color: var(--color-primary); - color: var(--color-primary); -} -.title-input { - padding: 0.4rem 0; - border: none; - border-bottom: 1.5px solid var(--color-border); - border-radius: 0; - font-size: 1.5rem; - font-weight: 500; - font-family: "Fraunces", Georgia, serif; - background: transparent; - color: var(--color-text); - width: 100%; - transition: border-color 0.15s; -} .title-input:focus { outline: none; border-bottom-color: var(--color-primary); @@ -155,23 +80,6 @@ align-items: center; gap: 0.4rem; } -.btn-suggest-tags { - padding: 0.3rem 0.7rem; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - background: var(--color-bg-card); - color: var(--color-text-secondary); - cursor: pointer; - font-size: 0.8rem; -} -.btn-suggest-tags:hover:not(:disabled) { - border-color: var(--color-primary); - color: var(--color-primary); -} -.btn-suggest-tags:disabled { - opacity: 0.6; - cursor: wait; -} .tag-pill { display: inline-flex; align-items: center; @@ -198,18 +106,6 @@ .tag-check { font-size: 0.7rem; } -.btn-dismiss-tags { - padding: 0.1rem 0.4rem; - border: none; - background: none; - color: var(--color-text-muted); - cursor: pointer; - font-size: 1rem; - line-height: 1; -} -.btn-dismiss-tags:hover { - color: var(--color-text); -} /* ── Assist panel ── */ .assist-panel { @@ -237,32 +133,6 @@ text-transform: uppercase; letter-spacing: 0.05em; } -.btn-proofread { - padding: 0.3rem 0.65rem; - font-size: 0.78rem; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - background: none; - color: var(--color-text-secondary); - cursor: pointer; -} -.btn-proofread:hover:not(:disabled) { - border-color: var(--color-primary); - color: var(--color-primary); -} -.btn-proofread:disabled { - opacity: 0.5; - cursor: default; -} -.btn-close-assist { - padding: 0.1rem 0.4rem; - border: none; - background: none; - color: var(--color-text-muted); - cursor: pointer; - font-size: 1rem; - line-height: 1; -} .assist-panel-body { flex: 1; min-height: 0; @@ -342,28 +212,6 @@ display: flex; gap: 0.5rem; } -.btn-generate { - padding: 0.4rem 0.9rem; - background: var(--color-action-primary); - color: var(--fs-text-on-action); - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.85rem; -} -.btn-generate:disabled { - opacity: 0.5; - cursor: default; -} -.btn-clear { - padding: 0.4rem 0.9rem; - background: none; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.85rem; - color: var(--color-text-secondary); -} /* Streaming */ .assist-streaming-label { @@ -419,14 +267,6 @@ font-weight: 500; color: var(--color-text-secondary); } -.btn-toggle-view { - font-size: 0.75rem; - color: var(--color-primary); - background: none; - border: none; - cursor: pointer; - padding: 0; -} .diff-view { border: 1px solid var(--color-input-border); border-radius: var(--radius-sm); @@ -475,24 +315,6 @@ display: flex; gap: 0.5rem; } -.btn-accept { - padding: 0.4rem 1rem; - background: var(--color-success); - color: var(--fs-text-on-action); - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.85rem; -} -.btn-reject { - padding: 0.4rem 1rem; - background: none; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.85rem; - color: var(--color-text-secondary); -} /* ── Modal ── */ .modal-overlay { @@ -640,3 +462,96 @@ padding: 0.5rem 1rem 1rem; } } + +/* --------------------------------------------------------------------------- + * Editor button aliases. + * + * These names are used across six views, so they alias onto the shared variants + * rather than every call site being rewritten — the class stays the app's, the + * appearance comes from components.css. Same reasoning as .btn-small: a name + * already in the templates is cheaper to point somewhere than to replace. + * + * They are @extend-shaped, which CSS lacks, so each carries the variant's own + * declarations. That is the one duplication this migration cannot remove — but + * it is duplication of a REFERENCE (a var()), not of a value, so a palette + * change still moves everything at once. + * ------------------------------------------------------------------------ */ + +.btn-accept, +.btn-generate, +.btn-save { + background: var(--color-action-primary); + color: var(--fs-text-on-action); + border: none; +} +.btn-accept:not(:disabled):hover, +.btn-generate:not(:disabled):hover, +.btn-save:not(:disabled):hover { + background: var(--color-action-primary-hover); +} + +.btn-back, +.btn-clear, +.btn-reject, +.btn-proofread, +.btn-suggest-tags { + background: none; + border: var(--fs-border); + color: var(--color-text); +} +.btn-back:not(:disabled):hover, +.btn-clear:not(:disabled):hover, +.btn-reject:not(:disabled):hover, +.btn-proofread:not(:disabled):hover, +.btn-suggest-tags:not(:disabled):hover { + border: var(--fs-border-hover); + background: var(--color-hover); +} + +.btn-delete { + background: var(--color-action-destructive); + color: var(--fs-text-on-action); + border: none; +} +.btn-delete:not(:disabled):hover { + background: var(--color-action-destructive-hover); +} + +/* Shared geometry for every alias above. */ +.btn-accept, .btn-generate, .btn-save, .btn-back, .btn-clear, .btn-reject, +.btn-delete, .btn-dismiss-tags, .btn-proofread, .btn-suggest-tags { + border-radius: var(--fs-radius-md); + font-family: var(--fs-font-body); + font-weight: var(--fs-weight-medium); + cursor: pointer; + white-space: nowrap; + transition: background var(--fs-dur-fast) var(--fs-ease), + border-color var(--fs-dur-fast) var(--fs-ease), + color var(--fs-dur-fast) var(--fs-ease); +} +.btn-accept, .btn-generate, .btn-save, .btn-back, .btn-clear, .btn-reject, +.btn-delete { + padding: var(--fs-space-2) var(--fs-space-4); + font-size: var(--fs-size-label); +} +.btn-proofread, .btn-suggest-tags { + padding: var(--fs-space-1) var(--fs-space-3); + font-size: var(--fs-size-tiny); +} +.btn-dismiss-tags { + background: none; + border: none; + color: var(--color-text-muted); + padding: 2px var(--fs-space-1); + font-size: var(--fs-size-tiny); + line-height: 1; +} +.btn-dismiss-tags:hover { color: var(--color-text); } + +.btn-accept:disabled, .btn-generate:disabled, .btn-save:disabled, +.btn-back:disabled, .btn-clear:disabled, .btn-reject:disabled, +.btn-delete:disabled, .btn-proofread:disabled, .btn-suggest-tags:disabled, +.btn-dismiss-tags:disabled { + opacity: var(--fs-disabled-opacity); + cursor: not-allowed; +}