Files
FabledCurator/frontend/src/components/common/MaintenanceTile.vue
T
bvandeusen 3b435dc0ba
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 18s
CI / backend-lint-and-test (push) Successful in 27s
CI / integration (push) Successful in 3m14s
feat(settings): tidy Cleanup tab into sectioned compact tiles (pass 1)
The Cleanup + Maintenance sections had ~17 full-width stacked cards with long
descriptions — a hunt to scan. Operator wants compact, sectioned, scannable tiles
(2026-06-18: keep both tabs, group inside, compact tiles in a grid).

New common/MaintenanceTile.vue: a compact expandable tile (icon + short title +
one-line blurb collapsed; click the header to expand the full controls/preview/
result inline; keyboard-accessible button + focus ring;  tints the
icon,  keeps a running task expanded).

Cleanup tab (this pass) restructured into 3 sections — Import-filter audits
(Min dimensions, Transparency, Single-color) / Duplicates & posts (Bare posts,
Duplicate posts, Deduplicate videos, Gated-post previews) / Tags (Unused, Legacy,
Reset content tagging, Standardize casing) — each a responsive grid of tiles.
PostMaintenanceCard split into 2 tiles, TagMaintenanceCard into 4. Moved
VideoDedupCard + GatedPurgeCard from the Maintenance tab here (both are
destructive content cleanup). All card logic unchanged — only the chrome.

Maintenance tab tiling is pass 2 (TODO noted in MaintenancePanel).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 23:48:18 -04:00

122 lines
3.1 KiB
Vue

<!--
Compact, expandable maintenance/cleanup action tile. Collapsed it shows just an
icon + short title + one-line purpose, so a section of these tiles in a grid is
scannable at a glance; clicking the header expands the full controls / preview /
result UI inline (the operator opted for "compact tiles in a grid, detail on
expand", 2026-06-18, replacing the old long stack of full-width cards).
Usage: wrap a card's action body in the default slot; pass icon/title/blurb.
`destructive` tints the icon error-red for delete actions. `open` can be forced
(e.g. keep a running task's tile expanded). Keyboard accessible: the header is a
real <button> with aria-expanded + focus ring.
-->
<template>
<v-card class="fc-tile" :class="{ 'fc-tile--open': isOpen }">
<button
type="button"
class="fc-tile__head"
:aria-expanded="isOpen"
@click="toggle"
>
<v-icon
:icon="icon"
:color="destructive ? 'error' : 'accent'"
class="fc-tile__icon"
/>
<span class="fc-tile__text">
<span class="fc-tile__title">{{ title }}</span>
<span class="fc-tile__blurb">{{ blurb }}</span>
</span>
<v-icon
:icon="isOpen ? 'mdi-chevron-up' : 'mdi-chevron-down'"
class="fc-tile__chev"
/>
</button>
<v-expand-transition>
<div v-show="isOpen" class="fc-tile__body">
<slot />
</div>
</v-expand-transition>
</v-card>
</template>
<script setup>
import { computed, ref, watch } from 'vue'
const props = defineProps({
icon: { type: String, required: true },
title: { type: String, required: true },
blurb: { type: String, default: '' },
destructive: { type: Boolean, default: false },
// Force-open (e.g. a tile whose task is mid-run). When set, the operator can
// still collapse it locally, but a change to `open` re-applies.
open: { type: Boolean, default: false },
})
const local = ref(props.open)
watch(() => props.open, (v) => { local.value = v })
const isOpen = computed(() => local.value)
function toggle() {
local.value = !local.value
}
</script>
<style scoped>
.fc-tile {
border-radius: 8px;
overflow: hidden;
}
.fc-tile__head {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
padding: 12px 14px;
background: transparent;
border: none;
text-align: left;
cursor: pointer;
color: inherit;
}
.fc-tile__head:hover {
background: rgba(var(--v-theme-on-surface), 0.04);
}
.fc-tile__head:focus-visible {
outline: 2px solid rgb(var(--v-theme-accent));
outline-offset: -2px;
}
.fc-tile__icon {
flex: 0 0 auto;
}
.fc-tile__text {
display: flex;
flex-direction: column;
min-width: 0;
flex: 1 1 auto;
}
.fc-tile__title {
font-weight: 600;
font-size: 0.95rem;
line-height: 1.2;
}
.fc-tile__blurb {
font-size: 0.8rem;
line-height: 1.25;
color: rgb(var(--v-theme-on-surface-variant));
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fc-tile--open .fc-tile__blurb {
white-space: normal;
}
.fc-tile__chev {
flex: 0 0 auto;
color: rgb(var(--v-theme-on-surface-variant));
}
.fc-tile__body {
padding: 0 14px 14px;
}
</style>