refactor(ui): the two workspace panels migrate onto the shared buttons
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / TypeScript typecheck (push) Successful in 38s
CI & Build / Python tests (push) Canceled after 1m35s
CI & Build / integration (push) Canceled after 1m35s
CI & Build / Build & push image (push) Canceled after 0s

Eighteen bespoke button rules across the two densest components, replaced by
composition in the template. Net -279 lines.

These files are where the size taxonomy earns itself: almost every button here
is an inline affordance — a dismiss ×, a confirm tick, an add-chip — sitting
inside a card or a line of text. Forcing them to the standard 8/16px would have
broken the layouts, which is why the previous commit measured the clusters
before assuming a button is a button.

What the migration left behind is the useful signal. Each residual rule is now
one line stating only what the shared classes genuinely cannot:

  .btn-add            { font-size: 1rem; }      a '+' glyph, not a label
  .btn-search-clear   { padding: 0; flex-shrink: 0; }   sits in the field
  .btn-suggest-tags   { flex-shrink: 0; align-self: center; }
  .btn-delete-task    { margin-left: 0.25rem; }

Four residuals were deleted rather than kept, because the shared sheet already
said the same thing: a disabled opacity, two hover colours, and a danger-outline
hover fill. Keeping them would have recreated the drift in miniature.

Two accent hovers went with them. .btn-suggest-tags tinted its border and label
with the accent on hover, which is the same house-style violation corrected in
f491b6d — it survived that pass because it was a hover, not a fill.

.btn-tag-suggestion and .btn-chip-link stay bespoke, deliberately. They are
tag-shaped rather than button-shaped, and the house style does put the accent on
tags — so they are not drift, they are a different component wearing a btn-
prefix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs
This commit is contained in:
2026-08-01 22:44:21 -04:00
co-authored by Claude Opus 5
parent 67fdf7c55b
commit c7cf07824a
2 changed files with 26 additions and 279 deletions
+11 -81
View File
@@ -232,7 +232,7 @@ defineExpose({ reload: loadAll });
placeholder="New task..."
@keydown.enter="addTask"
/>
<button class="btn-add" :disabled="addingTask || !newTaskTitle.trim()" @click="addTask">+</button>
<button class="btn-primary btn-inline btn-add" :disabled="addingTask || !newTaskTitle.trim()" @click="addTask">+</button>
</div>
<div v-if="loading" class="state-msg">Loading...</div>
@@ -293,18 +293,18 @@ defineExpose({ reload: loadAll });
<Transition name="detail-fade">
<div v-if="activeTask" class="task-detail">
<div class="detail-header">
<RouterLink :to="`/tasks/${activeTask.id}/edit`" target="_blank" class="btn-edit-task" title="Open full editor">Edit </RouterLink>
<RouterLink :to="`/tasks/${activeTask.id}/edit`" target="_blank" class="btn-text btn-edit-task" title="Open full editor">Edit </RouterLink>
<span :class="['status-badge', `status-${activeTask.status}`]" @click="cycleStatus(activeTask, $event)" title="Click to cycle status">
{{ STATUS_ICON[activeTask.status] ?? "○" }} {{ activeTask.status.replace("_", " ") }}
</span>
<template v-if="deleteConfirmPending">
<button class="btn-delete-confirm" :disabled="deletingTask" @click="deleteActiveTask">{{ deletingTask ? '...' : 'Delete?' }}</button>
<button class="btn-delete-cancel" aria-label="Cancel delete" @click="cancelDeleteTask"><X :size="16" /></button>
<button class="btn-danger-outline btn-inline btn-delete-confirm" :disabled="deletingTask" @click="deleteActiveTask">{{ deletingTask ? '...' : 'Delete?' }}</button>
<button class="btn-text" aria-label="Cancel delete" @click="cancelDeleteTask"><X :size="16" /></button>
</template>
<button v-else class="btn-delete-task" title="Delete task" @click="deleteActiveTask">
<button v-else class="btn-text btn-delete-task" title="Delete task" @click="deleteActiveTask">
<Trash2 :size="16" />
</button>
<button class="btn-close-detail" @click="closeTask" aria-label="Close detail"><X :size="16" /></button>
<button class="btn-text btn-close-detail" @click="closeTask" aria-label="Close detail"><X :size="16" /></button>
</div>
<h3 class="detail-title">{{ activeTask.title }}</h3>
@@ -396,17 +396,7 @@ defineExpose({ reload: loadAll });
}
.task-add-input:focus { outline: none; border-color: var(--color-primary); }
.btn-add {
background: var(--color-action-primary);
color: var(--fs-text-on-action);
border: none;
border-radius: 5px;
padding: 0.28rem 0.55rem;
font-size: 1rem;
cursor: pointer;
line-height: 1;
}
.btn-add:disabled { opacity: 0.4; cursor: default; }
.btn-add { font-size: 1rem; } /* a '+' glyph, not a label */
.groups-scroll {
flex: 1;
@@ -534,17 +524,7 @@ defineExpose({ reload: loadAll });
.status-badge.status-in_progress { border-color: var(--color-primary); color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 10%, transparent); }
.status-badge.status-done { border-color: var(--color-success, #27ae60); color: var(--color-success, #27ae60); background: color-mix(in srgb, var(--color-success, #27ae60) 10%, transparent); }
.btn-edit-task {
background: none;
border: none;
color: var(--color-primary);
font-size: 0.78rem;
cursor: pointer;
padding: 0.1rem 0.3rem;
border-radius: 3px;
text-decoration: none;
flex-shrink: 0;
}
.btn-edit-task { margin-left: 0.25rem; }
.btn-edit-task:hover { text-decoration: underline; }
.detail-body {
@@ -566,51 +546,11 @@ defineExpose({ reload: loadAll });
color: var(--color-text);
}
.btn-delete-task {
background: none;
border: none;
color: var(--color-text-muted);
font-size: 0.8rem;
cursor: pointer;
padding: 0.15rem 0.3rem;
border-radius: 3px;
margin-left: 0.25rem;
}
.btn-delete-task { margin-left: 0.25rem; }
.btn-delete-task:hover { color: var(--color-action-destructive); }
.btn-delete-confirm {
background: none;
border: 1px solid var(--color-action-destructive);
color: var(--color-action-destructive);
font-size: 0.72rem;
font-weight: 500;
cursor: pointer;
padding: 0.15rem 0.5rem;
border-radius: 4px;
margin-left: 0.25rem;
transition: background 0.15s, color 0.15s;
}
.btn-delete-confirm:hover:not(:disabled) { background: var(--color-action-destructive); color: var(--fs-text-on-action); }
.btn-delete-confirm:disabled { opacity: 0.5; cursor: default; }
.btn-delete-confirm { margin-left: 0.25rem; }
.btn-delete-cancel {
background: none;
border: none;
color: var(--color-text-muted);
font-size: 0.75rem;
cursor: pointer;
padding: 0.1rem 0.3rem;
}
.btn-delete-cancel:hover { color: var(--color-text); }
.detail-title {
padding: 0.75rem 0.75rem 0.25rem;
font-size: 0.95rem;
font-weight: 500;
margin: 0;
color: var(--color-text);
flex-shrink: 0;
}
.detail-meta {
display: flex;
@@ -679,15 +619,5 @@ defineExpose({ reload: loadAll });
}
/* Close detail button */
.btn-close-detail {
background: none;
border: none;
color: var(--color-text-muted);
font-size: 0.75rem;
cursor: pointer;
padding: 0.15rem 0.3rem;
border-radius: 3px;
margin-left: 0.2rem;
}
.btn-close-detail:hover { color: var(--color-text); }
.btn-close-detail { margin-left: 0.2rem; }
</style>