From f491b6d7b99b9604ad2d863e2474261d9670c0c5 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 1 Aug 2026 22:13:58 -0400 Subject: [PATCH] refactor(ui): action buttons stop wearing the accent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 21 buttons filled with --color-primary, which resolves to Scribe's violet accent: every auth Submit (Login, Register, Invite, Forgot, Reset), plus Invite, Add, Confirm, Restore, Generate, Log-save, Subtask-confirm, Toggle-open, the modal primary, the version-restore, the inline-assist button, the milestone-plan actions, the task-advance hover, and both empty-state CTAs. The house style is explicit that the accent never appears on an action button: action colours are universal across the family precisely so a Save button looks identical in every app, while the accent carries identity. Doing both makes the accent mean two things and neither clearly. Operator's call, and the reasoning is worth keeping: the violet-on-Scribe- actions treatment was a deliberate early choice to give the web UI its own personality, made when much more of the app was user-facing. That is no longer true, so consistency is now worth more than the distinction it was buying. Found in two passes, which is the part worth noting. The first scan looked for `.btn-*` and found 13. Seven more were the same thing under different names — .modal-btn-primary, .vh-btn-restore, .inline-assist-btn, .empty-action, .task-advance-btn — plus .ms-plan-actions .btn-primary, a compound override flagged in the previous commit. Searching by naming convention finds what was named consistently, which is never the whole set. Deliberately NOT changed: progress-bar fills, active tab / page / selection states, tag-pill hover, the duration badge, the skip link, the assist pulse. Those are identity and active-state, which is exactly where the accent belongs. After this the accent appears only there, which is what makes it read as identity rather than as decoration. Colour swaps only — 25 lines changed, no geometry, no structure, no templates. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs --- frontend/src/assets/editor-shared.css | 4 ++-- frontend/src/components/HistoryPanel.vue | 2 +- frontend/src/components/TaskLogSection.vue | 2 +- frontend/src/components/VersionHistorySection.vue | 2 +- frontend/src/components/WorkspaceNoteEditor.vue | 2 +- frontend/src/components/WorkspaceTaskPanel.vue | 2 +- frontend/src/views/ForgotPasswordView.vue | 2 +- frontend/src/views/LoginView.vue | 2 +- frontend/src/views/NoteEditorView.vue | 2 +- frontend/src/views/ProjectListView.vue | 8 ++++---- frontend/src/views/ProjectView.vue | 4 ++-- frontend/src/views/RegisterInviteView.vue | 2 +- frontend/src/views/RegisterView.vue | 2 +- frontend/src/views/ResetPasswordView.vue | 2 +- frontend/src/views/SnippetListView.vue | 6 +++--- frontend/src/views/TaskEditorView.vue | 2 +- frontend/src/views/UserManagementView.vue | 4 ++-- 17 files changed, 25 insertions(+), 25 deletions(-) diff --git a/frontend/src/assets/editor-shared.css b/frontend/src/assets/editor-shared.css index dcd044af..f7c09df1 100644 --- a/frontend/src/assets/editor-shared.css +++ b/frontend/src/assets/editor-shared.css @@ -344,7 +344,7 @@ } .btn-generate { padding: 0.4rem 0.9rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); @@ -547,7 +547,7 @@ z-index: 100; transform: translateX(-50%); padding: 0.3rem 0.75rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); diff --git a/frontend/src/components/HistoryPanel.vue b/frontend/src/components/HistoryPanel.vue index c91a9c86..a4c72ba6 100644 --- a/frontend/src/components/HistoryPanel.vue +++ b/frontend/src/components/HistoryPanel.vue @@ -395,7 +395,7 @@ onMounted(loadVersions); .btn-restore { padding: 0.45rem 1rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); diff --git a/frontend/src/components/TaskLogSection.vue b/frontend/src/components/TaskLogSection.vue index 3f734e05..803890b0 100644 --- a/frontend/src/components/TaskLogSection.vue +++ b/frontend/src/components/TaskLogSection.vue @@ -311,7 +311,7 @@ onMounted(loadLogs); .btn-log-save { margin-left: auto; padding: 0.3rem 0.75rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); diff --git a/frontend/src/components/VersionHistorySection.vue b/frontend/src/components/VersionHistorySection.vue index 6113d250..199d606f 100644 --- a/frontend/src/components/VersionHistorySection.vue +++ b/frontend/src/components/VersionHistorySection.vue @@ -236,7 +236,7 @@ function restore() { .vh-btn-back:hover { border-color: var(--color-primary); color: var(--color-primary); } .vh-btn-restore { - background: var(--color-primary); + background: var(--color-action-primary); border: none; border-radius: var(--radius-sm); padding: 0.25rem 0.6rem; diff --git a/frontend/src/components/WorkspaceNoteEditor.vue b/frontend/src/components/WorkspaceNoteEditor.vue index 975c71e8..ee3a7b5b 100644 --- a/frontend/src/components/WorkspaceNoteEditor.vue +++ b/frontend/src/components/WorkspaceNoteEditor.vue @@ -670,7 +670,7 @@ defineExpose({ reload: loadProjectNotes }); .new-note-input:focus { outline: none; } .btn-confirm { - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: 4px; diff --git a/frontend/src/components/WorkspaceTaskPanel.vue b/frontend/src/components/WorkspaceTaskPanel.vue index 95044785..dff15cdf 100644 --- a/frontend/src/components/WorkspaceTaskPanel.vue +++ b/frontend/src/components/WorkspaceTaskPanel.vue @@ -397,7 +397,7 @@ defineExpose({ reload: loadAll }); .task-add-input:focus { outline: none; border-color: var(--color-primary); } .btn-add { - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: 5px; diff --git a/frontend/src/views/ForgotPasswordView.vue b/frontend/src/views/ForgotPasswordView.vue index e274c381..d43bbf8c 100644 --- a/frontend/src/views/ForgotPasswordView.vue +++ b/frontend/src/views/ForgotPasswordView.vue @@ -140,7 +140,7 @@ async function handleSubmit() { .btn-submit { width: 100%; padding: 0.6rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); diff --git a/frontend/src/views/LoginView.vue b/frontend/src/views/LoginView.vue index 4098d427..3eb05dae 100644 --- a/frontend/src/views/LoginView.vue +++ b/frontend/src/views/LoginView.vue @@ -179,7 +179,7 @@ function loginWithOAuth() { .btn-submit { width: 100%; padding: 0.6rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); diff --git a/frontend/src/views/NoteEditorView.vue b/frontend/src/views/NoteEditorView.vue index 8dd5890b..b7d1d6a6 100644 --- a/frontend/src/views/NoteEditorView.vue +++ b/frontend/src/views/NoteEditorView.vue @@ -748,7 +748,7 @@ onUnmounted(() => assist.clearSelection()); cursor: pointer; font-family: inherit; } -.btn-link-all:hover { background: var(--color-primary); color: var(--fs-text-on-action); } +.btn-link-all:hover { background: var(--color-action-primary); color: var(--fs-text-on-action); } .link-suggest-list { display: flex; diff --git a/frontend/src/views/ProjectListView.vue b/frontend/src/views/ProjectListView.vue index 9e8d2c11..f4573aa8 100644 --- a/frontend/src/views/ProjectListView.vue +++ b/frontend/src/views/ProjectListView.vue @@ -326,8 +326,8 @@ function overallPct(project: Project): { total: number; pct: number } { .empty-icon { font-size: 2.5rem; margin-bottom: 0.75rem; opacity: 0.3; } .empty-title { font-size: 1rem; font-weight: 500; color: var(--color-text-secondary); margin: 0 0 0.35rem; } .empty-sub { font-size: 0.85rem; margin: 0 0 1rem; } -.empty-action { display: inline-block; padding: 0.4rem 1rem; border: 1px solid var(--color-primary); border-radius: var(--radius-sm); color: var(--color-primary); background: none; cursor: pointer; font-size: 0.85rem; transition: background 0.15s, color 0.15s; } -.empty-action:hover { background: var(--color-primary); color: var(--fs-text-on-action); } +.empty-action { display: inline-block; padding: 0.4rem 1rem; border: 1px solid var(--color-action-primary); border-radius: var(--radius-sm); color: var(--color-action-primary); background: none; cursor: pointer; font-size: 0.85rem; transition: background 0.15s, color 0.15s; } +.empty-action:hover { background: var(--color-action-primary); color: var(--fs-text-on-action); } .skeleton-card { height: 140px; @@ -578,8 +578,8 @@ function overallPct(project: Project): { total: number; pct: number } { background: var(--color-bg); } .modal-btn-primary { - background: var(--color-primary); - border-color: var(--color-primary); + background: var(--color-action-primary); + border-color: var(--color-action-primary); color: var(--fs-text-on-action); } .modal-btn-primary:hover:not(:disabled) { diff --git a/frontend/src/views/ProjectView.vue b/frontend/src/views/ProjectView.vue index 9785df16..efdb4a99 100644 --- a/frontend/src/views/ProjectView.vue +++ b/frontend/src/views/ProjectView.vue @@ -1224,7 +1224,7 @@ async function confirmDelete() { cursor: pointer; border: 1px solid var(--color-border); } -.ms-plan-actions .btn-primary { background: var(--color-primary); color: var(--fs-text-on-action); border-color: var(--color-primary); } +.ms-plan-actions .btn-primary { background: var(--color-action-primary); color: var(--fs-text-on-action); border-color: var(--color-action-primary); } .ms-plan-actions .btn-primary:disabled { opacity: 0.6; cursor: default; } .ms-plan-actions .btn-secondary { background: var(--color-bg-card); color: var(--color-text); } @@ -1393,7 +1393,7 @@ async function confirmDelete() { line-height: 1; } .task-card:hover .task-advance-btn { opacity: 1; } -.task-advance-btn:hover { background: var(--color-primary); border-color: var(--color-primary); color: var(--fs-text-on-action); } +.task-advance-btn:hover { background: var(--color-action-primary); border-color: var(--color-action-primary); color: var(--fs-text-on-action); } .task-advance-btn--done:hover { background: var(--color-success, #22c55e); border-color: var(--color-success, #22c55e); color: var(--fs-text-on-action); } .task-advance-btn:disabled { opacity: 0.4; cursor: default; } diff --git a/frontend/src/views/RegisterInviteView.vue b/frontend/src/views/RegisterInviteView.vue index de7d1621..f188cc2a 100644 --- a/frontend/src/views/RegisterInviteView.vue +++ b/frontend/src/views/RegisterInviteView.vue @@ -250,7 +250,7 @@ async function handleSubmit() { .btn-submit { width: 100%; padding: 0.6rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); diff --git a/frontend/src/views/RegisterView.vue b/frontend/src/views/RegisterView.vue index 24112a48..63cab267 100644 --- a/frontend/src/views/RegisterView.vue +++ b/frontend/src/views/RegisterView.vue @@ -219,7 +219,7 @@ async function handleSubmit() { .btn-submit { width: 100%; padding: 0.6rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); diff --git a/frontend/src/views/ResetPasswordView.vue b/frontend/src/views/ResetPasswordView.vue index 92a4af87..9cbaa706 100644 --- a/frontend/src/views/ResetPasswordView.vue +++ b/frontend/src/views/ResetPasswordView.vue @@ -198,7 +198,7 @@ async function handleSubmit() { .btn-submit { width: 100%; padding: 0.6rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); diff --git a/frontend/src/views/SnippetListView.vue b/frontend/src/views/SnippetListView.vue index b4b95b13..c0828b85 100644 --- a/frontend/src/views/SnippetListView.vue +++ b/frontend/src/views/SnippetListView.vue @@ -654,16 +654,16 @@ function usageTitle(s: SnippetListItem): string { .empty-action { display: inline-block; padding: 0.4rem 1rem; - border: 1px solid var(--color-primary); + border: 1px solid var(--color-action-primary); border-radius: var(--radius-sm); - color: var(--color-primary); + color: var(--color-action-primary); background: none; cursor: pointer; font-size: 0.85rem; transition: background 0.15s, color 0.15s; } .empty-action:hover { - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); } diff --git a/frontend/src/views/TaskEditorView.vue b/frontend/src/views/TaskEditorView.vue index 6032a11c..f8e43c41 100644 --- a/frontend/src/views/TaskEditorView.vue +++ b/frontend/src/views/TaskEditorView.vue @@ -970,7 +970,7 @@ useEditorGuards(dirty, save); .subtask-input:focus { outline: none; border-color: var(--color-primary); } .btn-subtask-confirm { padding: 0.25rem 0.5rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); diff --git a/frontend/src/views/UserManagementView.vue b/frontend/src/views/UserManagementView.vue index 1fb17211..29460c96 100644 --- a/frontend/src/views/UserManagementView.vue +++ b/frontend/src/views/UserManagementView.vue @@ -330,7 +330,7 @@ function formatDate(iso: string): string { } .btn-invite { padding: 0.45rem 1rem; - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); border: none; border-radius: var(--radius-sm); @@ -394,7 +394,7 @@ function formatDate(iso: string): string { cursor: default; } .btn-toggle-open { - background: var(--color-primary); + background: var(--color-action-primary); color: var(--fs-text-on-action); } .btn-toggle-open:hover:not(:disabled) {