-
-
-
{{ label }}
+
+
+
+
+
+ All done
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+ {{ item.data.label }}
+
+
+
+ {{ item.name }}
+
-
- {{ name }}
-
+
diff --git a/src/frontend/settings/languages/components/language-table-row.vue b/src/frontend/settings/languages/components/language-table-row.vue
index 7ebefe12..3dcda645 100644
--- a/src/frontend/settings/languages/components/language-table-row.vue
+++ b/src/frontend/settings/languages/components/language-table-row.vue
@@ -14,7 +14,7 @@
-
+
|
@@ -76,7 +76,7 @@
import { computed } from 'vue';
import { BookOpen, Trash2, Users } from '@lucide/vue';
import MemberRow from './member-row.vue';
-import RingBlock from '../../../dashboard/ring-block.vue';
+import Ring from '../../../dashboard/ring.vue';
import LangStrip from './language-strip.vue';
import type { LanguageTableItem } from '../../../../types';
diff --git a/src/frontend/shared/colors.palette.ts b/src/frontend/shared/colors.palette.ts
index 70f67e69..b662544c 100644
--- a/src/frontend/shared/colors.palette.ts
+++ b/src/frontend/shared/colors.palette.ts
@@ -146,12 +146,6 @@ export const colorSections: ColorSection[] = [
{ name: 'orange-700', class: 'bg-orange-700' },
],
},
- {
- title: 'Teal',
- colors: [
- { name: 'teal-500', class: 'bg-teal-500' },
- ],
- },
{
title: 'Violet',
colors: [
diff --git a/src/frontend/shared/colors.usage.ts b/src/frontend/shared/colors.usage.ts
index 21de5a83..0380e077 100644
--- a/src/frontend/shared/colors.usage.ts
+++ b/src/frontend/shared/colors.usage.ts
@@ -71,9 +71,8 @@ export const colorUsage: Record = {
'index.css',
'shared/pill-button.vue',
] },
- 'blue-50': { count: 67, files: [
+ 'blue-50': { count: 66, files: [
'audience/audience-index.vue',
- 'dashboard/ring-block.vue',
'fields/select-field.vue',
'index.css',
'invitation/invitation-index-item.vue',
@@ -104,9 +103,8 @@ export const colorUsage: Record = {
'ui/components/ui-string-item.vue',
'ui/ui-page.vue',
] },
- 'blue-500': { count: 38, files: [
+ 'blue-500': { count: 37, files: [
'audience/audience-index.vue',
- 'dashboard/ring-block.vue',
'fields/select-field.vue',
'index.css',
'invitation/invitations-index.vue',
@@ -242,9 +240,8 @@ export const colorUsage: Record = {
'streams/components/stream-item.vue',
'team/components/user-row.vue',
] },
- 'gray-200': { count: 97, files: [
+ 'gray-200': { count: 96, files: [
'audience/audience-index.vue',
- 'dashboard/ring-block.vue',
'dashboard/stat-tile.vue',
'fields/attachments/file-upload.vue',
'fields/attachments/video-meta.vue',
@@ -365,7 +362,6 @@ export const colorUsage: Record = {
'audience/audience-index.vue',
'audience/components/audience-row.vue',
'dashboard/language-block.vue',
- 'dashboard/ring-block.vue',
'dashboard/ring.vue',
'dashboard/stat-tile.vue',
'fields/attachments/attachment-field.vue',
@@ -434,7 +430,6 @@ export const colorUsage: Record = {
'audience/audience-index.vue',
'audience/components/audience-row.vue',
'dashboard/language-block.vue',
- 'dashboard/ring-block.vue',
'dashboard/ring.vue',
'dashboard/stat-tile.vue',
'fields/attachments/attachment-field.vue',
@@ -563,7 +558,6 @@ export const colorUsage: Record = {
'gray-800': { count: 26, files: [
'dashboard/action-card.vue',
'dashboard/dashboard-index.vue',
- 'dashboard/ring-block.vue',
'dashboard/ring.vue',
'fields/section-panel-field.vue',
'index.css',
@@ -771,9 +765,10 @@ export const colorUsage: Record = {
'streams/components/stream-item.vue',
] },
'studio-dark': { count: 0, files: [] },
- 'studio-forest': { count: 6, files: [
+ 'studio-forest': { count: 9, files: [
'dashboard/language-block.vue',
'dashboard/ring.vue',
+ 'shared/app-footer.vue',
'shared/index-tab-button.vue',
'shared/studio-button.vue',
] },
@@ -783,7 +778,7 @@ export const colorUsage: Record = {
'stories/components/resource-empty-state.vue',
'stories/components/resource-picker.vue',
] },
- 'studio-lime': { count: 5, files: [
+ 'studio-lime': { count: 6, files: [
'dashboard/language-block.vue',
'dashboard/ring.vue',
'dashboard/stat-tile.vue',
@@ -793,11 +788,7 @@ export const colorUsage: Record = {
'studio-yellow': { count: 1, files: [
'dashboard/action-card.vue',
] },
- 'teal-500': { count: 4, files: [
- 'dashboard/ring-block.vue',
- ] },
- 'transparent': { count: 26, files: [
- 'dashboard/ring-block.vue',
+ 'transparent': { count: 23, files: [
'dashboard/ring.vue',
'fields/attachments/video-progress.vue',
'fields/boolean-field.vue',
@@ -829,7 +820,6 @@ export const colorUsage: Record = {
'audience/audience-index.vue',
'dashboard/action-card.vue',
'dashboard/language-block.vue',
- 'dashboard/ring-block.story.vue',
'dashboard/ring.story.vue',
'dashboard/stat-tile.vue',
'fields/attachments/attachment-field.vue',
From 2d90c717c47717efe3398674c5a7534df885f85b Mon Sep 17 00:00:00 2001
From: Timothy Koech
Date: Wed, 29 Jul 2026 14:36:31 +0300
Subject: [PATCH 17/39] style: update button variant and tint color in
invitation components
---
src/frontend/invitation/invitations-edit.vue | 2 +-
src/frontend/invitation/invitations-index.vue | 2 +-
src/frontend/shared/studio-button.vue | 3 ++-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/frontend/invitation/invitations-edit.vue b/src/frontend/invitation/invitations-edit.vue
index cdda2c70..086d163f 100644
--- a/src/frontend/invitation/invitations-edit.vue
+++ b/src/frontend/invitation/invitations-edit.vue
@@ -8,7 +8,7 @@
label: 'Published',
widget: 'boolean',
default: false,
- tintColor: 'green-400',
+ tintColor: 'studio-forest',
labelOrder: 'start',
}"
:is-nested="true"
diff --git a/src/frontend/invitation/invitations-index.vue b/src/frontend/invitation/invitations-index.vue
index 39db1559..c3d4619d 100644
--- a/src/frontend/invitation/invitations-index.vue
+++ b/src/frontend/invitation/invitations-index.vue
@@ -1,7 +1,7 @@
-
+
diff --git a/src/frontend/shared/studio-button.vue b/src/frontend/shared/studio-button.vue
index 8854f9f2..e39cc079 100644
--- a/src/frontend/shared/studio-button.vue
+++ b/src/frontend/shared/studio-button.vue
@@ -87,7 +87,8 @@ const shapeClasses = computed(() =>
);
const variantClassMap: Record = {
- primary: 'bg-studio-forest text-studio-lime enabled:hover:bg-studio-green/90',
+ primary:
+ 'bg-studio-forest text-studio-lime enabled:hover:bg-studio-green enabled:hover:text-studio-forest',
outline:
'border border-studio-green bg-transparent text-studio-green enabled:hover:bg-studio-green/5',
secondary:
From eb33542a9b7d59c062da20ed68550042aef764f6 Mon Sep 17 00:00:00 2001
From: Timothy Koech
Date: Wed, 29 Jul 2026 15:39:03 +0300
Subject: [PATCH 18/39] style: update button variants to primary and adjust tab
button styles for consistency
---
src/frontend/resources/resources-edit.vue | 2 +-
src/frontend/shared/index-filter.vue | 5 +-
src/frontend/shared/tab-button.story.vue | 220 ++++++++++++++++++
src/frontend/shared/tab-button.vue | 10 +-
.../stories/components/resource-picker.vue | 13 +-
.../stories/components/workflow-actions.vue | 2 +-
src/frontend/stories/story-create.vue | 2 +-
src/frontend/stories/story-edit.vue | 2 +-
8 files changed, 240 insertions(+), 16 deletions(-)
create mode 100644 src/frontend/shared/tab-button.story.vue
diff --git a/src/frontend/resources/resources-edit.vue b/src/frontend/resources/resources-edit.vue
index 4a3161ca..b25107ca 100644
--- a/src/frontend/resources/resources-edit.vue
+++ b/src/frontend/resources/resources-edit.vue
@@ -6,7 +6,7 @@
v-if="!resource.id"
label="Create Resource"
:disabled="isSaving || !canCreate"
- variant="secondary"
+ variant="primary"
@click="save"
/>
{{ tab.count }}
diff --git a/src/frontend/shared/tab-button.story.vue b/src/frontend/shared/tab-button.story.vue
new file mode 100644
index 00000000..26fd3784
--- /dev/null
+++ b/src/frontend/shared/tab-button.story.vue
@@ -0,0 +1,220 @@
+
+
+
+
+
+ {{ tab }}
+
+
+
+
+
+
+
+ {{ tab.label }}
+
+ {{ tab.count }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Tab Button
+
+Shared pill-shaped button used to build tab-like controls: filter tabs
+(`index-filter.vue`), editor sidebar sections (`tab-navigation.vue`),
+toolbar sort toggles (`ui-toolbar.vue`, `story-gallery.vue`), and
+translation column visibility toggles (`translation-index.vue`).
+
+## Props
+
+- `label` — optional text rendered after the default slot; usages that need
+ the label inside slot content (e.g. filter tab counts) omit this and put
+ text directly in the slot instead.
+- `isActive` — highlights the button as the current selection.
+- `hasError` — shows an error indicator dot and error coloring.
+- `isAction` — `true` (default) renders a clickable `
diff --git a/src/frontend/shared/tab-button.vue b/src/frontend/shared/tab-button.vue
index d9adb3aa..0496e10a 100644
--- a/src/frontend/shared/tab-button.vue
+++ b/src/frontend/shared/tab-button.vue
@@ -3,7 +3,7 @@
:is="isAction ? 'button' : 'span'"
:type="isAction ? 'button' : undefined"
:disabled="isAction && disabled ? true : undefined"
- class="font-dmsans box-border inline-flex flex-none items-center gap-2 rounded-full border-b border-white px-4 py-3 text-sm font-medium leading-[19px] tracking-[-0.15px] [&_svg]:size-4"
+ class="font-dmsans box-border inline-flex flex-none items-center gap-2 rounded-full border px-4 py-3 text-sm font-medium leading-[19px] tracking-[-0.15px] [&_svg]:size-4"
:class="[
stateClasses,
isAction
@@ -55,13 +55,13 @@ const onClick = () => {
const stateClasses = computed(() => {
if (props.isActive) {
if (props.hasError) {
- return 'border border-error bg-[#F3F4F6] text-error [&_svg]:text-error';
+ return 'border-error bg-[#F3F4F6] text-error [&_svg]:text-error';
}
- return 'bg-[#F3F4F6] text-[#182E33] [&_svg]:text-[#111827]';
+ return 'border-studio-forest bg-studio-lime font-semibold text-studio-forest [&_svg]:text-studio-forest';
}
if (props.hasError) {
- return 'bg-transparent text-error [&_svg]:text-error';
+ return 'border-transparent bg-transparent text-error [&_svg]:text-error';
}
- return 'bg-transparent text-[#6A7282] [&_svg]:text-[#6A7282]';
+ return 'border-gray-200 bg-white text-studio-forest [&_svg]:text-studio-forest';
});
diff --git a/src/frontend/stories/components/resource-picker.vue b/src/frontend/stories/components/resource-picker.vue
index a419b779..cebda0a8 100644
--- a/src/frontend/stories/components/resource-picker.vue
+++ b/src/frontend/stories/components/resource-picker.vue
@@ -16,15 +16,15 @@
@input="showSearch = true"
/>
-
+
+
diff --git a/src/frontend/stories/story-create.vue b/src/frontend/stories/story-create.vue
index 1e76c952..e9e1e279 100644
--- a/src/frontend/stories/story-create.vue
+++ b/src/frontend/stories/story-create.vue
@@ -3,7 +3,7 @@
diff --git a/src/frontend/stories/story-edit.vue b/src/frontend/stories/story-edit.vue
index cc7aaff0..3a022cd2 100644
--- a/src/frontend/stories/story-edit.vue
+++ b/src/frontend/stories/story-edit.vue
@@ -12,7 +12,7 @@
From 2216fdf4059559e24026f65eb3e63132e4556ba3 Mon Sep 17 00:00:00 2001
From: Timothy Koech
Date: Thu, 30 Jul 2026 07:32:24 +0300
Subject: [PATCH 19/39] increment: update streams
---
docs/qa/changelog-qa.story.md | 115 ++++++++++
package.json | 1 +
scripts/generate-qa-changelog.mjs | 298 ++++++++++++++++++++++++++
src/frontend/streams/stream-index.vue | 19 +-
4 files changed, 426 insertions(+), 7 deletions(-)
create mode 100644 docs/qa/changelog-qa.story.md
create mode 100644 scripts/generate-qa-changelog.mjs
diff --git a/docs/qa/changelog-qa.story.md b/docs/qa/changelog-qa.story.md
new file mode 100644
index 00000000..a1ffef86
--- /dev/null
+++ b/docs/qa/changelog-qa.story.md
@@ -0,0 +1,115 @@
+---
+title: QA sco
+group: top
+icon: carbon:checklist
+---
+
+# QA: sco-2751-refine-studio-colours-brand
+
+**Base:** main @ `e214281`
+**Histoire:** `npm run dev` — open this page from the sidebar under the top group, or use relative links below.
+
+_Generated by `npm run changelog:qa -- --format histoire`. Edit the Summary section below._
+
+## Summary
+
+- _Describe the main themes of this branch for QA_
+
+## Visual checks — changed (Histoire)
+
+| Area | Group | Component | Open in Histoire |
+|------|-------|-----------|------------------|
+| Action card | dashboard | `action-card.vue` | [Action card](../../src/frontend/dashboard/action-card.story.vue) |
+| Action grid | dashboard | `action-grid.vue` | [Action grid](../../src/frontend/dashboard/action-grid.story.vue) |
+| Colors | shared | `colors.vue` | [Colors](../../src/frontend/shared/colors.story.vue) |
+| Dashboard Index | dashboard | `dashboard-index.vue` | [Dashboard Index](../../src/frontend/dashboard/dashboard-index.story.vue) |
+| Index Filter | shared | `index-filter.vue` | [Index Filter](../../src/frontend/shared/index-filter.story.vue) |
+| Index Page | pages | `pages-index.vue` | [Index Page](../../src/frontend/pages/pages-index.story.vue) |
+| Index Tabs | shared | `index-tabs.vue` | [Index Tabs](../../src/frontend/shared/index-tabs.story.vue) |
+| Invitation edit | invitation | `invitations-edit.vue` | [Invitation edit](../../src/frontend/invitation/invitations-edit.story.vue) |
+| Invitations index page | invitation | `invitations-index.vue` | [Invitations index page](../../src/frontend/invitation/invitations-index.story.vue) |
+| Language block | dashboard | `language-block.vue` | [Language block](../../src/frontend/dashboard/language-block.story.vue) |
+| Language List | settings | `language-list.vue` | [Language List](../../src/frontend/settings/languages/language-list.story.vue) |
+| Languages Edit | settings | `languages-edit.vue` | [Languages Edit](../../src/frontend/settings/languages/languages-edit.story.vue) |
+| Panel List | stories | `panel-list.vue` | [Panel List](../../src/frontend/stories/components/panel-list.story.vue) |
+| Preview | stories | `chapter-preview.vue` | [Preview](../../src/frontend/stories/chapter-preview.story.vue) |
+| Request Feedback Modal | settings | `request-feedback-modal.vue` | [Request Feedback Modal](../../src/frontend/settings/languages/components/request-feedback-modal.story.vue) |
+| Resource edit | resources | `resources-edit.vue` | [Resource edit](../../src/frontend/resources/resources-edit.story.vue) |
+| Resource Empty State | resources | `resource-empty-state.vue` | [Resource Empty State](../../src/frontend/stories/components/resource-empty-state.story.vue) |
+| Resource Picker | resources | `resource-picker.vue` | [Resource Picker](../../src/frontend/stories/components/resource-picker.story.vue) |
+| Ring | dashboard | `ring.vue` | [Ring](../../src/frontend/dashboard/ring.story.vue) |
+| Stat tiles | dashboard | `stat-tiles.vue` | [Stat tiles](../../src/frontend/dashboard/stat-tiles.story.vue) |
+| Story Create | stories | `story-create.vue` | [Story Create](../../src/frontend/stories/story-create.story.vue) |
+| Story Edit | stories | `story-edit.vue` | [Story Edit](../../src/frontend/stories/story-edit.story.vue) |
+| Studio Button | shared | `studio-button.vue` | [Studio Button](../../src/frontend/shared/studio-button.story.vue) |
+| Tab Button | shared | `tab-button.vue` | [Tab Button](../../src/frontend/shared/tab-button.story.vue) |
+| Workflow Buttons | stories | `workflow-actions.vue` | [Workflow Buttons](../../src/frontend/stories/components/workflow-actions.story.vue) |
+
+## Unchanged — regression check
+
+_Unchanged `.vue` files with co-located stories in folders where something changed. Confirm these still look correct._
+
+| Area | Group | Component | Open in Histoire |
+|------|-------|-----------|------------------|
+| Action Button | shared | `action-button.vue` | [Action Button](../../src/frontend/shared/action-button.story.vue) |
+| Add Item Button | shared | `add-item-button.vue` | [Add Item Button](../../src/frontend/shared/add-item-button.story.vue) |
+| App Layout Header | shared | `app-layout-header.vue` | [App Layout Header](../../src/frontend/shared/app-layout-header.story.vue) |
+| Bible Translations Modal | settings | `bible-translations-modal.vue` | [Bible Translations Modal](../../src/frontend/settings/languages/components/bible-translations-modal.story.vue) |
+| Bookmark Action | shared | `bookmark-action.vue` | [Bookmark Action](../../src/frontend/shared/bookmark-action.story.vue) |
+| Context Menu | shared | `context-menu.vue` | [Context Menu](../../src/frontend/shared/context-menu.story.vue) |
+| Draft Page | stories | `draft-index.vue` | [Draft Page](../../src/frontend/stories/draft-index.story.vue) |
+| Drop Down | shared | `drop-down.vue` | [Drop Down](../../src/frontend/shared/drop-down.story.vue) |
+| Expandable Search | shared | `expandable-search.vue` | [Expandable Search](../../src/frontend/shared/expandable-search.story.vue) |
+| Gallery Grid | shared | `gallery-grid.vue` | [Gallery Grid](../../src/frontend/shared/gallery-grid.story.vue) |
+| Glass Button | shared | `glass-button.vue` | [Glass Button](../../src/frontend/shared/glass-button.story.vue) |
+| Icon Button | shared | `icon-button.vue` | [Icon Button](../../src/frontend/shared/icon-button.story.vue) |
+| Index Card | stories | `index-card.vue` | [Index Card](../../src/frontend/stories/components/index-card.story.vue) |
+| Invitation index item | invitation | `invitation-index-item.vue` | [Invitation index item](../../src/frontend/invitation/invitation-index-item.story.vue) |
+| Label Button | shared | `label-button.vue` | [Label Button](../../src/frontend/shared/label-button.story.vue) |
+| Language List Item | settings | `language-list-item.vue` | [Language List Item](../../src/frontend/settings/languages/components/language-list-item.story.vue) |
+| Language Table | settings | `language-table.vue` | [Language Table](../../src/frontend/settings/languages/components/language-table.story.vue) |
+| List Switcher | shared | `list-switcher.vue` | [List Switcher](../../src/frontend/shared/list-switcher.story.vue) |
+| Message | shared | `message-centre.vue` | [Message](../../src/frontend/shared/message-centre.story.vue) |
+| Meta Box | shared | `meta-box.vue` | [Meta Box](../../src/frontend/shared/meta-box.story.vue) |
+| Meta Meta Box | stories | `meta-meta-box.vue` | [Meta Meta Box](../../src/frontend/stories/components/meta-meta-box.story.vue) |
+| Nav rail panel | shared | `nav-rail-panel.vue` | [Nav rail panel](../../src/frontend/shared/nav-rail-panel.story.vue) |
+| Navigation pane | shared | `navigation-pane.vue` | [Navigation pane](../../src/frontend/shared/navigation-pane.story.vue) |
+| Page Index Item | pages | `page-index-item.vue` | [Page Index Item](../../src/frontend/pages/page-index-item.story.vue) |
+| Pages Edit | pages | `pages-edit.vue` | [Pages Edit](../../src/frontend/pages/pages-edit.story.vue) |
+| Remove Language Modal | settings | `remove-language-modal.vue` | [Remove Language Modal](../../src/frontend/settings/languages/components/remove-language-modal.story.vue) |
+| Request App Update Modal | settings | `request-app-update-modal.vue` | [Request App Update Modal](../../src/frontend/settings/languages/components/request-app-update-modal.story.vue) |
+| Resource Attached Item | resources | `resource-attached-item.vue` | [Resource Attached Item](../../src/frontend/stories/components/resource-attached-item.story.vue) |
+| Resource Attached List | resources | `resource-attached-list.vue` | [Resource Attached List](../../src/frontend/stories/components/resource-attached-list.story.vue) |
+| Resource Index Item | resources | `resource-index-item.vue` | [Resource Index Item](../../src/frontend/resources/resource-index-item.story.vue) |
+| Resource Label Group | resources | `resource-label-group.vue` | [Resource Label Group](../../src/frontend/stories/components/resource-label-group.story.vue) |
+| Resource not found | resources | `resource-not-found.vue` | [Resource not found](../../src/frontend/resources/resource-not-found.story.vue) |
+| Resource Thumbnail | resources | `resource-thumbnail.vue` | [Resource Thumbnail](../../src/frontend/stories/components/resource-thumbnail.story.vue) |
+| Resource Type Badge | resources | `resource-type-badge.vue` | [Resource Type Badge](../../src/frontend/stories/components/resource-type-badge.story.vue) |
+| Resource Used In | resources | `resource-used-in.vue` | [Resource Used In](../../src/frontend/resources/resource-used-in.story.vue) |
+| Resources index page | resources | `resources-index.vue` | [Resources index page](../../src/frontend/resources/resources-index.story.vue) |
+| Rich Listbox | shared | `rich-listbox.vue` | [Rich Listbox](../../src/frontend/shared/rich-listbox.story.vue) |
+| Status Tag | shared | `status-tag.vue` | [Status Tag](../../src/frontend/shared/status-tag.story.vue) |
+| Story Edit Details | stories | `story-edit-details.vue` | [Story Edit Details](../../src/frontend/stories/components/story-edit-details.story.vue) |
+| Story Edit Resources | resources | `story-edit-resources.vue` | [Story Edit Resources](../../src/frontend/stories/components/story-edit-resources.story.vue) |
+| Story Edit Sections | stories | `story-edit-sections.vue` | [Story Edit Sections](../../src/frontend/stories/components/story-edit-sections.story.vue) |
+| Story Gallery | stories | `story-gallery.vue` | [Story Gallery](../../src/frontend/stories/story-gallery.story.vue) |
+| Story Index | stories | `story-index.vue` | [Story Index](../../src/frontend/stories/story-index.story.vue) |
+| Story Item | stories | `story-item.vue` | [Story Item](../../src/frontend/stories/components/story-item.story.vue) |
+| Tab navigation | shared | `tab-navigation.vue` | [Tab navigation](../../src/frontend/shared/tab-navigation.story.vue) |
+| Toggle Button | shared | `toggle-button.vue` | [Toggle Button](../../src/frontend/shared/toggle-button.story.vue) |
+| Translation Page | stories | `translation-index.vue` | [Translation Page](../../src/frontend/stories/translation-index.story.vue) |
+
+## No dedicated story — test indirectly
+
+| Component | Notes |
+|-----------|-------|
+| `src/frontend/dashboard/ring-block.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/dashboard/stat-tile.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/fields/list/foldable-list.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/settings/languages/components/language-table-row.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/shared/app-footer.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/shared/app-layout.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/shared/icon.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/shared/index-tab-button.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/team/components/user-form-modal.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/team/components/user-row.vue` | Find a parent page story or add a co-located `.story.vue` |
diff --git a/package.json b/package.json
index b9574006..f7fa086d 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"scripts": {
"dev": "histoire dev",
"colors:usage": "node scripts/generate-color-usage.mjs",
+ "changelog:qa": "node scripts/generate-qa-changelog.mjs",
"todo-lint": "eslint .",
"clean": "del-cli dist",
"types:build": "tsc -p tsconfig.types.json",
diff --git a/scripts/generate-qa-changelog.mjs b/scripts/generate-qa-changelog.mjs
new file mode 100644
index 00000000..2f4d0e84
--- /dev/null
+++ b/scripts/generate-qa-changelog.mjs
@@ -0,0 +1,298 @@
+import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
+import { dirname, join, relative } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { execSync } from 'node:child_process';
+import { kebabCase } from 'change-case';
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const root = join(__dirname, '..');
+const defaultOutDir = join(root, 'docs', 'qa');
+
+function parseArgs(argv) {
+ const options = {
+ base: 'main',
+ port: 6006,
+ out: null,
+ host: 'http://localhost',
+ format: 'github',
+ };
+
+ for (let i = 0; i < argv.length; i++) {
+ const arg = argv[i];
+ if (arg === '--base') options.base = argv[++i];
+ else if (arg === '--port') options.port = Number(argv[++i]);
+ else if (arg === '--out') options.out = argv[++i];
+ else if (arg === '--host') options.host = argv[++i].replace(/\/$/, '');
+ else if (arg === '--format') {
+ const value = argv[++i];
+ options.format = value === 'historie' ? 'histoire' : value;
+ }
+ }
+
+ return options;
+}
+
+function git(command) {
+ return execSync(command, { cwd: root, encoding: 'utf8' }).trim();
+}
+
+function storyLink(storyPath, options, outPath) {
+ if (options.format === 'histoire') {
+ const rel = relative(dirname(outPath), join(root, storyPath)).replace(/\\/g, '/');
+ return rel.startsWith('.') ? rel : `./${rel}`;
+ }
+
+ const id = kebabCase(storyPath.toLowerCase());
+ return `${options.host}:${options.port}/story/${id}`;
+}
+
+function siblingStoryPath(vuePath) {
+ if (vuePath.endsWith('.story.vue')) return vuePath;
+ const slash = vuePath.lastIndexOf('/');
+ const dir = vuePath.substring(0, slash);
+ const base = vuePath.substring(slash + 1).replace(/\.vue$/, '');
+ return `${dir}/${base}.story.vue`;
+}
+
+function componentFileName(storyPath) {
+ return storyPath.replace(/\.story\.vue$/, '.vue').split('/').pop();
+}
+
+function parseStoryMeta(storyPath) {
+ const content = readFileSync(storyPath, 'utf8');
+ const title = content.match(/]*\stitle="([^"]+)"/)?.[1] ?? storyPath;
+ const group = content.match(/]*\sgroup="([^"]+)"/)?.[1] ?? '';
+ return { title, group };
+}
+
+function collectChangedVueFiles(mergeBase) {
+ return git(`git diff --name-only ${mergeBase}..HEAD -- '*.vue'`)
+ .split('\n')
+ .filter(Boolean);
+}
+
+function collectStories(changedVueFiles) {
+ const stories = new Map();
+
+ for (const file of changedVueFiles) {
+ const storyPath = siblingStoryPath(file);
+ if (!existsSync(storyPath)) continue;
+ if (stories.has(storyPath)) continue;
+
+ const { title, group } = parseStoryMeta(storyPath);
+ stories.set(storyPath, { title, group, sourceFiles: [file] });
+ }
+
+ for (const file of changedVueFiles) {
+ if (file.endsWith('.story.vue') && existsSync(file) && !stories.has(file)) {
+ const { title, group } = parseStoryMeta(file);
+ stories.set(file, { title, group, sourceFiles: [file] });
+ }
+ }
+
+ return stories;
+}
+
+function collectUnchangedStories(changedVueFiles, changedStories) {
+ const changed = new Set(changedVueFiles);
+ const changedStoryPaths = new Set(changedStories.keys());
+ const dirs = [...new Set(changedVueFiles.map((f) => f.replace(/\/[^/]+$/, '')))];
+ const stories = new Map();
+
+ for (const dir of dirs.sort()) {
+ const files = git(`git ls-files '${dir}/*.vue'`).split('\n').filter(Boolean);
+ for (const file of files) {
+ if (changed.has(file)) continue;
+ if (file.endsWith('.story.vue')) continue;
+
+ const storyPath = siblingStoryPath(file);
+ if (!existsSync(storyPath)) continue;
+ if (changedStoryPaths.has(storyPath)) continue;
+ if (stories.has(storyPath)) continue;
+
+ const { title, group } = parseStoryMeta(storyPath);
+ stories.set(storyPath, { title, group, sourceFile: file });
+ }
+ }
+
+ return stories;
+}
+
+function collectNoStoryFiles(changedVueFiles, stories) {
+ const covered = new Set();
+ for (const storyPath of stories.keys()) {
+ covered.add(storyPath);
+ covered.add(storyPath.replace(/\.story\.vue$/, '.vue'));
+ }
+
+ return changedVueFiles.filter((file) => {
+ if (file.endsWith('.story.vue')) return false;
+ if (covered.has(file)) return false;
+ return !existsSync(siblingStoryPath(file));
+ });
+}
+
+function appendStoryTable(lines, stories, options, outPath) {
+ for (const [storyPath, meta] of [...stories.entries()].sort((a, b) =>
+ a[1].title.localeCompare(b[1].title),
+ )) {
+ const url = storyLink(storyPath, options, outPath);
+ lines.push(
+ `| ${meta.title} | ${meta.group} | \`${componentFileName(storyPath)}\` | [${meta.title}](${url}) |`,
+ );
+ }
+}
+
+function buildGithubMarkdown({
+ branch,
+ mergeBase,
+ options,
+ stories,
+ unchangedStories,
+ noStoryFiles,
+ outPath,
+}) {
+ const baseUrl = `${options.host}:${options.port}`;
+ const lines = [
+ `# QA: ${branch}`,
+ '',
+ `**Base:** ${options.base} @ \`${mergeBase.slice(0, 7)}\` `,
+ `**Histoire (local):** \`npm run dev\` → ${baseUrl} `,
+ '**Histoire (preview):** After opening a PR, use the Cloudflare Pages deployment URL from the PR checks (project: `kit`). Replace the localhost base URL below.',
+ '',
+ '_Generated by `npm run changelog:qa`. Edit the Summary section below._',
+ '',
+ '## Summary',
+ '',
+ '- _Describe the main themes of this branch for QA_',
+ '',
+ '## Visual checks — changed (Histoire)',
+ '',
+ '| Area | Group | Component | Open in Histoire |',
+ '|------|-------|-----------|------------------|',
+ ];
+
+ appendStoryTable(lines, stories, options, outPath);
+
+ lines.push(
+ '',
+ '## Unchanged — regression check',
+ '',
+ '_Unchanged `.vue` files with co-located stories in folders where something changed. Confirm these still look correct._',
+ '',
+ '| Area | Group | Component | Open in Histoire |',
+ '|------|-------|-----------|------------------|',
+ );
+
+ appendStoryTable(lines, unchangedStories, options, outPath);
+
+ lines.push('', '## No dedicated story — test indirectly', '', '| Component | Notes |', '|-----------|-------|');
+
+ if (noStoryFiles.length === 0) {
+ lines.push('| _None_ | All changed `.vue` files have co-located stories or are covered above |');
+ } else {
+ for (const file of noStoryFiles.sort()) {
+ lines.push(`| \`${file}\` | Find a parent page story or add a co-located \`.story.vue\` |`);
+ }
+ }
+
+ lines.push('');
+
+ return lines.join('\n');
+}
+
+function buildHistoireMarkdown({
+ branch,
+ mergeBase,
+ options,
+ stories,
+ unchangedStories,
+ noStoryFiles,
+ outPath,
+}) {
+ const lines = [
+ '---',
+ `title: QA ${branch.split('-')[0] ?? branch}`,
+ 'group: top',
+ 'icon: carbon:checklist',
+ '---',
+ '',
+ `# QA: ${branch}`,
+ '',
+ `**Base:** ${options.base} @ \`${mergeBase.slice(0, 7)}\` `,
+ '**Histoire:** `npm run dev` — open this page from the sidebar under the top group, or use relative links below.',
+ '',
+ '_Generated by `npm run changelog:qa -- --format histoire`. Edit the Summary section below._',
+ '',
+ '## Summary',
+ '',
+ '- _Describe the main themes of this branch for QA_',
+ '',
+ '## Visual checks — changed (Histoire)',
+ '',
+ '| Area | Group | Component | Open in Histoire |',
+ '|------|-------|-----------|------------------|',
+ ];
+
+ appendStoryTable(lines, stories, options, outPath);
+
+ lines.push(
+ '',
+ '## Unchanged — regression check',
+ '',
+ '_Unchanged `.vue` files with co-located stories in folders where something changed. Confirm these still look correct._',
+ '',
+ '| Area | Group | Component | Open in Histoire |',
+ '|------|-------|-----------|------------------|',
+ );
+
+ appendStoryTable(lines, unchangedStories, options, outPath);
+
+ lines.push('', '## No dedicated story — test indirectly', '', '| Component | Notes |', '|-----------|-------|');
+
+ if (noStoryFiles.length === 0) {
+ lines.push('| _None_ | All changed `.vue` files have co-located stories or are covered above |');
+ } else {
+ for (const file of noStoryFiles.sort()) {
+ lines.push(`| \`${file}\` | Find a parent page story or add a co-located \`.story.vue\` |`);
+ }
+ }
+
+ lines.push('');
+
+ return lines.join('\n');
+}
+
+function main() {
+ const options = parseArgs(process.argv.slice(2));
+ const branch = git('git branch --show-current');
+ const mergeBase = git(`git merge-base HEAD ${options.base}`);
+ const changedVueFiles = collectChangedVueFiles(mergeBase);
+ const stories = collectStories(changedVueFiles);
+ const unchangedStories = collectUnchangedStories(changedVueFiles, stories);
+ const noStoryFiles = collectNoStoryFiles(changedVueFiles, stories);
+
+ const extension = options.format === 'histoire' ? '.story.md' : '.md';
+ const outPath = options.out ?? join(defaultOutDir, `changelog-qa${extension}`);
+
+ const build = options.format === 'histoire' ? buildHistoireMarkdown : buildGithubMarkdown;
+ const markdown = build({
+ branch,
+ mergeBase,
+ options,
+ stories,
+ unchangedStories,
+ noStoryFiles,
+ outPath,
+ });
+
+ mkdirSync(dirname(outPath), { recursive: true });
+ writeFileSync(outPath, markdown);
+
+ console.log(`Wrote ${outPath} (${options.format} format)`);
+ console.log(` ${stories.size} changed Histoire stories`);
+ console.log(` ${unchangedStories.size} unchanged Histoire stories`);
+ console.log(` ${noStoryFiles.length} changed files without stories`);
+}
+
+main();
diff --git a/src/frontend/streams/stream-index.vue b/src/frontend/streams/stream-index.vue
index 9626b441..5c0aa853 100644
--- a/src/frontend/streams/stream-index.vue
+++ b/src/frontend/streams/stream-index.vue
@@ -13,14 +13,18 @@
>
-
+ @click="sortDescending = !sortDescending"
+ >
+
+
+
@@ -67,7 +71,8 @@
import { SharedPageProps } from '../../types';
import IndexFilter from '../shared/index-filter.vue';
-import ToggleButton from '../shared/toggle-button.vue';
+import TabButton from '../shared/tab-button.vue';
+import { ArrowDownWideNarrow, ArrowUpWideNarrow } from '@lucide/vue';
import AppLayout from '../shared/app-layout.vue';
import Icon from '../shared/icon.vue';
From a2208a4496d46e6671c6c2f19bce70fd419f0394 Mon Sep 17 00:00:00 2001
From: Timothy Koech
Date: Thu, 30 Jul 2026 07:42:06 +0300
Subject: [PATCH 20/39] refactor: remove ToggleButton component and its
associated story
---
docs/qa/changelog-qa.story.md | 7 ++-
src/frontend/index.ts | 2 -
src/frontend/shared/colors.palette.ts | 1 -
src/frontend/shared/colors.usage.ts | 49 ++++++++++++---------
src/frontend/shared/toggle-button.story.vue | 31 -------------
src/frontend/shared/toggle-button.vue | 35 ---------------
6 files changed, 33 insertions(+), 92 deletions(-)
delete mode 100644 src/frontend/shared/toggle-button.story.vue
delete mode 100644 src/frontend/shared/toggle-button.vue
diff --git a/docs/qa/changelog-qa.story.md b/docs/qa/changelog-qa.story.md
index a1ffef86..f0600d1d 100644
--- a/docs/qa/changelog-qa.story.md
+++ b/docs/qa/changelog-qa.story.md
@@ -41,6 +41,7 @@ _Generated by `npm run changelog:qa -- --format histoire`. Edit the Summary sect
| Stat tiles | dashboard | `stat-tiles.vue` | [Stat tiles](../../src/frontend/dashboard/stat-tiles.story.vue) |
| Story Create | stories | `story-create.vue` | [Story Create](../../src/frontend/stories/story-create.story.vue) |
| Story Edit | stories | `story-edit.vue` | [Story Edit](../../src/frontend/stories/story-edit.story.vue) |
+| Stream Index | streams | `stream-index.vue` | [Stream Index](../../src/frontend/streams/stream-index.story.vue) |
| Studio Button | shared | `studio-button.vue` | [Studio Button](../../src/frontend/shared/studio-button.story.vue) |
| Tab Button | shared | `tab-button.vue` | [Tab Button](../../src/frontend/shared/tab-button.story.vue) |
| Workflow Buttons | stories | `workflow-actions.vue` | [Workflow Buttons](../../src/frontend/stories/components/workflow-actions.story.vue) |
@@ -59,6 +60,9 @@ _Unchanged `.vue` files with co-located stories in folders where something chang
| Context Menu | shared | `context-menu.vue` | [Context Menu](../../src/frontend/shared/context-menu.story.vue) |
| Draft Page | stories | `draft-index.vue` | [Draft Page](../../src/frontend/stories/draft-index.story.vue) |
| Drop Down | shared | `drop-down.vue` | [Drop Down](../../src/frontend/shared/drop-down.story.vue) |
+| Drop Edit | streams | `drop-edit.vue` | [Drop Edit](../../src/frontend/streams/drop-edit.story.vue) |
+| Drop Item | streams | `drop-item.vue` | [Drop Item](../../src/frontend/streams/components/drop-item.story.vue) |
+| Drop Meta Box | streams | `drop-meta-box.vue` | [Drop Meta Box](../../src/frontend/streams/components/drop-meta-box.story.vue) |
| Expandable Search | shared | `expandable-search.vue` | [Expandable Search](../../src/frontend/shared/expandable-search.story.vue) |
| Gallery Grid | shared | `gallery-grid.vue` | [Gallery Grid](../../src/frontend/shared/gallery-grid.story.vue) |
| Glass Button | shared | `glass-button.vue` | [Glass Button](../../src/frontend/shared/glass-button.story.vue) |
@@ -95,8 +99,9 @@ _Unchanged `.vue` files with co-located stories in folders where something chang
| Story Gallery | stories | `story-gallery.vue` | [Story Gallery](../../src/frontend/stories/story-gallery.story.vue) |
| Story Index | stories | `story-index.vue` | [Story Index](../../src/frontend/stories/story-index.story.vue) |
| Story Item | stories | `story-item.vue` | [Story Item](../../src/frontend/stories/components/story-item.story.vue) |
+| Stream Gallery | streams | `stream-gallery.vue` | [Stream Gallery](../../src/frontend/streams/stream-gallery.story.vue) |
+| Stream Item | streams | `stream-item.vue` | [Stream Item](../../src/frontend/streams/components/stream-item.story.vue) |
| Tab navigation | shared | `tab-navigation.vue` | [Tab navigation](../../src/frontend/shared/tab-navigation.story.vue) |
-| Toggle Button | shared | `toggle-button.vue` | [Toggle Button](../../src/frontend/shared/toggle-button.story.vue) |
| Translation Page | stories | `translation-index.vue` | [Translation Page](../../src/frontend/stories/translation-index.story.vue) |
## No dedicated story — test indirectly
diff --git a/src/frontend/index.ts b/src/frontend/index.ts
index 93385277..c2d902b4 100644
--- a/src/frontend/index.ts
+++ b/src/frontend/index.ts
@@ -58,7 +58,6 @@ import StreamGallery from './streams/stream-gallery.vue';
import StreamIndex from './streams/stream-index.vue';
import StringField from './fields/string-field.vue';
import TagField from './fields/tag-field.vue';
-import ToggleButton from './shared/toggle-button.vue';
import TranslationIndex from './stories/translation-index.vue';
import UiPage from './ui/ui-page.vue';
import UsersIndex from './team/users-index.vue';
@@ -132,7 +131,6 @@ export {
StreamIndex,
StringField,
TagField,
- ToggleButton,
TranslationIndex,
UiPage,
UsersIndex,
diff --git a/src/frontend/shared/colors.palette.ts b/src/frontend/shared/colors.palette.ts
index b662544c..e66f0f62 100644
--- a/src/frontend/shared/colors.palette.ts
+++ b/src/frontend/shared/colors.palette.ts
@@ -118,7 +118,6 @@ export const colorSections: ColorSection[] = [
{
title: 'Indigo',
colors: [
- { name: 'indigo-100', class: 'bg-indigo-100' },
{ name: 'indigo-200', class: 'bg-indigo-200' },
{ name: 'indigo-50', class: 'bg-indigo-50' },
{ name: 'indigo-500', class: 'bg-indigo-500' },
diff --git a/src/frontend/shared/colors.usage.ts b/src/frontend/shared/colors.usage.ts
index 0380e077..028a162d 100644
--- a/src/frontend/shared/colors.usage.ts
+++ b/src/frontend/shared/colors.usage.ts
@@ -71,7 +71,7 @@ export const colorUsage: Record = {
'index.css',
'shared/pill-button.vue',
] },
- 'blue-50': { count: 66, files: [
+ 'blue-50': { count: 65, files: [
'audience/audience-index.vue',
'fields/select-field.vue',
'index.css',
@@ -89,7 +89,6 @@ export const colorUsage: Record = {
'shared/draft-actions.vue',
'shared/expandable-search.vue',
'shared/glass-button.vue',
- 'shared/index-filter.vue',
'shared/label-hint.vue',
'shared/message-centre.vue',
'shared/pill-button.vue',
@@ -141,11 +140,10 @@ export const colorUsage: Record = {
'team/components/user-row.vue',
'ui/components/ui-card.vue',
] },
- 'blue-700': { count: 9, files: [
+ 'blue-700': { count: 8, files: [
'invitation/invitation-index-item.vue',
'resources/resource-index-item.vue',
'settings/languages/components/request-app-update-modal.vue',
- 'shared/index-filter.vue',
'stories/components/resource-utils.ts',
'team/components/user-row.vue',
] },
@@ -200,7 +198,7 @@ export const colorUsage: Record = {
'dashboard/stat-tile.vue',
'fields/list/foldable-list.vue',
] },
- 'gray-100': { count: 71, files: [
+ 'gray-100': { count: 73, files: [
'fields/list/flat-list.vue',
'fields/region-field.vue',
'fields/scripture-field.vue',
@@ -221,6 +219,7 @@ export const colorUsage: Record = {
'shared/drop-down.vue',
'shared/drop-up.vue',
'shared/gallery-grid.story.vue',
+ 'shared/index-filter.vue',
'shared/index-tab-button.vue',
'shared/label-hint-popup.vue',
'shared/language-selector.vue',
@@ -228,6 +227,7 @@ export const colorUsage: Record = {
'shared/meta-box.vue',
'shared/nav-rail-panel.vue',
'shared/nav-rail-toolbar.vue',
+ 'shared/tab-button.story.vue',
'stories/components/index-card.vue',
'stories/components/panel-list.vue',
'stories/components/resource-attached-item.vue',
@@ -240,7 +240,7 @@ export const colorUsage: Record = {
'streams/components/stream-item.vue',
'team/components/user-row.vue',
] },
- 'gray-200': { count: 96, files: [
+ 'gray-200': { count: 97, files: [
'audience/audience-index.vue',
'dashboard/stat-tile.vue',
'fields/attachments/file-upload.vue',
@@ -274,6 +274,7 @@ export const colorUsage: Record = {
'shared/pill-button.vue',
'shared/rich-listbox.vue',
'shared/studio-button.vue',
+ 'shared/tab-button.vue',
'stories/components/index-card.story.vue',
'stories/components/index-card.vue',
'stories/components/panel-list.vue',
@@ -287,7 +288,7 @@ export const colorUsage: Record = {
'ui/components/ui-card.vue',
'ui/components/ui-string-item.vue',
] },
- 'gray-300': { count: 61, files: [
+ 'gray-300': { count: 60, files: [
'audience/audience-index.vue',
'auth/create-account.vue',
'auth/login-index.vue',
@@ -316,7 +317,6 @@ export const colorUsage: Record = {
'shared/pagination.vue',
'shared/rich-listbox.vue',
'shared/studio-button.vue',
- 'shared/toggle-button.vue',
'stories/components/resource-picker.vue',
'streams/stream-index.vue',
'ui/components/ui-card.vue',
@@ -358,7 +358,7 @@ export const colorUsage: Record = {
'team/components/user-row.vue',
'ui/components/ui-card.vue',
] },
- 'gray-50': { count: 229, files: [
+ 'gray-50': { count: 231, files: [
'audience/audience-index.vue',
'audience/components/audience-row.vue',
'dashboard/language-block.vue',
@@ -404,6 +404,7 @@ export const colorUsage: Record = {
'shared/gallery-grid.story.vue',
'shared/gallery-item.vue',
'shared/glass-button.story.vue',
+ 'shared/index-filter.vue',
'shared/index-tab-button.vue',
'shared/list-switcher.vue',
'shared/meta-box.vue',
@@ -411,6 +412,7 @@ export const colorUsage: Record = {
'shared/pagination.vue',
'shared/public-layout.vue',
'shared/rich-listbox.vue',
+ 'shared/tab-button.story.vue',
'stories/components/index-card.story.vue',
'stories/components/index-card.vue',
'stories/components/resource-attached-item.vue',
@@ -426,7 +428,7 @@ export const colorUsage: Record = {
'team/users-index.vue',
'ui/ui-page.vue',
] },
- 'gray-500': { count: 159, files: [
+ 'gray-500': { count: 161, files: [
'audience/audience-index.vue',
'audience/components/audience-row.vue',
'dashboard/language-block.vue',
@@ -467,10 +469,12 @@ export const colorUsage: Record = {
'shared/expandable-search.vue',
'shared/gallery-grid.story.vue',
'shared/gallery-item.vue',
+ 'shared/index-filter.vue',
'shared/index-tab-button.vue',
'shared/list-switcher.vue',
'shared/meta-box.vue',
'shared/rich-listbox.vue',
+ 'shared/tab-button.story.vue',
'stories/components/index-card.story.vue',
'stories/components/index-card.vue',
'stories/components/resource-attached-item.vue',
@@ -528,7 +532,7 @@ export const colorUsage: Record = {
'team/components/user-row.vue',
'ui/components/ui-card.vue',
] },
- 'gray-700': { count: 46, files: [
+ 'gray-700': { count: 45, files: [
'fields/attachments/video-meta.vue',
'fields/list/foldable-list.vue',
'fields/panel-field.vue',
@@ -547,7 +551,6 @@ export const colorUsage: Record = {
'shared/pagination.vue',
'shared/pill-button.vue',
'shared/studio-button.vue',
- 'shared/toggle-button.vue',
'stories/components/resource-attached-item.vue',
'stories/components/resource-picker.vue',
'stories/components/resource-utils.ts',
@@ -654,9 +657,6 @@ export const colorUsage: Record = {
'stories/components/story-item.vue',
'streams/components/stream-item.vue',
] },
- 'indigo-100': { count: 1, files: [
- 'shared/toggle-button.vue',
- ] },
'indigo-200': { count: 2, files: [
'settings/languages/components/request-app-update-modal.vue',
] },
@@ -688,12 +688,11 @@ export const colorUsage: Record = {
'ui/components/ui-card.vue',
'ui/ui-page.vue',
] },
- 'indigo-700': { count: 7, files: [
+ 'indigo-700': { count: 5, files: [
'fields/attachments/file-upload.vue',
'fields/section-panel-field.vue',
'shared/add-item-button.vue',
'shared/navigation-pane.vue',
- 'shared/toggle-button.vue',
] },
'orange-100': { count: 1, files: [
'stories/components/resource-utils.ts',
@@ -765,25 +764,31 @@ export const colorUsage: Record = {
'streams/components/stream-item.vue',
] },
'studio-dark': { count: 0, files: [] },
- 'studio-forest': { count: 9, files: [
+ 'studio-forest': { count: 17, files: [
'dashboard/language-block.vue',
'dashboard/ring.vue',
'shared/app-footer.vue',
+ 'shared/index-filter.vue',
'shared/index-tab-button.vue',
'shared/studio-button.vue',
+ 'shared/tab-button.story.vue',
+ 'shared/tab-button.vue',
] },
- 'studio-green': { count: 12, files: [
+ 'studio-green': { count: 11, files: [
+ 'shared/index-filter.vue',
'shared/studio-button.vue',
+ 'shared/tab-button.story.vue',
'stories/components/panel-list.vue',
'stories/components/resource-empty-state.vue',
'stories/components/resource-picker.vue',
] },
- 'studio-lime': { count: 6, files: [
+ 'studio-lime': { count: 7, files: [
'dashboard/language-block.vue',
'dashboard/ring.vue',
'dashboard/stat-tile.vue',
'shared/index-tab-button.vue',
'shared/studio-button.vue',
+ 'shared/tab-button.vue',
] },
'studio-yellow': { count: 1, files: [
'dashboard/action-card.vue',
@@ -816,7 +821,7 @@ export const colorUsage: Record = {
'violet-700': { count: 1, files: [
'stories/components/resource-utils.ts',
] },
- 'white': { count: 168, files: [
+ 'white': { count: 175, files: [
'audience/audience-index.vue',
'dashboard/action-card.vue',
'dashboard/language-block.vue',
@@ -877,8 +882,8 @@ export const colorUsage: Record = {
'shared/pill-button.vue',
'shared/rich-listbox.vue',
'shared/studio-button.vue',
+ 'shared/tab-button.story.vue',
'shared/tab-button.vue',
- 'shared/toggle-button.vue',
'stories/components/index-card.story.vue',
'stories/components/index-card.vue',
'stories/components/panel-list.vue',
diff --git a/src/frontend/shared/toggle-button.story.vue b/src/frontend/shared/toggle-button.story.vue
deleted file mode 100644
index 4416d488..00000000
--- a/src/frontend/shared/toggle-button.story.vue
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/frontend/shared/toggle-button.vue b/src/frontend/shared/toggle-button.vue
deleted file mode 100644
index 507ca8a9..00000000
--- a/src/frontend/shared/toggle-button.vue
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
From ad5c98b66d502997d2a1b11adb3b5923c776c1db Mon Sep 17 00:00:00 2001
From: Timothy Koech
Date: Thu, 30 Jul 2026 07:53:18 +0300
Subject: [PATCH 21/39] style: update ListSwitcher button styles and replace
icon with Grid3X3
---
docs/qa/changelog-qa.story.md | 1 +
src/frontend/shared/list-switcher.vue | 12 ++++++------
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/docs/qa/changelog-qa.story.md b/docs/qa/changelog-qa.story.md
index f0600d1d..a6e27fb6 100644
--- a/docs/qa/changelog-qa.story.md
+++ b/docs/qa/changelog-qa.story.md
@@ -116,5 +116,6 @@ _Unchanged `.vue` files with co-located stories in folders where something chang
| `src/frontend/shared/app-layout.vue` | Find a parent page story or add a co-located `.story.vue` |
| `src/frontend/shared/icon.vue` | Find a parent page story or add a co-located `.story.vue` |
| `src/frontend/shared/index-tab-button.vue` | Find a parent page story or add a co-located `.story.vue` |
+| `src/frontend/shared/toggle-button.vue` | Find a parent page story or add a co-located `.story.vue` |
| `src/frontend/team/components/user-form-modal.vue` | Find a parent page story or add a co-located `.story.vue` |
| `src/frontend/team/components/user-row.vue` | Find a parent page story or add a co-located `.story.vue` |
diff --git a/src/frontend/shared/list-switcher.vue b/src/frontend/shared/list-switcher.vue
index f86f30b6..c0df6664 100644
--- a/src/frontend/shared/list-switcher.vue
+++ b/src/frontend/shared/list-switcher.vue
@@ -6,18 +6,18 @@
>
-
@@ -126,7 +128,7 @@
diff --git a/src/frontend/shared/nav-rail-language-selector.story.vue b/src/frontend/shared/nav-rail-language-selector.story.vue
index f9377061..c02bd147 100644
--- a/src/frontend/shared/nav-rail-language-selector.story.vue
+++ b/src/frontend/shared/nav-rail-language-selector.story.vue
@@ -26,6 +26,12 @@
+
+
+
+
+
+
import { ref } from 'vue';
+import NavRailLanguageIndicator from './nav-rail-language-indicator.vue';
import NavRailLanguageSelector from './nav-rail-language-selector.vue';
import { english, german, spanish, ukrainian } from '../test/mocks';
diff --git a/src/frontend/shared/nav-rail-toolbar.vue b/src/frontend/shared/nav-rail-toolbar.vue
index 9913ca2b..9384b463 100644
--- a/src/frontend/shared/nav-rail-toolbar.vue
+++ b/src/frontend/shared/nav-rail-toolbar.vue
@@ -20,6 +20,10 @@
:is-read-only="!shared.user.isManager"
@change="onLanguage"
/>
+
|