From 5452bd5589d488431dde7a5afd0b77c5504d7bc6 Mon Sep 17 00:00:00 2001 From: FragginWagon Date: Tue, 8 Sep 2026 21:55:34 -0400 Subject: [PATCH] feat: compose public collectible detail views --- apps/web/src/assets/styles/global.scss | 2 +- .../organisms/CollectibleDetail.stories.js | 31 ++++++++++++ .../organisms/CollectibleDetail.vue | 48 +++++++++++++++++++ apps/web/src/pages/ListingDetailPage.vue | 15 +++--- apps/web/src/pages/ProductDetailPage.vue | 23 ++++----- 5 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 apps/web/src/components/organisms/CollectibleDetail.stories.js create mode 100644 apps/web/src/components/organisms/CollectibleDetail.vue diff --git a/apps/web/src/assets/styles/global.scss b/apps/web/src/assets/styles/global.scss index a76f928..3f18156 100644 --- a/apps/web/src/assets/styles/global.scss +++ b/apps/web/src/assets/styles/global.scss @@ -13,7 +13,7 @@ h1, h2, h3, h4 { margin: 0; font-family: var(--font-display); line-height: var(- .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; } +.catalog-kicker, .listing-card__status { color: var(--color-interactive-text); 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); } diff --git a/apps/web/src/components/organisms/CollectibleDetail.stories.js b/apps/web/src/components/organisms/CollectibleDetail.stories.js new file mode 100644 index 0000000..c1dd6ed --- /dev/null +++ b/apps/web/src/components/organisms/CollectibleDetail.stories.js @@ -0,0 +1,31 @@ +import CollectibleDetail from './CollectibleDetail.vue'; + +export default { title: 'Organisms/CollectibleDetail', component: CollectibleDetail }; + +export const ListingDetail = { + args: { + title: 'Charizard ex #199/165', + status: 'AVAILABLE', + priceMinor: 11500, + condition: 'Near Mint', + description: 'A clean collector copy with a clear front and back.', + facts: [ + { label: 'Set', value: 'Scarlet & Violet 151' }, + { label: 'Card number', value: '199/165' }, + { label: 'Market context', value: '$120 reference' }, + { label: 'Updated', value: 'Today' }, + ], + images: [ + { id: 'front', label: 'FRONT', alt: 'Front of Charizard ex' }, + { id: 'back', label: 'BACK', alt: 'Back of Charizard ex' }, + ], + }, +}; + +export const ProductWithoutImages = { + args: { + title: 'Pikachu World Collection', + description: 'A representative product identity with images still to be added.', + facts: [{ label: 'Category', value: 'Collectible merchandise' }], + }, +}; \ No newline at end of file diff --git a/apps/web/src/components/organisms/CollectibleDetail.vue b/apps/web/src/components/organisms/CollectibleDetail.vue new file mode 100644 index 0000000..4d95aa7 --- /dev/null +++ b/apps/web/src/components/organisms/CollectibleDetail.vue @@ -0,0 +1,48 @@ + + + + + \ No newline at end of file diff --git a/apps/web/src/pages/ListingDetailPage.vue b/apps/web/src/pages/ListingDetailPage.vue index e75b0c5..bf022de 100644 --- a/apps/web/src/pages/ListingDetailPage.vue +++ b/apps/web/src/pages/ListingDetailPage.vue @@ -3,6 +3,7 @@ import { onMounted, ref } from 'vue'; import { RouterLink, useRoute } from 'vue-router'; import { getPublicListing } from '@/services/catalog-service.js'; +import CollectibleDetail from '@/components/organisms/CollectibleDetail.vue'; const route = useRoute(); const listing = ref(null); @@ -25,11 +26,13 @@ onMounted(async () => { Back to catalog

Loading listing...

{{ error.message }}

-
-

{{ listing.status }}

-

{{ listing.productName }}

-

${{ (listing.askingPriceMinor / 100).toFixed(2) }}

-

{{ listing.notes }}

-
+ \ No newline at end of file diff --git a/apps/web/src/pages/ProductDetailPage.vue b/apps/web/src/pages/ProductDetailPage.vue index 7c10576..965c05c 100644 --- a/apps/web/src/pages/ProductDetailPage.vue +++ b/apps/web/src/pages/ProductDetailPage.vue @@ -3,6 +3,7 @@ import { onMounted, ref } from 'vue'; import { RouterLink, useRoute } from 'vue-router'; import { getPublicProduct } from '@/services/catalog-service.js'; +import CollectibleDetail from '@/components/organisms/CollectibleDetail.vue'; const route = useRoute(); const product = ref(null); @@ -25,16 +26,16 @@ onMounted(async () => { Back to catalog

Loading product...

{{ error.message }}

-
-

Product catalog

-

{{ product.name }}

-

{{ product.description }}

-
-
Brand
{{ product.brand }}
-
Set
{{ product.setName }}
-
Card number
{{ product.cardNumber }}
-
Release year
{{ product.releaseYear }}
-
-
+ \ No newline at end of file