From c774042a85f428881b9b216a405a436a147be9a8 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 9 Jun 2026 22:25:11 -0400 Subject: [PATCH] refactor(ui): consolidate 7 hand-rolled kebabs into one KebabMenu (DRY pattern sweep) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First pattern-consistency DRY pass (process #594). The overflow kebab was hand-rolled 7 ways in two divergent activator strategies — Pattern A (#activator + v-bind) which silently breaks inside the teleported image modal (#711), and Pattern B (manual v-model + activator=parent + open-on-click=false + z-index 2400) the modal kebabs needed as a workaround. New (components/common) bakes in the modal-safe strategy UNIVERSALLY, so every kebab works in modal and non-modal contexts — folding the latent #711-class bug fix into all five Pattern-A sites. Menu items go in the default slot; variations (size/variant/location/label/min-width) are props. Adopted across all 7: TagChip, SuggestionItem, TagCard, SeriesView card, SeriesManageView, BackupRunsTable, SourceActions. Exhaustiveness (§8b): mdi-dots-vertical now lives only in KebabMenu. Labeled dropdowns / nav menus / filter popovers are a different concept and left alone. Seeded the pattern catalog so new code reuses the primitive. Test: KebabMenu renders slot items + trigger label/glyph + presentational props. Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/src/components/common/KebabMenu.vue | 50 +++++++++++++++++ frontend/src/components/discovery/TagCard.vue | 48 +++++++--------- .../src/components/modal/SuggestionItem.vue | 52 +++++------------- frontend/src/components/modal/TagChip.vue | 43 ++++----------- .../components/settings/BackupRunsTable.vue | 34 +++++------- .../subscriptions/SourceActions.vue | 51 ++++++++--------- frontend/src/views/SeriesManageView.vue | 55 ++++++++----------- frontend/src/views/SeriesView.vue | 36 +++++------- frontend/test/components/kebabMenu.spec.js | 38 +++++++++++++ 9 files changed, 211 insertions(+), 196 deletions(-) create mode 100644 frontend/src/components/common/KebabMenu.vue create mode 100644 frontend/test/components/kebabMenu.spec.js diff --git a/frontend/src/components/common/KebabMenu.vue b/frontend/src/components/common/KebabMenu.vue new file mode 100644 index 0000000..0052df7 --- /dev/null +++ b/frontend/src/components/common/KebabMenu.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/frontend/src/components/discovery/TagCard.vue b/frontend/src/components/discovery/TagCard.vue index db7b3df..81e5376 100644 --- a/frontend/src/components/discovery/TagCard.vue +++ b/frontend/src/components/discovery/TagCard.vue @@ -46,34 +46,25 @@ {{ card.kind }}
{{ card.image_count }} - - - - - - - - + + + + +
@@ -82,6 +73,7 @@ @@ -102,11 +85,6 @@ const scorePct = computed(() => `${Math.round(props.suggestion.score * 100)}%`) .fc-suggestion__accept :deep(.v-btn__content) { font-size: 12px; letter-spacing: 0.02em; } -.fc-suggestion__menu-wrap { - flex: 0 0 auto; - display: inline-flex; - align-items: center; -} .fc-suggestion__menu { flex: 0 0 auto; } diff --git a/frontend/src/components/modal/TagChip.vue b/frontend/src/components/modal/TagChip.vue index b6df29d..1dc5699 100644 --- a/frontend/src/components/modal/TagChip.vue +++ b/frontend/src/components/modal/TagChip.vue @@ -1,9 +1,4 @@