feat: migrate visual fixtures to storybook

This commit is contained in:
2026-09-08 21:43:26 -04:00
parent 41efdfe041
commit f7534d901b
69 changed files with 62947 additions and 589 deletions
+8 -2
View File
@@ -2,8 +2,8 @@
"version": 1,
"projectName": "pokemon-inventory",
"projectPath": "/Users/fragginwagon/Developer/Source Code/pokemon/pokemon-inventory",
"updatedAt": "2026-09-08T23:54:46.326Z",
"lastSeenAt": "2026-09-08T23:54:46.326Z",
"updatedAt": "2026-09-09T01:42:54.487Z",
"lastSeenAt": "2026-09-09T01:42:54.487Z",
"ports": [
{
"service": "api",
@@ -23,6 +23,12 @@
"port": 5433,
"notes": ""
},
{
"service": "storybook",
"protocol": "tcp",
"port": 6006,
"notes": ""
},
{
"service": "redis",
"protocol": "tcp",
+10
View File
@@ -83,6 +83,16 @@ This command starts healthy PostgreSQL and Redis containers, applies migrations,
The command does not provision an administrator automatically. Run `npm run provision:admin` once after setting the initial administrator variables in `.env` when admin access is needed. Stop the application processes with `Ctrl+C`; stop the containers separately with `npm run db:down` when they are no longer needed.
## Visual Development
Run Storybook to inspect the authoritative design tokens and mock visual fixtures without requiring API data:
```sh
npm run storybook
```
Open `http://localhost:6006/`. Use the Storybook theme toolbar to switch between light and dark themes. The accessibility addon is enabled for component review. The fixture showcase is intentionally mock-only and is not part of the production router.
## Initial Administrator
After the development database is migrated, set `INITIAL_ADMIN_EMAIL`, `INITIAL_ADMIN_PASSWORD`, and `INITIAL_SELLER_NAME` in your local `.env`, then run `npm run provision:admin` once. The command creates the only initial administrator and linked Seller; it refuses to run after any User exists.
+20
View File
@@ -0,0 +1,20 @@
import { fileURLToPath } from 'node:url';
export default {
stories: ['../src/**/*.stories.js'],
addons: ['@storybook/addon-essentials', '@storybook/addon-a11y'],
framework: {
name: '@storybook/vue3-vite',
options: {},
},
viteFinal: async (config) => ({
...config,
resolve: {
...config.resolve,
alias: {
...config.resolve?.alias,
'@': fileURLToPath(new URL('../src', import.meta.url)),
},
},
}),
};
+26
View File
@@ -0,0 +1,26 @@
import '../src/assets/styles/global.scss';
export const globalTypes = {
theme: {
description: 'Global color theme',
defaultValue: 'light',
toolbar: {
icon: 'paintbrush',
items: ['light', 'dark'],
dynamicTitle: true,
},
},
};
export const decorators = [
(story, context) => {
document.documentElement.dataset.theme = context.globals.theme;
return story();
},
];
export const parameters = {
controls: { expanded: true },
a11y: { test: 'todo' },
layout: 'fullscreen',
};
+2
View File
@@ -5,6 +5,8 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"test": "node --test tests/*.test.js"
},
"dependencies": {
+3
View File
@@ -1,5 +1,8 @@
<script setup>
import { RouterView } from 'vue-router';
import { useTheme } from '@/composables/useTheme.js';
useTheme();
</script>
<template>
@@ -0,0 +1,110 @@
@use 'sass:map';
:root {
--color-white: #ffffff;
--color-black: #0b0d10;
--color-cobalt-500: #1769ff;
--color-cobalt-400: #4d8cff;
--color-cobalt-700: #0e45b5;
--color-gray-050: #f8fafc;
--color-gray-100: #f1f4f8;
--color-gray-200: #e3e8ef;
--color-gray-300: #c7d0dc;
--color-gray-500: #667384;
--color-gray-700: #344052;
--color-gray-900: #161b22;
--color-success-500: #12a150;
--color-warning-500: #d88a00;
--color-danger-500: #e5484d;
--color-info-500: #1683c4;
--font-ui: 'Manrope', ui-sans-serif, system-ui, sans-serif;
--font-display: 'Space Grotesk', 'Manrope', ui-sans-serif, sans-serif;
--weight-regular: 400;
--weight-medium: 500;
--weight-semibold: 600;
--weight-bold: 700;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-md: 1rem;
--text-lg: 1.25rem;
--text-xl: 1.5rem;
--text-2xl: 2rem;
--text-display: clamp(2.5rem, 8vw, 5.5rem);
--leading-tight: 1.05;
--leading-normal: 1.5;
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-6: 24px;
--space-8: 32px;
--space-12: 48px;
--space-16: 64px;
--space-24: 96px;
--radius-sm: 4px;
--radius-md: 6px;
--radius-lg: 8px;
--radius-xl: 12px;
--radius-2xl: 16px;
--radius-full: 999px;
--border-thin: 1px;
--border-strong: 2px;
--shadow-sm: 0 2px 8px rgb(11 13 16 / 8%);
--shadow-md: 0 8px 24px rgb(11 13 16 / 12%);
--duration-fast: 80ms;
--duration-standard: 180ms;
--duration-slow: 350ms;
--breakpoint-sm: 640px;
--breakpoint-md: 768px;
--breakpoint-lg: 1024px;
--breakpoint-xl: 1280px;
--breakpoint-2xl: 1536px;
}
:root,
[data-theme='light'] {
color-scheme: light;
--color-background: var(--color-gray-050);
--color-surface: var(--color-white);
--color-surface-raised: var(--color-white);
--color-surface-muted: var(--color-gray-100);
--color-text: var(--color-gray-900);
--color-text-muted: var(--color-gray-500);
--color-text-subtle: var(--color-gray-700);
--color-border: var(--color-gray-200);
--color-border-strong: var(--color-gray-300);
--color-interactive: var(--color-cobalt-500);
--color-interactive-hover: var(--color-cobalt-700);
--color-on-interactive: var(--color-white);
--color-focus: var(--color-cobalt-500);
--color-stage: var(--color-gray-100);
--glow-focus: 0 0 0 4px rgb(23 105 255 / 22%);
--glow-selection: 0 0 0 3px rgb(23 105 255 / 18%);
}
[data-theme='dark'] {
color-scheme: dark;
--color-background: #0b0d10;
--color-surface: #11161d;
--color-surface-raised: #18202b;
--color-surface-muted: #202a37;
--color-text: #f5f7fa;
--color-text-muted: #a7b2c2;
--color-text-subtle: #d1d8e2;
--color-border: #2b3745;
--color-border-strong: #425064;
--color-interactive: var(--color-cobalt-400);
--color-interactive-hover: #83adff;
--color-on-interactive: #07142f;
--color-focus: var(--color-cobalt-400);
--color-stage: #202630;
--glow-focus: 0 0 0 4px rgb(77 140 255 / 28%);
--glow-selection: 0 0 0 3px rgb(77 140 255 / 24%);
}
@media (prefers-reduced-motion: reduce) {
:root { --duration-fast: 0ms; --duration-standard: 0ms; --duration-slow: 0ms; }
}
+90 -46
View File
@@ -1,53 +1,97 @@
:root {
color: #22231f;
background: #f3efe6;
font-family: Georgia, 'Times New Roman', serif;
font-synthesis: none;
text-rendering: optimizeLegibility;
}
@use './global-tokens';
@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap');
* { box-sizing: border-box; }
body { margin: 0; min-width: 320px; }
button, input { font: inherit; }
html { background: var(--color-background); }
body { min-width: 320px; margin: 0; background: var(--color-background); color: var(--color-text); font-family: var(--font-ui); font-synthesis: none; line-height: var(--leading-normal); text-rendering: optimizeLegibility; transition: background var(--duration-standard) ease, color var(--duration-standard) ease; }
button, input, select, textarea { font: inherit; }
button, a, input, select, textarea { &:focus-visible { outline: var(--border-strong) solid var(--color-focus); outline-offset: 3px; box-shadow: var(--glow-focus); } }
button { cursor: pointer; }
h1, h2, h3, h4 { margin: 0; font-family: var(--font-display); line-height: var(--leading-tight); }
.catalog-page {
min-height: 100vh;
background: radial-gradient(circle at 85% 12%, #d9e7df 0, transparent 30%), #f3efe6;
}
.catalog-header, .catalog-results { width: min(1120px, calc(100% - 40px)); margin: 0 auto; }
.catalog-header { padding: 88px 0 72px; }
.catalog-kicker, .listing-card__status { color: #a3482a; font: 700 0.75rem/1.2 Arial, sans-serif; letter-spacing: 0.14em; text-transform: uppercase; }
h1 { max-width: 680px; margin: 12px 0 18px; font-size: clamp(3.2rem, 9vw, 7rem); line-height: 0.92; font-weight: 500; }
.catalog-intro { max-width: 480px; color: #61625a; font: 1.1rem/1.5 Arial, sans-serif; }
.search-field { display: block; max-width: 720px; margin-top: 48px; color: #61625a; font: 700 0.8rem/1 Arial, sans-serif; text-transform: uppercase; letter-spacing: 0.08em; }
.search-field input { display: block; width: 100%; margin-top: 12px; padding: 18px 20px; border: 1px solid #9ca69b; border-radius: 2px; background: #fffdf8; color: #22231f; font-size: 1.05rem; letter-spacing: 0; text-transform: none; outline-offset: 4px; }
.catalog-results { padding-bottom: 88px; }
.results-heading { display: flex; align-items: baseline; justify-content: space-between; border-bottom: 1px solid #c9c8bd; padding-bottom: 14px; }
h2 { margin: 0; font-size: 1.8rem; font-weight: 500; }
.results-heading span { color: #77786f; font: 0.85rem Arial, sans-serif; }
.listing-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 24px; }
.detail-page { width: min(920px, calc(100% - 40px)); min-height: 100vh; margin: 0 auto; padding: 48px 0 88px; }
.detail-back { color: #386052; font: 700 0.85rem Arial, sans-serif; }
.detail-content { max-width: 680px; padding-top: 96px; }
.catalog-page, .detail-page, .showcase-page { min-height: 100vh; background: var(--color-background); }
.catalog-header, .catalog-results { width: min(1120px, calc(100% - var(--space-8))); margin: 0 auto; }
.catalog-header { padding: var(--space-24) 0 var(--space-16); }
.catalog-kicker, .listing-card__status { color: var(--color-interactive); font-size: var(--text-xs); font-weight: var(--weight-bold); letter-spacing: 0.12em; text-transform: uppercase; }
h1 { max-width: 760px; margin: var(--space-3) 0 var(--space-4); font-size: var(--text-display); }
.catalog-intro { max-width: 560px; color: var(--color-text-muted); font-size: var(--text-lg); }
.search-field { display: block; max-width: 720px; margin-top: var(--space-12); color: var(--color-text-subtle); font-size: var(--text-sm); font-weight: var(--weight-bold); }
.search-field input { display: block; width: 100%; margin-top: var(--space-2); border: var(--border-thin) solid var(--color-border-strong); border-radius: var(--radius-lg); padding: var(--space-4) var(--space-6); background: var(--color-surface); color: var(--color-text); }
.catalog-results { padding-bottom: var(--space-24); }
.results-heading { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); border-bottom: var(--border-thin) solid var(--color-border); padding-bottom: var(--space-3); }
.results-heading span { color: var(--color-text-muted); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
.listing-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); margin-top: var(--space-6); }
.detail-page { width: min(920px, calc(100% - var(--space-8))); margin: 0 auto; padding: var(--space-12) 0 var(--space-24); }
.detail-back { color: var(--color-interactive); font-weight: var(--weight-bold); text-decoration: none; }
.detail-content { max-width: 680px; padding-top: var(--space-16); }
.detail-content h1 { font-size: clamp(3rem, 8vw, 6rem); }
.detail-price { font: 700 1.25rem Arial, sans-serif; }
.detail-notes { max-width: 520px; color: #61625a; font: 1.1rem/1.5 Arial, sans-serif; }
.product-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 32px; max-width: 560px; margin-top: 40px; border-top: 1px solid #c9c8bd; padding-top: 22px; }
.product-facts div { display: grid; gap: 6px; }
.product-facts dt { color: #77786f; font: 700 0.72rem Arial, sans-serif; letter-spacing: 0.1em; text-transform: uppercase; }
.product-facts dd { margin: 0; font: 1rem Arial, sans-serif; }
.catalog-state { padding: 48px 0; color: #61625a; font: 1rem/1.5 Arial, sans-serif; }
.catalog-state--error { color: #a3482a; }
.pagination { display: flex; align-items: center; justify-content: center; gap: 18px; margin-top: 28px; color: #61625a; font: 0.85rem Arial, sans-serif; }
.pagination button { border: 1px solid #9ca69b; padding: 10px 14px; background: #fffdf8; color: #386052; cursor: pointer; }
.pagination button:hover:not(:disabled) { border-color: #386052; }
.pagination button:focus-visible { outline: 3px solid #a3482a; outline-offset: 3px; }
.detail-price { color: var(--color-text); font-size: var(--text-xl); font-weight: var(--weight-bold); font-variant-numeric: tabular-nums; }
.detail-notes { max-width: 560px; color: var(--color-text-muted); font-size: var(--text-lg); }
.product-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6) var(--space-8); max-width: 560px; margin-top: var(--space-12); border-top: var(--border-thin) solid var(--color-border); padding-top: var(--space-6); }
.product-facts div { display: grid; gap: var(--space-2); }
.product-facts dt { color: var(--color-text-muted); font-size: var(--text-xs); font-weight: var(--weight-bold); letter-spacing: 0.1em; text-transform: uppercase; }
.product-facts dd { margin: 0; }
.catalog-state { padding: var(--space-12) 0; color: var(--color-text-muted); }
.catalog-state--error { color: var(--color-danger-500); }
.pagination { display: flex; align-items: center; justify-content: center; gap: var(--space-6); margin-top: var(--space-8); color: var(--color-text-muted); font-size: var(--text-sm); }
.pagination button { min-width: 44px; min-height: 44px; border: var(--border-thin) solid var(--color-border-strong); border-radius: var(--radius-md); padding: var(--space-2) var(--space-4); background: var(--color-surface); color: var(--color-interactive); }
.pagination button:disabled { cursor: not-allowed; opacity: 0.45; }
@media (max-width: 720px) {
.catalog-header { padding-top: 56px; }
.listing-grid { grid-template-columns: 1fr; }
h1 { font-size: 4rem; }
.showcase-page { padding: var(--space-12) max(var(--space-4), calc((100vw - 1200px) / 2)); }
.showcase-header { display: flex; align-items: end; justify-content: space-between; gap: var(--space-8); margin-bottom: var(--space-12); }
.showcase-header h1 { max-width: 720px; }
.showcase-header p { max-width: 600px; color: var(--color-text-muted); }
.showcase-section { margin-top: var(--space-16); }
.showcase-section h2 { margin-bottom: var(--space-6); font-size: var(--text-2xl); }
.showcase-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); }
.showcase-panel { border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-xl); padding: var(--space-6); background: var(--color-surface); box-shadow: var(--shadow-sm); }
.showcase-panel h3 { margin-bottom: var(--space-4); font-size: var(--text-lg); }
.theme-controls, .control-row, .status-row, .swatch-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.theme-controls { justify-content: end; }
.theme-controls label, .fixture-label { color: var(--color-text-muted); font-size: var(--text-xs); font-weight: var(--weight-bold); }
.theme-controls select, .fixture-input { min-height: 44px; border: var(--border-thin) solid var(--color-border-strong); border-radius: var(--radius-md); padding: var(--space-2) var(--space-3); background: var(--color-surface); color: var(--color-text); }
.button { min-height: 44px; border: var(--border-thin) solid transparent; border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); font-weight: var(--weight-bold); }
.button--primary { background: var(--color-interactive); color: var(--color-on-interactive); }
.button--secondary { border-color: var(--color-border-strong); background: var(--color-surface); color: var(--color-text); }
.button--danger { background: var(--color-danger-500); color: var(--color-white); }
.button:disabled { cursor: not-allowed; opacity: 0.45; }
.swatch { display: grid; gap: var(--space-2); color: var(--color-text-muted); font-size: var(--text-xs); }
.swatch__chip { width: 72px; height: 44px; border-radius: var(--radius-md); }
.swatch__chip--cobalt { background: var(--color-cobalt-500); }
.swatch__chip--success { background: var(--color-success-500); }
.swatch__chip--warning { background: var(--color-warning-500); }
.swatch__chip--danger { background: var(--color-danger-500); }
.swatch__chip--info { background: var(--color-info-500); }
.type-sample { display: grid; gap: var(--space-3); }
.type-sample__display { font-family: var(--font-display); font-size: var(--text-2xl); }
.type-sample__ui { font-weight: var(--weight-semibold); }
.type-sample__numeric { font-size: var(--text-xl); font-variant-numeric: tabular-nums; }
.status { display: inline-flex; align-items: center; gap: var(--space-2); border-radius: var(--radius-full); padding: var(--space-2) var(--space-3); font-size: var(--text-xs); font-weight: var(--weight-bold); }
.status::before { width: 8px; height: 8px; border-radius: 50%; background: currentColor; content: ''; }
.status--available { background: color-mix(in srgb, var(--color-success-500) 14%, transparent); color: var(--color-success-500); }
.status--pending { background: color-mix(in srgb, var(--color-warning-500) 16%, transparent); color: var(--color-warning-500); }
.status--sold { background: color-mix(in srgb, var(--color-danger-500) 14%, transparent); color: var(--color-danger-500); }
.condition { border: var(--border-thin) solid var(--color-border-strong); border-radius: var(--radius-md); padding: var(--space-2) var(--space-3); color: var(--color-text-subtle); font-size: var(--text-sm); }
.condition--selected { border-color: var(--color-interactive); box-shadow: var(--glow-selection); }
.fixture-stage { display: grid; place-items: center; min-height: 180px; border-radius: var(--radius-lg); background: var(--color-stage); color: var(--color-text-muted); text-align: center; }
.fixture-stage--image { min-height: 240px; background: linear-gradient(135deg, var(--color-stage), var(--color-surface-muted)); }
.fixture-stage__glyph { font-family: var(--font-display); font-size: 3rem; font-weight: var(--weight-bold); }
.fixture-card { display: grid; gap: var(--space-4); border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-xl); padding: var(--space-4); background: var(--color-surface-raised); }
.fixture-card h3 { font-size: var(--text-lg); }
.fixture-card__meta { color: var(--color-text-muted); font-size: var(--text-sm); }
.fixture-card__price { font-size: var(--text-lg); font-weight: var(--weight-bold); font-variant-numeric: tabular-nums; }
.fixture-card__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.state-stack { display: grid; gap: var(--space-3); }
.state { border-radius: var(--radius-lg); padding: var(--space-4); }
.state--empty { border: var(--border-thin) dashed var(--color-border-strong); color: var(--color-text-muted); }
.state--loading { background: var(--color-surface-muted); color: var(--color-text-muted); }
.state--error { background: color-mix(in srgb, var(--color-danger-500) 10%, transparent); color: var(--color-danger-500); }
@media (max-width: 768px) {
.catalog-header { padding-top: var(--space-16); }
.listing-grid, .showcase-grid { grid-template-columns: 1fr; }
.showcase-header { display: grid; align-items: start; }
.theme-controls { justify-content: start; }
.product-facts { grid-template-columns: 1fr; }
}
}
@@ -1,19 +1,20 @@
.listing-card {
display: grid;
grid-template-columns: 60px 1fr;
gap: 18px;
gap: var(--space-4);
min-height: 180px;
padding: 20px;
border: 1px solid #d6d3c7;
background: #fffdf8;
color: #22231f;
border: var(--border-thin) solid var(--color-border);
border-radius: var(--radius-xl);
padding: var(--space-6);
background: var(--color-surface-raised);
color: var(--color-text);
box-shadow: var(--shadow-sm);
text-decoration: none;
transition: border-color 160ms ease, transform 160ms ease;
transition: border-color var(--duration-standard) ease, transform var(--duration-standard) ease;
}
.listing-card:hover { border-color: #386052; transform: translateY(-2px); }
.listing-card:focus-visible { outline: 3px solid #a3482a; outline-offset: 4px; }
.listing-card__mark { display: grid; place-items: center; aspect-ratio: 1; align-self: start; background: #d9e7df; color: #386052; font: 700 0.85rem Arial, sans-serif; }
.listing-card__status { display: block; margin-top: 2px; color: #386052; font: 700 0.75rem/1.2 Arial, sans-serif; letter-spacing: 0.14em; text-transform: uppercase; }
.listing-card__name { display: block; margin: 8px 0 16px; font-size: 1.25rem; }
.listing-card__price { display: block; font: 700 1rem Arial, sans-serif; }
.listing-card:hover { border-color: var(--color-interactive); transform: translateY(-2px); }
.listing-card__mark { display: grid; place-items: center; aspect-ratio: 1; align-self: start; border-radius: var(--radius-md); background: var(--color-stage); color: var(--color-interactive); font: var(--weight-bold) var(--text-sm) var(--font-display); }
.listing-card__status { display: block; margin-top: 2px; }
.listing-card__name { display: block; margin: var(--space-2) 0 var(--space-4); font-family: var(--font-display); font-size: var(--text-lg); }
.listing-card__price { display: block; font-size: var(--text-md); font-weight: var(--weight-bold); font-variant-numeric: tabular-nums; }
@@ -9,4 +9,26 @@ export const available = {
status: 'AVAILABLE',
},
},
};
export const pending = {
args: {
listing: {
id: 'listing-2',
productName: 'Pikachu World Collection',
askingPriceMinor: 8200,
status: 'PENDING',
},
},
};
export const sold = {
args: {
listing: {
id: 'listing-3',
productName: 'Gengar holo promo',
askingPriceMinor: 4500,
status: 'SOLD',
},
},
};
@@ -0,0 +1,8 @@
import DesignSystemShowcase from './DesignSystemShowcase.vue';
export default {
title: 'Organisms/Design System Showcase',
component: DesignSystemShowcase,
};
export const AllFixtures = {};
@@ -0,0 +1,136 @@
<script setup>
import { ref } from 'vue';
const selectedCondition = ref('Near Mint');
const listings = [
{ id: 'fixture-charizard', productName: 'Charizard ex #199/165', askingPriceMinor: 11500, status: 'AVAILABLE' },
{ id: 'fixture-pikachu', productName: 'Pikachu World Collection', askingPriceMinor: 8200, status: 'PENDING' },
{ id: 'fixture-gengar', productName: 'Gengar holo promo', askingPriceMinor: 4500, status: 'SOLD' },
];
</script>
<template>
<main class="showcase-page">
<header class="showcase-header">
<div>
<p class="catalog-kicker">Design system fixture</p>
<h1>Collectible data, made precise.</h1>
<p>Representative visual fixtures for the catalog, detail views, controls, states, and themes. This component uses mock data only.</p>
</div>
<p class="fixture-label">Use the Storybook theme toolbar to inspect light and dark themes.</p>
</header>
<section class="showcase-section" aria-labelledby="type-title">
<h2 id="type-title">Typography and tokens</h2>
<div class="showcase-grid">
<article class="showcase-panel type-sample">
<h3>Type scale</h3>
<p class="type-sample__display">Space Grotesk display</p>
<p class="type-sample__ui">Manrope interface and metadata</p>
<p class="type-sample__numeric">$1,150.00 · 12 copies · 199/165</p>
</article>
<article class="showcase-panel">
<h3>Primitive palette</h3>
<div class="swatch-row">
<span class="swatch"><span class="swatch__chip swatch__chip--cobalt" />Cobalt</span>
<span class="swatch"><span class="swatch__chip swatch__chip--success" />Success</span>
<span class="swatch"><span class="swatch__chip swatch__chip--warning" />Warning</span>
<span class="swatch"><span class="swatch__chip swatch__chip--danger" />Danger</span>
<span class="swatch"><span class="swatch__chip swatch__chip--info" />Info</span>
</div>
</article>
<article class="showcase-panel">
<h3>Controls</h3>
<div class="control-row">
<button class="button button--primary" type="button">Primary</button>
<button class="button button--secondary" type="button">Secondary</button>
<button class="button button--danger" type="button">Remove</button>
<button class="button button--secondary" type="button" disabled>Disabled</button>
</div>
<label class="fixture-label" for="fixture-input">Persistent label</label>
<input id="fixture-input" class="fixture-input" value="Charizard ex" />
</article>
</div>
</section>
<section class="showcase-section" aria-labelledby="state-title">
<h2 id="state-title">Statuses, conditions, and feedback</h2>
<div class="showcase-grid">
<article class="showcase-panel">
<h3>Status treatments</h3>
<div class="status-row">
<span class="status status--available">Available</span>
<span class="status status--pending">Pending</span>
<span class="status status--sold">Sold</span>
</div>
</article>
<article class="showcase-panel">
<h3>Condition selection</h3>
<div class="control-row">
<button v-for="condition in ['Near Mint', 'Lightly Played', 'Damaged']" :key="condition" class="condition" :class="{ 'condition--selected': selectedCondition === condition }" type="button" @click="selectedCondition = condition">
{{ condition }}
</button>
</div>
<p class="fixture-label">Selected: {{ selectedCondition }}</p>
</article>
<article class="showcase-panel state-stack">
<h3>Feedback states</h3>
<p class="state state--empty">No relevant matches found.</p>
<p class="state state--loading" role="status">Loading collectible...</p>
<p class="state state--error" role="alert">Unable to load marketplace values.</p>
</article>
</div>
</section>
<section class="showcase-section" aria-labelledby="card-title">
<h2 id="card-title">Collectible cards</h2>
<div class="showcase-grid">
<article v-for="listing in listings" :key="listing.id" class="fixture-card">
<div class="fixture-stage" aria-label="Neutral collectible image stage"><span class="fixture-stage__glyph">PK</span></div>
<div>
<p class="fixture-card__meta">Trading card · Scarlet & Violet 151</p>
<h3>{{ listing.productName }}</h3>
<p class="fixture-card__meta">Condition: {{ listing.status === 'SOLD' ? 'Lightly Played' : 'Near Mint' }}</p>
</div>
<span :class="['status', `status--${listing.status.toLowerCase()}`]">{{ listing.status }}</span>
<p v-if="listing.status !== 'SOLD'" class="fixture-card__price">${{ (listing.askingPriceMinor / 100).toFixed(2) }}</p>
<p v-else class="fixture-card__meta">Sold history retained</p>
<div class="fixture-card__actions">
<button class="button button--primary" type="button">View collectible</button>
<button class="button button--secondary" type="button">Compare</button>
</div>
</article>
</div>
</section>
<section class="showcase-section" aria-labelledby="detail-title">
<h2 id="detail-title">Detail and gallery treatment</h2>
<div class="showcase-grid">
<article class="showcase-panel">
<h3>Collectible detail</h3>
<div class="fixture-stage fixture-stage--image" aria-label="Neutral image gallery stage"><span class="fixture-stage__glyph">01</span></div>
<p class="catalog-kicker">Identity</p>
<h3>Charizard ex #199/165</h3>
<p class="fixture-card__meta">Scarlet & Violet 151 · Trading card · Near Mint</p>
</article>
<article class="showcase-panel">
<h3>Listing detail</h3>
<p class="catalog-kicker">Available</p>
<h3>Asking price</h3>
<p class="fixture-card__price">$115.00</p>
<dl class="product-facts">
<div><dt>Condition</dt><dd>Near Mint</dd></div>
<div><dt>Market context</dt><dd>$120 reference</dd></div>
<div><dt>Updated</dt><dd>Today</dd></div>
<div><dt>Seller note</dt><dd>Clean front and back</dd></div>
</dl>
</article>
<article class="showcase-panel">
<h3>Image treatment</h3>
<div class="fixture-stage fixture-stage--image" aria-label="Museum-style contained collectible image stage"><span class="fixture-stage__glyph">GALLERY</span></div>
<p class="fixture-card__meta">Contained, neutral, aspect-ratio preserving, and free of cobalt image backgrounds.</p>
</article>
</div>
</section>
</main>
</template>
+30
View File
@@ -0,0 +1,30 @@
import { onMounted, onUnmounted, ref } from 'vue';
const preference = ref('system');
function applyTheme() {
const resolved = preference.value === 'system'
? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
: preference.value;
document.documentElement.dataset.theme = resolved;
}
export function useTheme() {
function setTheme(nextTheme) {
preference.value = nextTheme;
localStorage.setItem('pokemon-inventory-theme', nextTheme);
applyTheme();
}
onMounted(() => {
preference.value = localStorage.getItem('pokemon-inventory-theme') ?? 'system';
applyTheme();
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', applyTheme);
});
onUnmounted(() => {
window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', applyTheme);
});
return { preference, setTheme };
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,28 @@
const u={title:"Molecules/ListingCard"},r={args:{listing:{id:"listing-1",productName:"Charizard ex",askingPriceMinor:2499,status:"AVAILABLE"}}},s={args:{listing:{id:"listing-2",productName:"Pikachu World Collection",askingPriceMinor:8200,status:"PENDING"}}},a={args:{listing:{id:"listing-3",productName:"Gengar holo promo",askingPriceMinor:4500,status:"SOLD"}}};var i,n,e;r.parameters={...r.parameters,docs:{...(i=r.parameters)==null?void 0:i.docs,source:{originalSource:`{
args: {
listing: {
id: 'listing-1',
productName: 'Charizard ex',
askingPriceMinor: 2499,
status: 'AVAILABLE'
}
}
}`,...(e=(n=r.parameters)==null?void 0:n.docs)==null?void 0:e.source}}};var o,t,c;s.parameters={...s.parameters,docs:{...(o=s.parameters)==null?void 0:o.docs,source:{originalSource:`{
args: {
listing: {
id: 'listing-2',
productName: 'Pikachu World Collection',
askingPriceMinor: 8200,
status: 'PENDING'
}
}
}`,...(c=(t=s.parameters)==null?void 0:t.docs)==null?void 0:c.source}}};var d,g,l;a.parameters={...a.parameters,docs:{...(d=a.parameters)==null?void 0:d.docs,source:{originalSource:`{
args: {
listing: {
id: 'listing-3',
productName: 'Gengar holo promo',
askingPriceMinor: 4500,
status: 'SOLD'
}
}
}`,...(l=(g=a.parameters)==null?void 0:g.docs)==null?void 0:l.source}}};const p=["available","pending","sold"];export{p as __namedExportsOrder,r as available,u as default,s as pending,a as sold};
@@ -0,0 +1 @@
function e(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}export{e as g};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{h as p,c as y,i as h,r as d,a as w}from"./vue.esm-bundler-c7-UdoSZ.js";var v=Object.defineProperty,P=(r,t)=>{for(var e in t)v(r,e,{get:t[e],enumerable:!0})};const{sanitizeStoryContextUpdate:U}=__STORYBOOK_MODULE_PREVIEW_API__;var b={};P(b,{applyDecorators:()=>z,mount:()=>A,parameters:()=>C,render:()=>j,renderToCanvas:()=>N});var j=(r,t)=>{let{id:e,component:i}=t;if(!i)throw new Error(`Unable to render story ${e} as the component annotation is missing from the default export`);return()=>p(i,r,E(r,t))},I=async(r,t)=>{globalThis&&globalThis.PLUGINS_SETUP_FUNCTIONS&&await Promise.all([...globalThis.PLUGINS_SETUP_FUNCTIONS].map(e=>e(r,t)))},f=new Map;async function N({storyFn:r,forceRemount:t,showMain:e,showException:i,storyContext:n,id:a},s){let o=f.get(s);if(o&&!t){let l=r(),c=S(l,n);return R(o.reactiveArgs,c),()=>{g(o.vueApp,s)}}o&&t&&g(o.vueApp,s);let u=y({setup(){n.args=d(n.args);let l=r(),c=S(l,n),_={vueApp:u,reactiveArgs:d(c)};return f.set(s,_),()=>p(l)}});return u.config.errorHandler=(l,c,_)=>{var m;(m=window.__STORYBOOK_PREVIEW__)!=null&&m.storyRenders.some(O=>O.id===a&&O.phase==="playing")?setTimeout(()=>{throw l},0):i(l)},await I(u,n),u.mount(s),e(),()=>{g(u,s)}}function E(r,t){let{argTypes:e}=t,i=Object.entries(r).filter(([n])=>{var a,s;return((s=(a=e[n])==null?void 0:a.table)==null?void 0:s.category)==="slots"}).map(([n,a])=>[n,typeof a=="function"?a:()=>a]);return Object.fromEntries(i)}function S(r,t){return r.props&&h(r)?r.props:t.args}function R(r,t){if(Object.keys(t).length===0)return;let e=w(r)?r:d(r);Object.keys(e).forEach(i=>{i in t||delete e[i]}),Object.assign(e,t)}function g(r,t){r==null||r.unmount(),f.has(t)&&f.delete(t)}function F(r){return typeof r=="function"?{render:r,name:r.name}:r}function T(r,t){let e=r;return e===null?null:typeof e=="function"?e:t?{...F(e),components:{...e.components||{},story:t}}:{render(){return p(e)}}}function z(r,t){return t.reduce((e,i)=>n=>{let a,s=i(o=>{let u=U(o);return o&&(u.args=Object.assign(n.args,u.args)),a=e({...n,...u}),a},n);return a||(a=e(n)),s===a?a:T(s,()=>p(a))},e=>T(r(e)))}var A=r=>async(t,e)=>(t&&(r.originalStoryFn=()=>()=>p(t,e==null?void 0:e.props,e==null?void 0:e.slots)),await r.renderToCanvas(),r.canvas),C={renderer:"vue3"};export{z as applyDecorators,A as mount,C as parameters,j as render,N as renderToCanvas};
@@ -0,0 +1,16 @@
import{c as _,n as C,z as j,o as v,g as $,b as N,y as A}from"./index-8_2S3kac.js";import{w as E,i as O}from"./vue.esm-bundler-c7-UdoSZ.js";const{addons:T}=__STORYBOOK_MODULE_PREVIEW_API__;var V=["props","events","slots","exposed","expose"],D=e=>{if(!j(e))return null;let t="exposed"in e.__docgenInfo?"vue-component-meta":"vue-docgen-api",a={};return V.forEach(r=>{v(e,r).forEach(n=>{let l;if(t==="vue-docgen-api"){let u=n.docgenInfo;l=M(u,r,n)}else{let u=n.docgenInfo;l=q(u,r)}!l||a[l.name]||(["events","expose","exposed"].includes(r)&&(l.control={disable:!0}),a[l.name]=l)})}),a},M=(e,t,a)=>{var u,s,i;let r,n;if(t==="events"&&(r=(u=e.type)==null?void 0:u.names.join(),n={name:"other",value:r??"",required:!1}),t==="slots"){let o=(s=e.bindings)==null?void 0:s.filter(m=>!!m.name).map(m=>{var p;return`${m.name}: ${((p=m.type)==null?void 0:p.name)??"unknown"}`}).join("; ");r=o?`{ ${o} }`:void 0,n={name:"other",value:r??"",required:!1}}if(t==="props"){let o=e;if(r=(i=o.type)==null?void 0:i.name,n=a?N(a.docgenInfo):{name:"other",value:r},o.type&&"elements"in o.type&&Array.isArray(o.type.elements)&&o.type.elements.length>0){let m=o.type.elements.map(p=>p.name);r==="Array"&&(r=`${m.length===1?m[0]:`(${m.join(" | ")})`}[]`),r==="union"?r=m.join(" | "):r==="intersection"&&(r=m.join(" & "))}}let l="required"in e?e.required??!1:!1;return{name:e.name,description:e.description,type:n?{...n,required:l}:{name:"other",value:r??""},table:{type:r?{summary:r}:void 0,defaultValue:(a==null?void 0:a.propDef.defaultValue)??void 0,jsDocTags:a==null?void 0:a.propDef.jsDocTags,category:t}}},q=(e,t)=>{if("global"in e&&e.global)return;let a={summary:e.type.replace(" | undefined","")};if(t==="props"){let r=e,n=r.default?{summary:r.default}:void 0;return{name:r.name,description:w(r.description,r.tags),defaultValue:n,type:f(r),table:{type:a,defaultValue:n,category:t}}}else return{name:e.name,description:"description"in e?e.description:"",type:{name:"other",value:e.type},table:{type:a,category:t}}},f=e=>{var l,u;let t=e.schema,a=e.required,r={name:"other",value:e.type,required:a},n=["string","number","function","boolean","symbol"];if(typeof t=="string")return n.includes(t)?{name:t,required:a}:r;switch(t.kind){case"enum":{let s=((l=t.schema)==null?void 0:l.filter(i=>i!=="undefined"))??[];return W(s)?{name:"boolean",required:a}:F(s)||B(s)?{name:"enum",value:s.map(i=>i.replace(/"/g,"")),required:a}:s.length===1?f({schema:s[0],type:e.type,required:a}):(s.length>2&&s.includes("true")&&s.includes("false")&&(s=s.filter(i=>i!=="true"&&i!=="false"),s.push("boolean")),{name:"union",value:s.map(i=>f(typeof i=="object"?{schema:i,type:i.type,required:!1}:{schema:i,type:i,required:!1})),required:a})}case"array":{let s=((u=t.schema)==null?void 0:u.filter(i=>i!=="undefined"))??[];return s.length===0?r:s.length===1?{name:"array",value:f({schema:s[0],type:e.type,required:!1}),required:a}:{name:"union",value:s.map(i=>f(typeof i=="object"?{schema:i,type:i.type,required:!1}:{schema:i,type:i,required:!1})),required:a}}case"object":return{name:"object",value:{},required:a};default:return r}},w=(e,t)=>!(t!=null&&t.length)||!e?e??"":`${t.map(a=>`@${a.name}: ${a.text}`).join("<br>")}<br><br>${e}`,F=e=>e.every(t=>typeof t=="string"&&t.startsWith('"')&&t.endsWith('"')),B=e=>e.every(t=>typeof t=="string"&&t.includes(".")),W=e=>e.length===2&&e.includes("true")&&e.includes("false"),y=Symbol("DEEP_ACCESS_SYMBOL"),k=e=>!!(e&&typeof e=="object"&&y in e),R=(e,t)=>{let a=e();if(Y(t))return a;let r=T.getChannel();return E(()=>t.args,()=>{let n=I(t);r.emit(A,{id:t.id,args:t.args,source:n,format:"vue"})},{immediate:!0,deep:!0}),a},I=e=>{let t={imports:{},scriptVariables:{}},{displayName:a,slotNames:r,eventNames:n}=G(e.component),l=h(e.args,r,n,t),u=b(e.args,r,t),s=a||e.title.split("/").at(-1),i=u?`<${s} ${l}> ${u} </${s}>`:`<${s} ${l} />`,o=Object.entries(t.scriptVariables).map(([d,c])=>`const ${d} = ${c};`).join(`
`),m=Object.entries(t.imports).map(([d,c])=>`import { ${Array.from(c.values()).sort().join(", ")} } from "${d}";`).join(`
`),p=`<template>
${i}
</template>`;return!m&&!o?p:`<script lang="ts" setup>
${m?`${m}
${o}`:o}
<\/script>
${p}`},Y=e=>{var a;let t=(a=e==null?void 0:e.parameters.docs)==null?void 0:a.source;return(t==null?void 0:t.type)===$.DYNAMIC?!1:!(e!=null&&e.parameters.__isArgsStory)||(t==null?void 0:t.code)||(t==null?void 0:t.type)===$.CODE},G=e=>{if(!e||!("__docgenInfo"in e)||!e.__docgenInfo||typeof e.__docgenInfo!="object")return{displayName:e==null?void 0:e.__name,eventNames:[],slotNames:[]};let t=e.__docgenInfo,a="displayName"in t&&typeof t.displayName=="string"?t.displayName:void 0,r=n=>!(n in t)||!Array.isArray(t[n])?[]:t[n].map(l=>l&&typeof l=="object"&&"name"in l?l.name:void 0).filter(l=>typeof l=="string");return{displayName:a||e.__name,slotNames:r("slots").sort((n,l)=>n==="default"?-1:l==="default"?1:n.localeCompare(l)),eventNames:r("events")}},h=(e,t,a,r)=>{let n=[];Object.entries(e).forEach(([u,s])=>{if(!t.includes(u)&&s!=null)switch(k(s)&&(s=s.toString()),typeof s){case"string":if(s==="")return;n.push({name:u,value:s.includes('"')?`'${s}'`:`"${s}"`,templateFn:(i,o)=>`${i}=${o}`});break;case"number":n.push({name:u,value:s.toString(),templateFn:(i,o)=>`:${i}="${o}"`});break;case"bigint":n.push({name:u,value:`BigInt(${s.toString()})`,templateFn:(i,o)=>`:${i}="${o}"`});break;case"boolean":n.push({name:u,value:s?"true":"false",templateFn:(i,o)=>o==="true"?i:`:${i}="false"`});break;case"symbol":n.push({name:u,value:`Symbol(${s.description?`'${s.description}'`:""})`,templateFn:(i,o)=>`:${i}="${o}"`});break;case"object":{n.push({name:u,value:U(s??{}),templateFn:void 0});break}}}),n.sort((u,s)=>u.name.localeCompare(s.name));let l=[];return n.forEach(u=>{let s=a.includes(`update:${u.name}`);if(!s&&u.templateFn){l.push(u.templateFn(u.name,u.value));return}let i=u.name;if(i in r.scriptVariables){let o=1;do i=`${u.name}${o}`,o++;while(i in r.scriptVariables)}if(!s){r.scriptVariables[i]=u.value,l.push(`:${u.name}="${i}"`);return}r.scriptVariables[i]=`ref(${u.value})`,r.imports.vue||(r.imports.vue=new Set),r.imports.vue.add("ref"),u.name==="modelValue"?l.push(`v-model="${i}"`):l.push(`v-model:${u.name}="${i}"`)}),l.join(" ")},b=(e,t,a)=>{let r=[];return t.forEach(n=>{let l=e[n];if(!l)return;let u=g([l],a);if(!u)return;let s=typeof l=="function"?S(l):[];n==="default"&&!s.length?r.push(u):r.push(`<template ${J(n,s)}>${u}</template>`)}),r.join(`
`)},g=(e,t)=>{let a=[],r=n=>{if(O(n))return K(n,t);switch(typeof n){case"string":case"number":case"boolean":return n.toString();case"object":return n===null?"":Array.isArray(n)?n.map(r).filter(l=>l!=="").join(`
`):JSON.stringify(n);case"function":{let l=S(n).filter(i=>!["{","}"].includes(i)),u={};l.forEach(i=>{u[i]=new Proxy({[y]:!0},{get:(o,m)=>m===y?o[y]:[Symbol.toPrimitive,Symbol.toStringTag,"toString"].includes(m)?()=>`{{ ${i} }}`:m==="v-bind"?`${i}`:`{{ ${i}.${m.toString()} }}`,ownKeys:()=>["v-bind"],getOwnPropertyDescriptor:()=>({configurable:!0,enumerable:!0,value:i,writable:!0})})});let s=n(u);return g([s],t).replaceAll(/ (\S+)="{{ (\S+) }}"/g,' :$1="$2"')}case"bigint":return`{{ BigInt(${n.toString()}) }}`;default:return""}};return e.forEach(n=>{let l=r(n);l!==""&&a.push(l)}),a.join(`
`)},K=(e,t)=>{let a=L(e),r="";typeof e.children=="string"?r=e.children:Array.isArray(e.children)?r=g(e.children,t):e.children&&(r=b(e.children,Object.keys(e.children).filter(l=>l!=="$stable"),t));let n=e.props?h(e.props,[],[],t):"";return r?`<${a}${n?` ${n}`:""}>${r}</${a}>`:`<${a}${n?` ${n}`:""} />`},L=e=>{if(typeof e.type=="string")return e.type;if(typeof e.type=="object"){if("name"in e.type&&e.type.name)return e.type.name;if("__name"in e.type&&e.type.__name)return e.type.__name}return"component"},S=e=>{let t=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,a=/([^\s,]+)/g,r=e.toString().replace(t,""),n=r.slice(r.indexOf("(")+1,r.indexOf(")")).match(a);return n?n.flatMap(l=>{if(["{","}"].includes(l))return l;let u=l.split(":")[0].trim();return u.startsWith("{")?["{",u.substring(1)]:l.endsWith("}")&&!u.endsWith("}")?[u,"}"]:u}):[]},J=(e,t)=>t.length?t.length===1?`#${e}="${t[0]}"`:`#${e}="{ ${t.filter(a=>!["{","}"].includes(a)).join(", ")} }"`:`#${e}`,U=e=>Object.values(e).every(t=>t==null||typeof t!="object")?JSON.stringify(e):JSON.stringify(e,null,2),Q={docs:{story:{inline:!0},extractArgTypes:D,extractComponentDescription:C}},X=[R],Z=[_];export{Z as argTypesEnhancers,X as decorators,Q as parameters};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
function l(i){for(var f=[],c=1;c<arguments.length;c++)f[c-1]=arguments[c];var n=Array.from(typeof i=="string"?[i]:i);n[n.length-1]=n[n.length-1].replace(/\r?\n([\t ]*)$/,"");var s=n.reduce(function(t,g){var a=g.match(/\n([\t ]+|(?!\s).)/g);return a?t.concat(a.map(function(u){var r,e;return(e=(r=u.match(/[\t ]/g))===null||r===void 0?void 0:r.length)!==null&&e!==void 0?e:0})):t},[]);if(s.length){var d=new RegExp(`
[ ]{`.concat(Math.min.apply(Math,s),"}"),"g");n=n.map(function(t){return t.replace(d,`
`)})}n[0]=n[0].replace(/^\r?\n/,"");var o=n[0];return f.forEach(function(t,g){var a=o.match(/(?:^|\n)( *)$/),u=a?a[1]:"",r=t;typeof t=="string"&&t.includes(`
`)&&(r=String(t).split(`
`).map(function(e,h){return h===0?e:"".concat(u).concat(e)}).join(`
`)),o+=r+n[g+1]}),o}export{l as d};
@@ -0,0 +1 @@
import{R as o}from"./DocsRenderer-CFRXHY34-BZ6DD22w.js";import"./iframe-BYP-OqC3.js";import"./_commonjsHelpers-CqkleIqs.js";import"./index-8_2S3kac.js";import"./index-Bhqu_tAV.js";const e={},c=o.createContext(e);function m(t){const n=o.useContext(c);return o.useMemo(function(){return typeof t=="function"?t(n):{...n,...t}},[n,t])}function a(t){let n;return t.disableParentContext?n=typeof t.components=="function"?t.components(e):t.components||e:n=m(t.components),o.createElement(c.Provider,{value:n},t.children)}export{a as MDXProvider,m as useMDXComponents};
File diff suppressed because one or more lines are too long
@@ -0,0 +1,34 @@
import{d as P}from"./index-Bhqu_tAV.js";const{useEffect:_,useMemo:h}=__STORYBOOK_MODULE_PREVIEW_API__,{global:j}=__STORYBOOK_MODULE_GLOBAL__,{logger:X}=__STORYBOOK_MODULE_CLIENT_LOGGER__;var p="backgrounds",U={light:{name:"light",value:"#F8F8F8"},dark:{name:"dark",value:"#333"}},{document:b,window:O}=j,D=()=>{var r;return!!((r=O==null?void 0:O.matchMedia("(prefers-reduced-motion: reduce)"))!=null&&r.matches)},A=r=>{(Array.isArray(r)?r:[r]).forEach(N)},N=r=>{var t;let e=b.getElementById(r);e&&((t=e.parentElement)==null||t.removeChild(e))},F=(r,e)=>{let t=b.getElementById(r);if(t)t.innerHTML!==e&&(t.innerHTML=e);else{let o=b.createElement("style");o.setAttribute("id",r),o.innerHTML=e,b.head.appendChild(o)}},Y=(r,e,t)=>{var a;let o=b.getElementById(r);if(o)o.innerHTML!==e&&(o.innerHTML=e);else{let d=b.createElement("style");d.setAttribute("id",r),d.innerHTML=e;let i=`addon-backgrounds-grid${t?`-docs-${t}`:""}`,n=b.getElementById(i);n?(a=n.parentElement)==null||a.insertBefore(d,n):b.head.appendChild(d)}},W={cellSize:100,cellAmount:10,opacity:.8},w="addon-backgrounds",R="addon-backgrounds-grid",q=D()?"":"transition: background-color 0.3s;",J=(r,e)=>{let{globals:t,parameters:o,viewMode:a,id:d}=e,{options:i=U,disable:n,grid:s=W}=o[p]||{},c=t[p]||{},u=c.value,l=u?i[u]:void 0,$=(l==null?void 0:l.value)||"transparent",f=c.grid||!1,y=!!l&&!n,m=a==="docs"?`#anchor--${d} .docs-story`:".sb-show-main",E=a==="docs"?`#anchor--${d} .docs-story`:".sb-show-main",H=o.layout===void 0||o.layout==="padded",L=a==="docs"?20:H?16:0,{cellAmount:k,cellSize:g,opacity:x,offsetX:v=L,offsetY:S=L}=s,B=a==="docs"?`${w}-docs-${d}`:`${w}-color`,G=a==="docs"?d:null;_(()=>{let M=`
${m} {
background: ${$} !important;
${q}
}`;if(!y){A(B);return}Y(B,M,G)},[m,B,G,y,$]);let T=a==="docs"?`${R}-docs-${d}`:`${R}`;return _(()=>{if(!f){A(T);return}let M=[`${g*k}px ${g*k}px`,`${g*k}px ${g*k}px`,`${g}px ${g}px`,`${g}px ${g}px`].join(", "),K=`
${E} {
background-size: ${M} !important;
background-position: ${v}px ${S}px, ${v}px ${S}px, ${v}px ${S}px, ${v}px ${S}px !important;
background-blend-mode: difference !important;
background-image: linear-gradient(rgba(130, 130, 130, ${x}) 1px, transparent 1px),
linear-gradient(90deg, rgba(130, 130, 130, ${x}) 1px, transparent 1px),
linear-gradient(rgba(130, 130, 130, ${x/2}) 1px, transparent 1px),
linear-gradient(90deg, rgba(130, 130, 130, ${x/2}) 1px, transparent 1px) !important;
}
`;F(T,K)},[k,g,E,T,f,v,S,x]),r()},Q=(r,e=[],t)=>{if(r==="transparent")return"transparent";if(e.find(a=>a.value===r)||r)return r;let o=e.find(a=>a.name===t);if(o)return o.value;if(t){let a=e.map(d=>d.name).join(", ");X.warn(P`
Backgrounds Addon: could not find the default color "${t}".
These are the available colors for your story based on your configuration:
${a}.
`)}return"transparent"},Z=(r,e)=>{var u;let{globals:t,parameters:o}=e,a=(u=t[p])==null?void 0:u.value,d=o[p],i=h(()=>d.disable?"transparent":Q(a,d.values,d.default),[d,a]),n=h(()=>i&&i!=="transparent",[i]),s=e.viewMode==="docs"?`#anchor--${e.id} .docs-story`:".sb-show-main",c=h(()=>`
${s} {
background: ${i} !important;
${D()?"":"transition: background-color 0.3s;"}
}
`,[i,s]);return _(()=>{let l=e.viewMode==="docs"?`addon-backgrounds-docs-${e.id}`:"addon-backgrounds-color";if(!n){A(l);return}Y(l,c,e.viewMode==="docs"?e.id:null)},[n,c,e]),r()},V=(r,e)=>{var y;let{globals:t,parameters:o}=e,a=o[p].grid,d=((y=t[p])==null?void 0:y.grid)===!0&&a.disable!==!0,{cellAmount:i,cellSize:n,opacity:s}=a,c=e.viewMode==="docs",u=o.layout===void 0||o.layout==="padded"?16:0,l=a.offsetX??(c?20:u),$=a.offsetY??(c?20:u),f=h(()=>{let m=e.viewMode==="docs"?`#anchor--${e.id} .docs-story`:".sb-show-main",E=[`${n*i}px ${n*i}px`,`${n*i}px ${n*i}px`,`${n}px ${n}px`,`${n}px ${n}px`].join(", ");return`
${m} {
background-size: ${E} !important;
background-position: ${l}px ${$}px, ${l}px ${$}px, ${l}px ${$}px, ${l}px ${$}px !important;
background-blend-mode: difference !important;
background-image: linear-gradient(rgba(130, 130, 130, ${s}) 1px, transparent 1px),
linear-gradient(90deg, rgba(130, 130, 130, ${s}) 1px, transparent 1px),
linear-gradient(rgba(130, 130, 130, ${s/2}) 1px, transparent 1px),
linear-gradient(90deg, rgba(130, 130, 130, ${s/2}) 1px, transparent 1px) !important;
}
`},[n]);return _(()=>{let m=e.viewMode==="docs"?`addon-backgrounds-grid-docs-${e.id}`:"addon-backgrounds-grid";if(!d){A(m);return}F(m,f)},[d,f,e]),r()},C,ae=(C=globalThis.FEATURES)!=null&&C.backgroundsStoryGlobals?[J]:[V,Z],I,oe={[p]:{grid:{cellSize:20,opacity:.5,cellAmount:5},disable:!1,...!((I=globalThis.FEATURES)!=null&&I.backgroundsStoryGlobals)&&{values:Object.values(U)}}},ee={[p]:{value:void 0,grid:!1}},z,de=(z=globalThis.FEATURES)!=null&&z.backgroundsStoryGlobals?ee:{[p]:null};export{ae as decorators,de as initialGlobals,oe as parameters};
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./DocsRenderer-CFRXHY34-BZ6DD22w.js","./iframe-BYP-OqC3.js","./_commonjsHelpers-CqkleIqs.js","./index-8_2S3kac.js","./index-Bhqu_tAV.js"])))=>i.map(i=>d[i]);
import{_ as a}from"./iframe-BYP-OqC3.js";var i=Object.defineProperty,s=(e,r)=>{for(var t in r)i(e,t,{get:r[t],enumerable:!0})},_={};s(_,{parameters:()=>d});var p=Object.entries(globalThis.TAGS_OPTIONS??{}).reduce((e,r)=>{let[t,o]=r;return o.excludeFromDocsStories&&(e[t]=!0),e},{}),d={docs:{renderer:async()=>{let{DocsRenderer:e}=await a(()=>import("./DocsRenderer-CFRXHY34-BZ6DD22w.js").then(r=>r.D),__vite__mapDeps([0,1,2,3,4]),import.meta.url);return new e},stories:{filter:e=>{var r;return(e.tags||[]).filter(t=>p[t]).length===0&&!((r=e.parameters.docs)!=null&&r.disable)}}}};export{d as parameters};
@@ -0,0 +1,396 @@
import{d as $}from"./index-Bhqu_tAV.js";const{useMemo:x,useEffect:f}=__STORYBOOK_MODULE_PREVIEW_API__,{global:p}=__STORYBOOK_MODULE_GLOBAL__;var m="outline",u=i=>{(Array.isArray(i)?i:[i]).forEach(r)},r=i=>{let t=typeof i=="string"?i:i.join(""),o=p.document.getElementById(t);o&&o.parentElement&&o.parentElement.removeChild(o)},b=(i,t)=>{let o=p.document.getElementById(i);if(o)o.innerHTML!==t&&(o.innerHTML=t);else{let n=p.document.createElement("style");n.setAttribute("id",i),n.innerHTML=t,p.document.head.appendChild(n)}};function s(i){return $`
${i} body {
outline: 1px solid #2980b9 !important;
}
${i} article {
outline: 1px solid #3498db !important;
}
${i} nav {
outline: 1px solid #0088c3 !important;
}
${i} aside {
outline: 1px solid #33a0ce !important;
}
${i} section {
outline: 1px solid #66b8da !important;
}
${i} header {
outline: 1px solid #99cfe7 !important;
}
${i} footer {
outline: 1px solid #cce7f3 !important;
}
${i} h1 {
outline: 1px solid #162544 !important;
}
${i} h2 {
outline: 1px solid #314e6e !important;
}
${i} h3 {
outline: 1px solid #3e5e85 !important;
}
${i} h4 {
outline: 1px solid #449baf !important;
}
${i} h5 {
outline: 1px solid #c7d1cb !important;
}
${i} h6 {
outline: 1px solid #4371d0 !important;
}
${i} main {
outline: 1px solid #2f4f90 !important;
}
${i} address {
outline: 1px solid #1a2c51 !important;
}
${i} div {
outline: 1px solid #036cdb !important;
}
${i} p {
outline: 1px solid #ac050b !important;
}
${i} hr {
outline: 1px solid #ff063f !important;
}
${i} pre {
outline: 1px solid #850440 !important;
}
${i} blockquote {
outline: 1px solid #f1b8e7 !important;
}
${i} ol {
outline: 1px solid #ff050c !important;
}
${i} ul {
outline: 1px solid #d90416 !important;
}
${i} li {
outline: 1px solid #d90416 !important;
}
${i} dl {
outline: 1px solid #fd3427 !important;
}
${i} dt {
outline: 1px solid #ff0043 !important;
}
${i} dd {
outline: 1px solid #e80174 !important;
}
${i} figure {
outline: 1px solid #ff00bb !important;
}
${i} figcaption {
outline: 1px solid #bf0032 !important;
}
${i} table {
outline: 1px solid #00cc99 !important;
}
${i} caption {
outline: 1px solid #37ffc4 !important;
}
${i} thead {
outline: 1px solid #98daca !important;
}
${i} tbody {
outline: 1px solid #64a7a0 !important;
}
${i} tfoot {
outline: 1px solid #22746b !important;
}
${i} tr {
outline: 1px solid #86c0b2 !important;
}
${i} th {
outline: 1px solid #a1e7d6 !important;
}
${i} td {
outline: 1px solid #3f5a54 !important;
}
${i} col {
outline: 1px solid #6c9a8f !important;
}
${i} colgroup {
outline: 1px solid #6c9a9d !important;
}
${i} button {
outline: 1px solid #da8301 !important;
}
${i} datalist {
outline: 1px solid #c06000 !important;
}
${i} fieldset {
outline: 1px solid #d95100 !important;
}
${i} form {
outline: 1px solid #d23600 !important;
}
${i} input {
outline: 1px solid #fca600 !important;
}
${i} keygen {
outline: 1px solid #b31e00 !important;
}
${i} label {
outline: 1px solid #ee8900 !important;
}
${i} legend {
outline: 1px solid #de6d00 !important;
}
${i} meter {
outline: 1px solid #e8630c !important;
}
${i} optgroup {
outline: 1px solid #b33600 !important;
}
${i} option {
outline: 1px solid #ff8a00 !important;
}
${i} output {
outline: 1px solid #ff9619 !important;
}
${i} progress {
outline: 1px solid #e57c00 !important;
}
${i} select {
outline: 1px solid #e26e0f !important;
}
${i} textarea {
outline: 1px solid #cc5400 !important;
}
${i} details {
outline: 1px solid #33848f !important;
}
${i} summary {
outline: 1px solid #60a1a6 !important;
}
${i} command {
outline: 1px solid #438da1 !important;
}
${i} menu {
outline: 1px solid #449da6 !important;
}
${i} del {
outline: 1px solid #bf0000 !important;
}
${i} ins {
outline: 1px solid #400000 !important;
}
${i} img {
outline: 1px solid #22746b !important;
}
${i} iframe {
outline: 1px solid #64a7a0 !important;
}
${i} embed {
outline: 1px solid #98daca !important;
}
${i} object {
outline: 1px solid #00cc99 !important;
}
${i} param {
outline: 1px solid #37ffc4 !important;
}
${i} video {
outline: 1px solid #6ee866 !important;
}
${i} audio {
outline: 1px solid #027353 !important;
}
${i} source {
outline: 1px solid #012426 !important;
}
${i} canvas {
outline: 1px solid #a2f570 !important;
}
${i} track {
outline: 1px solid #59a600 !important;
}
${i} map {
outline: 1px solid #7be500 !important;
}
${i} area {
outline: 1px solid #305900 !important;
}
${i} a {
outline: 1px solid #ff62ab !important;
}
${i} em {
outline: 1px solid #800b41 !important;
}
${i} strong {
outline: 1px solid #ff1583 !important;
}
${i} i {
outline: 1px solid #803156 !important;
}
${i} b {
outline: 1px solid #cc1169 !important;
}
${i} u {
outline: 1px solid #ff0430 !important;
}
${i} s {
outline: 1px solid #f805e3 !important;
}
${i} small {
outline: 1px solid #d107b2 !important;
}
${i} abbr {
outline: 1px solid #4a0263 !important;
}
${i} q {
outline: 1px solid #240018 !important;
}
${i} cite {
outline: 1px solid #64003c !important;
}
${i} dfn {
outline: 1px solid #b4005a !important;
}
${i} sub {
outline: 1px solid #dba0c8 !important;
}
${i} sup {
outline: 1px solid #cc0256 !important;
}
${i} time {
outline: 1px solid #d6606d !important;
}
${i} code {
outline: 1px solid #e04251 !important;
}
${i} kbd {
outline: 1px solid #5e001f !important;
}
${i} samp {
outline: 1px solid #9c0033 !important;
}
${i} var {
outline: 1px solid #d90047 !important;
}
${i} mark {
outline: 1px solid #ff0053 !important;
}
${i} bdi {
outline: 1px solid #bf3668 !important;
}
${i} bdo {
outline: 1px solid #6f1400 !important;
}
${i} ruby {
outline: 1px solid #ff7b93 !important;
}
${i} rt {
outline: 1px solid #ff2f54 !important;
}
${i} rp {
outline: 1px solid #803e49 !important;
}
${i} span {
outline: 1px solid #cc2643 !important;
}
${i} br {
outline: 1px solid #db687d !important;
}
${i} wbr {
outline: 1px solid #db175b !important;
}`}var e=(i,t)=>{let{globals:o}=t,n=[!0,"true"].includes(o[m]),d=t.viewMode==="docs",l=x(()=>s(d?'[data-story-block="true"]':".sb-show-main"),[t]);return f(()=>{let a=d?`addon-outline-docs-${t.id}`:"addon-outline";return n?b(a,l):u(a),()=>{u(a)}},[n,l,t]),i()},h=[e],g={[m]:!1};export{h as decorators,g as initialGlobals};
@@ -0,0 +1 @@
const o={theme:{description:"Global color theme",defaultValue:"light",toolbar:{icon:"paintbrush",items:["light","dark"],dynamicTitle:!0}}},l=[(e,t)=>(document.documentElement.dataset.theme=t.globals.theme,e())],a={controls:{expanded:!0},a11y:{test:"todo"},layout:"fullscreen"};export{l as decorators,o as globalTypes,a as parameters};
@@ -0,0 +1 @@
var o="viewport",a={[o]:{value:void 0,isRotated:!1}},t={viewport:"reset",viewportRotated:!1},e,l=(e=globalThis.FEATURES)!=null&&e.viewportStoryGlobals?a:t;export{l as initialGlobals};
@@ -0,0 +1 @@
let p;const S=new Uint8Array(16);function A(){if(!p&&(p=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!p))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return p(S)}const o=[];for(let e=0;e<256;++e)o.push((e+256).toString(16).slice(1));function D(e,t=0){return o[e[t+0]]+o[e[t+1]]+o[e[t+2]]+o[e[t+3]]+"-"+o[e[t+4]]+o[e[t+5]]+"-"+o[e[t+6]]+o[e[t+7]]+"-"+o[e[t+8]]+o[e[t+9]]+"-"+o[e[t+10]]+o[e[t+11]]+o[e[t+12]]+o[e[t+13]]+o[e[t+14]]+o[e[t+15]]}const I=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),h={randomUUID:I};function f(e,t,r){if(h.randomUUID&&!e)return h.randomUUID();e=e||{};const n=e.random||(e.rng||A)();return n[6]=n[6]&15|64,n[8]=n[8]&63|128,D(n)}const{addons:v}=__STORYBOOK_MODULE_PREVIEW_API__,{ImplicitActionsDuringRendering:U}=__STORYBOOK_MODULE_CORE_EVENTS_PREVIEW_ERRORS__,{global:d}=__STORYBOOK_MODULE_GLOBAL__;var w="storybook/actions",j=`${w}/action-event`,V={depth:10,clearOnStoryChange:!0,limit:50},E=(e,t)=>{let r=Object.getPrototypeOf(e);return!r||t(r)?r:E(r,t)},C=e=>!!(typeof e=="object"&&e&&E(e,t=>/^Synthetic(?:Base)?Event$/.test(t.constructor.name))&&typeof e.persist=="function"),K=e=>{if(C(e)){let t=Object.create(e.constructor.prototype,Object.getOwnPropertyDescriptors(e));t.persist();let r=Object.getOwnPropertyDescriptor(t,"view"),n=r==null?void 0:r.value;return typeof n=="object"&&(n==null?void 0:n.constructor.name)==="Window"&&Object.defineProperty(t,"view",{...r,value:Object.create(n.constructor.prototype)}),t}return e},L=()=>typeof crypto=="object"&&typeof crypto.getRandomValues=="function"?f():Date.now().toString(36)+Math.random().toString(36).substring(2);function _(e,t={}){let r={...V,...t},n=function(...s){var g,O;if(t.implicit){let y=(g="__STORYBOOK_PREVIEW__"in d?d.__STORYBOOK_PREVIEW__:void 0)==null?void 0:g.storyRenders.find(l=>l.phase==="playing"||l.phase==="rendering");if(y){let l=!((O=globalThis==null?void 0:globalThis.FEATURES)!=null&&O.disallowImplicitActionsInRenderV8),R=new U({phase:y.phase,name:e,deprecated:l});if(l)console.warn(R);else throw R}}let i=v.getChannel(),c=L(),a=5,u=s.map(K),b=s.length>1?u:u[0],x={id:c,count:0,data:{name:e,args:b},options:{...r,maxDepth:a+(r.depth||3),allowFunction:r.allowFunction||!1}};i.emit(j,x)};return n.isAction=!0,n.implicit=t.implicit,n}var T=(e,t)=>typeof t[e]>"u"&&!(e in t),B=e=>{let{initialArgs:t,argTypes:r,id:n,parameters:{actions:s}}=e;if(!s||s.disable||!s.argTypesRegex||!r)return{};let i=new RegExp(s.argTypesRegex);return Object.entries(r).filter(([c])=>!!i.test(c)).reduce((c,[a,u])=>(T(a,t)&&(c[a]=_(a,{implicit:!0,id:n})),c),{})},M=e=>{let{initialArgs:t,argTypes:r,parameters:{actions:n}}=e;return n!=null&&n.disable||!r?{}:Object.entries(r).filter(([s,i])=>!!i.action).reduce((s,[i,c])=>(T(i,t)&&(s[i]=_(typeof c.action=="string"?c.action:i)),s),{})},Y=[M,B],m=!1,P=e=>{let{parameters:{actions:t}}=e;if(!(t!=null&&t.disable)&&!m&&"__STORYBOOK_TEST_ON_MOCK_CALL__"in d&&typeof d.__STORYBOOK_TEST_ON_MOCK_CALL__=="function"){let r=d.__STORYBOOK_TEST_ON_MOCK_CALL__;r((n,s)=>{let i=n.getMockName();i!=="spy"&&(!/^next\/.*::/.test(i)||["next/router::useRouter()","next/navigation::useRouter()","next/navigation::redirect","next/cache::","next/headers::cookies().set","next/headers::cookies().delete","next/headers::headers().set","next/headers::headers().delete"].some(c=>i.startsWith(c)))&&_(i)(s)}),m=!0}},N=[P];export{Y as argsEnhancers,N as loaders};
@@ -0,0 +1,7 @@
const{STORY_CHANGED:r}=__STORYBOOK_MODULE_CORE_EVENTS__,{addons:s}=__STORYBOOK_MODULE_PREVIEW_API__,{global:O}=__STORYBOOK_MODULE_GLOBAL__;var d="storybook/highlight",i="storybookHighlight",g=`${d}/add`,E=`${d}/reset`,{document:l}=O,H=(e="#FF4785",t="dashed")=>`
outline: 2px ${t} ${e};
outline-offset: 2px;
box-shadow: 0 0 0 6px rgba(255,255,255,0.6);
`,h=s.getChannel(),T=e=>{let t=i;n();let o=Array.from(new Set(e.elements)),_=l.createElement("style");_.setAttribute("id",t),_.innerHTML=o.map(a=>`${a}{
${H(e.color,e.style)}
}`).join(" "),l.head.appendChild(_)},n=()=>{var o;let e=i,t=l.getElementById(e);t&&((o=t.parentNode)==null||o.removeChild(t))};h.on(r,n);h.on(E,n);h.on(g,T);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svgjs="http://svgjs.com/svgjs" xmlns:xlink="http://www.w3.org/1999/xlink" width="164" height="164" version="1.1"><svg xmlns="http://www.w3.org/2000/svg" width="164" height="164" fill="none" viewBox="0 0 164 164"><path fill="#FF4785" d="M22.467 147.762 17.5 15.402a8.062 8.062 0 0 1 7.553-8.35L137.637.016a8.061 8.061 0 0 1 8.565 8.047v144.23a8.063 8.063 0 0 1-8.424 8.054l-107.615-4.833a8.062 8.062 0 0 1-7.695-7.752Z"/><path fill="#fff" fill-rule="evenodd" d="m128.785.57-15.495.968-.755 18.172a1.203 1.203 0 0 0 1.928 1.008l7.06-5.354 5.962 4.697a1.202 1.202 0 0 0 1.946-.987L128.785.569Zm-12.059 60.856c-2.836 2.203-23.965 3.707-23.965.57.447-11.969-4.912-12.494-7.889-12.494-2.828 0-7.59.855-7.59 7.267 0 6.534 6.96 10.223 15.13 14.553 11.607 6.15 25.654 13.594 25.654 32.326 0 17.953-14.588 27.871-33.194 27.871-19.201 0-35.981-7.769-34.086-34.702.744-3.163 25.156-2.411 25.156 0-.298 11.114 2.232 14.383 8.633 14.383 4.912 0 7.144-2.708 7.144-7.267 0-6.9-7.252-10.973-15.595-15.657C64.827 81.933 51.53 74.468 51.53 57.34c0-17.098 11.76-28.497 32.747-28.497 20.988 0 32.449 11.224 32.449 32.584Z" clip-rule="evenodd"/></svg><style>@media (prefers-color-scheme:light){:root{filter:none}}</style></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+666
View File
@@ -0,0 +1,666 @@
<!doctype html>
<!--suppress HtmlUnknownTarget -->
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Storybook</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('./sb-common-assets/nunito-sans-regular.woff2') format('woff2');
}
@font-face {
font-family: 'Nunito Sans';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('./sb-common-assets/nunito-sans-italic.woff2') format('woff2');
}
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('./sb-common-assets/nunito-sans-bold.woff2') format('woff2');
}
@font-face {
font-family: 'Nunito Sans';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url('./sb-common-assets/nunito-sans-bold-italic.woff2') format('woff2');
}
</style>
<script>
window.CONFIG_TYPE = 'PRODUCTION';
window.LOGLEVEL = 'info';
window.FRAMEWORK_OPTIONS = {};
window.CHANNEL_OPTIONS = {};
window.FEATURES = {"argTypeTargetsV7":true,"legacyDecoratorFileOrder":false,"disallowImplicitActionsInRenderV8":true};
window.STORIES = [{"titlePrefix":"","directory":"./src","files":"**/*.stories.js","importPathMatcher":"^\\.[\\\\/](?:src(?:\\/(?!\\.)(?:(?:(?!(?:^|\\/)\\.).)*?)\\/|\\/|$)(?!\\.)(?=.)[^/]*?\\.stories\\.js)$"}];
window.DOCS_OPTIONS = {"defaultName":"Docs","autodocs":"tag"};
window.TAGS_OPTIONS = {"dev-only":{"excludeFromDocsStories":true},"docs-only":{"excludeFromSidebar":true},"test-only":{"excludeFromSidebar":true,"excludeFromDocsStories":true}};
// We do this so that "module && module.hot" etc. in Storybook source code
// doesn't fail (it will simply be disabled)
window.module = undefined;
window.global = window;
</script>
<base target="_parent" />
<style>
/* While we aren't showing the main block yet, but still preparing, we want everything the user
has rendered, which may or may not be in #storybook-root, to be display none */
.sb-show-preparing-story:not(.sb-show-main) > :not(.sb-preparing-story) {
display: none;
}
.sb-show-preparing-docs:not(.sb-show-main) > :not(.sb-preparing-docs) {
display: none;
}
/* Hide our own blocks when we aren't supposed to be showing them */
:not(.sb-show-preparing-story) > .sb-preparing-story,
:not(.sb-show-preparing-docs) > .sb-preparing-docs,
:not(.sb-show-nopreview) > .sb-nopreview,
:not(.sb-show-errordisplay) > .sb-errordisplay {
display: none;
}
.sb-show-main.sb-main-centered {
margin: 0;
display: flex;
align-items: center;
min-height: 100vh;
}
.sb-show-main.sb-main-centered #storybook-root {
box-sizing: border-box;
margin: auto;
padding: 1rem;
max-height: 100%;
/* Hack for centering correctly in IE11 */
}
/* Vertical centering fix for IE11 */
@media screen and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.sb-show-main.sb-main-centered:after {
content: '';
min-height: inherit;
font-size: 0;
}
}
.sb-show-main.sb-main-fullscreen {
margin: 0;
padding: 0;
display: block;
}
.sb-show-main.sb-main-padded {
margin: 0;
padding: 1rem;
display: block;
box-sizing: border-box;
}
.sb-wrapper {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
box-sizing: border-box;
padding: 40px;
font-family:
'Nunito Sans',
-apple-system,
'.SFNSText-Regular',
'San Francisco',
BlinkMacSystemFont,
'Segoe UI',
'Helvetica Neue',
Helvetica,
Arial,
sans-serif;
-webkit-font-smoothing: antialiased;
overflow: auto;
}
@media (max-width: 700px) {
.sb-wrapper {
padding: 20px;
}
}
@media (max-width: 500px) {
.sb-wrapper {
padding: 10px;
}
}
.sb-heading {
font-size: 14px;
font-weight: 600;
letter-spacing: 0.2px;
margin: 10px 0;
padding-right: 25px;
}
.sb-nopreview {
display: flex;
align-content: center;
justify-content: center;
box-sizing: border-box;
}
.sb-nopreview_main {
margin: auto;
padding: 30px;
border-radius: 10px;
background: rgba(0, 0, 0, 0.03);
}
.sb-nopreview_heading {
text-align: center;
}
.sb-errordisplay {
background: #f6f9fc;
color: black;
z-index: 999999;
width: 100vw;
min-height: 100vh;
box-sizing: border-box;
& ol {
padding-left: 18px;
margin: 0;
}
& h1 {
font-family: Nunito Sans;
font-size: 22px;
font-weight: 400;
line-height: 30px;
font-weight: normal;
margin: 0;
&::before {
content: '';
display: inline-block;
width: 12px;
height: 12px;
background: #ff4400;
border-radius: 50%;
margin-right: 8px;
}
}
& p,
& ol {
font-family: Nunito Sans;
font-size: 14px;
font-weight: 400;
line-height: 19px;
margin: 0;
}
& li + li {
margin: 0;
padding: 0;
padding-top: 12px;
}
& a {
color: currentColor;
}
}
.sb-errordisplay_main {
margin: auto;
padding: 24px;
display: flex;
box-sizing: border-box;
flex-direction: column;
min-height: 100%;
width: 100%;
border-radius: 6px;
background: white;
border: 1px solid #ff0000;
box-shadow: 0 0 64px rgba(0, 0, 0, 0.1);
gap: 24px;
}
.sb-errordisplay_code {
padding: 10px;
flex: 1;
background: #242424;
color: #c6c6c6;
box-sizing: border-box;
font-size: 14px;
font-weight: 400;
line-height: 19px;
border-radius: 4px;
font-family: 'Operator Mono', 'Fira Code Retina', 'Fira Code', 'FiraCode-Retina', 'Andale Mono',
'Lucida Console', Consolas, Monaco, monospace;
margin: 0;
overflow: auto;
}
.sb-errordisplay pre {
white-space: pre-wrap;
white-space: revert;
}
@-webkit-keyframes sb-rotate360 {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes sb-rotate360 {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@-webkit-keyframes sb-glow {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
@keyframes sb-glow {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
/* We display the preparing loaders *over* the rendering story */
.sb-preparing-story,
.sb-preparing-docs {
background-color: white;
/* Maximum possible z-index. It would be better to use stacking contexts to ensure it's always
on top, but this isn't possible as it would require making CSS changes that could affect user code */
z-index: 2147483647;
}
.sb-loader {
-webkit-animation: sb-rotate360 0.7s linear infinite;
animation: sb-rotate360 0.7s linear infinite;
border-color: rgba(97, 97, 97, 0.29);
border-radius: 50%;
border-style: solid;
border-top-color: #646464;
border-width: 2px;
display: inline-block;
height: 32px;
left: 50%;
margin-left: -16px;
margin-top: -16px;
mix-blend-mode: difference;
overflow: hidden;
position: absolute;
top: 50%;
transition: all 200ms ease-out;
vertical-align: top;
width: 32px;
z-index: 4;
}
.sb-previewBlock {
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 4px;
box-shadow: rgba(0, 0, 0, 0.1) 0 1px 3px 0;
margin: 25px auto 40px;
max-width: 600px;
}
.sb-previewBlock_header {
align-items: center;
box-shadow: rgba(0, 0, 0, 0.1) 0 -1px 0 0 inset;
display: flex;
gap: 14px;
height: 40px;
padding: 0 12px;
}
.sb-previewBlock_icon {
-webkit-animation: sb-glow 1.5s ease-in-out infinite;
animation: sb-glow 1.5s ease-in-out infinite;
background: #e6e6e6;
height: 14px;
width: 14px;
}
.sb-previewBlock_icon:last-child {
margin-left: auto;
}
.sb-previewBlock_body {
-webkit-animation: sb-glow 1.5s ease-in-out infinite;
animation: sb-glow 1.5s ease-in-out infinite;
height: 182px;
position: relative;
}
.sb-argstableBlock {
border-collapse: collapse;
border-spacing: 0;
font-size: 13px;
line-height: 20px;
margin: 25px auto 40px;
max-width: 600px;
text-align: left;
width: 100%;
}
.sb-argstableBlock th:first-of-type,
.sb-argstableBlock td:first-of-type {
padding-left: 20px;
}
.sb-argstableBlock th:nth-of-type(2),
.sb-argstableBlock td:nth-of-type(2) {
width: 35%;
}
.sb-argstableBlock th:nth-of-type(3),
.sb-argstableBlock td:nth-of-type(3) {
width: 15%;
}
.sb-argstableBlock th:last-of-type,
.sb-argstableBlock td:last-of-type {
width: 25%;
padding-right: 20px;
}
.sb-argstableBlock th span,
.sb-argstableBlock td span {
-webkit-animation: sb-glow 1.5s ease-in-out infinite;
animation: sb-glow 1.5s ease-in-out infinite;
background-color: rgba(0, 0, 0, 0.1);
border-radius: 0;
box-shadow: none;
color: transparent;
}
.sb-argstableBlock th {
padding: 10px 15px;
}
.sb-argstableBlock-body {
border-radius: 4px;
box-shadow:
rgba(0, 0, 0, 0.1) 0 1px 3px 1px,
rgba(0, 0, 0, 0.065) 0 0 0 1px;
}
.sb-argstableBlock-body tr {
background: transparent;
overflow: hidden;
}
.sb-argstableBlock-body tr:not(:first-child) {
border-top: 1px solid #e6e6e6;
}
.sb-argstableBlock-body tr:first-child td:first-child {
border-top-left-radius: 4px;
}
.sb-argstableBlock-body tr:first-child td:last-child {
border-top-right-radius: 4px;
}
.sb-argstableBlock-body tr:last-child td:first-child {
border-bottom-left-radius: 4px;
}
.sb-argstableBlock-body tr:last-child td:last-child {
border-bottom-right-radius: 4px;
}
.sb-argstableBlock-body td {
background: #fff;
padding-bottom: 10px;
padding-top: 10px;
vertical-align: top;
}
.sb-argstableBlock-body td:not(:first-of-type) {
padding-left: 15px;
padding-right: 15px;
}
.sb-argstableBlock-body button {
-webkit-animation: sb-glow 1.5s ease-in-out infinite;
animation: sb-glow 1.5s ease-in-out infinite;
background-color: rgba(0, 0, 0, 0.1);
border: 0;
border-radius: 0;
box-shadow: none;
color: transparent;
display: inline;
font-size: 12px;
line-height: 1;
padding: 10px 16px;
}
.sb-argstableBlock-summary {
margin-top: 4px;
}
.sb-argstableBlock-code {
margin-right: 4px;
margin-bottom: 4px;
padding: 2px 5px;
}
</style>
<script>
/* globals window */
/* eslint-disable no-underscore-dangle */
try {
if (window.top !== window) {
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.top.__REACT_DEVTOOLS_GLOBAL_HOOK__;
window.__VUE_DEVTOOLS_GLOBAL_HOOK__ = window.top.__VUE_DEVTOOLS_GLOBAL_HOOK__;
window.top.__VUE_DEVTOOLS_CONTEXT__ = window.document;
}
} catch (e) {
// eslint-disable-next-line no-console
console.warn('unable to connect to top frame for connecting dev tools');
}
</script>
<script type="module" crossorigin src="./assets/iframe-BYP-OqC3.js"></script>
</head>
<body>
<div class="sb-preparing-story sb-wrapper">
<div class="sb-loader"></div>
</div>
<div class="sb-preparing-docs sb-wrapper">
<div class="sb-previewBlock">
<div class="sb-previewBlock_header">
<div class="sb-previewBlock_icon"></div>
<div class="sb-previewBlock_icon"></div>
<div class="sb-previewBlock_icon"></div>
<div class="sb-previewBlock_icon"></div>
</div>
<div class="sb-previewBlock_body">
<div class="sb-loader"></div>
</div>
</div>
<table aria-hidden="true" class="sb-argstableBlock">
<thead class="sb-argstableBlock-head">
<tr>
<th><span>Name</span></th>
<th><span>Description</span></th>
<th><span>Default</span></th>
<th><span>Control </span></th>
</tr>
</thead>
<tbody class="sb-argstableBlock-body">
<tr>
<td><span>propertyName</span><span title="Required">*</span></td>
<td>
<div><span>This is a short description</span></div>
<div class="sb-argstableBlock-summary">
<div><span class="sb-argstableBlock-code">summary</span></div>
</div>
</td>
<td>
<div><span class="sb-argstableBlock-code">defaultValue</span></div>
</td>
<td><button>Set string</button></td>
</tr>
<tr>
<td><span>propertyName</span><span>*</span></td>
<td>
<div><span>This is a short description</span></div>
<div class="sb-argstableBlock-summary">
<div><span class="sb-argstableBlock-code">summary</span></div>
</div>
</td>
<td>
<div><span class="sb-argstableBlock-code">defaultValue</span></div>
</td>
<td><button>Set string</button></td>
</tr>
<tr>
<td><span>propertyName</span><span>*</span></td>
<td>
<div><span>This is a short description</span></div>
<div class="sb-argstableBlock-summary">
<div><span class="sb-argstableBlock-code">summary</span></div>
</div>
</td>
<td>
<div><span class="sb-argstableBlock-code">defaultValue</span></div>
</td>
<td><button>Set string</button></td>
</tr>
</tbody>
</table>
</div>
<div class="sb-nopreview sb-wrapper">
<div class="sb-nopreview_main">
<h1 class="sb-nopreview_heading sb-heading">No Preview</h1>
<p>Sorry, but you either have no stories or none are selected somehow.</p>
<ul>
<li>Please check the Storybook config.</li>
<li>Try reloading the page.</li>
</ul>
<p>
If the problem persists, check the browser console, or the terminal you've run Storybook from.
</p>
</div>
</div>
<div class="sb-errordisplay sb-wrapper">
<div class="sb-errordisplay_main">
<h1 id="error-message"></h1>
<p>
The component failed to render properly, likely due to a configuration issue in Storybook.
Here are some common causes and how you can address them:
</p>
<ol>
<li>
<strong>Missing Context/Providers</strong>: You can use decorators to supply specific
contexts or providers, which are sometimes necessary for components to render correctly. For
detailed instructions on using decorators, please visit the
<a href="https://storybook.js.org/docs/writing-stories/decorators"
>Decorators documentation</a
>.
</li>
<li>
<strong>Misconfigured Webpack or Vite</strong>: Verify that Storybook picks up all necessary
settings for loaders, plugins, and other relevant parameters. You can find step-by-step
guides for configuring
<a href="https://storybook.js.org/docs/builders/webpack">Webpack</a> or
<a href="https://storybook.js.org/docs/builders/vite">Vite</a>
with Storybook.
</li>
<li>
<strong>Missing Environment Variables</strong>: Your Storybook may require specific
environment variables to function as intended. You can set up custom environment variables
as outlined in the
<a href="https://storybook.js.org/docs/configure/environment-variables"
>Environment Variables documentation</a
>.
</li>
</ol>
<pre class="sb-errordisplay_code"><code id="error-stack"></code></pre>
</div>
</div>
<div id="storybook-root"></div>
<div id="storybook-docs"></div>
<script>
// eslint-disable-next-line no-underscore-dangle, @typescript-eslint/naming-convention
function __onViteAppLoadingError(event) {
const hostname = globalThis.location.hostname;
if (hostname !== 'localhost' && globalThis.CONFIG_TYPE === 'DEVELOPMENT') {
const message = `Failed to load the Storybook preview file 'vite-app.js':
It looks like you're visiting the Storybook development server on another hostname than localhost: '${hostname}', but you haven't configured the necessary security features to support this.
Please re-run your Storybook development server with the '--host ${hostname}' flag, or manually configure your Vite allowedHosts configuration with viteFinal.
See:`;
const docs = [
'https://storybook.js.org/docs/api/cli-options#dev',
'https://storybook.js.org/docs/api/main-config/main-config-vite-final',
'https://vite.dev/config/server-options.html#server-allowedhosts',
];
console.error(`${message}\n${docs.map((doc) => `- ${doc}`).join('\n')}`);
document.getElementById('storybook-root').innerHTML =
`<p style="color: red; max-width: 70ch">${message.replaceAll(
'\n',
'<br/>'
)}<ul>${docs.map((doc) => `<li><a href='${doc}' target='_blank'>${doc}</a></li>`).join('')}<ul></p>`;
return;
}
}
</script>
</body>
</html>
+173
View File
@@ -0,0 +1,173 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@storybook/core - Storybook</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="icon" type="image/svg+xml" href="./favicon.svg" />
<style>
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('./sb-common-assets/nunito-sans-regular.woff2') format('woff2');
}
@font-face {
font-family: 'Nunito Sans';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('./sb-common-assets/nunito-sans-italic.woff2') format('woff2');
}
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('./sb-common-assets/nunito-sans-bold.woff2') format('woff2');
}
@font-face {
font-family: 'Nunito Sans';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url('./sb-common-assets/nunito-sans-bold-italic.woff2') format('woff2');
}
</style>
<link href="./sb-manager/runtime.js" rel="modulepreload" />
<link href="./sb-addons/storybook-core-core-server-presets-0/common-manager-bundle.js" rel="modulepreload" />
<link href="./sb-addons/essentials-controls-1/manager-bundle.js" rel="modulepreload" />
<link href="./sb-addons/essentials-actions-2/manager-bundle.js" rel="modulepreload" />
<link href="./sb-addons/essentials-docs-3/manager-bundle.js" rel="modulepreload" />
<link href="./sb-addons/essentials-backgrounds-4/manager-bundle.js" rel="modulepreload" />
<link href="./sb-addons/essentials-viewport-5/manager-bundle.js" rel="modulepreload" />
<link href="./sb-addons/essentials-toolbars-6/manager-bundle.js" rel="modulepreload" />
<link href="./sb-addons/essentials-measure-7/manager-bundle.js" rel="modulepreload" />
<link href="./sb-addons/essentials-outline-8/manager-bundle.js" rel="modulepreload" />
<link href="./sb-addons/a11y-9/manager-bundle.js" rel="modulepreload" />
<style>
#storybook-root[hidden] {
display: none !important;
}
</style>
</head>
<body>
<div id="root"></div>
<script>
window['FEATURES'] = {
"argTypeTargetsV7": true,
"legacyDecoratorFileOrder": false,
"disallowImplicitActionsInRenderV8": true
};
window['REFS'] = {};
window['LOGLEVEL'] = "info";
window['DOCS_OPTIONS'] = {
"defaultName": "Docs",
"autodocs": "tag"
};
window['CONFIG_TYPE'] = "PRODUCTION";
window['TAGS_OPTIONS'] = {
"dev-only": {
"excludeFromDocsStories": true
},
"docs-only": {
"excludeFromSidebar": true
},
"test-only": {
"excludeFromSidebar": true,
"excludeFromDocsStories": true
}
};
window['STORYBOOK_RENDERER'] = "vue3";
window['STORYBOOK_BUILDER'] = "@storybook/builder-vite";
window['STORYBOOK_FRAMEWORK'] = "@storybook/vue3-vite";
</script>
<script type="module">
import './sb-manager/globals-runtime.js';
import './sb-addons/storybook-core-core-server-presets-0/common-manager-bundle.js';
import './sb-addons/essentials-controls-1/manager-bundle.js';
import './sb-addons/essentials-actions-2/manager-bundle.js';
import './sb-addons/essentials-docs-3/manager-bundle.js';
import './sb-addons/essentials-backgrounds-4/manager-bundle.js';
import './sb-addons/essentials-viewport-5/manager-bundle.js';
import './sb-addons/essentials-toolbars-6/manager-bundle.js';
import './sb-addons/essentials-measure-7/manager-bundle.js';
import './sb-addons/essentials-outline-8/manager-bundle.js';
import './sb-addons/a11y-9/manager-bundle.js';
import './sb-manager/runtime.js';
</script>
</body>
</html>
+1
View File
@@ -0,0 +1 @@
{"v":5,"entries":{"molecules-listingcard--available":{"type":"story","id":"molecules-listingcard--available","name":"Available","title":"Molecules/ListingCard","importPath":"./src/components/molecules/ListingCard.stories.js","tags":["dev","test"]},"molecules-listingcard--pending":{"type":"story","id":"molecules-listingcard--pending","name":"Pending","title":"Molecules/ListingCard","importPath":"./src/components/molecules/ListingCard.stories.js","tags":["dev","test"]},"molecules-listingcard--sold":{"type":"story","id":"molecules-listingcard--sold","name":"Sold","title":"Molecules/ListingCard","importPath":"./src/components/molecules/ListingCard.stories.js","tags":["dev","test"]},"organisms-design-system-showcase--all-fixtures":{"type":"story","id":"organisms-design-system-showcase--all-fixtures","name":"All Fixtures","title":"Organisms/Design System Showcase","importPath":"./src/components/organisms/DesignSystemShowcase.stories.js","componentPath":"./src/components/organisms/DesignSystemShowcase.vue","tags":["dev","test"]}}}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
{"generatedAt":1788918193718,"userSince":1747527064134,"hasCustomBabel":false,"hasCustomWebpack":false,"hasStaticDirs":false,"hasStorybookEslint":false,"refCount":0,"testPackages":{},"hasRouterPackage":true,"monorepo":"Workspaces","packageManager":{"type":"npm","agent":"npm"},"preview":{"usesGlobals":true},"framework":{"name":"@storybook/vue3-vite","options":{}},"builder":"@storybook/builder-vite","renderer":"@storybook/vue3","portableStoriesFileCount":0,"applicationFileCount":0,"language":"javascript","storybookPackages":{},"addons":{"@storybook/addon-essentials":{"version":"8.6.14"},"@storybook/addon-a11y":{"version":"8.6.14"}}}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
try{
(()=>{var T=__STORYBOOK_API__,{ActiveTabs:h,Consumer:g,ManagerContext:f,Provider:v,RequestResponseError:A,addons:n,combineParameters:x,controlOrMetaKey:P,controlOrMetaSymbol:k,eventMatchesShortcut:M,eventToShortcut:R,experimental_MockUniversalStore:C,experimental_UniversalStore:U,experimental_requestResponse:w,experimental_useUniversalStore:B,isMacLike:E,isShortcutTaken:I,keyToSymbol:K,merge:N,mockChannel:G,optionOrAltSymbol:L,shortcutMatchesShortcut:Y,shortcutToHumanString:q,types:D,useAddonState:F,useArgTypes:H,useArgs:j,useChannel:V,useGlobalTypes:z,useGlobals:J,useParameter:Q,useSharedState:W,useStoryPrepared:X,useStorybookApi:Z,useStorybookState:$}=__STORYBOOK_API__;var S=(()=>{let e;return typeof window<"u"?e=window:typeof globalThis<"u"?e=globalThis:typeof window<"u"?e=window:typeof self<"u"?e=self:e={},e})(),c="tag-filters",p="static-filter";n.register(c,e=>{let u=Object.entries(S.TAGS_OPTIONS??{}).reduce((t,r)=>{let[o,i]=r;return i.excludeFromSidebar&&(t[o]=!0),t},{});e.experimental_setFilter(p,t=>{let r=t.tags??[];return(r.includes("dev")||t.type==="docs")&&r.filter(o=>u[o]).length===0})});})();
}catch(e){ console.error("[Storybook] One of your manager-entries failed: " + import.meta.url, e); }
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svgjs="http://svgjs.com/svgjs" xmlns:xlink="http://www.w3.org/1999/xlink" width="164" height="164" version="1.1"><svg xmlns="http://www.w3.org/2000/svg" width="164" height="164" fill="none" viewBox="0 0 164 164"><path fill="#FF4785" d="M22.467 147.762 17.5 15.402a8.062 8.062 0 0 1 7.553-8.35L137.637.016a8.061 8.061 0 0 1 8.565 8.047v144.23a8.063 8.063 0 0 1-8.424 8.054l-107.615-4.833a8.062 8.062 0 0 1-7.695-7.752Z"/><path fill="#fff" fill-rule="evenodd" d="m128.785.57-15.495.968-.755 18.172a1.203 1.203 0 0 0 1.928 1.008l7.06-5.354 5.962 4.697a1.202 1.202 0 0 0 1.946-.987L128.785.569Zm-12.059 60.856c-2.836 2.203-23.965 3.707-23.965.57.447-11.969-4.912-12.494-7.889-12.494-2.828 0-7.59.855-7.59 7.267 0 6.534 6.96 10.223 15.13 14.553 11.607 6.15 25.654 13.594 25.654 32.326 0 17.953-14.588 27.871-33.194 27.871-19.201 0-35.981-7.769-34.086-34.702.744-3.163 25.156-2.411 25.156 0-.298 11.114 2.232 14.383 8.633 14.383 4.912 0 7.144-2.708 7.144-7.267 0-6.9-7.252-10.973-15.595-15.657C64.827 81.933 51.53 74.468 51.53 57.34c0-17.098 11.76-28.497 32.747-28.497 20.988 0 32.449 11.224 32.449 32.584Z" clip-rule="evenodd"/></svg><style>@media (prefers-color-scheme:light){:root{filter:none}}</style></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,48 @@
import ESM_COMPAT_Module from "node:module";
import { fileURLToPath as ESM_COMPAT_fileURLToPath } from 'node:url';
import { dirname as ESM_COMPAT_dirname } from 'node:path';
const __filename = ESM_COMPAT_fileURLToPath(import.meta.url);
const __dirname = ESM_COMPAT_dirname(__filename);
const require = ESM_COMPAT_Module.createRequire(import.meta.url);
// src/manager/globals/globals.ts
var _ = {
react: "__REACT__",
"react-dom": "__REACT_DOM__",
"react-dom/client": "__REACT_DOM_CLIENT__",
"@storybook/icons": "__STORYBOOK_ICONS__",
"storybook/internal/manager-api": "__STORYBOOK_API__",
"@storybook/manager-api": "__STORYBOOK_API__",
"@storybook/core/manager-api": "__STORYBOOK_API__",
"storybook/internal/components": "__STORYBOOK_COMPONENTS__",
"@storybook/components": "__STORYBOOK_COMPONENTS__",
"@storybook/core/components": "__STORYBOOK_COMPONENTS__",
"storybook/internal/channels": "__STORYBOOK_CHANNELS__",
"@storybook/channels": "__STORYBOOK_CHANNELS__",
"@storybook/core/channels": "__STORYBOOK_CHANNELS__",
"storybook/internal/core-errors": "__STORYBOOK_CORE_EVENTS__",
"@storybook/core-events": "__STORYBOOK_CORE_EVENTS__",
"@storybook/core/core-events": "__STORYBOOK_CORE_EVENTS__",
"storybook/internal/manager-errors": "__STORYBOOK_CORE_EVENTS_MANAGER_ERRORS__",
"@storybook/core-events/manager-errors": "__STORYBOOK_CORE_EVENTS_MANAGER_ERRORS__",
"@storybook/core/manager-errors": "__STORYBOOK_CORE_EVENTS_MANAGER_ERRORS__",
"storybook/internal/router": "__STORYBOOK_ROUTER__",
"@storybook/router": "__STORYBOOK_ROUTER__",
"@storybook/core/router": "__STORYBOOK_ROUTER__",
"storybook/internal/theming": "__STORYBOOK_THEMING__",
"@storybook/theming": "__STORYBOOK_THEMING__",
"@storybook/core/theming": "__STORYBOOK_THEMING__",
"storybook/internal/theming/create": "__STORYBOOK_THEMING_CREATE__",
"@storybook/theming/create": "__STORYBOOK_THEMING_CREATE__",
"@storybook/core/theming/create": "__STORYBOOK_THEMING_CREATE__",
"storybook/internal/client-logger": "__STORYBOOK_CLIENT_LOGGER__",
"@storybook/client-logger": "__STORYBOOK_CLIENT_LOGGER__",
"@storybook/core/client-logger": "__STORYBOOK_CLIENT_LOGGER__",
"storybook/internal/types": "__STORYBOOK_TYPES__",
"@storybook/types": "__STORYBOOK_TYPES__",
"@storybook/core/types": "__STORYBOOK_TYPES__"
}, o = Object.keys(_);
export {
o as globalPackages,
_ as globalsNameReferenceMap
};
File diff suppressed because it is too large Load Diff
+669 -33
View File
@@ -1,43 +1,679 @@
# Design System Direction
# DESIGN.md
## Principles
## Purpose
- Minimal
- Clean
- Information-dense without clutter
- Accessible
- Responsive
- Consistent
- Component-driven
This document defines the visual design system, interaction principles, component expectations, and UI constraints for the collectibles platform.
## Component architecture
The platform is category-independent and must support Pokémon, sports cards, comics, figures, sealed products, and future collectible categories without requiring a redesign.
Build atomic/reusable Vue components.
When implementation details are ambiguous, prioritize:
```text
Collectible
↓
Important Data
↓
Application Branding
```
The collectible and its data are always more important than the application itself.
---
# Core Design Principles
The application should be:
* Minimal
* Clean
* Information-dense without clutter
* Accessible
* Responsive
* Consistent
* Component-driven
* Collector-focused
* Mobile-first
* Category-independent
The experience should feel:
* Premium
* Modern
* Precise
* Fast
* Purpose-built for collectors
Avoid:
* Generic SaaS styling
* Excessive decoration
* Rainbow UI design
* Marketplace-branded interfaces
* Gaming-style visual overload
---
# Visual Direction
## Theme
**Monochrome + Electric Cobalt**
Primary brand color:
```text
#1769FF
```
Use Electric Cobalt for:
* Brand identity
* Focus states
* Selection states
* Interactive controls
* Navigation highlights
Do NOT use Electric Cobalt for:
* Prices
* Marketplace values
* Condition indicators
* Generic status indicators
---
# Typography
## Primary UI Font
```text
Manrope
```
Used for:
* Navigation
* Forms
* Tables
* Metadata
* Prices
* Statuses
* Body copy
## Display Font
```text
Space Grotesk
```
Used for:
* Page titles
* Section headings
* Collectible names
* Display typography
## Numeric Presentation
Use tabular numerals for:
* Prices
* Quantities
* Grades
* Market values
---
# Color System
## Brand
```text
Electric Cobalt
#1769FF
```
## Semantic Colors
Success:
```text
#12A150
```
Warning:
```text
#D88A00
```
Danger:
```text
#E5484D
```
Information:
```text
#1683C4
```
Rules:
* Never rely on color alone.
* Pair color with labels, icons, or text.
* Maintain WCAG 2.2 AA contrast compliance.
---
# Controlled Luminescence
Glow is a branding tool.
Glow should be used sparingly.
Allowed:
* Focus
* Selection
* Primary action emphasis
Avoid:
* Constant glowing interfaces
* Price glow
* Status glow
* Decorative glow
Users may choose:
* Standard
* Reduced
* Off
Disabling glow must never remove focus visibility.
---
# Spacing System
Use an 8px spacing system.
```text
4
8
12
16
24
32
48
64
96
```
Avoid arbitrary spacing values.
---
# Shape Language
Use controlled geometry.
Radius scale:
```text
4px
6px
8px
12px
16px
Full
```
Default card radius:
```text
12px
```
The mobile Add button is intentionally circular.
---
# Layout Philosophy
## Browsing
Collection browsing should feel spacious and visual.
## Management
Inventory management should feel efficient and information-dense.
Rule:
> Browsing breathes. Managing is efficient.
---
# Responsive Design
Mobile is a first-class platform.
Do not design desktop first and collapse later.
Primary breakpoints:
```text
640
768
1024
1280
1536
```
All major workflows must be usable on mobile.
---
# Navigation
Use adaptive navigation.
Desktop:
* Sidebar navigation
Mobile:
* Bottom navigation
* Prominent circular Add action
The Add action is a signature interaction.
---
# Component Architecture
Build reusable Vue components.
Examples:
- SearchBar
- ProductCard
- InventoryGroup
- InventoryCopyRow
- PriceDisplay
- ConditionBadge
- StatusBadge
- ImageGallery
- FilterPanel
- SortControl
- Modal/Dialog
- FormField
- ValidationMessage
- DataTable
- EmptyState
- LoadingState
- ErrorState
- ActivityTimeline
Components should have clear responsibilities and avoid embedding domain business rules.
* SearchBar
* CollectibleCard
* InventoryGroup
* InventoryCopyRow
* PriceDisplay
* ConditionBadge
* StatusBadge
* ImageGallery
* FilterPanel
* SortControl
* Modal
* Dialog
* BottomSheet
* FormField
* ValidationMessage
* DataTable
* EmptyState
* LoadingState
* ErrorState
* ActivityTimeline
* MarketValue
* MarketplaceSource
* TaskProgress
## Visual decisions
Rules:
Exact color palette, typography, spacing tokens, and final visual styling can evolve during implementation, but must preserve accessibility and the documented information hierarchy.
* Single responsibility
* Reusable
* Accessible
* Domain logic belongs outside components
* Components consume semantic tokens, not raw colors
No color-only indication of state or condition.
---
# Collectible Presentation
## Image Treatment
Use a gallery/museum presentation style.
Rules:
* Preserve aspect ratio
* Use contain by default
* Avoid unnecessary cropping
* Neutral image stages
* No cobalt image backgrounds
* No artificial image enhancements
Collectibles are the visual hero.
---
# Card Structure
Default hierarchy:
1. Image
2. Name
3. Identity metadata
4. Condition / Grade
5. Price
6. Status
Cards should adapt to context rather than forcing a single universal layout.
---
# Detail Pages
Use a hybrid detail page.
Primary section:
* Images
* Identity
* Price
* Condition
* Status
* Primary actions
Secondary sections:
* Overview
* Market
* Copies
* Listings
* Activity
---
# Prices
Prices are important but not the hero.
Rules:
* Use tabular numerals
* Distinguish actual vs market values
* Distinguish source values vs converted values
* Do not make all prices green
---
# Market Data
The system must support:
* Reference values
* Marketplace values
* Data freshness
* Provenance
* Mapping confidence
Users must be able to understand:
* Where a value came from
* When it was updated
* Whether it was calculated or imported
---
# Condition, Grade, and Status
These are separate concepts.
Condition:
* Near Mint
* Lightly Played
* etc.
Grade:
* Certification provider
* Grade
* Certification number
Status:
* Inventory status
* Listing status
* Workflow status
Do not merge these concepts.
---
# Collectible vs Physical Copy
The system distinguishes:
## Collectible Identity
What the item is.
## Physical Copy
The specific owned instance.
Copy-specific data includes:
* Condition
* Grade
* Images
* Acquisition data
* Storage
* Listings
* Notes
Never collapse meaningful copies into quantity-only inventory.
---
# Multiple Copies
Default view:
```text
Grouped by collectible
```
Users may switch to:
```text
Individual copies
```
Both modes must be supported.
---
# Category Hierarchy
Hierarchy is category-defined.
Examples:
* Set
* Series
* Product
* Issue
Do not hard-code Pokémon-specific concepts.
---
# Collection Organization
Treat these separately:
## Physical Location
Always private.
Examples:
* Binder
* Shelf
* Cabinet
* Vault
## User Collections
Curated groupings.
A copy may belong to multiple collections.
## Tags
Flexible labels.
## Saved Views
Saved filters/configurations.
---
# Search
Support:
* Global search
* Identification search
* Marketplace mapping search
Global search includes archived items.
Architecture should support future command-style search.
---
# Forms
Rules:
* Persistent labels
* Progressive validation
* Progressive disclosure
* Draft protection
* Mobile-friendly inputs
Avoid placeholder-only forms.
---
# Feedback States
Support:
* Loading
* Success
* Warning
* Error
* Empty
Use:
* Skeletons
* Toasts
* Inline validation
* Progress indicators
Avoid excessive animations.
---
# Motion
Motion should communicate:
* Responsiveness
* Hierarchy
* State changes
Not decoration.
Target timing:
```text
80–350ms
```
Respect reduced-motion preferences.
---
# Accessibility
Minimum standard:
```text
WCAG 2.2 AA
```
Requirements:
* Keyboard navigation
* Visible focus states
* Screen-reader support
* 44x44 touch targets
* No color-only meaning
* Reduced motion support
Accessibility is part of component acceptance criteria.
---
# Privacy
Default:
```text
Private
```
Visibility options:
* Private
* Public
* Custom
Provide:
* Public preview
* Visibility summaries
* Explicit visibility decisions
Storage locations must never be public.
---
# Future Considerations
Architect so future support is possible for:
* Wishlist
* Price alerts
* Additional marketplaces
* Search commands
* Dashboard customization
Do not implement these unless specifically planned.
---
# Implementation Rule
When generating UI:
1. Use semantic tokens.
2. Preserve the collectible → data → branding hierarchy.
3. Favor reusable components.
4. Prioritize mobile usability.
5. Maintain accessibility.
6. Keep the interface visually restrained.
7. Let collectibles remain the visual focus.
+1
View File
@@ -100,6 +100,7 @@ docker context use orbstack
- The web catalog now provides keyboard-accessible listing cards with stable `/listings/:id` links, a public listing detail page, and service-level detail loading/error handling.
- Catalog search and pagination are synchronized to the browser URL (`q` and `page`) with accessible previous/next controls; the web port `5173` is declared in the project port registry.
- The web catalog includes a stable `/products/:slug` product detail route with API-backed loading, not-found/error states, and semantic product facts.
- The visual design foundation is centralized in web tokens with light/dark/system runtime theme support; the fixture composition has moved to Storybook at port `6006` with the accessibility addon and component stories for available, pending, and sold states.
- `ImageStorage`, traversal-safe local storage, multipart upload transport, and binary signature validation are implemented; derivative processing remains.
- Derivative orchestration now defines thumbnail, medium, and large WebP storage outputs behind an injected renderer; the concrete worker-backed renderer remains.
- The worker owns an image derivative job runner with explicit processing, completion, and failure outcomes; queue transport and persistent job records remain.
+3107 -495
View File
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -15,6 +15,8 @@
"dev:api": "npm run start --workspace=@pokemon-inventory/api",
"dev:prepare": "npm run db:up && npm run db:migrate",
"dev:web": "npm run dev --workspace=@pokemon-inventory/web",
"storybook": "npm run storybook --workspace=@pokemon-inventory/web",
"build-storybook": "npm run build-storybook --workspace=@pokemon-inventory/web",
"provision:admin": "npm run provision:admin --workspace=@pokemon-inventory/api",
"test:application": "npm run test:application --workspace=@pokemon-inventory/api",
"test:domain": "npm run test:domain --workspace=@pokemon-inventory/api",
@@ -23,8 +25,12 @@
"test": "npm run test:domain && npm run test:application && npm run test:http"
},
"devDependencies": {
"@storybook/addon-a11y": "^8.6.14",
"@storybook/addon-essentials": "^8.6.14",
"@storybook/vue3-vite": "^8.6.14",
"concurrently": "^10.0.5",
"dotenv": "^16.6.1",
"drizzle-kit": "^0.31.8"
"drizzle-kit": "^0.31.8",
"storybook": "^8.6.14"
}
}