diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..fcbd9ff4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,128 @@ +# AGENTS.md — @story-cms/kit + +Instructions for AI coding agents (Codex, Cursor, Claude Code, Copilot, etc.) working in this repository. + +## Project overview + +**Journeys Studio Kit** (`@story-cms/kit`) is a publishable npm package that provides: + +- **Frontend**: Vue 3 + Inertia.js UI components, field widgets, and Pinia stores +- **Backend**: AdonisJS 6 services, models, middleware, and scaffolding stubs +- **Documentation**: [Histoire](https://histoire.dev/) component stories (not Storybook) + +This repo is the **kit library**, not a full CMS app. Client apps (e.g. `@bnap/cms`) consume the built package. Local development uses Histoire (`npm run dev`) to preview and document components. + +## Repository map + +| Path | Purpose | +|------|---------| +| `src/frontend/` | Vue components, stores, styles | +| `src/backend/` | Adonis services, models, middleware, stubs | +| `src/types.ts` | Shared TypeScript types | +| `tests/unit/` | Playwright unit tests | +| `tests/e2e/` | Playwright end-to-end tests | +| `scripts/` | Build helpers (e.g. color usage generator) | +| `.cursor/rules/` | Detailed, file-scoped Cursor rules (see index below) | + +Full directory tree: `.cursor/rules/project-structure.mdc` + +## Commands + +```bash +npm run dev # Histoire dev server (component docs) +npm run build # types + frontend (Vite) + backend (tsc) +npm run ui:build # Frontend only +npm run backend:build # Backend only +npm run lint # ESLint +npm run lint:fix # ESLint with auto-fix +npm run test # Playwright unit tests +npm run test:e2e # Playwright e2e tests +npm run colors:usage # Regenerate colors.palette.ts + colors.usage.ts +npm run story:build # Build Histoire static site +npm run story:preview # Preview built Histoire site +``` + +Run `npm run colors:usage` after changing theme tokens in `tailwind.config.js` or color-class usage in the frontend. + +## Frontend conventions + +- Vue 3 **Composition API** with ` diff --git a/src/frontend/dashboard/action-card.vue b/src/frontend/dashboard/action-card.vue new file mode 100644 index 00000000..52f6055a --- /dev/null +++ b/src/frontend/dashboard/action-card.vue @@ -0,0 +1,34 @@ + + + + + + + {{ title }} + + + {{ description }} + + + + + + + + diff --git a/src/frontend/dashboard/action-grid.story.vue b/src/frontend/dashboard/action-grid.story.vue new file mode 100644 index 00000000..fc3bd371 --- /dev/null +++ b/src/frontend/dashboard/action-grid.story.vue @@ -0,0 +1,41 @@ + + + + + + + + + diff --git a/src/frontend/dashboard/action-grid.vue b/src/frontend/dashboard/action-grid.vue new file mode 100644 index 00000000..fab690b8 --- /dev/null +++ b/src/frontend/dashboard/action-grid.vue @@ -0,0 +1,40 @@ + + + Quick actions + + + + + + + diff --git a/src/frontend/dashboard/dashboard-index.story.vue b/src/frontend/dashboard/dashboard-index.story.vue index bf00c72b..864ffa20 100644 --- a/src/frontend/dashboard/dashboard-index.story.vue +++ b/src/frontend/dashboard/dashboard-index.story.vue @@ -55,7 +55,6 @@ isManager: true, isAdmin: false, role: 'editor', - language: '*', }" :translation-progress="translationProgress" :is-read-only="false" @@ -75,23 +74,19 @@ const loadData: StoryHandler = ({ app, story, variant }): void => { miniSidebar({ app, story, variant }); }; +const daysAgo = (days: number): string => + new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString(); + +const yesterday = daysAgo(1); +const aboutAWeekAgo = daysAgo(8); +const earlyLastYear = daysAgo(400); +const overAYearAgo = daysAgo(750); + const translationProgress = [ { progress: [ - { - name: 'Interface', - done: 100, - draft: 0, - total: 100, - lastUpdated: '2025-04-10 15:22:16.448+03', - }, - { - name: 'Content', - done: 200, - draft: 0, - total: 200, - lastUpdated: '2025-04-10 15:22:16.448+03', - }, + { name: 'Interface', done: 100, draft: 0, total: 100, lastUpdated: yesterday }, + { name: 'Content', done: 35, draft: 15, total: 100, lastUpdated: yesterday }, ], language: 'German', locale: 'de', @@ -99,23 +94,95 @@ const translationProgress = [ }, { progress: [ - { - name: 'Interface', - done: 75, - draft: 0, - total: 100, - lastUpdated: '2025-04-10 15:22:16.448+03', - }, - { - name: 'Content', - done: 150, - draft: 50, - total: 200, - lastUpdated: '2025-04-10 15:22:16.448+03', - }, + { name: 'Interface', done: 100, draft: 0, total: 100, lastUpdated: earlyLastYear }, + { name: 'Content', done: 200, draft: 0, total: 200, lastUpdated: earlyLastYear }, + ], + language: 'Francais', + locale: 'fr', + isReadOnly: false, + }, + { + progress: [ + { name: 'Interface', done: 100, draft: 0, total: 100, lastUpdated: earlyLastYear }, + { name: 'Content', done: 150, draft: 0, total: 150, lastUpdated: earlyLastYear }, + ], + language: 'Latviešu', + locale: 'lv', + isReadOnly: false, + }, + { + progress: [ + { name: 'Interface', done: 100, draft: 0, total: 100, lastUpdated: aboutAWeekAgo }, + { name: 'Content', done: 70, draft: 30, total: 100, lastUpdated: aboutAWeekAgo }, + ], + language: 'Español', + locale: 'es', + isReadOnly: false, + }, + { + progress: [ + { name: 'Interface', done: 100, draft: 0, total: 100, lastUpdated: yesterday }, + { name: 'Content', done: 35, draft: 15, total: 100, lastUpdated: yesterday }, + ], + language: 'Hindi', + locale: 'hi', + isReadOnly: false, + }, + { + progress: [ + { name: 'Interface', done: 75, draft: 0, total: 100, lastUpdated: yesterday }, + { name: 'Content', done: 50, draft: 0, total: 100, lastUpdated: yesterday }, + ], + language: 'Swiss German Alemanni', + locale: 'gsw', + isReadOnly: false, + }, + { + progress: [ + { name: 'Interface', done: 100, draft: 0, total: 100, lastUpdated: yesterday }, + { name: 'Content', done: 80, draft: 20, total: 100, lastUpdated: yesterday }, + ], + language: 'Japanese', + locale: 'ja', + isReadOnly: false, + }, + { + // done: 1 (not 0) keeps `done !== total` so language-block.vue doesn't + // treat this trivially-equal 0-total pair as "all done"; total: 0 gives + // each ring's blank/no-data look. + progress: [ + { name: 'Interface', done: 1, draft: 0, total: 0, lastUpdated: overAYearAgo }, + { name: 'Content', done: 1, draft: 0, total: 0, lastUpdated: overAYearAgo }, + ], + language: 'Korean', + locale: 'ko', + isReadOnly: false, + }, + { + progress: [ + { name: 'Interface', done: 75, draft: 0, total: 100, lastUpdated: yesterday }, + { name: 'Content', done: 100, draft: 0, total: 200, lastUpdated: yesterday }, + ], + language: 'Marathi', + locale: 'mr', + isReadOnly: false, + }, + { + progress: [ + { name: 'Interface', done: 100, draft: 0, total: 100, lastUpdated: yesterday }, + { name: 'Content', done: 35, draft: 15, total: 100, lastUpdated: yesterday }, + ], + language: 'Portuguese', + locale: 'pt', + isReadOnly: false, + }, + { + progress: [ + { name: 'Interface', done: 0, draft: 0, total: 0, lastUpdated: '' }, + { name: 'Content', done: 0, draft: 0, total: 0, lastUpdated: '' }, ], - language: 'Bengali', - locale: 'bn', + language: 'Cantonese', + locale: 'yue', isReadOnly: false, }, ]; diff --git a/src/frontend/dashboard/dashboard-index.vue b/src/frontend/dashboard/dashboard-index.vue index 487ce706..ef873a19 100644 --- a/src/frontend/dashboard/dashboard-index.vue +++ b/src/frontend/dashboard/dashboard-index.vue @@ -1,46 +1,16 @@ - - - - - - New Page - - - - New User - - - - Get Support - - - + - - - - + + + + + - - {{ isMultiLingual ? 'Language translation' : '' }} - + + {{ isMultiLingual ? 'Translations' : '' }} + - - - Done + + Done - - Pending + + Pending - + import AppLayout from '../shared/app-layout.vue'; import StatTiles from './stat-tiles.vue'; -import IndexFilter from '../shared/index-filter.vue'; +import IndexTabs from '../shared/index-tabs.vue'; import LanguageBlock from './language-block.vue'; +import ActionGrid, { ActionGridItem } from './action-grid.vue'; import Icon from '../shared/icon.vue'; +import { BookOpen, FileText, Languages } from '@lucide/vue'; import { ref, computed, onMounted } from 'vue'; -import { Link } from '@inertiajs/vue3'; +import { router } from '@inertiajs/vue3'; import axios from 'axios'; import { SharedPageProps, DashboardProps, StatMetric } from '../../types'; @@ -114,6 +86,42 @@ const greeting = computed(() => { return `Hey ${firstName}!`; }); +const actionItems = computed(() => { + const disabled = !shared.user.isAdmin; + + return [ + { + url: `/${shared.locale}/story/create`, + icon: BookOpen, + title: 'Create a story', + description: 'Build a devotional, course, or other structured content series.', + disabled, + label: 'Create story', + }, + { + url: `/${shared.locale}/page/create`, + icon: FileText, + title: 'Create a page', + description: + 'Share links, acknowledgements, and information about your organisation.', + disabled, + label: 'Create page', + }, + { + url: `/${shared.locale}/settings/languages/edit`, + icon: Languages, + title: 'Add a user', + description: 'Invite teammates to create, edit, and manage content.', + disabled, + label: 'Add user', + }, + ]; +}); + +const handleActionGrid = (url: string) => { + router.visit(url); +}; + const activeFilter = ref<'To do' | 'All'>('To do'); const todoCount = computed(() => { diff --git a/src/frontend/dashboard/language-block.story.vue b/src/frontend/dashboard/language-block.story.vue index acf6ed4f..36b3d3fc 100644 --- a/src/frontend/dashboard/language-block.story.vue +++ b/src/frontend/dashboard/language-block.story.vue @@ -75,9 +75,36 @@ }" /> + + + diff --git a/src/frontend/dashboard/language-block.vue b/src/frontend/dashboard/language-block.vue index b03e18ba..6490d992 100644 --- a/src/frontend/dashboard/language-block.vue +++ b/src/frontend/dashboard/language-block.vue @@ -4,10 +4,10 @@ :class="progress.isReadOnly ? 'opacity-60' : ''" > - - - - + + All done @@ -30,17 +30,14 @@ hasCompleteRings ? 'mt-3' : 'mt-10', ]" > - - - {{ englishName }} + + {{ englishName }} ({{ progress.locale }}) - - + + Last update: {{ lastUpdate }} + No updates @@ -48,9 +45,10 @@ diff --git a/src/frontend/dashboard/ring-block.story.vue b/src/frontend/dashboard/ring-block.story.vue deleted file mode 100644 index e35ef4b4..00000000 --- a/src/frontend/dashboard/ring-block.story.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/frontend/dashboard/ring-block.vue b/src/frontend/dashboard/ring-block.vue deleted file mode 100644 index fe0ab80c..00000000 --- a/src/frontend/dashboard/ring-block.vue +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - All done - - - - - - {{ item.name }} - - - - - - - - - - - - - {{ item.label }} - - - - - - - - - - diff --git a/src/frontend/dashboard/ring.story.vue b/src/frontend/dashboard/ring.story.vue index 580109c7..e80ddbc7 100644 --- a/src/frontend/dashboard/ring.story.vue +++ b/src/frontend/dashboard/ring.story.vue @@ -1,61 +1,153 @@ - - - + + + + + - - + + + + - - + + + + - - + + + + - - + + + + - - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/dashboard/ring.vue b/src/frontend/dashboard/ring.vue index 302cac66..70554070 100644 --- a/src/frontend/dashboard/ring.vue +++ b/src/frontend/dashboard/ring.vue @@ -1,115 +1,226 @@ - - - + + - - - - - - - - - - + + + All done + + + + + {{ item.name }} + + + - {{ - label - }} + + + + + + + + + + + {{ item.data.label }} + + + + {{ item.name }} + - - {{ name }} - + diff --git a/src/frontend/dashboard/stat-tile.vue b/src/frontend/dashboard/stat-tile.vue index f24c85ee..82ecd477 100644 --- a/src/frontend/dashboard/stat-tile.vue +++ b/src/frontend/dashboard/stat-tile.vue @@ -1,7 +1,7 @@ - + {{ props.metric.name }} - + {{ props.metric.stat.toLocaleString() }} - from {{ props.metric.previousStat.toLocaleString() }} @@ -30,26 +32,25 @@ v-if="!isLoading" :class="[ changeType === 'increase' - ? 'bg-green-100 text-green-800' - : 'bg-red-100 text-red-800', + ? 'bg-studio-lime text-green-800' + : 'bg-error-light text-error', 'inline-flex items-baseline rounded-full px-2.5 py-0.5 text-sm font-medium md:mt-2 lg:mt-0', ]" > - - - {{ changeType === 'increase' ? 'Increased' : 'Decreased' }} by {{ changePercentage }} + + diff --git a/src/frontend/shared/app-layout-header.story.vue b/src/frontend/shared/app-layout-header.story.vue index 4b0b00bc..f405d506 100644 --- a/src/frontend/shared/app-layout-header.story.vue +++ b/src/frontend/shared/app-layout-header.story.vue @@ -4,7 +4,7 @@ - + @@ -70,14 +70,14 @@ - + - - + + diff --git a/src/frontend/shared/app-layout.vue b/src/frontend/shared/app-layout.vue index 332bf961..5be78fef 100644 --- a/src/frontend/shared/app-layout.vue +++ b/src/frontend/shared/app-layout.vue @@ -34,7 +34,9 @@ - + @@ -55,10 +57,12 @@ import { usePage } from '@inertiajs/vue3'; import { useSharedStore } from '../store'; import AppLayoutHeader from './app-layout-header.vue'; import type { SharedPageProps } from '../../types'; +import AppFooter from './app-footer.vue'; defineProps<{ title?: string; subtitle?: string; + showBrand?: boolean; }>(); const shared = useSharedStore(); diff --git a/src/frontend/shared/colors.palette.ts b/src/frontend/shared/colors.palette.ts new file mode 100644 index 00000000..2cc331c7 --- /dev/null +++ b/src/frontend/shared/colors.palette.ts @@ -0,0 +1,149 @@ +// Generated by scripts/generate-color-usage.mjs — do not edit +// Re-run: npm run colors:usage +export type ColorSwatch = { + name: string; + class?: string; + style?: string; + hex?: string; +}; + +export type ColorSection = { + title: string; + colors: ColorSwatch[]; +}; + +export const colorSections: ColorSection[] = [ + { + title: 'Brand', + colors: [ + { name: 'black', class: 'bg-black', hex: '#2E2D2C' }, + { name: 'current', class: 'bg-current' }, + { name: 'transparent', class: 'bg-transparent' }, + { name: 'white', class: 'bg-white', hex: '#FFFFFF' }, + ], + }, + { + title: 'Accent', + colors: [ + { name: 'accent', class: 'bg-accent', hex: '#39CCFB' }, + ], + }, + { + title: 'Studio', + colors: [ + { name: 'studio-dark', class: 'bg-studio-dark', hex: '#64748B' }, + { name: 'studio-forest', class: 'bg-studio-forest', hex: '#102F35' }, + { name: 'studio-green', class: 'bg-studio-green', hex: '#B9E86C' }, + { name: 'studio-lime', class: 'bg-studio-lime', hex: '#D7FE96' }, + { name: 'studio-yellow', class: 'bg-studio-yellow', hex: '#FBFF96' }, + ], + }, + { + title: 'Error', + colors: [ + { name: 'error', class: 'bg-error', hex: '#DC2626' }, + { name: 'error-light', class: 'bg-error-light', hex: '#FECACA' }, + ], + }, + { + title: 'CSS Variables', + colors: [ + { name: '--primary-color', style: 'background: var(--primary-color)', hex: '#39CCFB' }, + { name: '--secondary-color', style: 'background: var(--secondary-color)', hex: '#34D399' }, + ], + }, + { + title: 'Gray', + colors: [ + { name: 'gray-100', class: 'bg-gray-100' }, + { name: 'gray-200', class: 'bg-gray-200' }, + { name: 'gray-300', class: 'bg-gray-300' }, + { name: 'gray-400', class: 'bg-gray-400' }, + { name: 'gray-50', class: 'bg-gray-50' }, + { name: 'gray-500', class: 'bg-gray-500' }, + { name: 'gray-600', class: 'bg-gray-600' }, + { name: 'gray-700', class: 'bg-gray-700' }, + { name: 'gray-800', class: 'bg-gray-800' }, + { name: 'gray-900', class: 'bg-gray-900' }, + ], + }, + { + title: 'Blue', + colors: [ + { name: 'blue-100', class: 'bg-blue-100' }, + { name: 'blue-200', class: 'bg-blue-200' }, + { name: 'blue-400', class: 'bg-blue-400' }, + { name: 'blue-50', class: 'bg-blue-50' }, + { name: 'blue-500', class: 'bg-blue-500' }, + { name: 'blue-600', class: 'bg-blue-600' }, + { name: 'blue-700', class: 'bg-blue-700' }, + { name: 'blue-800', class: 'bg-blue-800' }, + { name: 'blue-900', class: 'bg-blue-900' }, + ], + }, + { + title: 'Green', + colors: [ + { name: 'green-100', class: 'bg-green-100' }, + { name: 'green-200', class: 'bg-green-200' }, + { name: 'green-400', class: 'bg-green-400' }, + { name: 'green-500', class: 'bg-green-500' }, + { name: 'green-600', class: 'bg-green-600' }, + { name: 'green-700', class: 'bg-green-700' }, + { name: 'green-800', class: 'bg-green-800' }, + ], + }, + { + title: 'Red', + colors: [ + { name: 'red-100', class: 'bg-red-100' }, + { name: 'red-300', class: 'bg-red-300' }, + { name: 'red-400', class: 'bg-red-400' }, + { name: 'red-50', class: 'bg-red-50' }, + { name: 'red-500', class: 'bg-red-500' }, + { name: 'red-600', class: 'bg-red-600' }, + { name: 'red-800', class: 'bg-red-800' }, + ], + }, + { + title: 'Yellow', + colors: [ + { name: 'yellow-100', class: 'bg-yellow-100' }, + { name: 'yellow-50', class: 'bg-yellow-50' }, + { name: 'yellow-500', class: 'bg-yellow-500' }, + { name: 'yellow-600', class: 'bg-yellow-600' }, + { name: 'yellow-800', class: 'bg-yellow-800' }, + ], + }, + { + title: 'Indigo', + colors: [ + { name: 'indigo-200', class: 'bg-indigo-200' }, + { name: 'indigo-50', class: 'bg-indigo-50' }, + { name: 'indigo-500', class: 'bg-indigo-500' }, + { name: 'indigo-600', class: 'bg-indigo-600' }, + { name: 'indigo-700', class: 'bg-indigo-700' }, + ], + }, + { + title: 'Amber', + colors: [ + { name: 'amber-100', class: 'bg-amber-100' }, + { name: 'amber-700', class: 'bg-amber-700' }, + ], + }, + { + title: 'Emerald', + colors: [ + { name: 'emerald-500', class: 'bg-emerald-500' }, + ], + }, + { + title: 'Violet', + colors: [ + { name: 'violet-100', class: 'bg-violet-100' }, + { name: 'violet-50', class: 'bg-violet-50' }, + { name: 'violet-600', class: 'bg-violet-600' }, + ], + }, +]; diff --git a/src/frontend/shared/colors.story.vue b/src/frontend/shared/colors.story.vue new file mode 100644 index 00000000..a7f2fba9 --- /dev/null +++ b/src/frontend/shared/colors.story.vue @@ -0,0 +1,45 @@ + + + + + + {{ section.title }} + + + + {{ color.name }} + {{ color.hex }} + + + Used {{ colorUsage[color.name].count }} times in + {{ colorUsage[color.name].files.length }} files + + + + {{ file }} + + + + No uses found + + + + + + + + + diff --git a/src/frontend/shared/colors.usage.ts b/src/frontend/shared/colors.usage.ts new file mode 100644 index 00000000..34cd542e --- /dev/null +++ b/src/frontend/shared/colors.usage.ts @@ -0,0 +1,920 @@ +// Generated by scripts/generate-color-usage.mjs — do not edit +// Re-run: npm run colors:usage +export type ColorUsage = { count: number; files: string[] }; + +export const colorUsage: Record = { + '--primary-color': { count: 5, files: [ + 'auth/login-index.vue', + 'index.css', + 'shared/pagination.vue', + ] }, + '--secondary-color': { count: 6, files: [ + 'auth/login-index.vue', + 'index.css', + ] }, + 'accent': { count: 3, files: [ + 'fields/attachments/attachment-field.vue', + 'fields/attachments/video-progress.vue', + ] }, + 'amber-100': { count: 1, files: [ + 'invitation/invitation-index-item.vue', + ] }, + 'amber-700': { count: 1, files: [ + 'invitation/invitation-index-item.vue', + ] }, + 'black': { count: 29, files: [ + 'audience/audience-index.vue', + 'auth/create-account.vue', + 'auth/forgot-password.vue', + 'auth/login-index.vue', + 'dashboard/action-card.vue', + 'dashboard/dashboard-index.vue', + 'fields/scripture-field.vue', + 'index.css', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-modal.vue', + 'settings/languages/components/language-table-row.vue', + 'settings/languages/components/member-row.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'settings/languages/components/request-feedback-modal.vue', + 'settings/languages/language-list.vue', + 'settings/languages/languages-edit.vue', + 'shared/app-layout-header.story.vue', + 'shared/context-menu.vue', + 'shared/drop-down.vue', + 'shared/label-hint-popup.vue', + 'shared/nav-rail-language-selector.vue', + 'ui/components/ui-string-item.vue', + ] }, + 'blue-100': { count: 8, files: [ + 'invitation/invitation-index-item.vue', + 'settings/languages/components/language-list-controls.vue', + 'shared/icon-button.story.vue', + 'shared/icon-button.vue', + 'shared/label-button.vue', + 'shared/nav-rail-language-selector.vue', + 'shared/status-tag.vue', + 'stories/components/resource-picker.vue', + ] }, + 'blue-200': { count: 5, files: [ + 'invitation/invitations-index.vue', + 'resources/resources-index.vue', + 'shared/icon-button.story.vue', + 'shared/icon-button.vue', + 'shared/label-button.vue', + ] }, + 'blue-400': { count: 3, files: [ + 'audience/audience-index.vue', + 'index.css', + 'shared/pill-button.vue', + ] }, + 'blue-50': { count: 59, files: [ + 'audience/audience-index.vue', + 'fields/select-field.vue', + 'index.css', + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'resources/resource-index-item.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.story.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-list-item.vue', + 'settings/languages/components/language-table-row.vue', + 'settings/languages/components/remove-language-modal.story.vue', + 'settings/languages/components/request-feedback-modal.story.vue', + 'settings/settings-index.vue', + 'shared/expandable-search.vue', + 'shared/glass-button.vue', + 'shared/label-hint.vue', + 'shared/message-centre.vue', + 'shared/pill-button.vue', + 'shared/rich-listbox.vue', + 'stories/components/index-card.vue', + 'stories/components/resource-attached-item.vue', + 'stories/components/resource-picker.vue', + 'stories/components/story-item.vue', + 'team/components/user-row.vue', + 'ui/components/ui-card.vue', + 'ui/components/ui-string-item.vue', + 'ui/ui-page.vue', + ] }, + 'blue-500': { count: 36, files: [ + 'audience/audience-index.vue', + 'fields/select-field.vue', + 'index.css', + 'invitation/invitations-index.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.story.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-list-item.vue', + 'settings/languages/components/remove-language-modal.story.vue', + 'settings/languages/components/request-feedback-modal.story.vue', + 'settings/settings-index.vue', + 'shared/expandable-search.vue', + 'shared/glass-button.vue', + 'shared/label-hint.vue', + 'shared/message-centre.vue', + 'shared/pill-button.vue', + 'shared/rich-listbox.vue', + 'ui/components/ui-card.vue', + 'ui/components/ui-string-item.vue', + ] }, + 'blue-600': { count: 17, files: [ + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'resources/resource-index-item.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-table-row.vue', + 'settings/settings-index.vue', + 'stories/components/index-card.vue', + 'stories/components/resource-attached-item.vue', + 'stories/components/resource-label-group.vue', + 'stories/components/resource-picker.vue', + 'stories/components/story-item.vue', + 'team/components/user-row.vue', + 'ui/components/ui-card.vue', + ] }, + 'blue-700': { count: 7, files: [ + 'invitation/invitation-index-item.vue', + 'resources/resource-index-item.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'team/components/user-row.vue', + ] }, + 'blue-800': { count: 6, files: [ + 'fields/pill/pill-field.vue', + 'shared/icon-button.story.vue', + 'shared/icon-button.vue', + 'shared/label-button.vue', + 'shared/nav-rail-language-selector.vue', + 'shared/status-tag.vue', + ] }, + 'blue-900': { count: 2, files: [ + 'settings/languages/components/request-app-update-modal.vue', + ] }, + 'current': { count: 6, files: [ + 'shared/bookmark-action.vue', + 'shared/index-filter.vue', + 'shared/index-tabs.vue', + 'shared/navigation-pane.vue', + 'shared/tab-navigation.vue', + ] }, + 'emerald-500': { count: 5, files: [ + 'test/error-control.vue', + 'test/language-control.vue', + 'test/model-control.vue', + ] }, + 'error': { count: 45, files: [ + 'auth/create-account.vue', + 'auth/forgot-password.vue', + 'auth/login-index.vue', + 'auth/reset-password.vue', + 'dashboard/stat-tile.vue', + 'fields/attachments/attachment-field.vue', + 'fields/attachments/file-upload.vue', + 'fields/boolean-field.vue', + 'fields/list/flat-list.vue', + 'fields/list/foldable-list.vue', + 'fields/markdown-field.vue', + 'fields/number-field.vue', + 'fields/panel-field.vue', + 'fields/pill/pill-field.vue', + 'fields/scripture-field.vue', + 'fields/section-panel-field.vue', + 'fields/select-field.vue', + 'fields/string-field.vue', + 'shared/tab-button.vue', + 'stories/components/panel-list.vue', + 'team/components/user-form-modal.vue', + ] }, + 'error-light': { count: 2, files: [ + 'dashboard/stat-tile.vue', + 'fields/list/foldable-list.vue', + ] }, + 'gray-100': { count: 71, files: [ + 'fields/list/flat-list.vue', + 'fields/region-field.vue', + 'fields/scripture-field.vue', + 'fields/scripture-reference-field.vue', + 'fields/section-panel-field.vue', + 'invitation/invitation-index-item.vue', + 'pages/page-index-item.story.vue', + 'pages/pages-index.vue', + 'resources/resource-index-item.vue', + 'resources/resource-used-in.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-list-controls.vue', + 'settings/languages/components/language-list-item.vue', + 'settings/languages/components/language-modal.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'shared/action-button.vue', + 'shared/context-menu.vue', + 'shared/drop-down.vue', + 'shared/gallery-grid.story.vue', + 'shared/index-filter.vue', + 'shared/index-tab-button.vue', + 'shared/label-hint-popup.vue', + 'shared/list-switcher.vue', + 'shared/meta-box.vue', + 'shared/nav-rail-language-selector.vue', + 'shared/nav-rail-panel.vue', + 'shared/nav-rail-toolbar.vue', + 'shared/rich-listbox.vue', + 'shared/tab-button.story.vue', + 'stories/components/index-card.vue', + 'stories/components/panel-list.vue', + 'stories/components/resource-label-group.vue', + 'stories/components/resource-picker.vue', + 'stories/components/resource-thumbnail.vue', + 'stories/components/resource-type-badge.vue', + 'stories/components/resource-utils.ts', + 'stories/components/story-item.vue', + 'streams/components/drop-item.vue', + 'streams/components/stream-item.vue', + 'team/components/user-row.vue', + ] }, + 'gray-200': { count: 112, files: [ + 'audience/audience-index.vue', + 'dashboard/stat-tile.vue', + 'fields/attachments/file-upload.vue', + 'fields/attachments/video-meta.vue', + 'fields/boolean-field.vue', + 'fields/date-field.vue', + 'fields/date-range-field.vue', + 'fields/image-field.story.vue', + 'fields/list/flat-list.vue', + 'fields/list/foldable-list.vue', + 'fields/pill/pill-field.vue', + 'fields/scripture-field.vue', + 'fields/section-panel-field.vue', + 'fields/select-field.vue', + 'fields/string-field.vue', + 'index.css', + 'invitation/invitation-index-item.story.vue', + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'pages/page-index-item.story.vue', + 'pages/pages-index.vue', + 'resources/resource-index-item.story.vue', + 'resources/resource-index-item.vue', + 'resources/resource-used-in.vue', + 'resources/resources-index.vue', + 'settings/languages/components/language-table.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'shared/language-option-label.story.vue', + 'shared/list-switcher.vue', + 'shared/nav-rail-language-selector.story.vue', + 'shared/nav-rail-panel.vue', + 'shared/navigation-pane.vue', + 'shared/pagination.vue', + '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', + 'stories/components/resource-label-group.vue', + 'stories/components/resource-picker.vue', + 'stories/components/story-item.story.vue', + 'stories/components/story-item.vue', + 'stories/story-gallery.vue', + 'stories/story-index.vue', + 'team/users-index.vue', + 'ui/components/ui-card.vue', + 'ui/components/ui-string-item.vue', + ] }, + 'gray-300': { count: 61, files: [ + 'audience/audience-index.vue', + 'auth/create-account.vue', + 'auth/login-index.vue', + 'fields/attachments/attachment-field.vue', + 'fields/attachments/video-progress.vue', + 'fields/list/flat-list.vue', + 'fields/list/foldable-list.vue', + 'fields/panel-field.vue', + 'fields/pill/pill-field.vue', + 'fields/region-field.vue', + 'fields/select-field.vue', + 'index.css', + 'invitation/invitations-index.vue', + 'pages/page-index-item.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-list-item.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'shared/context-menu.vue', + 'shared/drop-down.vue', + 'shared/expandable-search.story.vue', + 'shared/expandable-search.vue', + 'shared/index-tabs.vue', + 'shared/list-switcher.vue', + 'shared/navigation-pane.vue', + 'shared/pagination.vue', + 'shared/rich-listbox.vue', + 'shared/studio-button.vue', + 'stories/components/resource-picker.vue', + 'streams/stream-index.vue', + 'ui/components/ui-card.vue', + 'ui/ui-page.vue', + ] }, + 'gray-400': { count: 78, files: [ + 'audience/audience-index.vue', + 'dashboard/dashboard-index.vue', + 'dashboard/ring.vue', + 'fields/attachments/attachment-field.vue', + 'fields/section-panel-field.vue', + 'index.css', + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'pages/page-index-item.vue', + 'resources/resource-index-item.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-modal.vue', + 'settings/languages/components/language-table-row.vue', + 'shared/app-layout-header.vue', + 'shared/bookmark-action.vue', + 'shared/draft-actions.vue', + 'shared/expandable-search.vue', + 'shared/label-hint-popup.vue', + 'shared/label-hint.vue', + 'shared/pagination.vue', + 'shared/pill-button.vue', + 'shared/rich-listbox.vue', + 'stories/components/index-card.vue', + 'stories/components/panel-list.vue', + 'stories/components/resource-attached-item.vue', + 'stories/components/resource-label-group.vue', + 'stories/components/resource-picker.vue', + 'stories/components/story-edit-details.vue', + 'stories/components/story-item.vue', + 'streams/stream-index.vue', + 'team/components/user-form-modal.vue', + 'team/components/user-row.vue', + 'ui/components/ui-card.vue', + ] }, + 'gray-50': { count: 252, files: [ + 'audience/audience-index.vue', + 'audience/components/audience-row.vue', + 'dashboard/language-block.vue', + 'dashboard/ring.vue', + 'dashboard/stat-tile.vue', + 'fields/attachments/attachment-field.vue', + 'fields/attachments/file-upload.vue', + 'fields/attachments/video-meta.vue', + 'fields/attachments/video-progress.vue', + 'fields/list/flat-list.vue', + 'fields/list/foldable-list.vue', + 'fields/panel-field.vue', + 'fields/scripture-field.vue', + 'fields/scripture-reference-field.vue', + 'fields/section-panel-field.vue', + 'index.css', + 'invitation/invitation-index-item.story.vue', + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'pages/page-index-item.vue', + 'pages/pages-index.vue', + 'resources/resource-index-item.story.vue', + 'resources/resource-index-item.vue', + 'resources/resource-not-found.vue', + 'resources/resource-used-in.vue', + 'resources/resources-edit.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-list-controls.vue', + 'settings/languages/components/language-strip.vue', + 'settings/languages/components/language-table-row.vue', + 'settings/languages/components/language-table.story.vue', + 'settings/languages/components/language-table.vue', + 'settings/languages/components/member-row.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'settings/settings-index.vue', + 'shared/action-button.vue', + 'shared/app-layout-header.story.vue', + 'shared/app-layout.vue', + 'shared/context-menu.vue', + 'shared/draft-actions.vue', + 'shared/expandable-search.story.vue', + 'shared/expandable-search.vue', + 'shared/gallery-grid.story.vue', + 'shared/gallery-item.vue', + 'shared/glass-button.story.vue', + 'shared/index-filter.vue', + 'shared/index-tab-button.vue', + 'shared/language-option-label.vue', + 'shared/list-switcher.vue', + 'shared/meta-box.vue', + 'shared/nav-rail-language-selector.story.vue', + 'shared/nav-rail-panel.story.vue', + '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', + 'stories/components/resource-attached-list.vue', + 'stories/components/resource-label-group.vue', + 'stories/components/resource-picker.vue', + 'stories/components/resource-thumbnail.vue', + 'stories/components/story-item.story.vue', + 'stories/components/story-item.vue', + 'stories/story-gallery.vue', + 'stories/story-index.vue', + 'team/components/user-row.vue', + 'team/users-index.vue', + 'ui/ui-page.vue', + ] }, + 'gray-500': { count: 174, files: [ + 'audience/audience-index.vue', + 'audience/components/audience-row.vue', + 'dashboard/language-block.vue', + 'dashboard/ring.vue', + 'dashboard/stat-tile.vue', + 'fields/attachments/attachment-field.vue', + 'fields/attachments/file-upload.vue', + 'fields/attachments/video-meta.vue', + 'fields/attachments/video-progress.vue', + 'fields/list/flat-list.vue', + 'fields/list/foldable-list.vue', + 'fields/scripture-field.vue', + 'fields/scripture-reference-field.vue', + 'fields/section-panel-field.vue', + 'index.css', + 'invitation/invitation-index-item.story.vue', + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'pages/page-index-item.vue', + 'pages/pages-index.vue', + 'resources/resource-index-item.story.vue', + 'resources/resource-index-item.vue', + 'resources/resource-not-found.vue', + 'resources/resource-used-in.vue', + 'resources/resources-edit.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-list-controls.vue', + 'settings/languages/components/language-strip.vue', + 'settings/languages/components/language-table-row.vue', + 'settings/languages/components/language-table.story.vue', + 'settings/languages/components/language-table.vue', + 'settings/languages/components/member-row.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'settings/settings-index.vue', + 'shared/action-button.vue', + 'shared/expandable-search.story.vue', + 'shared/expandable-search.vue', + 'shared/gallery-grid.story.vue', + 'shared/gallery-item.vue', + 'shared/index-filter.vue', + 'shared/index-tab-button.vue', + 'shared/language-option-label.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', + 'stories/components/resource-attached-list.vue', + 'stories/components/resource-label-group.vue', + 'stories/components/resource-picker.vue', + 'stories/components/resource-thumbnail.vue', + 'stories/components/story-item.story.vue', + 'stories/components/story-item.vue', + 'stories/story-gallery.vue', + 'stories/story-index.vue', + 'team/components/user-row.vue', + 'team/users-index.vue', + 'ui/ui-page.vue', + ] }, + 'gray-600': { count: 61, files: [ + 'auth/login-index.vue', + 'fields/attachments/attachment-field.vue', + 'fields/attachments/file-upload.vue', + 'fields/date-field.vue', + 'fields/date-range-field.vue', + 'fields/markdown-field.vue', + 'fields/number-field.vue', + 'fields/pill/pill-field.vue', + 'fields/region-field.vue', + 'fields/scripture-field.vue', + 'fields/select-field.vue', + 'fields/string-field.vue', + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'resources/resource-index-item.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-modal.vue', + 'shared/action-button.story.vue', + 'shared/draft-actions.vue', + 'shared/expandable-search.story.vue', + 'shared/expandable-search.vue', + 'shared/glass-button.story.vue', + 'shared/index-tabs.story.vue', + 'shared/label-hint-popup.vue', + 'shared/label-hint.vue', + 'shared/list-switcher.story.vue', + 'shared/meta-box.vue', + 'shared/navigation-pane.story.vue', + 'shared/navigation-pane.vue', + 'shared/rich-listbox.vue', + 'shared/tab-navigation.story.vue', + 'stories/components/panel-list.vue', + 'stories/components/resource-attached-list.vue', + 'stories/components/resource-picker.vue', + 'stories/components/story-edit-details.vue', + 'stories/components/story-item.story.vue', + 'stories/components/story-item.vue', + 'stories/story-index.vue', + 'team/components/user-row.vue', + 'ui/components/ui-card.vue', + ] }, + 'gray-700': { count: 41, files: [ + 'fields/attachments/video-meta.vue', + 'fields/list/foldable-list.vue', + 'fields/panel-field.vue', + 'index.css', + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'resources/resource-index-item.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'shared/context-menu.vue', + 'shared/drop-down.vue', + 'shared/expandable-search.vue', + 'shared/list-switcher.vue', + 'shared/nav-rail-language-selector.vue', + 'shared/pagination.vue', + 'shared/pill-button.vue', + 'shared/studio-button.vue', + 'stories/components/resource-picker.vue', + 'stories/components/resource-type-badge.vue', + 'stories/components/resource-utils.ts', + 'stories/components/story-item.vue', + 'team/components/user-row.vue', + 'ui/components/ui-card.vue', + ] }, + 'gray-800': { count: 27, files: [ + 'dashboard/action-card.vue', + 'dashboard/dashboard-index.vue', + 'dashboard/ring.vue', + 'fields/section-panel-field.vue', + 'index.css', + 'settings/languages/components/language-list-controls.vue', + 'settings/languages/components/language-table-row.vue', + 'settings/languages/components/language-table.story.vue', + 'settings/settings-index.vue', + 'shared/gallery-grid.story.vue', + 'shared/gallery-item.vue', + 'shared/rich-listbox.vue', + 'shared/studio-button.vue', + 'stories/components/panel-list.vue', + 'streams/components/drop-item.vue', + 'streams/components/stream-item.vue', + 'ui/ui-page.vue', + ] }, + 'gray-900': { count: 50, files: [ + 'audience/components/audience-row.vue', + 'auth/login-index.vue', + 'auth/reset-password.vue', + 'dashboard/stat-tile.vue', + 'fields/attachments/video-meta.vue', + 'fields/boolean-field.vue', + 'fields/pill/pill-field.vue', + 'fields/region-field.vue', + 'fields/select-field.vue', + 'index.css', + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'pages/page-index-item.vue', + 'resources/resource-index-item.vue', + 'resources/resource-not-found.vue', + 'resources/resource-used-in.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-list-controls.vue', + 'settings/languages/components/language-strip.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'shared/context-menu.vue', + 'shared/drop-down.vue', + 'shared/expandable-search.vue', + 'shared/language-option-label.vue', + 'shared/list-switcher.vue', + 'shared/nav-rail-language-selector.vue', + 'shared/navigation-pane.vue', + 'shared/pagination.vue', + 'shared/rich-listbox.vue', + 'shared/studio-button.vue', + 'stories/components/index-card.vue', + 'stories/components/resource-attached-item.vue', + 'stories/components/resource-label-group.vue', + 'stories/components/resource-picker.vue', + 'stories/components/story-item.vue', + 'streams/stream-index.vue', + 'team/components/user-row.vue', + 'ui/components/ui-card.vue', + ] }, + 'green-100': { count: 5, files: [ + 'invitation/invitation-index-item.vue', + 'pages/page-index-item.vue', + 'stories/components/story-item.vue', + 'streams/components/stream-item.vue', + ] }, + 'green-200': { count: 1, files: [ + 'settings/languages/components/language-modal.vue', + ] }, + 'green-400': { count: 2, files: [ + 'shared/pill-button.vue', + 'shared/studio-button.vue', + ] }, + 'green-500': { count: 9, files: [ + 'auth/forgot-password.vue', + 'auth/reset-password.vue', + 'dashboard/stat-tile.vue', + 'settings/languages/components/request-app-update-modal.story.vue', + 'shared/message-centre.vue', + 'shared/pill-button.vue', + 'shared/status-tag.vue', + 'shared/studio-button.vue', + ] }, + 'green-600': { count: 10, files: [ + 'shared/icon-button.story.vue', + 'shared/label-button.story.vue', + ] }, + 'green-700': { count: 3, files: [ + 'invitation/invitation-index-item.vue', + 'pages/page-index-item.vue', + 'stories/components/story-item.vue', + ] }, + 'green-800': { count: 4, files: [ + 'dashboard/stat-tile.vue', + 'settings/languages/components/language-modal.vue', + 'stories/components/story-item.vue', + 'streams/components/stream-item.vue', + ] }, + 'indigo-200': { count: 2, files: [ + 'settings/languages/components/request-app-update-modal.vue', + ] }, + 'indigo-50': { count: 14, files: [ + 'audience/audience-index.vue', + 'fields/attachments/file-upload.vue', + 'fields/list/foldable-list.vue', + 'fields/panel-field.vue', + 'fields/section-panel-field.vue', + 'index.css', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'shared/add-item-button.vue', + 'shared/pill-button.vue', + ] }, + 'indigo-500': { count: 10, files: [ + 'audience/audience-index.vue', + 'fields/attachments/file-upload.vue', + 'fields/list/foldable-list.vue', + 'fields/panel-field.vue', + 'index.css', + 'settings/languages/components/bible-translations-modal.vue', + 'shared/pill-button.vue', + ] }, + 'indigo-600': { count: 14, files: [ + 'settings/languages/components/request-app-update-modal.vue', + 'shared/navigation-pane.vue', + 'streams/stream-index.vue', + 'ui/components/ui-card.vue', + 'ui/ui-page.vue', + ] }, + 'indigo-700': { count: 5, files: [ + 'fields/attachments/file-upload.vue', + 'fields/section-panel-field.vue', + 'shared/add-item-button.vue', + 'shared/navigation-pane.vue', + ] }, + 'red-100': { count: 2, files: [ + 'settings/languages/components/language-modal.vue', + 'streams/components/stream-item.vue', + ] }, + 'red-300': { count: 2, files: [ + 'fields/video-field.vue', + 'team/components/user-row.vue', + ] }, + 'red-400': { count: 2, files: [ + 'shared/pill-button.vue', + 'shared/studio-button.vue', + ] }, + 'red-50': { count: 24, files: [ + 'auth/create-account.vue', + 'dashboard/stat-tiles.vue', + 'fields/date-field.vue', + 'fields/date-range-field.vue', + 'fields/select-field.vue', + 'index.css', + 'pages/page-index-item.vue', + 'resources/resource-index-item.vue', + 'settings/languages/components/language-table-row.vue', + 'settings/languages/components/request-feedback-modal.story.vue', + 'shared/draft-actions.vue', + 'shared/drop-down.vue', + 'shared/message-centre.vue', + 'shared/pill-button.vue', + 'shared/status-tag.vue', + 'shared/studio-button.vue', + 'stories/components/panel-list.vue', + 'stories/components/resource-attached-item.vue', + 'team/components/user-row.vue', + ] }, + 'red-500': { count: 16, files: [ + 'auth/create-account.vue', + 'dashboard/stat-tiles.vue', + 'fields/date-field.vue', + 'fields/date-range-field.vue', + 'fields/select-field.vue', + 'index.css', + 'settings/languages/components/request-feedback-modal.story.vue', + 'shared/drop-down.vue', + 'shared/message-centre.vue', + 'shared/pill-button.vue', + 'shared/status-tag.vue', + 'shared/studio-button.vue', + ] }, + 'red-600': { count: 9, files: [ + 'pages/page-index-item.vue', + 'resources/resource-index-item.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-table-row.vue', + 'shared/draft-actions.vue', + 'stories/components/panel-list.vue', + 'stories/components/resource-attached-item.vue', + 'team/components/user-row.vue', + ] }, + 'red-800': { count: 2, files: [ + 'settings/languages/components/language-modal.vue', + 'streams/components/stream-item.vue', + ] }, + 'studio-dark': { count: 0, files: [] }, + 'studio-forest': { count: 22, 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', + 'stories/components/resource-utils.ts', + ] }, + 'studio-green': { count: 9, 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', + 'stories/components/resource-utils.ts', + ] }, + 'studio-lime': { count: 9, files: [ + 'dashboard/language-block.vue', + 'dashboard/ring.vue', + 'dashboard/stat-tile.vue', + 'shared/index-tab-button.vue', + 'shared/nav-rail-language-selector.vue', + 'shared/studio-button.vue', + 'shared/tab-button.vue', + 'stories/components/resource-utils.ts', + ] }, + 'studio-yellow': { count: 2, files: [ + 'dashboard/action-card.vue', + 'stories/components/resource-utils.ts', + ] }, + 'transparent': { count: 23, files: [ + 'dashboard/ring.vue', + 'fields/attachments/video-progress.vue', + 'fields/boolean-field.vue', + 'fields/markdown/toolbar-buttons.ts', + 'fields/pill/pill-field.vue', + 'index.css', + 'invitation/invitations-index.vue', + 'resources/resources-index.vue', + 'shared/expandable-search.vue', + 'shared/navigation-pane.vue', + 'shared/studio-button.vue', + 'shared/tab-button.vue', + 'stories/components/resource-picker.vue', + ] }, + 'violet-100': { count: 1, files: [ + 'resources/resource-used-in.vue', + ] }, + 'violet-50': { count: 1, files: [ + 'resources/resource-used-in.vue', + ] }, + 'violet-600': { count: 1, files: [ + 'resources/resource-used-in.vue', + ] }, + 'white': { count: 178, files: [ + 'audience/audience-index.vue', + 'dashboard/action-card.vue', + 'dashboard/language-block.vue', + 'dashboard/ring.story.vue', + 'dashboard/stat-tile.vue', + 'fields/attachments/attachment-field.vue', + 'fields/attachments/file-upload.vue', + 'fields/attachments/video-progress.vue', + 'fields/boolean-field.vue', + 'fields/date-field.vue', + 'fields/date-range-field.vue', + 'fields/list/flat-list.vue', + 'fields/list/foldable-list.vue', + 'fields/markdown-field.vue', + 'fields/number-field.vue', + 'fields/object-field.vue', + 'fields/panel-field.vue', + 'fields/pill/pill-field.vue', + 'fields/region-field.vue', + 'fields/scripture-field.vue', + 'fields/section-panel-field.vue', + 'fields/select-field.vue', + 'fields/string-field.vue', + 'index.css', + 'invitation/invitation-index-item.story.vue', + 'invitation/invitation-index-item.vue', + 'invitation/invitations-index.vue', + 'pages/page-index-item.story.vue', + 'pages/pages-index.vue', + 'resources/resource-index-item.story.vue', + 'resources/resource-index-item.vue', + 'resources/resource-used-in.vue', + 'resources/resources-index.vue', + 'settings/languages/components/bible-translations-modal.story.vue', + 'settings/languages/components/bible-translations-modal.vue', + 'settings/languages/components/language-list-item.vue', + 'settings/languages/components/language-modal.vue', + 'settings/languages/components/language-table.vue', + 'settings/languages/components/remove-language-modal.story.vue', + 'settings/languages/components/request-app-update-modal.story.vue', + 'settings/languages/components/request-app-update-modal.vue', + 'settings/languages/components/request-feedback-modal.story.vue', + 'shared/context-menu.vue', + 'shared/drop-down.vue', + 'shared/expandable-search.vue', + 'shared/gallery-item.vue', + 'shared/glass-button.vue', + 'shared/index-filter.story.vue', + 'shared/index-tab-button.vue', + 'shared/index-tabs.story.vue', + 'shared/label-hint-popup.vue', + 'shared/language-option-label.story.vue', + 'shared/message-centre.story.vue', + 'shared/meta-box.vue', + 'shared/nav-rail-language-selector.vue', + 'shared/pagination.vue', + 'shared/pill-button.vue', + 'shared/rich-listbox.vue', + 'shared/studio-button.vue', + 'shared/tab-button.story.vue', + 'shared/tab-button.vue', + 'stories/components/index-card.story.vue', + 'stories/components/index-card.vue', + 'stories/components/panel-list.vue', + 'stories/components/resource-label-group.vue', + 'stories/components/resource-picker.vue', + 'stories/components/resource-visibility-badge.story.vue', + 'stories/components/story-item.story.vue', + 'stories/components/story-item.vue', + 'stories/journa-story-edit.vue', + 'stories/story-gallery.vue', + 'stories/story-index.vue', + 'streams/components/drop-item.vue', + 'streams/components/stream-item.vue', + 'streams/stream-index.vue', + 'team/components/user-row.vue', + 'team/users-index.vue', + 'ui/components/ui-card.vue', + 'ui/components/ui-string-item.vue', + 'ui/ui-page.vue', + ] }, + 'yellow-100': { count: 2, files: [ + 'stories/components/story-item.vue', + 'streams/components/stream-item.vue', + ] }, + 'yellow-50': { count: 5, files: [ + 'shared/bookmark-action.vue', + 'shared/message-centre.vue', + 'shared/status-tag.vue', + ] }, + 'yellow-500': { count: 3, files: [ + 'shared/bookmark-action.vue', + 'shared/message-centre.vue', + 'shared/status-tag.vue', + ] }, + 'yellow-600': { count: 2, files: [ + 'shared/bookmark-action.vue', + ] }, + 'yellow-800': { count: 3, files: [ + 'shared/status-tag.vue', + 'stories/components/story-item.vue', + 'streams/components/stream-item.vue', + ] }, +}; diff --git a/src/frontend/shared/draft-actions.vue b/src/frontend/shared/draft-actions.vue index 1c3e640f..45f8966b 100644 --- a/src/frontend/shared/draft-actions.vue +++ b/src/frontend/shared/draft-actions.vue @@ -5,8 +5,8 @@ :class="[ 'rounded-xl p-1.5 transition-colors', shared.showMetaBox - ? 'bg-blue-50 text-blue-600' - : 'text-gray-400 hover:bg-blue-50 hover:text-blue-600', + ? 'bg-gray-50 text-gray-600' + : 'text-gray-400 hover:bg-gray-50 hover:text-gray-600', ]" :aria-pressed="shared.showMetaBox" aria-label="Toggle meta box" @@ -20,8 +20,8 @@ :class="[ 'rounded-xl p-1.5 transition-colors', shared.showAppPreview - ? 'bg-blue-50 text-blue-600' - : 'text-gray-400 hover:bg-blue-50 hover:text-blue-600', + ? 'bg-gray-50 text-gray-600' + : 'text-gray-400 hover:bg-gray-50 hover:text-gray-600', ]" :aria-pressed="shared.showAppPreview" aria-label="Toggle app preview" diff --git a/src/frontend/shared/drop-up.vue b/src/frontend/shared/drop-up.vue deleted file mode 100644 index 06c6b3c0..00000000 --- a/src/frontend/shared/drop-up.vue +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - {{ model }} - - - - - - - - - - - - {{ option }} - - - - - - - - - - - - - - - - diff --git a/src/frontend/shared/helpers.ts b/src/frontend/shared/helpers.ts index f629acb9..e94b5206 100644 --- a/src/frontend/shared/helpers.ts +++ b/src/frontend/shared/helpers.ts @@ -62,30 +62,29 @@ export const formatDate = (value: string): string => { }; export const toRelativeTime = (value: string, now?: DateTime): string => { - const saved = DateTime.fromISO(value); + const date = DateTime.fromISO(value); const currentTime = now ?? DateTime.now(); - const pluralize = (n: number, unit: string): string => `${n} ${unit}${n === 1 ? '' : 's'} ago`; - - const elapsedSeconds = Math.floor(currentTime.diff(saved, 'seconds').seconds); - if (elapsedSeconds < 60) return pluralize(Math.max(1, elapsedSeconds), 'sec'); - - const elapsedMinutes = Math.floor(elapsedSeconds / 60); - if (elapsedMinutes < 60) return pluralize(elapsedMinutes, 'min'); - - const elapsedHours = Math.floor(elapsedMinutes / 60); - if (elapsedHours < 24) return pluralize(elapsedHours, 'hour'); - - const elapsedDays = Math.floor(elapsedHours / 24); - if (elapsedDays < 7) return pluralize(elapsedDays, 'day'); - - const display = saved.toUTC(); - const hour12 = display.hour % 12 === 0 ? 12 : display.hour % 12; - const meridiem = display.hour < 12 ? 'am' : 'pm'; + const diff = currentTime.diff(date, 'days').days; + + if (diff < 1) return 'Today'; + if (diff < 2) return 'Yesterday'; + if (diff < 7) return date.toFormat('cccc'); + + if (date.year === currentTime.year) { + const day = date.day; + const ordinal = + day === 1 || day === 21 || day === 31 + ? 'st' + : day === 2 || day === 22 + ? 'nd' + : day === 3 || day === 23 + ? 'rd' + : 'th'; + return `${day}${ordinal} ${date.toFormat('MMMM')}`; + } - return `on ${padZero(display.day)}/${padZero(display.month)}/${display.year} at ${hour12}:${padZero( - display.minute, - )}${meridiem}`; + return date.toFormat('dd/MM/yyyy'); }; export const indexCardTags = (scope: string, itemTags: string[]): string[] => { diff --git a/src/frontend/shared/icon.vue b/src/frontend/shared/icon.vue index 380246f8..c0a9ad22 100644 --- a/src/frontend/shared/icon.vue +++ b/src/frontend/shared/icon.vue @@ -998,6 +998,69 @@ d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" /> + + + + + + + + + + + + + + + + + diff --git a/src/frontend/shared/index-filter.vue b/src/frontend/shared/index-filter.vue index 14240bd9..f7cd2316 100644 --- a/src/frontend/shared/index-filter.vue +++ b/src/frontend/shared/index-filter.vue @@ -11,7 +11,10 @@ {{ tab.label }} {{ tab.count }} diff --git a/src/frontend/shared/index-tab-button.vue b/src/frontend/shared/index-tab-button.vue new file mode 100644 index 00000000..b6c8e6bb --- /dev/null +++ b/src/frontend/shared/index-tab-button.vue @@ -0,0 +1,46 @@ + + + + + {{ count }} + + + + + diff --git a/src/frontend/shared/index-tabs.story.vue b/src/frontend/shared/index-tabs.story.vue new file mode 100644 index 00000000..179c4ff4 --- /dev/null +++ b/src/frontend/shared/index-tabs.story.vue @@ -0,0 +1,48 @@ + + + + + + + + + + Selected: {{ currentTab }} + + + + + + + + + + + + diff --git a/src/frontend/shared/index-tabs.vue b/src/frontend/shared/index-tabs.vue new file mode 100644 index 00000000..41ee6e1b --- /dev/null +++ b/src/frontend/shared/index-tabs.vue @@ -0,0 +1,43 @@ + + + + + {{ tab.label }} + + + + + + diff --git a/src/frontend/shared/language-option-label.story.vue b/src/frontend/shared/language-option-label.story.vue new file mode 100644 index 00000000..3c4112a9 --- /dev/null +++ b/src/frontend/shared/language-option-label.story.vue @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/shared/language-option-label.vue b/src/frontend/shared/language-option-label.vue new file mode 100644 index 00000000..a8dd8901 --- /dev/null +++ b/src/frontend/shared/language-option-label.vue @@ -0,0 +1,31 @@ + + + + {{ displayName }} + + {{ subtitle }} + + + + diff --git a/src/frontend/shared/language-selector.vue b/src/frontend/shared/language-selector.vue deleted file mode 100644 index aadbbe1d..00000000 --- a/src/frontend/shared/language-selector.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - {{ currentLocale }} - - - - - - - - - - - {{ language.language }} - - - - - - - - - - diff --git a/src/frontend/shared/list-switcher.vue b/src/frontend/shared/list-switcher.vue index f86f30b6..3861efb2 100644 --- a/src/frontend/shared/list-switcher.vue +++ b/src/frontend/shared/list-switcher.vue @@ -1,23 +1,23 @@ - + diff --git a/src/frontend/shared/nav-rail-language-selector.story.vue b/src/frontend/shared/nav-rail-language-selector.story.vue new file mode 100644 index 00000000..c02bd147 --- /dev/null +++ b/src/frontend/shared/nav-rail-language-selector.story.vue @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/shared/nav-rail-language-selector.vue b/src/frontend/shared/nav-rail-language-selector.vue new file mode 100644 index 00000000..e84d03e8 --- /dev/null +++ b/src/frontend/shared/nav-rail-language-selector.vue @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + {{ currentLocale }} + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/shared/nav-rail-panel.vue b/src/frontend/shared/nav-rail-panel.vue index 0d6a9ff5..5c563165 100644 --- a/src/frontend/shared/nav-rail-panel.vue +++ b/src/frontend/shared/nav-rail-panel.vue @@ -113,10 +113,12 @@ - @@ -126,7 +128,7 @@ + + +# 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 ``; `false` + renders a non-interactive ``. +- `disabled` — disables the button when `isAction` is `true`. + +## Events + +- `click` — emitted when an enabled, actionable button is clicked. + 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/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 @@ - - - - {{ label }} - - - - diff --git a/src/frontend/stories/chapter-preview.vue b/src/frontend/stories/chapter-preview.vue index b68b03cf..8f5a8b67 100644 --- a/src/frontend/stories/chapter-preview.vue +++ b/src/frontend/stories/chapter-preview.vue @@ -2,7 +2,7 @@ - + diff --git a/src/frontend/stories/components/resource-attached-item.story.vue b/src/frontend/stories/components/resource-attached-item.story.vue index 944c99a3..84edb69c 100644 --- a/src/frontend/stories/components/resource-attached-item.story.vue +++ b/src/frontend/stories/components/resource-attached-item.story.vue @@ -1,12 +1,19 @@ - + + + + + - - {{ item.visibility }} - + - + There are no resources attached to this story. Search for resources above or create new ones to attach to this story diff --git a/src/frontend/stories/components/resource-picker.vue b/src/frontend/stories/components/resource-picker.vue index b4b808d1..cebda0a8 100644 --- a/src/frontend/stories/components/resource-picker.vue +++ b/src/frontend/stories/components/resource-picker.vue @@ -11,20 +11,20 @@ v-model="searchQuery" type="text" placeholder="Search resources to attach..." - class="w-full rounded-xl border border-gray-300 py-2.5 pl-11 pr-4 focus:border-transparent focus:ring-2 focus:ring-studio_forest_green" + class="focus:ring-studio-green w-full rounded-xl border border-gray-300 py-2.5 pl-11 pr-4 focus:border-transparent focus:ring-2" @focus="showSearch = true" @input="showSearch = true" /> - - - Create New Resource - + + {{ resourceTypeLabel(type) }} diff --git a/src/frontend/stories/components/resource-visibility-badge.vue b/src/frontend/stories/components/resource-visibility-badge.vue new file mode 100644 index 00000000..d4a4d6a0 --- /dev/null +++ b/src/frontend/stories/components/resource-visibility-badge.vue @@ -0,0 +1,16 @@ + + + {{ visibility }} + + + + diff --git a/src/frontend/stories/components/workflow-actions.vue b/src/frontend/stories/components/workflow-actions.vue index 4266e526..6b930405 100644 --- a/src/frontend/stories/components/workflow-actions.vue +++ b/src/frontend/stories/components/workflow-actions.vue @@ -2,20 +2,20 @@ 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..2cf09a6e 100644 --- a/src/frontend/stories/story-edit.vue +++ b/src/frontend/stories/story-edit.vue @@ -4,7 +4,7 @@ @@ -12,7 +12,7 @@ diff --git a/src/frontend/stories/story-gallery.vue b/src/frontend/stories/story-gallery.vue index d9c618f9..020f0479 100644 --- a/src/frontend/stories/story-gallery.vue +++ b/src/frontend/stories/story-gallery.vue @@ -5,7 +5,7 @@ diff --git a/src/frontend/stories/story-index.vue b/src/frontend/stories/story-index.vue index ed5523be..fb0b61e0 100644 --- a/src/frontend/stories/story-index.vue +++ b/src/frontend/stories/story-index.vue @@ -4,13 +4,13 @@ diff --git a/src/frontend/streams/stream-index.vue b/src/frontend/streams/stream-index.vue index 9626b441..490975b6 100644 --- a/src/frontend/streams/stream-index.vue +++ b/src/frontend/streams/stream-index.vue @@ -4,7 +4,9 @@ - + + + @@ -13,14 +15,18 @@ > - + @click="sortDescending = !sortDescending" + > + + + @@ -67,7 +73,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, Plus } from '@lucide/vue'; import AppLayout from '../shared/app-layout.vue'; import Icon from '../shared/icon.vue'; @@ -75,9 +82,9 @@ import { computed, ref } from 'vue'; import type { DropIndexItem, StreamIndexProps } from '../../types'; import DropItem from './components/drop-item.vue'; import ListSwitcher from '../shared/list-switcher.vue'; -import IconButton from '../shared/icon-button.vue'; import { router } from '@inertiajs/vue3'; import { useSharedStore } from '../store'; +import StudioButton from '../shared/studio-button.vue'; const props = defineProps(); const shared = useSharedStore(); diff --git a/src/frontend/team/components/user-form-modal.vue b/src/frontend/team/components/user-form-modal.vue index 8f9c53fc..f850d08d 100644 --- a/src/frontend/team/components/user-form-modal.vue +++ b/src/frontend/team/components/user-form-modal.vue @@ -72,8 +72,8 @@ - - + + diff --git a/src/frontend/team/components/user-row.vue b/src/frontend/team/components/user-row.vue index 30a6768b..127cfe6a 100644 --- a/src/frontend/team/components/user-row.vue +++ b/src/frontend/team/components/user-row.vue @@ -36,7 +36,9 @@ - + {{ language }} @@ -67,10 +69,10 @@
{{ description }}
All done
- {{ englishName }} +
+ +
Last update: {{ lastUpdate }}
No updates
- {{ item.name }} -
+ {{ item.name }} +
- {{ name }} -
{{ color.name }}
{{ color.hex }}
+ Used {{ colorUsage[color.name].count }} times in + {{ colorUsage[color.name].files.length }} files +
No uses found
Selected: {{ currentTab }}
+ {{ displayName }} +
{{ subtitle }}
+
There are no resources attached to this story. Search for resources above or create new ones to attach to this story