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 dcd044a..f7c09df 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 c91a9c8..a4c72ba 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 3f734e0..803890b 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 6113d25..199d606 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 975c71e..ee3a7b5 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 9504478..dff15cd 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 e274c38..d43bbf8 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 4098d42..3eb05da 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 8dd5890..b7d1d6a 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 9e8d2c1..f4573aa 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 9785df1..efdb4a9 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 de7d162..f188cc2 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 24112a4..63cab26 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 92a4af8..9cbaa70 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 b4b95b1..c0828b8 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 6032a11..f8e43c4 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 1fb1721..29460c9 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) {