diff --git a/ci-requirements.md b/ci-requirements.md index 217dbf4..ee09c7e 100644 --- a/ci-requirements.md +++ b/ci-requirements.md @@ -22,7 +22,7 @@ real Postgres), build (docker buildx). - uv (test + integration jobs run `uv sync --locked`; installed in the image since the ci-python Dockerfile started pip-installing it) - docker CLI + buildx (build job pushes the production image to the - Forgejo registry) + Fabled-Git registry) ## Per-job tool installs diff --git a/frontend/src/assets/components.css b/frontend/src/assets/components.css new file mode 100644 index 0000000..2b9c148 --- /dev/null +++ b/frontend/src/assets/components.css @@ -0,0 +1,193 @@ +/* Shared component styles — the house recipes, in one place. + * =========================================================================== + * + * WHY THIS FILE EXISTS + * + * `.btn-primary` was defined five times, in five scoped stylesheets, and all + * five had drifted: three paddings, three font sizes, three disabled opacities, + * and one view with no disabled style at all (#2273). Nothing detected that, + * 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. 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 ` diff --git a/frontend/src/components/ShareDialog.vue b/frontend/src/components/ShareDialog.vue index f68d8b8..a76278d 100644 --- a/frontend/src/components/ShareDialog.vue +++ b/frontend/src/components/ShareDialog.vue @@ -117,7 +117,7 @@ onMounted(async () => { @@ -333,7 +333,7 @@ defineExpose({ reload: loadProjectNotes }); type="search" aria-label="Search notes" /> - +
Loading…
@@ -358,12 +358,12 @@ defineExpose({ reload: loadProjectNotes });
-
@@ -382,7 +382,7 @@ defineExpose({ reload: loadProjectNotes }); Unsaved Saving… - + @@ -400,7 +400,7 @@ defineExpose({ reload: loadProjectNotes });
- +
@@ -429,8 +429,8 @@ defineExpose({ reload: loadProjectNotes }); - - + +
@@ -484,26 +484,6 @@ defineExpose({ reload: loadProjectNotes }); flex: 1; } -.btn-new-note { - background: none; - border: 1px solid var(--color-border); - border-radius: 4px; - padding: 0.15rem 0.4rem; - font-size: 0.7rem; - color: var(--color-text-muted); - cursor: pointer; - white-space: nowrap; -} -.btn-new-note:hover { border-color: var(--color-primary); color: var(--color-primary); } - -.rail-search { - display: flex; - align-items: center; - gap: 0.2rem; - padding: 0.3rem 0.5rem; - border-bottom: 1px solid var(--color-border); - flex-shrink: 0; -} .rail-search-input { flex: 1; @@ -517,17 +497,8 @@ defineExpose({ reload: loadProjectNotes }); .rail-search-input:focus { outline: none; } .rail-search-input::-webkit-search-cancel-button { display: none; } -.btn-search-clear { - background: none; - border: none; - color: var(--color-text-muted); - font-size: 0.68rem; - cursor: pointer; - padding: 0; - line-height: 1; - flex-shrink: 0; -} -.btn-search-clear:hover { color: var(--color-text); } +/* Sits inside the search field: no padding, and must not flex. */ +.btn-search-clear { padding: 0; flex-shrink: 0; } .rail-state { padding: 1rem 0.65rem; @@ -617,99 +588,7 @@ defineExpose({ reload: loadProjectNotes }); align-items: center; } -.btn-delete { - background: none; - border: none; - color: var(--color-text-muted); - cursor: pointer; - padding: 0.1rem; - border-radius: 3px; - opacity: 0; - transition: opacity 0.1s, color 0.1s; - display: flex; - align-items: center; -} .note-row:hover .btn-delete { opacity: 1; } -.btn-delete:hover { color: var(--color-action-destructive); } - -.btn-confirm-delete { - background: none; - border: 1px solid var(--color-action-destructive); - color: var(--color-action-destructive); - font-size: 0.65rem; - font-weight: 500; - cursor: pointer; - padding: 0.1rem 0.3rem; - border-radius: 3px; - transition: background 0.15s, color 0.15s; -} -.btn-confirm-delete:hover:not(:disabled) { background: var(--color-action-destructive); color: var(--fs-text-on-action); } -.btn-confirm-delete:disabled { opacity: 0.5; cursor: default; } - -.btn-cancel-delete { - background: none; - border: none; - color: var(--color-text-muted); - font-size: 0.7rem; - cursor: pointer; - padding: 0.1rem; -} -.btn-cancel-delete:hover { color: var(--color-text); } - -/* Inline new note */ -.new-note-input { - flex: 1; - background: var(--color-input-bg, var(--color-bg)); - border: 1px solid var(--color-primary); - border-radius: 4px; - padding: 0.15rem 0.35rem; - font-size: 0.78rem; - color: var(--color-text); - min-width: 0; -} -.new-note-input:focus { outline: none; } - -.btn-confirm { - background: var(--color-primary); - color: var(--fs-text-on-action); - border: none; - border-radius: 4px; - padding: 0.15rem 0.35rem; - font-size: 0.85rem; - cursor: pointer; - flex-shrink: 0; - line-height: 1; -} -.btn-confirm:disabled { opacity: 0.4; cursor: default; } - -.btn-cancel { - background: none; - border: none; - color: var(--color-text-muted); - font-size: 0.72rem; - cursor: pointer; - padding: 0.1rem; - flex-shrink: 0; -} -.btn-cancel:hover { color: var(--color-text); } - -/* ── Right editor pane ── */ -.note-editor-pane { - flex: 1; - display: flex; - flex-direction: column; - overflow: hidden; - min-width: 0; -} - -.editor-empty-state { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - color: var(--color-text-muted); - font-size: 0.85rem; -} /* Editor UI */ .panel-header { @@ -731,23 +610,6 @@ defineExpose({ reload: loadProjectNotes }); .saving-txt { font-size: 0.72rem; color: var(--color-primary); } /* Moss action-primary per Hybrid */ -.btn-save { - background: var(--color-action-primary); - color: var(--fs-text-on-action); - border: none; - border-radius: 5px; - padding: 0.25rem 0.7rem; - font-size: 0.8rem; - cursor: pointer; - transition: background 0.15s; -} -.btn-save:hover:not(:disabled) { background: var(--color-action-primary-hover); } -.btn-save:disabled { opacity: 0.4; cursor: default; } - -.note-title-row { - padding: 0.9rem 1.1rem 0.5rem; - flex-shrink: 0; -} .note-title-input { width: 100%; @@ -775,20 +637,7 @@ defineExpose({ reload: loadProjectNotes }); } .tag-row > :first-child { flex: 1; min-width: 0; } -.btn-suggest-tags { - background: none; - border: 1px solid var(--color-border); - border-radius: 5px; - padding: 0.25rem 0.55rem; - font-size: 0.75rem; - color: var(--color-text-muted); - cursor: pointer; - white-space: nowrap; - flex-shrink: 0; - align-self: center; -} -.btn-suggest-tags:hover:not(:disabled) { border-color: var(--color-primary); color: var(--color-primary); } -.btn-suggest-tags:disabled { opacity: 0.5; cursor: default; } +.btn-suggest-tags { flex-shrink: 0; align-self: center; } .tag-suggestions { display: flex; @@ -817,21 +666,6 @@ defineExpose({ reload: loadProjectNotes }); color: var(--color-primary); } -.btn-dismiss-suggestions { - background: none; - border: none; - color: var(--color-text-muted); - cursor: pointer; - font-size: 0.75rem; - margin-left: auto; - padding: 0.1rem 0.3rem; -} -.btn-dismiss-suggestions:hover { color: var(--color-text); } - -.toolbar-row { - padding: 0.3rem 0.6rem; - flex-shrink: 0; -} .link-suggest-strip { display: flex; @@ -865,21 +699,4 @@ defineExpose({ reload: loadProjectNotes }); } .btn-chip-link:hover { background: color-mix(in srgb, var(--color-primary) 15%, transparent); } -.btn-link-all { - background: none; - border: 1px solid var(--color-border); - border-radius: 4px; - padding: 0.1rem 0.4rem; - font-size: 0.7rem; - color: var(--color-text-muted); - cursor: pointer; - margin-left: 0.1rem; -} -.btn-link-all:hover { border-color: var(--color-primary); color: var(--color-primary); } - -.editor-area { - flex: 1; - overflow-y: auto; - padding: 0.5rem 0.6rem; -} diff --git a/frontend/src/components/WorkspaceTaskPanel.vue b/frontend/src/components/WorkspaceTaskPanel.vue index 9504478..4f6d305 100644 --- a/frontend/src/components/WorkspaceTaskPanel.vue +++ b/frontend/src/components/WorkspaceTaskPanel.vue @@ -232,7 +232,7 @@ defineExpose({ reload: loadAll }); placeholder="New task..." @keydown.enter="addTask" /> - +
Loading...
@@ -293,18 +293,18 @@ defineExpose({ reload: loadAll });
- Edit ↗ + Edit ↗ {{ STATUS_ICON[activeTask.status] ?? "○" }} {{ activeTask.status.replace("_", " ") }} - - +

{{ activeTask.title }}

@@ -396,17 +396,7 @@ defineExpose({ reload: loadAll }); } .task-add-input:focus { outline: none; border-color: var(--color-primary); } -.btn-add { - background: var(--color-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; } diff --git a/frontend/src/main.ts b/frontend/src/main.ts index cb8becd..865c447 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -3,6 +3,8 @@ import { createPinia } from "pinia"; import App from "./App.vue"; import router from "./router"; import "./assets/theme.css"; +// After theme.css — it consumes the tokens declared there. +import "./assets/components.css"; import "./assets/prose.css"; const app = createApp(App); diff --git a/frontend/src/views/DesignSystemsView.vue b/frontend/src/views/DesignSystemsView.vue index 76fd9f8..805f859 100644 --- a/frontend/src/views/DesignSystemsView.vue +++ b/frontend/src/views/DesignSystemsView.vue @@ -1262,47 +1262,6 @@ textarea.input { /* Buttons ---------------------------------------------------------------- */ -.btn-primary, -.btn-ghost, -.btn-danger { - border-radius: var(--radius-sm); - padding: 0.45rem 0.9rem; - font: inherit; - font-size: 0.85rem; - cursor: pointer; - border: 1px solid transparent; -} - -.btn-primary { - background: var(--color-action-primary); - color: var(--fs-text-on-action); -} - -.btn-primary:not(:disabled):hover { - background: var(--color-action-primary-hover); -} - -.btn-ghost { - background: none; - border-color: var(--color-border); - color: var(--color-text-secondary); -} - -.btn-danger { - background: var(--color-action-destructive); - color: #E8E4D8; -} - -.btn-small { - padding: 0.25rem 0.55rem; - font-size: 0.75rem; -} - -.btn-primary:disabled, -.btn-ghost:disabled { - opacity: 0.5; - cursor: not-allowed; -} .row-actions { diff --git a/frontend/src/views/DesignView.vue b/frontend/src/views/DesignView.vue index 8c142c9..9a6d4e4 100644 --- a/frontend/src/views/DesignView.vue +++ b/frontend/src/views/DesignView.vue @@ -12,11 +12,12 @@ * every specimen below is either a REAL component imported from the app, or a * real token read from the browser, or it is explicitly marked as missing. * - * Buttons are the case where that bites. Rule 65 specifies four variants, but - * `.btn-primary` is defined four separate times in four ` diff --git a/frontend/src/views/SnippetDetailView.vue b/frontend/src/views/SnippetDetailView.vue index 70cd7cd..28ffed9 100644 --- a/frontend/src/views/SnippetDetailView.vue +++ b/frontend/src/views/SnippetDetailView.vue @@ -249,34 +249,6 @@ async function confirmDelete() { flex-shrink: 0; } -.btn-ghost { - padding: 0.35rem 0.8rem; - border: 1px solid var(--color-border); - background: transparent; - color: var(--color-text); - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.85rem; - font-family: inherit; - transition: border-color 0.15s, color 0.15s; -} -.btn-ghost:hover { - border-color: var(--color-primary); - color: var(--color-primary); -} -.btn-danger { - padding: 0.35rem 0.8rem; - border: none; - background: var(--color-action-destructive, #6B2118); - color: var(--fs-text-on-action); - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.85rem; - font-family: inherit; -} -.btn-danger:hover { - opacity: 0.9; -} .when-to-use { margin: 0.75rem 0 1.25rem; diff --git a/frontend/src/views/SnippetEditorView.vue b/frontend/src/views/SnippetEditorView.vue index c672fe6..01774b7 100644 --- a/frontend/src/views/SnippetEditorView.vue +++ b/frontend/src/views/SnippetEditorView.vue @@ -572,37 +572,6 @@ function cancel() { gap: 0.5rem; margin-top: 0.25rem; } -.btn-primary { - padding: 0.5rem 1.1rem; - background: var(--color-action-primary); - color: var(--fs-text-on-action); - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.9rem; - font-family: inherit; - transition: background 0.15s; -} -.btn-primary:hover:not(:disabled) { - background: var(--color-action-primary-hover); -} -.btn-primary:disabled { - opacity: 0.5; - cursor: default; -} -.btn-secondary { - padding: 0.5rem 1.1rem; - background: var(--color-bg-secondary); - color: var(--color-text); - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.9rem; - font-family: inherit; -} -.btn-secondary:hover { - background: var(--color-bg); -} @media (max-width: 600px) { .field-row, diff --git a/frontend/src/views/SnippetListView.vue b/frontend/src/views/SnippetListView.vue index 6f7606b..c0828b8 100644 --- a/frontend/src/views/SnippetListView.vue +++ b/frontend/src/views/SnippetListView.vue @@ -543,21 +543,6 @@ function usageTitle(s: SnippetListItem): string { } /* Moss action-primary per Hybrid — utility action, not a brand moment. */ -.btn-primary { - padding: 0.45rem 1rem; - background: var(--color-action-primary); - color: var(--fs-text-on-action); - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.9rem; - font-family: inherit; - transition: background 0.15s; - white-space: nowrap; -} -.btn-primary:hover { - background: var(--color-action-primary-hover); -} .search-row { margin-bottom: 1.25rem; @@ -669,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); } @@ -870,21 +855,6 @@ function usageTitle(s: SnippetListItem): string { gap: 0.5rem; align-items: center; } -.btn-ghost { - padding: 0.4rem 0.85rem; - border: 1px solid var(--color-border); - background: transparent; - color: var(--color-text); - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.9rem; - font-family: inherit; - transition: border-color 0.15s, color 0.15s; -} -.btn-ghost:hover { - border-color: var(--color-primary); - color: var(--color-primary); -} /* Selected card = 2px accent border per the design system (featured/active). */ .snippet-card.selected { @@ -931,10 +901,6 @@ function usageTitle(s: SnippetListItem): string { flex: 1; min-width: 0; } -.select-bar .btn-primary:disabled { - opacity: 0.5; - cursor: default; -} /* Merge modal */ .modal-overlay { diff --git a/frontend/src/views/TaskEditorView.vue b/frontend/src/views/TaskEditorView.vue index 6032a11..fedbcf9 100644 --- a/frontend/src/views/TaskEditorView.vue +++ b/frontend/src/views/TaskEditorView.vue @@ -645,7 +645,7 @@ useEditorGuards(dirty, save); @focus="onParentFocus" @blur="hideParentDropdown" /> - +
Searching...
@@ -666,7 +666,7 @@ useEditorGuards(dirty, save);
Sub-tasks - +
Loading...
@@ -921,23 +921,6 @@ useEditorGuards(dirty, save); text-transform: uppercase; letter-spacing: 0.04em; } -.btn-add-subtask { - background: none; - border: none; - cursor: pointer; - color: var(--color-primary); - font-size: 0.78rem; - font-family: inherit; - padding: 0.1rem 0.2rem; -} -.btn-add-subtask:hover { opacity: 0.8; } -.subtasks-loading { font-size: 0.78rem; color: var(--color-text-muted); } -.subtask-row { - display: flex; - align-items: center; - gap: 0.4rem; - padding: 0.2rem 0; -} .subtask-checkbox { flex-shrink: 0; cursor: pointer; } .subtask-title { font-size: 0.83rem; @@ -968,33 +951,6 @@ useEditorGuards(dirty, save); font-family: inherit; } .subtask-input:focus { outline: none; border-color: var(--color-primary); } -.btn-subtask-confirm { - padding: 0.25rem 0.5rem; - background: var(--color-primary); - color: var(--fs-text-on-action); - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.78rem; - font-family: inherit; -} -.btn-subtask-confirm:disabled { opacity: 0.5; cursor: default; } -.btn-subtask-cancel { - padding: 0.25rem 0.5rem; - background: none; - border: 1px solid var(--color-border); - color: var(--color-text-secondary); - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.78rem; - font-family: inherit; -} - -/* Streaming preview */ -.stream-label { - font-size: 0.8rem; - color: var(--color-text-muted); -} .stream-preview { border: 1px solid var(--color-input-border); border-radius: var(--radius-sm); @@ -1125,24 +1081,4 @@ useEditorGuards(dirty, save); color: var(--color-primary, #6366f1); font-style: normal; } -.btn-reconsolidate { - margin-left: auto; - padding: 0.25rem 0.7rem; - font-size: 0.78rem; - font-style: normal; - color: inherit; - background: transparent; - border: 1px solid var(--color-border, rgba(255, 255, 255, 0.12)); - border-radius: 999px; - cursor: pointer; - transition: background 120ms ease; -} -.btn-reconsolidate:hover:not(:disabled) { - background: rgba(99, 102, 241, 0.12); - border-color: var(--color-primary, #6366f1); -} -.btn-reconsolidate:disabled { - opacity: 0.5; - cursor: progress; -} \ No newline at end of file diff --git a/frontend/src/views/TaskViewerView.vue b/frontend/src/views/TaskViewerView.vue index 44e7fbf..2cc007d 100644 --- a/frontend/src/views/TaskViewerView.vue +++ b/frontend/src/views/TaskViewerView.vue @@ -263,29 +263,29 @@ const subTaskProgress = computed(() => {
{{ store.currentTask.project_id ? "← Project" : "← Tasks" }} Edit - +
@@ -475,83 +475,6 @@ const subTaskProgress = computed(() => { gap: 0.75rem; margin-bottom: 0.75rem; } -.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); -} -/* Edit + Advance: Moss action-primary — both are "operating the software" - workflow actions, not brand moments. */ -.btn-edit, -.btn-advance { - display: inline-flex; - align-items: center; - padding: 0.45rem 1.1rem; - border: none; - border-radius: var(--radius-sm); - background: var(--color-action-primary); - color: var(--fs-text-on-action); - text-decoration: none; - cursor: pointer; - font-size: 0.875rem; - font-weight: 500; - transition: background 0.15s; -} -.btn-edit:hover, -.btn-advance:hover { - background: var(--color-action-primary-hover); - color: var(--fs-text-on-action); -} -/* Convert + Share: Bronze action-secondary — alternate paths */ -.btn-convert { - margin-left: auto; - padding: 0.3rem 0.75rem; - background: var(--color-action-secondary); - color: var(--fs-text-on-action); - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 0.85rem; - transition: background 0.15s; -} -.btn-convert:hover { background: var(--color-action-secondary-hover); } -.btn-convert:disabled { - opacity: 0.6; - cursor: default; -} - -.btn-share { - padding: 0.3rem 0.75rem; - background: var(--color-action-secondary); - border: none; - border-radius: var(--radius-sm); - color: var(--fs-text-on-action); - cursor: pointer; - font-size: 0.85rem; - font-family: inherit; - transition: background 0.15s; -} -.btn-share:hover { background: var(--color-action-secondary-hover); } - -.task-title { - font-family: "Fraunces", Georgia, serif; - font-size: 2rem; - font-weight: 500; - line-height: 1.2; - margin: 0.25rem 0 0.5rem; - color: var(--color-text); -} .meta { display: flex; diff --git a/frontend/src/views/TrashView.vue b/frontend/src/views/TrashView.vue index 2033d19..8c087e3 100644 --- a/frontend/src/views/TrashView.vue +++ b/frontend/src/views/TrashView.vue @@ -25,7 +25,7 @@ onMounted(() => store.fetchTrash());

Trash

@@ -52,8 +52,8 @@ onMounted(() => store.fetchTrash());
- - + +
@@ -64,25 +64,11 @@ onMounted(() => store.fetchTrash()); .trash-page { max-width: 900px; margin: 0 auto; padding: 1.5rem; } .trash-header { display: flex; align-items: center; justify-content: space-between; } .trash-header h1 { font-family: Fraunces, serif; font-style: italic; margin: 0; } -.btn-empty { - background: none; border: 1px solid var(--color-border, #2a2a2e); - color: inherit; border-radius: 6px; padding: 0.4rem 0.8rem; cursor: pointer; -} -.btn-empty:hover { border-color: var(--color-danger, #ef4444); color: var(--color-danger, #ef4444); } -.trash-note { opacity: 0.7; font-size: 0.9em; margin: 0.5rem 0 1.5rem; } -.trash-loading, .trash-empty { opacity: 0.6; font-style: italic; padding: 2rem 0; } -.batch-list { list-style: none; padding: 0; margin: 0; } -.batch { - display: flex; align-items: center; justify-content: space-between; - gap: 1rem; padding: 0.85rem 1rem; margin-bottom: 0.5rem; - background: var(--color-surface, #18181b); border-radius: 8px; - border-left: 2px solid var(--color-border, #2a2a2e); -} .batch-summary { font-weight: 500; } .batch-count { opacity: 0.6; font-weight: 400; font-size: 0.9em; margin-left: 0.35rem; } .batch-meta { font-size: 0.82em; opacity: 0.6; margin-top: 0.25rem; } .batch-actions { display: flex; gap: 0.5rem; flex-shrink: 0; } .batch-actions button { border-radius: 6px; padding: 0.35rem 0.7rem; cursor: pointer; border: 1px solid var(--color-border, #2a2a2e); background: none; color: inherit; } -.btn-restore:hover { border-color: var(--color-primary, #6366f1); color: var(--color-primary, #6366f1); } -.btn-purge:hover { border-color: var(--color-danger, #ef4444); color: var(--color-danger, #ef4444); } +.btn-restore:hover { border-color: var(--color-action-primary); color: var(--color-action-primary); } +.btn-purge:hover { border-color: var(--color-action-destructive); color: var(--color-action-destructive); } diff --git a/frontend/src/views/UserManagementView.vue b/frontend/src/views/UserManagementView.vue index 1fb1721..ce0918f 100644 --- a/frontend/src/views/UserManagementView.vue +++ b/frontend/src/views/UserManagementView.vue @@ -167,7 +167,7 @@ function formatDate(iso: string): string {