@burdenoff/microfe-coolandlovely 2026.706.2 → 2026.710.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/dist/coolandlovely/CoolAndLovelyRoot.d.ts +5 -0
  2. package/dist/coolandlovely/CoolAndLovelyRoot.d.ts.map +1 -0
  3. package/dist/coolandlovely/CoolAndLovelyRoot.js +62 -46
  4. package/dist/coolandlovely/CoolAndLovelyRoot.js.map +1 -1
  5. package/dist/coolandlovely/CoolAndLovelyRoutes.d.ts +4 -0
  6. package/dist/coolandlovely/CoolAndLovelyRoutes.d.ts.map +1 -0
  7. package/dist/coolandlovely/components/ActorName.d.ts +14 -0
  8. package/dist/coolandlovely/components/ActorName.d.ts.map +1 -0
  9. package/dist/coolandlovely/components/AddToLookbookButton.d.ts +10 -0
  10. package/dist/coolandlovely/components/AddToLookbookButton.d.ts.map +1 -0
  11. package/dist/coolandlovely/components/AddToLookbookButton.js +22 -22
  12. package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -1
  13. package/dist/coolandlovely/components/BrandCover.d.ts +17 -0
  14. package/dist/coolandlovely/components/BrandCover.d.ts.map +1 -0
  15. package/dist/coolandlovely/components/BrandCover.js +39 -0
  16. package/dist/coolandlovely/components/BrandCover.js.map +1 -0
  17. package/dist/coolandlovely/components/BrandCreatorAvatars.d.ts +14 -0
  18. package/dist/coolandlovely/components/BrandCreatorAvatars.d.ts.map +1 -0
  19. package/dist/coolandlovely/components/BrandCreatorAvatars.js +57 -0
  20. package/dist/coolandlovely/components/BrandCreatorAvatars.js.map +1 -0
  21. package/dist/coolandlovely/components/ColourSwatchRow.d.ts +11 -0
  22. package/dist/coolandlovely/components/ColourSwatchRow.d.ts.map +1 -0
  23. package/dist/coolandlovely/components/ColourSwatchRow.js +86 -0
  24. package/dist/coolandlovely/components/ColourSwatchRow.js.map +1 -0
  25. package/dist/coolandlovely/components/Comments.d.ts +14 -0
  26. package/dist/coolandlovely/components/Comments.d.ts.map +1 -0
  27. package/dist/coolandlovely/components/Comments.js +4 -4
  28. package/dist/coolandlovely/components/Comments.js.map +1 -1
  29. package/dist/coolandlovely/components/EmptyState.d.ts +14 -0
  30. package/dist/coolandlovely/components/EmptyState.d.ts.map +1 -0
  31. package/dist/coolandlovely/components/Field.d.ts +68 -0
  32. package/dist/coolandlovely/components/Field.d.ts.map +1 -0
  33. package/dist/coolandlovely/components/FileImage.d.ts +10 -0
  34. package/dist/coolandlovely/components/FileImage.d.ts.map +1 -0
  35. package/dist/coolandlovely/components/FileImage.js.map +1 -1
  36. package/dist/coolandlovely/components/FollowButton.d.ts +11 -0
  37. package/dist/coolandlovely/components/FollowButton.d.ts.map +1 -0
  38. package/dist/coolandlovely/components/ImageUploadField.d.ts +21 -0
  39. package/dist/coolandlovely/components/ImageUploadField.d.ts.map +1 -0
  40. package/dist/coolandlovely/components/ImageUploadField.js +139 -57
  41. package/dist/coolandlovely/components/ImageUploadField.js.map +1 -1
  42. package/dist/coolandlovely/components/LookCard.d.ts +17 -0
  43. package/dist/coolandlovely/components/LookCard.d.ts.map +1 -0
  44. package/dist/coolandlovely/components/LookCard.js +77 -0
  45. package/dist/coolandlovely/components/LookCard.js.map +1 -0
  46. package/dist/coolandlovely/components/MetricsCard.d.ts +16 -0
  47. package/dist/coolandlovely/components/MetricsCard.d.ts.map +1 -0
  48. package/dist/coolandlovely/components/MetricsCard.js +1 -1
  49. package/dist/coolandlovely/components/MetricsCard.js.map +1 -1
  50. package/dist/coolandlovely/components/PageLayout.d.ts +17 -0
  51. package/dist/coolandlovely/components/PageLayout.d.ts.map +1 -0
  52. package/dist/coolandlovely/components/ShopItemCard.d.ts +15 -0
  53. package/dist/coolandlovely/components/ShopItemCard.d.ts.map +1 -0
  54. package/dist/coolandlovely/components/ShopItemCard.js +45 -0
  55. package/dist/coolandlovely/components/ShopItemCard.js.map +1 -0
  56. package/dist/coolandlovely/components/StateViews.d.ts +16 -0
  57. package/dist/coolandlovely/components/StateViews.d.ts.map +1 -0
  58. package/dist/coolandlovely/components/StatusBadge.d.ts +9 -0
  59. package/dist/coolandlovely/components/StatusBadge.d.ts.map +1 -0
  60. package/dist/coolandlovely/components/StepTracker.d.ts +12 -0
  61. package/dist/coolandlovely/components/StepTracker.d.ts.map +1 -0
  62. package/dist/coolandlovely/components/StepTracker.js +35 -0
  63. package/dist/coolandlovely/components/StepTracker.js.map +1 -0
  64. package/dist/coolandlovely/components/TagList.d.ts +12 -0
  65. package/dist/coolandlovely/components/TagList.d.ts.map +1 -0
  66. package/dist/coolandlovely/components/Thumbnail.d.ts +23 -0
  67. package/dist/coolandlovely/components/Thumbnail.d.ts.map +1 -0
  68. package/dist/coolandlovely/components/Thumbnail.js +15 -11
  69. package/dist/coolandlovely/components/Thumbnail.js.map +1 -1
  70. package/dist/coolandlovely/components/VisibilityChip.d.ts +10 -0
  71. package/dist/coolandlovely/components/VisibilityChip.d.ts.map +1 -0
  72. package/dist/coolandlovely/components/VisibilityChip.js +32 -0
  73. package/dist/coolandlovely/components/VisibilityChip.js.map +1 -0
  74. package/dist/coolandlovely/components/index.d.ts +26 -0
  75. package/dist/coolandlovely/components/index.d.ts.map +1 -0
  76. package/dist/coolandlovely/context/CoolAndLovelyContext.d.ts +16 -0
  77. package/dist/coolandlovely/context/CoolAndLovelyContext.d.ts.map +1 -0
  78. package/dist/coolandlovely/context/index.d.ts +6 -0
  79. package/dist/coolandlovely/context/index.d.ts.map +1 -0
  80. package/dist/coolandlovely/hooks/index.d.ts +11 -0
  81. package/dist/coolandlovely/hooks/index.d.ts.map +1 -0
  82. package/dist/coolandlovely/hooks/useComments.d.ts +37 -0
  83. package/dist/coolandlovely/hooks/useComments.d.ts.map +1 -0
  84. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.d.ts +106 -0
  85. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.d.ts.map +1 -0
  86. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +94 -69
  87. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
  88. package/dist/coolandlovely/hooks/useFiles.d.ts +62 -0
  89. package/dist/coolandlovely/hooks/useFiles.d.ts.map +1 -0
  90. package/dist/coolandlovely/hooks/useFiles.js +49 -32
  91. package/dist/coolandlovely/hooks/useFiles.js.map +1 -1
  92. package/dist/coolandlovely/index.d.ts +11 -0
  93. package/dist/coolandlovely/index.d.ts.map +1 -0
  94. package/dist/coolandlovely/pages/HomePage.d.ts +10 -0
  95. package/dist/coolandlovely/pages/HomePage.d.ts.map +1 -0
  96. package/dist/coolandlovely/pages/HomePage.js +112 -133
  97. package/dist/coolandlovely/pages/HomePage.js.map +1 -1
  98. package/dist/coolandlovely/pages/brands/BrandDetailPage.d.ts +9 -0
  99. package/dist/coolandlovely/pages/brands/BrandDetailPage.d.ts.map +1 -0
  100. package/dist/coolandlovely/pages/brands/BrandDetailPage.js +253 -242
  101. package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
  102. package/dist/coolandlovely/pages/brands/BrandFormPage.d.ts +9 -0
  103. package/dist/coolandlovely/pages/brands/BrandFormPage.d.ts.map +1 -0
  104. package/dist/coolandlovely/pages/brands/BrandFormPage.js +116 -112
  105. package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -1
  106. package/dist/coolandlovely/pages/brands/BrandsListPage.d.ts +9 -0
  107. package/dist/coolandlovely/pages/brands/BrandsListPage.d.ts.map +1 -0
  108. package/dist/coolandlovely/pages/brands/BrandsListPage.js +13 -13
  109. package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
  110. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.d.ts +9 -0
  111. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.d.ts.map +1 -0
  112. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +117 -95
  113. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js.map +1 -1
  114. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.d.ts +10 -0
  115. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.d.ts.map +1 -0
  116. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +1 -1
  117. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.d.ts +9 -0
  118. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.d.ts.map +1 -0
  119. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js +50 -43
  120. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js.map +1 -1
  121. package/dist/coolandlovely/pages/collections/CollectionDetailPage.d.ts +9 -0
  122. package/dist/coolandlovely/pages/collections/CollectionDetailPage.d.ts.map +1 -0
  123. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +131 -108
  124. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
  125. package/dist/coolandlovely/pages/collections/CollectionFormPage.d.ts +9 -0
  126. package/dist/coolandlovely/pages/collections/CollectionFormPage.d.ts.map +1 -0
  127. package/dist/coolandlovely/pages/collections/CollectionFormPage.js +1 -1
  128. package/dist/coolandlovely/pages/collections/CollectionsListPage.d.ts +8 -0
  129. package/dist/coolandlovely/pages/collections/CollectionsListPage.d.ts.map +1 -0
  130. package/dist/coolandlovely/pages/collections/CollectionsListPage.js +59 -56
  131. package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
  132. package/dist/coolandlovely/pages/discover/DiscoverPage.d.ts +13 -0
  133. package/dist/coolandlovely/pages/discover/DiscoverPage.d.ts.map +1 -0
  134. package/dist/coolandlovely/pages/discover/DiscoverPage.js +1 -1
  135. package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -1
  136. package/dist/coolandlovely/pages/items/StyleItemDetailPage.d.ts +9 -0
  137. package/dist/coolandlovely/pages/items/StyleItemDetailPage.d.ts.map +1 -0
  138. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +175 -147
  139. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
  140. package/dist/coolandlovely/pages/items/StyleItemFormPage.d.ts +10 -0
  141. package/dist/coolandlovely/pages/items/StyleItemFormPage.d.ts.map +1 -0
  142. package/dist/coolandlovely/pages/items/StyleItemFormPage.js +1 -1
  143. package/dist/coolandlovely/pages/items/StyleItemsListPage.d.ts +9 -0
  144. package/dist/coolandlovely/pages/items/StyleItemsListPage.d.ts.map +1 -0
  145. package/dist/coolandlovely/pages/items/StyleItemsListPage.js +71 -62
  146. package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
  147. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.d.ts +12 -0
  148. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.d.ts.map +1 -0
  149. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +149 -127
  150. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
  151. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.d.ts +10 -0
  152. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.d.ts.map +1 -0
  153. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +69 -53
  154. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
  155. package/dist/coolandlovely/pages/looks/LookDetailPage.d.ts +9 -0
  156. package/dist/coolandlovely/pages/looks/LookDetailPage.d.ts.map +1 -0
  157. package/dist/coolandlovely/pages/looks/LookDetailPage.js +135 -113
  158. package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
  159. package/dist/coolandlovely/pages/looks/LookFormPage.d.ts +10 -0
  160. package/dist/coolandlovely/pages/looks/LookFormPage.d.ts.map +1 -0
  161. package/dist/coolandlovely/pages/looks/LookFormPage.js +122 -110
  162. package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
  163. package/dist/coolandlovely/pages/looks/LooksListPage.d.ts +9 -0
  164. package/dist/coolandlovely/pages/looks/LooksListPage.d.ts.map +1 -0
  165. package/dist/coolandlovely/pages/looks/LooksListPage.js +60 -97
  166. package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
  167. package/dist/coolandlovely/pages/profile/StyleProfilePage.d.ts +12 -0
  168. package/dist/coolandlovely/pages/profile/StyleProfilePage.d.ts.map +1 -0
  169. package/dist/coolandlovely/pages/profile/StyleProfilePage.js +372 -210
  170. package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
  171. package/dist/coolandlovely/pages/trends/TrendsPage.d.ts +11 -0
  172. package/dist/coolandlovely/pages/trends/TrendsPage.d.ts.map +1 -0
  173. package/dist/coolandlovely/pages/trends/TrendsPage.js +1 -1
  174. package/dist/coolandlovely/pages/trends/TrendsPage.js.map +1 -1
  175. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.d.ts +10 -0
  176. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.d.ts.map +1 -0
  177. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +130 -94
  178. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -1
  179. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.d.ts +12 -0
  180. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.d.ts.map +1 -0
  181. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +75 -76
  182. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
  183. package/dist/coolandlovely/store/coolandlovelyStore.d.ts +56 -0
  184. package/dist/coolandlovely/store/coolandlovelyStore.d.ts.map +1 -0
  185. package/dist/coolandlovely/store/index.d.ts +6 -0
  186. package/dist/coolandlovely/store/index.d.ts.map +1 -0
  187. package/dist/coolandlovely/types/index.d.ts +451 -0
  188. package/dist/coolandlovely/types/index.d.ts.map +1 -0
  189. package/dist/coolandlovely/utils/cn.d.ts +4 -0
  190. package/dist/coolandlovely/utils/cn.d.ts.map +1 -0
  191. package/dist/coolandlovely/utils/formatters.d.ts +101 -0
  192. package/dist/coolandlovely/utils/formatters.d.ts.map +1 -0
  193. package/dist/coolandlovely/utils/icons.d.ts +6 -0
  194. package/dist/coolandlovely/utils/icons.d.ts.map +1 -0
  195. package/dist/coolandlovely/utils/index.d.ts +9 -0
  196. package/dist/coolandlovely/utils/index.d.ts.map +1 -0
  197. package/dist/coolandlovely/utils/navigation.d.ts +20 -0
  198. package/dist/coolandlovely/utils/navigation.d.ts.map +1 -0
  199. package/dist/generated/global-operations.d.ts +2 -0
  200. package/dist/generated/global-operations.d.ts.map +1 -0
  201. package/dist/generated/global-types.d.ts +23527 -0
  202. package/dist/generated/global-types.d.ts.map +1 -0
  203. package/dist/generated/wspace-operations.d.ts +2 -0
  204. package/dist/generated/wspace-operations.d.ts.map +1 -0
  205. package/dist/generated/wspace-types.d.ts +57851 -0
  206. package/dist/generated/wspace-types.d.ts.map +1 -0
  207. package/dist/index.d.ts +6 -0
  208. package/dist/index.d.ts.map +1 -0
  209. package/dist/services/createSandboxAssistantTransport.d.ts +44 -0
  210. package/dist/services/createSandboxAssistantTransport.d.ts.map +1 -0
  211. package/dist/utils/pageContext.d.ts +28 -0
  212. package/dist/utils/pageContext.d.ts.map +1 -0
  213. package/package.json +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/collections/CollectionDetailPage.tsx"],"sourcesContent":["/**\n * Collection Detail Page\n * @module coolandlovely/pages/collections\n *\n * Single collection (`cooCollection`) with publish (`cooPublishCollection`),\n * edit, its brand link and member items.\n */\n\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Pencil, Rocket, Loader2, Shapes, Store, Plus } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCollection, usePublishCollection } from '../../hooks';\nimport { categoryIcon } from '../../utils/icons';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\n\nexport function CollectionDetailPage() {\n const { collectionId } = useParams<{ collectionId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useCollection(collectionId);\n const publish = usePublishCollection();\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Collection\">\n <LoadingView label=\"Loading collection…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Collection\">\n <ErrorView title=\"Collection not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const collection = query.data;\n const items = collection.items ?? [];\n const canPublish = collection.status === 'DRAFT' || collection.status === 'SCHEDULED';\n\n return (\n <PageLayout\n title={collection.name}\n description={collection.brand?.name ?? undefined}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/collections')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collections/${collection.id}/edit`)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n {canPublish && (\n <button\n type=\"button\"\n disabled={publish.isPending}\n onClick={() => publish.mutate(collection.id)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {publish.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Rocket className=\"h-4 w-4\" />\n )}\n Publish\n </button>\n )}\n </div>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <GlassCard treatment=\"glass\" className=\"overflow-hidden p-0\">\n <Thumbnail\n icon={<Shapes className=\"h-12 w-12\" />}\n seed={collection.id}\n fileId={collection.cover?.id}\n alt={collection.name}\n className=\"h-40 w-full\"\n />\n <div className=\"p-6\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"text-xl font-semibold text-text-primary\">{collection.name}</h2>\n <StatusBadge status={collection.status} className=\"ml-auto\" />\n </div>\n {collection.description && (\n <p className=\"mt-3 text-sm text-text-secondary\">{collection.description}</p>\n )}\n {collection.tags.length > 0 && <TagList tags={collection.tags} className=\"mt-4\" />}\n </div>\n </GlassCard>\n\n <section className=\"mt-6\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">Items ({items.length})</h3>\n {items.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No items in this collection yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3\">\n {items.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={categoryIcon(item.category, 24)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"h-24 w-full\"\n />\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {formatPrice(item.price, item.currency)}\n </p>\n </div>\n </button>\n ))}\n </div>\n )}\n <button\n type=\"button\"\n onClick={() =>\n navigateTo(`/items/new?brandId=${collection.brandId}&collectionId=${collection.id}`)\n }\n className=\"mt-3 inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Plus className=\"h-4 w-4\" /> Add item to this collection\n </button>\n </section>\n </div>\n\n <div className=\"space-y-4\">\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Details</h3>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Season</dt>\n <dd className=\"text-text-primary\">{titleCase(collection.season)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Publish at</dt>\n <dd className=\"text-text-primary\">\n {collection.publishAt\n ? formatDate(collection.publishAt, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Ends at</dt>\n <dd className=\"text-text-primary\">\n {collection.endAt\n ? formatDate(collection.endAt, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {collection.brand && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${collection.brand?.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Store className=\"h-5 w-5\" />}\n seed={collection.brand.id}\n className=\"h-10 w-10 shrink-0\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {collection.brand.name}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View brand</p>\n </div>\n </button>\n )}\n\n {publish.isError && (\n <p className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {publish.error instanceof Error ? publish.error.message : 'Publish failed'}\n </p>\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CollectionDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/collections/CollectionDetailPage.tsx"],"sourcesContent":["/**\n * Collection Detail Page\n * @module coolandlovely/pages/collections\n *\n * Single collection (`cooCollection`) with publish (`cooPublishCollection`),\n * edit, its brand link and member items.\n */\n\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Pencil, Rocket, Loader2, Shapes, Store, Plus } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { ColourSwatchRow } from '../../components/ColourSwatchRow';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCollection, usePublishCollection } from '../../hooks';\nimport { categoryIcon } from '../../utils/icons';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\n\nexport function CollectionDetailPage() {\n const { collectionId } = useParams<{ collectionId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useCollection(collectionId);\n const publish = usePublishCollection();\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Collection\">\n <LoadingView label=\"Loading collection…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Collection\">\n <ErrorView title=\"Collection not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const collection = query.data;\n const items = collection.items ?? [];\n const canPublish = collection.status === 'DRAFT' || collection.status === 'SCHEDULED';\n\n return (\n <PageLayout\n title={collection.name}\n description={collection.brand?.name ?? undefined}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/collections')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collections/${collection.id}/edit`)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n {canPublish && (\n <button\n type=\"button\"\n disabled={publish.isPending}\n onClick={() => publish.mutate(collection.id)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {publish.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Rocket className=\"h-4 w-4\" />\n )}\n Publish\n </button>\n )}\n </div>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <GlassCard treatment=\"glass\" className=\"group overflow-hidden p-0\">\n <Thumbnail\n icon={<Shapes className=\"h-12 w-12\" />}\n seed={collection.id}\n fileId={collection.cover?.id}\n alt={collection.name}\n className=\"aspect-[16/9] w-full sm:aspect-[21/9]\"\n overlay={\n <>\n <div className=\"pointer-events-none absolute inset-0 bg-gradient-to-t from-bg-canvas via-bg-canvas/55 to-transparent\" />\n <div className=\"absolute inset-x-0 bottom-0 flex flex-wrap items-end justify-between gap-3 p-6\">\n <div className=\"min-w-0\">\n <h2 className=\"font-serif text-3xl font-semibold leading-tight text-text-primary\">\n {collection.name}\n </h2>\n <div className=\"mt-2 flex flex-wrap items-center gap-2 text-sm text-text-secondary\">\n {collection.brand?.name && <span>{collection.brand.name}</span>}\n {collection.brand?.name && (\n <span aria-hidden=\"true\" className=\"opacity-60\">\n ·\n </span>\n )}\n <span className=\"rounded-full border border-border-seam bg-bg-surface/80 px-2.5 py-0.5 text-xs font-medium text-text-primary backdrop-blur-sm\">\n {titleCase(collection.season)}\n </span>\n </div>\n </div>\n <StatusBadge status={collection.status} className=\"shrink-0 shadow-sm\" />\n </div>\n </>\n }\n />\n {(collection.description || collection.tags.length > 0) && (\n <div className=\"p-6\">\n {collection.description && (\n <p className=\"text-sm text-text-secondary\">{collection.description}</p>\n )}\n {collection.tags.length > 0 && (\n <TagList\n tags={collection.tags}\n className={collection.description ? 'mt-4' : undefined}\n />\n )}\n </div>\n )}\n </GlassCard>\n\n <section className=\"mt-6\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">Items ({items.length})</h3>\n {items.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No items in this collection yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3\">\n {items.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"group overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={categoryIcon(item.category, 28)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[3/4] w-full\"\n />\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n <p className=\"mt-0.5 text-xs font-semibold text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n </p>\n {item.colours.length > 0 && (\n <ColourSwatchRow colours={item.colours} max={5} className=\"mt-2\" />\n )}\n </div>\n </button>\n ))}\n </div>\n )}\n <button\n type=\"button\"\n onClick={() =>\n navigateTo(`/items/new?brandId=${collection.brandId}&collectionId=${collection.id}`)\n }\n className=\"mt-3 inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Plus className=\"h-4 w-4\" /> Add item to this collection\n </button>\n </section>\n </div>\n\n <div className=\"space-y-4\">\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Details</h3>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Season</dt>\n <dd className=\"text-text-primary\">{titleCase(collection.season)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Publish at</dt>\n <dd className=\"text-text-primary\">\n {collection.publishAt\n ? formatDate(collection.publishAt, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Ends at</dt>\n <dd className=\"text-text-primary\">\n {collection.endAt\n ? formatDate(collection.endAt, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {collection.brand && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${collection.brand?.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Store className=\"h-5 w-5\" />}\n seed={collection.brand.id}\n className=\"h-10 w-10 shrink-0\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {collection.brand.name}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View brand</p>\n </div>\n </button>\n )}\n\n {publish.isError && (\n <p className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {publish.error instanceof Error ? publish.error.message : 'Publish failed'}\n </p>\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Collection Create / Edit Page
3
+ * @module coolandlovely/pages/collections
4
+ *
5
+ * Drives `cooCreateCollection` (new) and `cooUpdateCollection` (edit).
6
+ * Brand selection is required on create and locked on edit.
7
+ */
8
+ export declare function CollectionFormPage(): import("react").JSX.Element;
9
+ //# sourceMappingURL=CollectionFormPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollectionFormPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/collections/CollectionFormPage.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAqDH,wBAAgB,kBAAkB,gCA6OjC"}
@@ -3,8 +3,8 @@ import { PageLayout as t } from "../../components/PageLayout.js";
3
3
  import { ErrorView as n, LoadingView as r } from "../../components/StateViews.js";
4
4
  import { COO_FILE_FOLDERS as i } from "../../hooks/useFiles.js";
5
5
  import { useBrands as a, useCollection as o, useCreateCollection as s, useUpdateCollection as c } from "../../hooks/useCoolAndLovelyApi.js";
6
- import "../../hooks/index.js";
7
6
  import { parseCsv as l, titleCase as u } from "../../utils/formatters.js";
7
+ import "../../hooks/index.js";
8
8
  import { SelectField as d, TextAreaField as f, TextField as p } from "../../components/Field.js";
9
9
  import { ImageUploadField as m } from "../../components/ImageUploadField.js";
10
10
  import { useEffect as h, useMemo as g, useState as _ } from "react";
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Collections List Page
3
+ * @module coolandlovely/pages/collections
4
+ *
5
+ * Lists seasonal collections (`cooListCollections`) with status filter.
6
+ */
7
+ export declare function CollectionsListPage(): import("react").JSX.Element;
8
+ //# sourceMappingURL=CollectionsListPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollectionsListPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/collections/CollectionsListPage.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyBH,wBAAgB,mBAAmB,gCAkHlC"}
@@ -5,15 +5,15 @@ import { StatusBadge as r } from "../../components/StatusBadge.js";
5
5
  import { ErrorView as i, LoadingView as a } from "../../components/StateViews.js";
6
6
  import { Thumbnail as o } from "../../components/Thumbnail.js";
7
7
  import { useCollections as s } from "../../hooks/useCoolAndLovelyApi.js";
8
- import "../../hooks/index.js";
9
8
  import { formatDate as c, titleCase as l } from "../../utils/formatters.js";
9
+ import "../../hooks/index.js";
10
10
  import { TagList as u } from "../../components/TagList.js";
11
11
  import { EmptyState as d } from "../../components/EmptyState.js";
12
12
  import { useState as f } from "react";
13
13
  import { Plus as p, Shapes as m } from "lucide-react";
14
- import { jsx as h, jsxs as g } from "react/jsx-runtime";
14
+ import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
15
15
  //#region src/coolandlovely/pages/collections/CollectionsListPage.tsx
16
- var _ = [
16
+ var v = [
17
17
  {
18
18
  value: "ALL",
19
19
  label: "All"
@@ -39,86 +39,89 @@ var _ = [
39
39
  label: "Archived"
40
40
  }
41
41
  ];
42
- function v() {
43
- let { navigateTo: v } = e(), [y, b] = f("ALL"), x = s({ status: y === "ALL" ? void 0 : y }), S = x.data ?? [];
44
- return /* @__PURE__ */ g(n, {
42
+ function y() {
43
+ let { navigateTo: y } = e(), [b, x] = f("ALL"), S = s({ status: b === "ALL" ? void 0 : b }), C = S.data ?? [];
44
+ return /* @__PURE__ */ _(n, {
45
45
  title: "Collections",
46
46
  description: "Seasonal drops and curated edits grouped by brand",
47
- actions: /* @__PURE__ */ g("button", {
47
+ actions: /* @__PURE__ */ _("button", {
48
48
  type: "button",
49
- onClick: () => v("/collections/new"),
49
+ onClick: () => y("/collections/new"),
50
50
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
51
- children: [/* @__PURE__ */ h(p, { className: "h-4 w-4" }), " New collection"]
51
+ children: [/* @__PURE__ */ g(p, { className: "h-4 w-4" }), " New collection"]
52
52
  }),
53
- children: [/* @__PURE__ */ h("div", {
53
+ children: [/* @__PURE__ */ g("div", {
54
54
  className: "mb-6 flex flex-wrap items-center gap-2",
55
- children: _.map((e) => /* @__PURE__ */ h("button", {
55
+ children: v.map((e) => /* @__PURE__ */ g("button", {
56
56
  type: "button",
57
- onClick: () => b(e.value),
58
- className: t("rounded-full px-3 py-1.5 text-sm font-medium transition-colors", y === e.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
57
+ onClick: () => x(e.value),
58
+ className: t("rounded-full px-3 py-1.5 text-sm font-medium transition-colors", b === e.value ? "bg-accent-purple-subtle text-text-primary" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
59
59
  children: e.label
60
60
  }, e.value))
61
- }), x.isLoading ? /* @__PURE__ */ h(a, { label: "Loading collections…" }) : x.isError ? /* @__PURE__ */ h(i, { onRetry: () => void x.refetch() }) : S.length === 0 ? /* @__PURE__ */ h(d, {
61
+ }), S.isLoading ? /* @__PURE__ */ g(a, { label: "Loading collections…" }) : S.isError ? /* @__PURE__ */ g(i, { onRetry: () => void S.refetch() }) : C.length === 0 ? /* @__PURE__ */ g(d, {
62
62
  illustration: "empty-data",
63
- icon: /* @__PURE__ */ h(m, { className: "h-10 w-10" }),
63
+ icon: /* @__PURE__ */ g(m, { className: "h-10 w-10" }),
64
64
  title: "No collections yet",
65
65
  description: "Group pieces into a seasonal drop to start a collection.",
66
- action: /* @__PURE__ */ g("button", {
66
+ action: /* @__PURE__ */ _("button", {
67
67
  type: "button",
68
- onClick: () => v("/collections/new"),
68
+ onClick: () => y("/collections/new"),
69
69
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text",
70
- children: [/* @__PURE__ */ h(p, { className: "h-4 w-4" }), " New collection"]
70
+ children: [/* @__PURE__ */ g(p, { className: "h-4 w-4" }), " New collection"]
71
71
  })
72
- }) : /* @__PURE__ */ h("div", {
72
+ }) : /* @__PURE__ */ g("div", {
73
73
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
74
- children: S.map((e) => /* @__PURE__ */ g("button", {
74
+ children: C.map((e) => /* @__PURE__ */ _("button", {
75
75
  type: "button",
76
- onClick: () => v(`/collections/${e.id}`),
77
- className: "overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md",
78
- children: [/* @__PURE__ */ h(o, {
79
- icon: /* @__PURE__ */ h(m, { className: "h-9 w-9" }),
80
- seed: e.id,
81
- fileId: e.cover?.id,
82
- alt: e.name,
83
- className: "h-28 w-full"
84
- }), /* @__PURE__ */ g("div", {
85
- className: "p-4",
86
- children: [
87
- /* @__PURE__ */ g("div", {
88
- className: "flex items-start justify-between gap-2",
89
- children: [/* @__PURE__ */ g("div", {
76
+ onClick: () => y(`/collections/${e.id}`),
77
+ className: "group overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md",
78
+ children: [/* @__PURE__ */ _("div", {
79
+ className: "relative",
80
+ children: [/* @__PURE__ */ g(o, {
81
+ icon: /* @__PURE__ */ g(m, { className: "h-10 w-10" }),
82
+ seed: e.id,
83
+ fileId: e.cover?.id,
84
+ alt: e.name,
85
+ className: "aspect-[16/10] w-full",
86
+ overlay: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("div", { className: "pointer-events-none absolute inset-0 bg-gradient-to-t from-bg-canvas via-bg-canvas/55 to-transparent" }), /* @__PURE__ */ _("div", {
87
+ className: "absolute inset-x-0 bottom-0 flex items-end justify-between gap-2 p-4",
88
+ children: [/* @__PURE__ */ _("div", {
90
89
  className: "min-w-0",
91
- children: [/* @__PURE__ */ h("h3", {
92
- className: "truncate text-base font-semibold text-text-primary",
90
+ children: [/* @__PURE__ */ g("h3", {
91
+ className: "truncate text-lg font-semibold text-text-primary",
93
92
  children: e.name
94
- }), e.brand?.name && /* @__PURE__ */ h("p", {
93
+ }), e.brand?.name && /* @__PURE__ */ g("p", {
95
94
  className: "truncate text-xs text-text-secondary",
96
95
  children: e.brand.name
97
96
  })]
98
- }), /* @__PURE__ */ h(r, { status: e.status })]
99
- }),
100
- /* @__PURE__ */ g("div", {
101
- className: "mt-2 flex items-center gap-2 text-xs text-text-secondary",
102
- children: [/* @__PURE__ */ h("span", {
103
- className: "rounded-full bg-bg-sunken px-2 py-0.5",
104
- children: l(e.season)
105
- }), e.publishAt && /* @__PURE__ */ g("span", { children: ["Publishes ", c(e.publishAt, {
106
- hour: void 0,
107
- minute: void 0
108
- })] })]
109
- }),
110
- e.tags.length > 0 && /* @__PURE__ */ h(u, {
111
- tags: e.tags,
112
- max: 4,
113
- className: "mt-3"
114
- })
115
- ]
97
+ }), /* @__PURE__ */ g(r, {
98
+ status: e.status,
99
+ className: "shrink-0 shadow-sm"
100
+ })]
101
+ })] })
102
+ }), /* @__PURE__ */ g("span", {
103
+ className: "absolute right-3 top-3 rounded-full border border-border-seam bg-bg-surface/85 px-2.5 py-0.5 text-xs font-medium text-text-primary backdrop-blur-sm",
104
+ children: l(e.season)
105
+ })]
106
+ }), (e.publishAt || e.tags.length > 0) && /* @__PURE__ */ _("div", {
107
+ className: "p-4",
108
+ children: [e.publishAt && /* @__PURE__ */ _("p", {
109
+ className: "text-xs text-text-secondary",
110
+ children: ["Publishes ", c(e.publishAt, {
111
+ hour: void 0,
112
+ minute: void 0
113
+ })]
114
+ }), e.tags.length > 0 && /* @__PURE__ */ g(u, {
115
+ tags: e.tags,
116
+ max: 4,
117
+ className: e.publishAt ? "mt-2" : void 0
118
+ })]
116
119
  })]
117
120
  }, e.id))
118
121
  })]
119
122
  });
120
123
  }
121
124
  //#endregion
122
- export { v as CollectionsListPage };
125
+ export { y as CollectionsListPage };
123
126
 
124
127
  //# sourceMappingURL=CollectionsListPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionsListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/collections/CollectionsListPage.tsx"],"sourcesContent":["/**\n * Collections List Page\n * @module coolandlovely/pages/collections\n *\n * Lists seasonal collections (`cooListCollections`) with status filter.\n */\n\nimport { useState } from 'react';\nimport { Plus, Shapes } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCollections } from '../../hooks';\nimport { titleCase, formatDate } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooCollectionStatus } from '../../types';\n\nconst STATUS_OPTIONS: Array<{ value: CooCollectionStatus | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'LIVE', label: 'Live' },\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'ENDED', label: 'Ended' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nexport function CollectionsListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [status, setStatus] = useState<CooCollectionStatus | 'ALL'>('ALL');\n\n const query = useCollections({ status: status === 'ALL' ? undefined : status });\n const collections = query.data ?? [];\n\n return (\n <PageLayout\n title=\"Collections\"\n description=\"Seasonal drops and curated edits grouped by brand\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/collections/new')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Plus className=\"h-4 w-4\" /> New collection\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n {STATUS_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => setStatus(opt.value)}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n status === opt.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading collections…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : collections.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Shapes className=\"h-10 w-10\" />}\n title=\"No collections yet\"\n description=\"Group pieces into a seasonal drop to start a collection.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/collections/new')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n <Plus className=\"h-4 w-4\" /> New collection\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {collections.map((c) => (\n <button\n key={c.id}\n type=\"button\"\n onClick={() => navigateTo(`/collections/${c.id}`)}\n className=\"overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Shapes className=\"h-9 w-9\" />}\n seed={c.id}\n fileId={c.cover?.id}\n alt={c.name}\n className=\"h-28 w-full\"\n />\n <div className=\"p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">{c.name}</h3>\n {c.brand?.name && (\n <p className=\"truncate text-xs text-text-secondary\">{c.brand.name}</p>\n )}\n </div>\n <StatusBadge status={c.status} />\n </div>\n <div className=\"mt-2 flex items-center gap-2 text-xs text-text-secondary\">\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5\">\n {titleCase(c.season)}\n </span>\n {c.publishAt && (\n <span>\n Publishes {formatDate(c.publishAt, { hour: undefined, minute: undefined })}\n </span>\n )}\n </div>\n {c.tags.length > 0 && <TagList tags={c.tags} max={4} className=\"mt-3\" />}\n </div>\n </button>\n ))}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,IAAM,IAA+E;CACnF;EAAE,OAAO;EAAO,OAAO;EAAO;CAC9B;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAY,OAAO;EAAY;CACzC;AAED,SAAgB,IAAsB;CACpC,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAQ,KAAa,EAAsC,MAAM,EAElE,IAAQ,EAAe,EAAE,QAAQ,MAAW,QAAQ,KAAA,IAAY,GAAQ,CAAC,EACzE,IAAc,EAAM,QAAQ,EAAE;AAEpC,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,mBAAmB;GAC7C,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBACrB;;YAVb,CAaE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAe,KAAK,MACnB,kBAAC,UAAD;IAEE,MAAK;IACL,eAAe,EAAU,EAAI,MAAM;IACnC,WAAW,EACT,kEACA,MAAW,EAAI,QACX,kDACA,2DACL;cAEA,EAAI;IACE,EAXF,EAAI,MAWF,CACT;GACE,CAAA,EAEL,EAAM,YACL,kBAAC,GAAD,EAAa,OAAM,wBAAyB,CAAA,GAC1C,EAAM,UACR,kBAAC,GAAD,EAAW,eAAe,KAAK,EAAM,SAAS,EAAI,CAAA,GAChD,EAAY,WAAW,IACzB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAQ,WAAU,aAAc,CAAA;GACtC,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,mBAAmB;IAC7C,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBACrB;;GAEX,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAY,KAAK,MAChB,kBAAC,UAAD;IAEE,MAAK;IACL,eAAe,EAAW,gBAAgB,EAAE,KAAK;IACjD,WAAU;cAJZ,CAME,kBAAC,GAAD;KACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;KACpC,MAAM,EAAE;KACR,QAAQ,EAAE,OAAO;KACjB,KAAK,EAAE;KACP,WAAU;KACV,CAAA,EACF,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBAAsD,EAAE;SAAU,CAAA,EAC/E,EAAE,OAAO,QACR,kBAAC,KAAD;SAAG,WAAU;mBAAwC,EAAE,MAAM;SAAS,CAAA,CAEpE;WACN,kBAAC,GAAD,EAAa,QAAQ,EAAE,QAAU,CAAA,CAC7B;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAU,EAAE,OAAO;QACf,CAAA,EACN,EAAE,aACD,kBAAC,QAAD,EAAA,UAAA,CAAM,cACO,EAAW,EAAE,WAAW;QAAE,MAAM,KAAA;QAAW,QAAQ,KAAA;QAAW,CAAC,CACrE,EAAA,CAAA,CAEL;;MACL,EAAE,KAAK,SAAS,KAAK,kBAAC,GAAD;OAAS,MAAM,EAAE;OAAM,KAAK;OAAG,WAAU;OAAS,CAAA;MACpE;OACC;MAlCF,EAAE,GAkCA,CACT;GACE,CAAA,CAEG"}
1
+ {"version":3,"file":"CollectionsListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/collections/CollectionsListPage.tsx"],"sourcesContent":["/**\n * Collections List Page\n * @module coolandlovely/pages/collections\n *\n * Lists seasonal collections (`cooListCollections`) with status filter.\n */\n\nimport { useState } from 'react';\nimport { Plus, Shapes } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCollections } from '../../hooks';\nimport { titleCase, formatDate } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooCollectionStatus } from '../../types';\n\nconst STATUS_OPTIONS: Array<{ value: CooCollectionStatus | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'LIVE', label: 'Live' },\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'ENDED', label: 'Ended' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nexport function CollectionsListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [status, setStatus] = useState<CooCollectionStatus | 'ALL'>('ALL');\n\n const query = useCollections({ status: status === 'ALL' ? undefined : status });\n const collections = query.data ?? [];\n\n return (\n <PageLayout\n title=\"Collections\"\n description=\"Seasonal drops and curated edits grouped by brand\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/collections/new')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Plus className=\"h-4 w-4\" /> New collection\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n {STATUS_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => setStatus(opt.value)}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n status === opt.value\n ? 'bg-accent-purple-subtle text-text-primary'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading collections…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : collections.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Shapes className=\"h-10 w-10\" />}\n title=\"No collections yet\"\n description=\"Group pieces into a seasonal drop to start a collection.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/collections/new')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n <Plus className=\"h-4 w-4\" /> New collection\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {collections.map((c) => (\n <button\n key={c.id}\n type=\"button\"\n onClick={() => navigateTo(`/collections/${c.id}`)}\n className=\"group overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <div className=\"relative\">\n <Thumbnail\n icon={<Shapes className=\"h-10 w-10\" />}\n seed={c.id}\n fileId={c.cover?.id}\n alt={c.name}\n className=\"aspect-[16/10] w-full\"\n overlay={\n <>\n <div className=\"pointer-events-none absolute inset-0 bg-gradient-to-t from-bg-canvas via-bg-canvas/55 to-transparent\" />\n <div className=\"absolute inset-x-0 bottom-0 flex items-end justify-between gap-2 p-4\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-lg font-semibold text-text-primary\">\n {c.name}\n </h3>\n {c.brand?.name && (\n <p className=\"truncate text-xs text-text-secondary\">{c.brand.name}</p>\n )}\n </div>\n <StatusBadge status={c.status} className=\"shrink-0 shadow-sm\" />\n </div>\n </>\n }\n />\n <span className=\"absolute right-3 top-3 rounded-full border border-border-seam bg-bg-surface/85 px-2.5 py-0.5 text-xs font-medium text-text-primary backdrop-blur-sm\">\n {titleCase(c.season)}\n </span>\n </div>\n {(c.publishAt || c.tags.length > 0) && (\n <div className=\"p-4\">\n {c.publishAt && (\n <p className=\"text-xs text-text-secondary\">\n Publishes {formatDate(c.publishAt, { hour: undefined, minute: undefined })}\n </p>\n )}\n {c.tags.length > 0 && (\n <TagList tags={c.tags} max={4} className={c.publishAt ? 'mt-2' : undefined} />\n )}\n </div>\n )}\n </button>\n ))}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,IAAM,IAA+E;CACnF;EAAE,OAAO;EAAO,OAAO;EAAO;CAC9B;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAY,OAAO;EAAY;CACzC;AAED,SAAgB,IAAsB;CACpC,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAQ,KAAa,EAAsC,MAAM,EAElE,IAAQ,EAAe,EAAE,QAAQ,MAAW,QAAQ,KAAA,IAAY,GAAQ,CAAC,EACzE,IAAc,EAAM,QAAQ,EAAE;AAEpC,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,mBAAmB;GAC7C,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBACrB;;YAVb,CAaE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAe,KAAK,MACnB,kBAAC,UAAD;IAEE,MAAK;IACL,eAAe,EAAU,EAAI,MAAM;IACnC,WAAW,EACT,kEACA,MAAW,EAAI,QACX,8CACA,2DACL;cAEA,EAAI;IACE,EAXF,EAAI,MAWF,CACT;GACE,CAAA,EAEL,EAAM,YACL,kBAAC,GAAD,EAAa,OAAM,wBAAyB,CAAA,GAC1C,EAAM,UACR,kBAAC,GAAD,EAAW,eAAe,KAAK,EAAM,SAAS,EAAI,CAAA,GAChD,EAAY,WAAW,IACzB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAQ,WAAU,aAAc,CAAA;GACtC,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,mBAAmB;IAC7C,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBACrB;;GAEX,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAY,KAAK,MAChB,kBAAC,UAAD;IAEE,MAAK;IACL,eAAe,EAAW,gBAAgB,EAAE,KAAK;IACjD,WAAU;cAJZ,CAME,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,aAAc,CAAA;MACtC,MAAM,EAAE;MACR,QAAQ,EAAE,OAAO;MACjB,KAAK,EAAE;MACP,WAAU;MACV,SACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD,EAAK,WAAU,wGAAyG,CAAA,EACxH,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAE;SACA,CAAA,EACJ,EAAE,OAAO,QACR,kBAAC,KAAD;SAAG,WAAU;mBAAwC,EAAE,MAAM;SAAS,CAAA,CAEpE;WACN,kBAAC,GAAD;QAAa,QAAQ,EAAE;QAAQ,WAAU;QAAuB,CAAA,CAC5D;SACL,EAAA,CAAA;MAEL,CAAA,EACF,kBAAC,QAAD;MAAM,WAAU;gBACb,EAAU,EAAE,OAAO;MACf,CAAA,CACH;SACJ,EAAE,aAAa,EAAE,KAAK,SAAS,MAC/B,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAE,aACD,kBAAC,KAAD;MAAG,WAAU;gBAAb,CAA2C,cAC9B,EAAW,EAAE,WAAW;OAAE,MAAM,KAAA;OAAW,QAAQ,KAAA;OAAW,CAAC,CACxE;SAEL,EAAE,KAAK,SAAS,KACf,kBAAC,GAAD;MAAS,MAAM,EAAE;MAAM,KAAK;MAAG,WAAW,EAAE,YAAY,SAAS,KAAA;MAAa,CAAA,CAE5E;OAED;MA7CF,EAAE,GA6CA,CACT;GACE,CAAA,CAEG"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Discover Page
3
+ * @module coolandlovely/pages/discover
4
+ *
5
+ * A profile-tuned discovery feed computed entirely client-side over the REAL
6
+ * catalogue + social lists (cooListLooks / cooListStyleItems) and the caller's
7
+ * own style profile (cooMyStyleProfile) + follow graph (cooMyFollowing). It only
8
+ * ranks what is actually on the platform against the taste the shopper declared
9
+ * — no fabricated recommendations, no black-box "AI" (that is roadmap). When the
10
+ * shopper has no profile yet, it invites them to build one.
11
+ */
12
+ export declare function DiscoverPage(): import("react").JSX.Element;
13
+ //# sourceMappingURL=DiscoverPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DiscoverPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/discover/DiscoverPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiDH,wBAAgB,YAAY,gCA8O3B"}
@@ -3,8 +3,8 @@ import { PageLayout as t } from "../../components/PageLayout.js";
3
3
  import { ErrorView as n, LoadingView as r } from "../../components/StateViews.js";
4
4
  import { Thumbnail as i } from "../../components/Thumbnail.js";
5
5
  import { useLooks as a, useMyFollowing as o, useMyStyleProfile as s, useStyleItems as c } from "../../hooks/useCoolAndLovelyApi.js";
6
- import "../../hooks/index.js";
7
6
  import { titleCase as l } from "../../utils/formatters.js";
7
+ import "../../hooks/index.js";
8
8
  import { TagList as u } from "../../components/TagList.js";
9
9
  import { EmptyState as d } from "../../components/EmptyState.js";
10
10
  import { useMemo as f } from "react";
@@ -1 +1 @@
1
- {"version":3,"file":"DiscoverPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/discover/DiscoverPage.tsx"],"sourcesContent":["/**\n * Discover Page\n * @module coolandlovely/pages/discover\n *\n * A profile-tuned discovery feed computed entirely client-side over the REAL\n * catalogue + social lists (cooListLooks / cooListStyleItems) and the caller's\n * own style profile (cooMyStyleProfile) + follow graph (cooMyFollowing). It only\n * ranks what is actually on the platform against the taste the shopper declared\n * — no fabricated recommendations, no black-box \"AI\" (that is roadmap). When the\n * shopper has no profile yet, it invites them to build one.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useMemo } from 'react';\nimport { Compass, Sparkles, Heart, ShoppingBag, UserCheck, Users } from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useMyStyleProfile, useLooks, useStyleItems, useMyFollowing } from '../../hooks';\nimport type { CooLook, CooStyleItem } from '../../types';\nimport { titleCase } from '../../utils/formatters';\n\n/** Lower-cased token set used for overlap scoring. */\nfunction tokenSet(values: string[]): Set<string> {\n return new Set(values.map((v) => v.trim().toLowerCase()).filter(Boolean));\n}\n\n/** Count how many of `candidate`'s tokens appear in the taste set. */\nfunction overlap(candidate: string[], taste: Set<string>): number {\n let n = 0;\n for (const c of candidate) {\n if (taste.has(c.trim().toLowerCase())) n += 1;\n }\n return n;\n}\n\ninterface SectionProps {\n title: string;\n icon: ReactNode;\n children: ReactNode;\n sublabel?: string;\n}\n\nconst Section: FC<SectionProps> = ({ title, icon, sublabel, children }) => (\n <section className=\"mt-8\">\n <div className=\"mb-3\">\n <h2 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n {icon} {title}\n </h2>\n {sublabel ? <p className=\"mt-0.5 text-sm text-text-secondary\">{sublabel}</p> : null}\n </div>\n {children}\n </section>\n);\n\nexport function DiscoverPage() {\n const { navigateTo } = useCoolAndLovely();\n const profile = useMyStyleProfile();\n const looks = useLooks({ pagination: { limit: 100, offset: 0 } });\n const items = useStyleItems({ pagination: { limit: 100, offset: 0 } });\n const following = useMyFollowing();\n\n const isLoading = profile.isLoading || looks.isLoading || items.isLoading;\n const isError = looks.isError && items.isError;\n\n const feed = useMemo(() => {\n const p = profile.data;\n const lookRows = looks.data?.items ?? [];\n const itemRows = items.data?.items ?? [];\n const followingOwners = new Set((following.data ?? []).map((f) => f.ownerId));\n\n // Taste = declared style preferences ∪ palette ∪ favourite brands.\n const taste = tokenSet([\n ...(p?.stylePreferences ?? []),\n ...(p?.palette ?? []),\n ...(p?.favouriteBrands ?? []),\n ]);\n const paletteTokens = tokenSet(p?.palette ?? []);\n const brandTokens = tokenSet(p?.favouriteBrands ?? []);\n\n const scoreLook = (l: CooLook): number =>\n overlap(l.tags, taste) * 2 +\n (taste.has(l.occasion.toLowerCase()) ? 1 : 0) +\n l.likeCount * 0.05 +\n l.saveCount * 0.05;\n\n const scoreItem = (it: CooStyleItem): number =>\n overlap(it.tags, taste) * 2 +\n overlap(it.colours, paletteTokens) * 2 +\n (taste.has(it.category.toLowerCase()) ? 1 : 0) +\n (brandTokens.size && it.tags.some((t) => brandTokens.has(t.toLowerCase())) ? 1 : 0);\n\n const hasTaste = taste.size > 0;\n\n // \"Made for you\": when the shopper has taste, rank by match then engagement;\n // otherwise fall back to most-loved looks so the feed is never empty.\n const madeForYou = [...lookRows]\n .sort((a, b) =>\n hasTaste\n ? scoreLook(b) - scoreLook(a)\n : b.likeCount + b.saveCount - (a.likeCount + a.saveCount)\n )\n .slice(0, 8);\n\n const inYourPalette = [...itemRows]\n .filter((it) => (hasTaste ? scoreItem(it) > 0 : true))\n .sort((a, b) => scoreItem(b) - scoreItem(a))\n .slice(0, 8);\n\n const fromFollowing = lookRows\n .filter((l) => followingOwners.has(l.authorId))\n .sort((a, b) => b.likeCount + b.saveCount - (a.likeCount + a.saveCount))\n .slice(0, 8);\n\n return {\n hasProfile: Boolean(p),\n hasTaste,\n madeForYou,\n inYourPalette,\n fromFollowing,\n followingProfiles: following.data ?? [],\n };\n }, [profile.data, looks.data, items.data, following.data]);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Discover\">\n <LoadingView label=\"Curating your feed…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Discover\">\n <ErrorView\n onRetry={() => {\n void looks.refetch();\n void items.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Discover\" description=\"Looks and pieces tuned to your taste\" hero>\n <PagePurpose className=\"mb-6\">\n Your personalised feed, computed live from your style profile against the pieces and looks on\n the platform — the closer a piece matches the aesthetics, palette and brands you follow, the\n higher it ranks. Nothing here is fabricated.\n </PagePurpose>\n\n {!feed.hasProfile ? (\n <EmphasisPanel className=\"mb-8\">\n <div className=\"flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Build your style profile</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Tell us your aesthetics, palette and favourite brands and this feed tunes itself to you.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('/profile')}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <Sparkles className=\"h-4 w-4\" /> Create profile\n </button>\n </div>\n </EmphasisPanel>\n ) : null}\n\n <Section\n title=\"Made for you\"\n icon={<Compass className=\"h-5 w-5\" />}\n sublabel={feed.hasTaste ? 'Ranked to match your style profile' : 'Most-loved looks on the platform'}\n >\n {feed.madeForYou.length === 0 ? (\n <EmptyState\n title=\"No looks yet\"\n description=\"Once looks are published they will appear here, tuned to your taste.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.madeForYou.map((look) => (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{titleCase(look.occasion)}</p>\n <span className=\"mt-2 inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Heart className=\"h-3.5 w-3.5\" /> {look.likeCount}\n </span>\n </div>\n </button>\n ))}\n </div>\n )}\n </Section>\n\n {feed.inYourPalette.length > 0 ? (\n <Section\n title=\"In your palette\"\n icon={<ShoppingBag className=\"h-5 w-5\" />}\n sublabel=\"Pieces that match your colours, categories and tags\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.inYourPalette.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<ShoppingBag className=\"h-6 w-6\" />}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{titleCase(item.category)}</p>\n <TagList tags={item.colours.slice(0, 3)} className=\"mt-2\" />\n </div>\n </button>\n ))}\n </div>\n </Section>\n ) : null}\n\n <Section\n title=\"From people you follow\"\n icon={<UserCheck className=\"h-5 w-5\" />}\n sublabel={\n feed.followingProfiles.length === 0\n ? 'Follow creators and shoppers to see their looks here'\n : `You follow ${feed.followingProfiles.length} ${feed.followingProfiles.length === 1 ? 'person' : 'people'}`\n }\n >\n {feed.followingProfiles.length === 0 ? (\n <EmptyState\n title=\"You are not following anyone yet\"\n description=\"Open a look or a style profile and tap Follow to build a feed from people whose taste you love.\"\n icon={<Users className=\"h-8 w-8\" />}\n />\n ) : feed.fromFollowing.length === 0 ? (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n The people you follow have not published looks visible to you yet.\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.fromFollowing.map((look) => (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{titleCase(look.occasion)}</p>\n </div>\n </button>\n ))}\n </div>\n )}\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AA2BA,SAAS,EAAS,GAA+B;AAC/C,QAAO,IAAI,IAAI,EAAO,KAAK,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,QAAQ,CAAC;;AAI3E,SAAS,EAAQ,GAAqB,GAA4B;CAChE,IAAI,IAAI;AACR,MAAK,IAAM,KAAK,EACd,CAAI,EAAM,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC,KAAE,KAAK;AAE9C,QAAO;;AAUT,IAAM,KAA6B,EAAE,UAAO,SAAM,aAAU,kBAC1D,kBAAC,WAAD;CAAS,WAAU;WAAnB,CACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,MAAD;GAAI,WAAU;aAAd;IACG;IAAK;IAAE;IACL;MACJ,IAAW,kBAAC,KAAD;GAAG,WAAU;aAAsC;GAAa,CAAA,GAAG,KAC3E;KACL,EACO;;AAGZ,SAAgB,IAAe;CAC7B,IAAM,EAAE,kBAAe,GAAkB,EACnC,IAAU,GAAmB,EAC7B,IAAQ,EAAS,EAAE,YAAY;EAAE,OAAO;EAAK,QAAQ;EAAG,EAAE,CAAC,EAC3D,IAAQ,EAAc,EAAE,YAAY;EAAE,OAAO;EAAK,QAAQ;EAAG,EAAE,CAAC,EAChE,IAAY,GAAgB,EAE5B,IAAY,EAAQ,aAAa,EAAM,aAAa,EAAM,WAC1D,IAAU,EAAM,WAAW,EAAM,SAEjC,IAAO,QAAc;EACzB,IAAM,IAAI,EAAQ,MACZ,IAAW,EAAM,MAAM,SAAS,EAAE,EAClC,IAAW,EAAM,MAAM,SAAS,EAAE,EAClC,IAAkB,IAAI,KAAK,EAAU,QAAQ,EAAE,EAAE,KAAK,MAAM,EAAE,QAAQ,CAAC,EAGvE,IAAQ,EAAS;GACrB,GAAI,GAAG,oBAAoB,EAAE;GAC7B,GAAI,GAAG,WAAW,EAAE;GACpB,GAAI,GAAG,mBAAmB,EAAE;GAC7B,CAAC,EACI,IAAgB,EAAS,GAAG,WAAW,EAAE,CAAC,EAC1C,IAAc,EAAS,GAAG,mBAAmB,EAAE,CAAC,EAEhD,KAAa,MACjB,EAAQ,EAAE,MAAM,EAAM,GAAG,IACxB,KAAM,IAAI,EAAE,SAAS,aAAa,CAAC,GACpC,EAAE,YAAY,MACd,EAAE,YAAY,KAEV,KAAa,MACjB,EAAQ,EAAG,MAAM,EAAM,GAAG,IAC1B,EAAQ,EAAG,SAAS,EAAc,GAAG,IACpC,KAAM,IAAI,EAAG,SAAS,aAAa,CAAC,IACpC,EAAY,QAAQ,EAAG,KAAK,MAAM,MAAM,EAAY,IAAI,EAAE,aAAa,CAAC,CAAC,GAAG,IAAI,IAE7E,IAAW,EAAM,OAAO,GAIxB,IAAa,CAAC,GAAG,EAAS,CAC7B,MAAM,GAAG,MACR,IACI,EAAU,EAAE,GAAG,EAAU,EAAE,GAC3B,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,WAClD,CACA,MAAM,GAAG,EAAE,EAER,IAAgB,CAAC,GAAG,EAAS,CAChC,QAAQ,MAAQ,IAAW,EAAU,EAAG,GAAG,IAAI,GAAM,CACrD,MAAM,GAAG,MAAM,EAAU,EAAE,GAAG,EAAU,EAAE,CAAC,CAC3C,MAAM,GAAG,EAAE,EAER,IAAgB,EACnB,QAAQ,MAAM,EAAgB,IAAI,EAAE,SAAS,CAAC,CAC9C,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,CACvE,MAAM,GAAG,EAAE;AAEd,SAAO;GACL,YAAY,EAAQ;GACpB;GACA;GACA;GACA;GACA,mBAAmB,EAAU,QAAQ,EAAE;GACxC;IACA;EAAC,EAAQ;EAAM,EAAM;EAAM,EAAM;EAAM,EAAU;EAAK,CAAC;AAuB1D,QArBI,IAEA,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAa,OAAM,uBAAwB,CAAA;EAChC,CAAA,GAIb,IAEA,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EACE,eAAe;AAER,GADA,EAAM,SAAS,EACf,EAAM,SAAS;KAEtB,CAAA;EACS,CAAA,GAKf,kBAAC,GAAD;EAAY,OAAM;EAAW,aAAY;EAAuC,MAAA;YAAhF;GACE,kBAAC,GAAD;IAAa,WAAU;cAAO;IAIhB,CAAA;GAEZ,EAAK,aAkBH,OAjBF,kBAAC,GAAD;IAAe,WAAU;cACvB,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAA6B,CAAA,EACrF,kBAAC,KAAD;MAAG,WAAU;gBAAmC;MAE5C,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,WAAW;MACrC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA,EAAA,kBACzB;QACL;;IACQ,CAAA;GAGlB,kBAAC,GAAD;IACE,OAAM;IACN,MAAM,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA;IACrC,UAAU,EAAK,WAAW,uCAAuC;cAEhE,EAAK,WAAW,WAAW,IAC1B,kBAAC,GAAD;KACE,OAAM;KACN,aAAY;KACZ,CAAA,GAEF,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAK,WAAW,KAAK,MACpB,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAW,UAAU,EAAK,KAAK;MAC9C,WAAU;gBAJZ,CAME,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;OACtC,MAAM,EAAK;OACX,QAAQ,EAAK,OAAO;OACpB,KAAK,EAAK;OACV,WAAU;OACV,CAAA,EACF,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,KAAD;SAAG,WAAU;mBAAkD,EAAK;SAAU,CAAA;QAC9E,kBAAC,KAAD;SAAG,WAAU;mBAAsC,EAAU,EAAK,SAAS;SAAK,CAAA;QAChF,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACE,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA;;UAAE,EAAK;UACnC;;QACH;SACC;QAnBF,EAAK,GAmBH,CACT;KACE,CAAA;IAEA,CAAA;GAET,EAAK,cAAc,SAAS,IAC3B,kBAAC,GAAD;IACE,OAAM;IACN,MAAM,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;IACzC,UAAS;cAET,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAK,cAAc,KAAK,MACvB,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAW,UAAU,EAAK,KAAK;MAC9C,WAAU;gBAJZ,CAME,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;OACzC,MAAM,EAAK;OACX,QAAQ,EAAK,OAAO;OACpB,KAAK,EAAK;OACV,WAAU;OACV,CAAA,EACF,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,KAAD;SAAG,WAAU;mBAAkD,EAAK;SAAS,CAAA;QAC7E,kBAAC,KAAD;SAAG,WAAU;mBAAsC,EAAU,EAAK,SAAS;SAAK,CAAA;QAChF,kBAAC,GAAD;SAAS,MAAM,EAAK,QAAQ,MAAM,GAAG,EAAE;SAAE,WAAU;SAAS,CAAA;QACxD;SACC;QAjBF,EAAK,GAiBH,CACT;KACE,CAAA;IACE,CAAA,GACR;GAEJ,kBAAC,GAAD;IACE,OAAM;IACN,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;IACvC,UACE,EAAK,kBAAkB,WAAW,IAC9B,yDACA,cAAc,EAAK,kBAAkB,OAAO,GAAG,EAAK,kBAAkB,WAAW,IAAI,WAAW;cAGrG,EAAK,kBAAkB,WAAW,IACjC,kBAAC,GAAD;KACE,OAAM;KACN,aAAY;KACZ,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,CAAA,GACA,EAAK,cAAc,WAAW,IAChC,kBAAC,OAAD;KAAK,WAAU;eAAqF;KAE9F,CAAA,GAEN,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAK,cAAc,KAAK,MACvB,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAW,UAAU,EAAK,KAAK;MAC9C,WAAU;gBAJZ,CAME,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;OACtC,MAAM,EAAK;OACX,QAAQ,EAAK,OAAO;OACpB,KAAK,EAAK;OACV,WAAU;OACV,CAAA,EACF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAkD,EAAK;QAAU,CAAA,EAC9E,kBAAC,KAAD;QAAG,WAAU;kBAAsC,EAAU,EAAK,SAAS;QAAK,CAAA,CAC5E;SACC;QAhBF,EAAK,GAgBH,CACT;KACE,CAAA;IAEA,CAAA;GACC"}
1
+ {"version":3,"file":"DiscoverPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/discover/DiscoverPage.tsx"],"sourcesContent":["/**\n * Discover Page\n * @module coolandlovely/pages/discover\n *\n * A profile-tuned discovery feed computed entirely client-side over the REAL\n * catalogue + social lists (cooListLooks / cooListStyleItems) and the caller's\n * own style profile (cooMyStyleProfile) + follow graph (cooMyFollowing). It only\n * ranks what is actually on the platform against the taste the shopper declared\n * — no fabricated recommendations, no black-box \"AI\" (that is roadmap). When the\n * shopper has no profile yet, it invites them to build one.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useMemo } from 'react';\nimport { Compass, Sparkles, Heart, ShoppingBag, UserCheck, Users } from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useMyStyleProfile, useLooks, useStyleItems, useMyFollowing } from '../../hooks';\nimport type { CooLook, CooStyleItem } from '../../types';\nimport { titleCase } from '../../utils/formatters';\n\n/** Lower-cased token set used for overlap scoring. */\nfunction tokenSet(values: string[]): Set<string> {\n return new Set(values.map((v) => v.trim().toLowerCase()).filter(Boolean));\n}\n\n/** Count how many of `candidate`'s tokens appear in the taste set. */\nfunction overlap(candidate: string[], taste: Set<string>): number {\n let n = 0;\n for (const c of candidate) {\n if (taste.has(c.trim().toLowerCase())) n += 1;\n }\n return n;\n}\n\ninterface SectionProps {\n title: string;\n icon: ReactNode;\n children: ReactNode;\n sublabel?: string;\n}\n\nconst Section: FC<SectionProps> = ({ title, icon, sublabel, children }) => (\n <section className=\"mt-8\">\n <div className=\"mb-3\">\n <h2 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n {icon} {title}\n </h2>\n {sublabel ? <p className=\"mt-0.5 text-sm text-text-secondary\">{sublabel}</p> : null}\n </div>\n {children}\n </section>\n);\n\nexport function DiscoverPage() {\n const { navigateTo } = useCoolAndLovely();\n const profile = useMyStyleProfile();\n const looks = useLooks({ pagination: { limit: 100, offset: 0 } });\n const items = useStyleItems({ pagination: { limit: 100, offset: 0 } });\n const following = useMyFollowing();\n\n const isLoading = profile.isLoading || looks.isLoading || items.isLoading;\n const isError = looks.isError && items.isError;\n\n const feed = useMemo(() => {\n const p = profile.data;\n const lookRows = looks.data?.items ?? [];\n const itemRows = items.data?.items ?? [];\n const followingOwners = new Set((following.data ?? []).map((f) => f.ownerId));\n\n // Taste = declared style preferences ∪ palette ∪ favourite brands.\n const taste = tokenSet([\n ...(p?.stylePreferences ?? []),\n ...(p?.palette ?? []),\n ...(p?.favouriteBrands ?? []),\n ]);\n const paletteTokens = tokenSet(p?.palette ?? []);\n const brandTokens = tokenSet(p?.favouriteBrands ?? []);\n\n const scoreLook = (l: CooLook): number =>\n overlap(l.tags, taste) * 2 +\n (taste.has(l.occasion.toLowerCase()) ? 1 : 0) +\n l.likeCount * 0.05 +\n l.saveCount * 0.05;\n\n const scoreItem = (it: CooStyleItem): number =>\n overlap(it.tags, taste) * 2 +\n overlap(it.colours, paletteTokens) * 2 +\n (taste.has(it.category.toLowerCase()) ? 1 : 0) +\n (brandTokens.size && it.tags.some((t) => brandTokens.has(t.toLowerCase())) ? 1 : 0);\n\n const hasTaste = taste.size > 0;\n\n // \"Made for you\": when the shopper has taste, rank by match then engagement;\n // otherwise fall back to most-loved looks so the feed is never empty.\n const madeForYou = [...lookRows]\n .sort((a, b) =>\n hasTaste\n ? scoreLook(b) - scoreLook(a)\n : b.likeCount + b.saveCount - (a.likeCount + a.saveCount)\n )\n .slice(0, 8);\n\n const inYourPalette = [...itemRows]\n .filter((it) => (hasTaste ? scoreItem(it) > 0 : true))\n .sort((a, b) => scoreItem(b) - scoreItem(a))\n .slice(0, 8);\n\n const fromFollowing = lookRows\n .filter((l) => followingOwners.has(l.authorId))\n .sort((a, b) => b.likeCount + b.saveCount - (a.likeCount + a.saveCount))\n .slice(0, 8);\n\n return {\n hasProfile: Boolean(p),\n hasTaste,\n madeForYou,\n inYourPalette,\n fromFollowing,\n followingProfiles: following.data ?? [],\n };\n }, [profile.data, looks.data, items.data, following.data]);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Discover\">\n <LoadingView label=\"Curating your feed…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Discover\">\n <ErrorView\n onRetry={() => {\n void looks.refetch();\n void items.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Discover\" description=\"Looks and pieces tuned to your taste\" hero>\n <PagePurpose className=\"mb-6\">\n Your personalised feed, computed live from your style profile against the pieces and looks\n on the platform — the closer a piece matches the aesthetics, palette and brands you follow,\n the higher it ranks. Nothing here is fabricated.\n </PagePurpose>\n\n {!feed.hasProfile ? (\n <EmphasisPanel className=\"mb-8\">\n <div className=\"flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Build your style profile</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Tell us your aesthetics, palette and favourite brands and this feed tunes itself to\n you.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('/profile')}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <Sparkles className=\"h-4 w-4\" /> Create profile\n </button>\n </div>\n </EmphasisPanel>\n ) : null}\n\n <Section\n title=\"Made for you\"\n icon={<Compass className=\"h-5 w-5\" />}\n sublabel={\n feed.hasTaste ? 'Ranked to match your style profile' : 'Most-loved looks on the platform'\n }\n >\n {feed.madeForYou.length === 0 ? (\n <EmptyState\n title=\"No looks yet\"\n description=\"Once looks are published they will appear here, tuned to your taste.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.madeForYou.map((look) => (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{titleCase(look.occasion)}</p>\n <span className=\"mt-2 inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Heart className=\"h-3.5 w-3.5\" /> {look.likeCount}\n </span>\n </div>\n </button>\n ))}\n </div>\n )}\n </Section>\n\n {feed.inYourPalette.length > 0 ? (\n <Section\n title=\"In your palette\"\n icon={<ShoppingBag className=\"h-5 w-5\" />}\n sublabel=\"Pieces that match your colours, categories and tags\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.inYourPalette.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<ShoppingBag className=\"h-6 w-6\" />}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{titleCase(item.category)}</p>\n <TagList tags={item.colours.slice(0, 3)} className=\"mt-2\" />\n </div>\n </button>\n ))}\n </div>\n </Section>\n ) : null}\n\n <Section\n title=\"From people you follow\"\n icon={<UserCheck className=\"h-5 w-5\" />}\n sublabel={\n feed.followingProfiles.length === 0\n ? 'Follow creators and shoppers to see their looks here'\n : `You follow ${feed.followingProfiles.length} ${feed.followingProfiles.length === 1 ? 'person' : 'people'}`\n }\n >\n {feed.followingProfiles.length === 0 ? (\n <EmptyState\n title=\"You are not following anyone yet\"\n description=\"Open a look or a style profile and tap Follow to build a feed from people whose taste you love.\"\n icon={<Users className=\"h-8 w-8\" />}\n />\n ) : feed.fromFollowing.length === 0 ? (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n The people you follow have not published looks visible to you yet.\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.fromFollowing.map((look) => (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{titleCase(look.occasion)}</p>\n </div>\n </button>\n ))}\n </div>\n )}\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AA2BA,SAAS,EAAS,GAA+B;AAC/C,QAAO,IAAI,IAAI,EAAO,KAAK,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,QAAQ,CAAC;;AAI3E,SAAS,EAAQ,GAAqB,GAA4B;CAChE,IAAI,IAAI;AACR,MAAK,IAAM,KAAK,EACd,CAAI,EAAM,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC,KAAE,KAAK;AAE9C,QAAO;;AAUT,IAAM,KAA6B,EAAE,UAAO,SAAM,aAAU,kBAC1D,kBAAC,WAAD;CAAS,WAAU;WAAnB,CACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,MAAD;GAAI,WAAU;aAAd;IACG;IAAK;IAAE;IACL;MACJ,IAAW,kBAAC,KAAD;GAAG,WAAU;aAAsC;GAAa,CAAA,GAAG,KAC3E;KACL,EACO;;AAGZ,SAAgB,IAAe;CAC7B,IAAM,EAAE,kBAAe,GAAkB,EACnC,IAAU,GAAmB,EAC7B,IAAQ,EAAS,EAAE,YAAY;EAAE,OAAO;EAAK,QAAQ;EAAG,EAAE,CAAC,EAC3D,IAAQ,EAAc,EAAE,YAAY;EAAE,OAAO;EAAK,QAAQ;EAAG,EAAE,CAAC,EAChE,IAAY,GAAgB,EAE5B,IAAY,EAAQ,aAAa,EAAM,aAAa,EAAM,WAC1D,IAAU,EAAM,WAAW,EAAM,SAEjC,IAAO,QAAc;EACzB,IAAM,IAAI,EAAQ,MACZ,IAAW,EAAM,MAAM,SAAS,EAAE,EAClC,IAAW,EAAM,MAAM,SAAS,EAAE,EAClC,IAAkB,IAAI,KAAK,EAAU,QAAQ,EAAE,EAAE,KAAK,MAAM,EAAE,QAAQ,CAAC,EAGvE,IAAQ,EAAS;GACrB,GAAI,GAAG,oBAAoB,EAAE;GAC7B,GAAI,GAAG,WAAW,EAAE;GACpB,GAAI,GAAG,mBAAmB,EAAE;GAC7B,CAAC,EACI,IAAgB,EAAS,GAAG,WAAW,EAAE,CAAC,EAC1C,IAAc,EAAS,GAAG,mBAAmB,EAAE,CAAC,EAEhD,KAAa,MACjB,EAAQ,EAAE,MAAM,EAAM,GAAG,IACxB,KAAM,IAAI,EAAE,SAAS,aAAa,CAAC,GACpC,EAAE,YAAY,MACd,EAAE,YAAY,KAEV,KAAa,MACjB,EAAQ,EAAG,MAAM,EAAM,GAAG,IAC1B,EAAQ,EAAG,SAAS,EAAc,GAAG,IACpC,KAAM,IAAI,EAAG,SAAS,aAAa,CAAC,IACpC,EAAY,QAAQ,EAAG,KAAK,MAAM,MAAM,EAAY,IAAI,EAAE,aAAa,CAAC,CAAC,GAAG,IAAI,IAE7E,IAAW,EAAM,OAAO,GAIxB,IAAa,CAAC,GAAG,EAAS,CAC7B,MAAM,GAAG,MACR,IACI,EAAU,EAAE,GAAG,EAAU,EAAE,GAC3B,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,WAClD,CACA,MAAM,GAAG,EAAE,EAER,IAAgB,CAAC,GAAG,EAAS,CAChC,QAAQ,MAAQ,IAAW,EAAU,EAAG,GAAG,IAAI,GAAM,CACrD,MAAM,GAAG,MAAM,EAAU,EAAE,GAAG,EAAU,EAAE,CAAC,CAC3C,MAAM,GAAG,EAAE,EAER,IAAgB,EACnB,QAAQ,MAAM,EAAgB,IAAI,EAAE,SAAS,CAAC,CAC9C,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,CACvE,MAAM,GAAG,EAAE;AAEd,SAAO;GACL,YAAY,EAAQ;GACpB;GACA;GACA;GACA;GACA,mBAAmB,EAAU,QAAQ,EAAE;GACxC;IACA;EAAC,EAAQ;EAAM,EAAM;EAAM,EAAM;EAAM,EAAU;EAAK,CAAC;AAuB1D,QArBI,IAEA,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAa,OAAM,uBAAwB,CAAA;EAChC,CAAA,GAIb,IAEA,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EACE,eAAe;AAER,GADA,EAAM,SAAS,EACf,EAAM,SAAS;KAEtB,CAAA;EACS,CAAA,GAKf,kBAAC,GAAD;EAAY,OAAM;EAAW,aAAY;EAAuC,MAAA;YAAhF;GACE,kBAAC,GAAD;IAAa,WAAU;cAAO;IAIhB,CAAA;GAEZ,EAAK,aAmBH,OAlBF,kBAAC,GAAD;IAAe,WAAU;cACvB,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAA6B,CAAA,EACrF,kBAAC,KAAD;MAAG,WAAU;gBAAmC;MAG5C,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,WAAW;MACrC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA,EAAA,kBACzB;QACL;;IACQ,CAAA;GAGlB,kBAAC,GAAD;IACE,OAAM;IACN,MAAM,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA;IACrC,UACE,EAAK,WAAW,uCAAuC;cAGxD,EAAK,WAAW,WAAW,IAC1B,kBAAC,GAAD;KACE,OAAM;KACN,aAAY;KACZ,CAAA,GAEF,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAK,WAAW,KAAK,MACpB,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAW,UAAU,EAAK,KAAK;MAC9C,WAAU;gBAJZ,CAME,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;OACtC,MAAM,EAAK;OACX,QAAQ,EAAK,OAAO;OACpB,KAAK,EAAK;OACV,WAAU;OACV,CAAA,EACF,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,KAAD;SAAG,WAAU;mBAAkD,EAAK;SAAU,CAAA;QAC9E,kBAAC,KAAD;SAAG,WAAU;mBAAsC,EAAU,EAAK,SAAS;SAAK,CAAA;QAChF,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACE,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA;;UAAE,EAAK;UACnC;;QACH;SACC;QAnBF,EAAK,GAmBH,CACT;KACE,CAAA;IAEA,CAAA;GAET,EAAK,cAAc,SAAS,IAC3B,kBAAC,GAAD;IACE,OAAM;IACN,MAAM,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;IACzC,UAAS;cAET,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAK,cAAc,KAAK,MACvB,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAW,UAAU,EAAK,KAAK;MAC9C,WAAU;gBAJZ,CAME,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;OACzC,MAAM,EAAK;OACX,QAAQ,EAAK,OAAO;OACpB,KAAK,EAAK;OACV,WAAU;OACV,CAAA,EACF,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,KAAD;SAAG,WAAU;mBAAkD,EAAK;SAAS,CAAA;QAC7E,kBAAC,KAAD;SAAG,WAAU;mBAAsC,EAAU,EAAK,SAAS;SAAK,CAAA;QAChF,kBAAC,GAAD;SAAS,MAAM,EAAK,QAAQ,MAAM,GAAG,EAAE;SAAE,WAAU;SAAS,CAAA;QACxD;SACC;QAjBF,EAAK,GAiBH,CACT;KACE,CAAA;IACE,CAAA,GACR;GAEJ,kBAAC,GAAD;IACE,OAAM;IACN,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;IACvC,UACE,EAAK,kBAAkB,WAAW,IAC9B,yDACA,cAAc,EAAK,kBAAkB,OAAO,GAAG,EAAK,kBAAkB,WAAW,IAAI,WAAW;cAGrG,EAAK,kBAAkB,WAAW,IACjC,kBAAC,GAAD;KACE,OAAM;KACN,aAAY;KACZ,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,CAAA,GACA,EAAK,cAAc,WAAW,IAChC,kBAAC,OAAD;KAAK,WAAU;eAAqF;KAE9F,CAAA,GAEN,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAK,cAAc,KAAK,MACvB,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAW,UAAU,EAAK,KAAK;MAC9C,WAAU;gBAJZ,CAME,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;OACtC,MAAM,EAAK;OACX,QAAQ,EAAK,OAAO;OACpB,KAAK,EAAK;OACV,WAAU;OACV,CAAA,EACF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAkD,EAAK;QAAU,CAAA,EAC9E,kBAAC,KAAD;QAAG,WAAU;kBAAsC,EAAU,EAAK,SAAS;QAAK,CAAA,CAC5E;SACC;QAhBF,EAAK,GAgBH,CACT;KACE,CAAA;IAEA,CAAA;GACC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Style Item Detail Page
3
+ * @module coolandlovely/pages/items
4
+ *
5
+ * Renders a single catalogue piece (`cooStyleItem`) with edit + archive
6
+ * (`cooArchiveStyleItem`) actions.
7
+ */
8
+ export declare function StyleItemDetailPage(): import("react").JSX.Element;
9
+ //# sourceMappingURL=StyleItemDetailPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StyleItemDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/items/StyleItemDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkBH,wBAAgB,mBAAmB,gCAyPlC"}