@burdenoff/microfe-coolandlovely 2026.706.1 → 2026.706.2

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 (66) hide show
  1. package/dist/coolandlovely/CoolAndLovelyRoutes.js +14 -6
  2. package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
  3. package/dist/coolandlovely/components/ActorName.js +29 -0
  4. package/dist/coolandlovely/components/ActorName.js.map +1 -0
  5. package/dist/coolandlovely/components/AddToLookbookButton.js +81 -0
  6. package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -0
  7. package/dist/coolandlovely/components/Comments.js +109 -0
  8. package/dist/coolandlovely/components/Comments.js.map +1 -0
  9. package/dist/coolandlovely/components/Field.js +22 -2
  10. package/dist/coolandlovely/components/Field.js.map +1 -1
  11. package/dist/coolandlovely/components/FileImage.js +17 -0
  12. package/dist/coolandlovely/components/FileImage.js.map +1 -0
  13. package/dist/coolandlovely/components/FollowButton.js +24 -0
  14. package/dist/coolandlovely/components/FollowButton.js.map +1 -0
  15. package/dist/coolandlovely/components/ImageUploadField.js +71 -0
  16. package/dist/coolandlovely/components/ImageUploadField.js.map +1 -0
  17. package/dist/coolandlovely/components/Thumbnail.js +20 -13
  18. package/dist/coolandlovely/components/Thumbnail.js.map +1 -1
  19. package/dist/coolandlovely/hooks/index.js +2 -0
  20. package/dist/coolandlovely/hooks/useComments.js +68 -0
  21. package/dist/coolandlovely/hooks/useComments.js.map +1 -0
  22. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +74 -4
  23. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
  24. package/dist/coolandlovely/hooks/useFiles.js +94 -0
  25. package/dist/coolandlovely/hooks/useFiles.js.map +1 -0
  26. package/dist/coolandlovely/pages/HomePage.js +105 -87
  27. package/dist/coolandlovely/pages/HomePage.js.map +1 -1
  28. package/dist/coolandlovely/pages/brands/BrandDetailPage.js +144 -122
  29. package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
  30. package/dist/coolandlovely/pages/brands/BrandFormPage.js +128 -90
  31. package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -1
  32. package/dist/coolandlovely/pages/brands/BrandsListPage.js +2 -0
  33. package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
  34. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +5 -1
  35. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
  36. package/dist/coolandlovely/pages/collections/CollectionFormPage.js +117 -102
  37. package/dist/coolandlovely/pages/collections/CollectionFormPage.js.map +1 -1
  38. package/dist/coolandlovely/pages/collections/CollectionsListPage.js +2 -0
  39. package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
  40. package/dist/coolandlovely/pages/discover/DiscoverPage.js +223 -0
  41. package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -0
  42. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +99 -95
  43. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
  44. package/dist/coolandlovely/pages/items/StyleItemFormPage.js +144 -130
  45. package/dist/coolandlovely/pages/items/StyleItemFormPage.js.map +1 -1
  46. package/dist/coolandlovely/pages/items/StyleItemsListPage.js +2 -0
  47. package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
  48. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +190 -99
  49. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
  50. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +81 -68
  51. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
  52. package/dist/coolandlovely/pages/looks/LookDetailPage.js +195 -155
  53. package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
  54. package/dist/coolandlovely/pages/looks/LookFormPage.js +127 -88
  55. package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
  56. package/dist/coolandlovely/pages/looks/LooksListPage.js +2 -0
  57. package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
  58. package/dist/coolandlovely/pages/profile/StyleProfilePage.js +169 -101
  59. package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
  60. package/dist/coolandlovely/pages/trends/TrendsPage.js +249 -0
  61. package/dist/coolandlovely/pages/trends/TrendsPage.js.map +1 -0
  62. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +88 -76
  63. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -1
  64. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +2 -0
  65. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
  66. package/package.json +1 -1
@@ -0,0 +1,249 @@
1
+ import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
2
+ import { cn as t } from "../../utils/cn.js";
3
+ import { PageLayout as n } from "../../components/PageLayout.js";
4
+ import { MetricsCard as r } from "../../components/MetricsCard.js";
5
+ import { ErrorView as i, LoadingView as a } from "../../components/StateViews.js";
6
+ import { useBrands as o, useLooks as s, useStyleItems as c } from "../../hooks/useCoolAndLovelyApi.js";
7
+ import "../../hooks/index.js";
8
+ import { titleCase as l } from "../../utils/formatters.js";
9
+ import { useMemo as u } from "react";
10
+ import { CalendarHeart as d, Heart as f, Palette as p, Shapes as m, Shirt as h, Sparkles as g, Store as _, TrendingUp as v } from "lucide-react";
11
+ import { jsx as y, jsxs as b } from "react/jsx-runtime";
12
+ import { EmphasisPanel as x, GlassCard as S, PagePurpose as C } from "@burdenoff/fe-libs/ui";
13
+ //#region src/coolandlovely/pages/trends/TrendsPage.tsx
14
+ function w(e, t = 8) {
15
+ return [...e.entries()].map(([e, t]) => ({
16
+ label: e,
17
+ value: t
18
+ })).sort((e, t) => t.value - e.value).slice(0, t);
19
+ }
20
+ var T = ({ title: e, icon: n, items: r, unit: i, emptyLabel: a, className: o }) => {
21
+ let s = r.reduce((e, t) => Math.max(e, t.value), 0) || 1;
22
+ return /* @__PURE__ */ b(S, {
23
+ treatment: "plain",
24
+ className: t("p-5", o),
25
+ children: [/* @__PURE__ */ b("h3", {
26
+ className: "mb-4 flex items-center gap-2 text-base font-semibold text-text-primary",
27
+ children: [
28
+ n,
29
+ " ",
30
+ e
31
+ ]
32
+ }), r.length === 0 ? /* @__PURE__ */ y("p", {
33
+ className: "text-sm text-text-secondary",
34
+ children: a
35
+ }) : /* @__PURE__ */ y("ul", {
36
+ className: "space-y-3",
37
+ children: r.map((e) => /* @__PURE__ */ b("li", { children: [/* @__PURE__ */ b("div", {
38
+ className: "mb-1 flex items-center justify-between gap-2 text-sm",
39
+ children: [/* @__PURE__ */ y("span", {
40
+ className: "truncate text-text-primary",
41
+ children: e.label
42
+ }), /* @__PURE__ */ b("span", {
43
+ className: "shrink-0 tabular-nums text-text-secondary",
44
+ children: [
45
+ e.value.toLocaleString(),
46
+ " ",
47
+ i
48
+ ]
49
+ })]
50
+ }), /* @__PURE__ */ y("div", {
51
+ className: "h-2 w-full overflow-hidden rounded-full bg-bg-sunken",
52
+ role: "img",
53
+ "aria-label": `${e.label}: ${e.value} ${i}`,
54
+ children: /* @__PURE__ */ y("div", {
55
+ className: "h-full rounded-full bg-action-primary-bg",
56
+ style: { width: `${Math.max(4, Math.round(e.value / s * 100))}%` }
57
+ })
58
+ })] }, e.label))
59
+ })]
60
+ });
61
+ };
62
+ function E() {
63
+ e();
64
+ let t = o({ pagination: {
65
+ limit: 100,
66
+ offset: 0
67
+ } }), S = c({ pagination: {
68
+ limit: 100,
69
+ offset: 0
70
+ } }), E = s({ pagination: {
71
+ limit: 100,
72
+ offset: 0
73
+ } }), D = t.isLoading || S.isLoading || E.isLoading, O = t.isError && S.isError && E.isError, k = u(() => {
74
+ let e = t.data?.items ?? [], n = S.data?.items ?? [], r = E.data?.items ?? [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map();
75
+ for (let e of n) {
76
+ i.set(l(e.category), (i.get(l(e.category)) ?? 0) + 1);
77
+ for (let t of e.colours) {
78
+ let e = l(t);
79
+ a.set(e, (a.get(e) ?? 0) + 1);
80
+ }
81
+ }
82
+ let o = /* @__PURE__ */ new Map();
83
+ for (let t of e) for (let e of t.aesthetics) {
84
+ let t = l(e);
85
+ o.set(t, (o.get(t) ?? 0) + 1);
86
+ }
87
+ let s = /* @__PURE__ */ new Map(), c = 0, u = 0;
88
+ for (let e of r) {
89
+ let t = e.likeCount + e.saveCount, n = l(e.occasion);
90
+ s.set(n, (s.get(n) ?? 0) + t), c += e.likeCount, u += e.saveCount;
91
+ }
92
+ let d = [...r].sort((e, t) => t.likeCount + t.saveCount - (e.likeCount + e.saveCount)).slice(0, 5);
93
+ return {
94
+ brandCount: e.length,
95
+ itemCount: n.length,
96
+ lookCount: r.length,
97
+ totalLikes: c,
98
+ totalSaves: u,
99
+ topCategories: w(i, 8),
100
+ topColours: w(a, 8),
101
+ topAesthetics: w(o, 8),
102
+ risingOccasions: w(s, 8),
103
+ topLooks: d
104
+ };
105
+ }, [
106
+ t.data,
107
+ S.data,
108
+ E.data
109
+ ]);
110
+ if (D) return /* @__PURE__ */ y(n, {
111
+ title: "Trends",
112
+ children: /* @__PURE__ */ y(a, { label: "Reading platform signals…" })
113
+ });
114
+ if (O) return /* @__PURE__ */ y(n, {
115
+ title: "Trends",
116
+ children: /* @__PURE__ */ y(i, { onRetry: () => {
117
+ t.refetch(), S.refetch(), E.refetch();
118
+ } })
119
+ });
120
+ let A = [
121
+ {
122
+ icon: /* @__PURE__ */ y(_, { className: "h-5 w-5" }),
123
+ value: k.brandCount,
124
+ label: "Brands sampled"
125
+ },
126
+ {
127
+ icon: /* @__PURE__ */ y(h, { className: "h-5 w-5" }),
128
+ value: k.itemCount,
129
+ label: "Items sampled"
130
+ },
131
+ {
132
+ icon: /* @__PURE__ */ y(g, { className: "h-5 w-5" }),
133
+ value: k.lookCount,
134
+ label: "Looks sampled"
135
+ },
136
+ {
137
+ icon: /* @__PURE__ */ y(f, { className: "h-5 w-5" }),
138
+ value: k.totalLikes + k.totalSaves,
139
+ label: "Total engagement"
140
+ }
141
+ ];
142
+ return /* @__PURE__ */ b(n, {
143
+ title: "Trends",
144
+ description: "Signals from platform activity",
145
+ hero: !0,
146
+ children: [
147
+ /* @__PURE__ */ y(C, {
148
+ className: "mb-6",
149
+ children: "These are honest, client-side signals computed from the pieces, brands and looks currently on CoolAndLovely — the most-listed categories and colours, the aesthetics brands describe themselves with, and which occasions are drawing the most likes and saves. Nothing here is fabricated; it is a live read of the catalogue and social activity."
150
+ }),
151
+ /* @__PURE__ */ b(x, {
152
+ className: "mb-8",
153
+ children: [/* @__PURE__ */ y("h2", {
154
+ className: "mb-4 text-lg font-semibold text-text-primary",
155
+ children: "At a glance"
156
+ }), /* @__PURE__ */ y("div", {
157
+ className: "grid grid-cols-2 gap-4 lg:grid-cols-4",
158
+ children: A.map((e) => /* @__PURE__ */ y(r, {
159
+ icon: e.icon,
160
+ value: e.value.toLocaleString(),
161
+ label: e.label
162
+ }, e.label))
163
+ })]
164
+ }),
165
+ /* @__PURE__ */ b("div", {
166
+ className: "grid grid-cols-1 gap-4 lg:grid-cols-2",
167
+ children: [
168
+ /* @__PURE__ */ y(T, {
169
+ title: "Top categories",
170
+ icon: /* @__PURE__ */ y(m, { className: "h-5 w-5" }),
171
+ items: k.topCategories,
172
+ unit: "items",
173
+ emptyLabel: "No style items yet."
174
+ }),
175
+ /* @__PURE__ */ y(T, {
176
+ title: "Most-listed colours",
177
+ icon: /* @__PURE__ */ y(p, { className: "h-5 w-5" }),
178
+ items: k.topColours,
179
+ unit: "items",
180
+ emptyLabel: "No colours recorded on items yet."
181
+ }),
182
+ /* @__PURE__ */ y(T, {
183
+ title: "Brand aesthetics",
184
+ icon: /* @__PURE__ */ y(_, { className: "h-5 w-5" }),
185
+ items: k.topAesthetics,
186
+ unit: "brands",
187
+ emptyLabel: "No brand aesthetics recorded yet."
188
+ }),
189
+ /* @__PURE__ */ y(T, {
190
+ title: "Rising occasions",
191
+ icon: /* @__PURE__ */ y(d, { className: "h-5 w-5" }),
192
+ items: k.risingOccasions,
193
+ unit: "engagement",
194
+ emptyLabel: "No looks published yet."
195
+ })
196
+ ]
197
+ }),
198
+ /* @__PURE__ */ b("section", {
199
+ className: "mt-8",
200
+ children: [/* @__PURE__ */ b("h2", {
201
+ className: "mb-3 flex items-center gap-2 text-lg font-semibold text-text-primary",
202
+ children: [/* @__PURE__ */ y(v, { className: "h-5 w-5" }), " Most-loved looks"]
203
+ }), k.topLooks.length === 0 ? /* @__PURE__ */ y("p", {
204
+ className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
205
+ children: "No looks published yet."
206
+ }) : /* @__PURE__ */ y("div", {
207
+ className: "divide-y divide-border-seam rounded-lg border border-border-seam bg-bg-surface",
208
+ children: k.topLooks.map((e, t) => /* @__PURE__ */ b("div", {
209
+ className: "flex items-center gap-4 px-4 py-3",
210
+ children: [
211
+ /* @__PURE__ */ y("span", {
212
+ className: "w-6 shrink-0 text-center text-sm font-semibold tabular-nums text-text-secondary",
213
+ children: t + 1
214
+ }),
215
+ /* @__PURE__ */ b("div", {
216
+ className: "min-w-0 flex-1",
217
+ children: [/* @__PURE__ */ y("p", {
218
+ className: "truncate text-sm font-medium text-text-primary",
219
+ children: e.title
220
+ }), /* @__PURE__ */ y("p", {
221
+ className: "text-xs text-text-secondary",
222
+ children: l(e.occasion)
223
+ })]
224
+ }),
225
+ /* @__PURE__ */ b("span", {
226
+ className: "flex shrink-0 items-center gap-3 text-xs text-text-secondary",
227
+ children: [/* @__PURE__ */ b("span", {
228
+ className: "inline-flex items-center gap-1",
229
+ children: [
230
+ /* @__PURE__ */ y(f, { className: "h-3.5 w-3.5" }),
231
+ " ",
232
+ e.likeCount
233
+ ]
234
+ }), /* @__PURE__ */ b("span", {
235
+ className: "tabular-nums",
236
+ children: [e.saveCount, " saves"]
237
+ })]
238
+ })
239
+ ]
240
+ }, e.id))
241
+ })]
242
+ })
243
+ ]
244
+ });
245
+ }
246
+ //#endregion
247
+ export { E as TrendsPage };
248
+
249
+ //# sourceMappingURL=TrendsPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TrendsPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/trends/TrendsPage.tsx"],"sourcesContent":["/**\n * Trends Page\n * @module coolandlovely/pages/trends\n *\n * Client-side analytics computed over the real catalogue + social lists\n * (cooListBrands / cooListStyleItems / cooListLooks). Honest by construction —\n * it only counts and ranks what is actually on the platform. No fabricated\n * metrics. Header labels it \"Signals from platform activity.\"\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useMemo } from 'react';\nimport {\n TrendingUp,\n Palette,\n Shapes,\n Sparkles,\n Store,\n Shirt,\n Heart,\n CalendarHeart,\n} from 'lucide-react';\nimport { EmphasisPanel, GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useBrands, useStyleItems, useLooks } from '../../hooks';\nimport { titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\n\ninterface Ranked {\n label: string;\n value: number;\n sublabel?: string;\n}\n\nfunction rank(map: Map<string, number>, top = 8): Ranked[] {\n return [...map.entries()]\n .map(([label, value]) => ({ label, value }))\n .sort((a, b) => b.value - a.value)\n .slice(0, top);\n}\n\ninterface StatBarsProps {\n title: string;\n icon: ReactNode;\n items: Ranked[];\n unit: string;\n emptyLabel: string;\n className?: string;\n}\n\nconst StatBars: FC<StatBarsProps> = ({ title, icon, items, unit, emptyLabel, className }) => {\n const max = items.reduce((m, i) => Math.max(m, i.value), 0) || 1;\n return (\n <GlassCard treatment=\"plain\" className={cn('p-5', className)}>\n <h3 className=\"mb-4 flex items-center gap-2 text-base font-semibold text-text-primary\">\n {icon} {title}\n </h3>\n {items.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">{emptyLabel}</p>\n ) : (\n <ul className=\"space-y-3\">\n {items.map((item) => (\n <li key={item.label}>\n <div className=\"mb-1 flex items-center justify-between gap-2 text-sm\">\n <span className=\"truncate text-text-primary\">{item.label}</span>\n <span className=\"shrink-0 tabular-nums text-text-secondary\">\n {item.value.toLocaleString()} {unit}\n </span>\n </div>\n <div\n className=\"h-2 w-full overflow-hidden rounded-full bg-bg-sunken\"\n role=\"img\"\n aria-label={`${item.label}: ${item.value} ${unit}`}\n >\n <div\n className=\"h-full rounded-full bg-action-primary-bg\"\n style={{ width: `${Math.max(4, Math.round((item.value / max) * 100))}%` }}\n />\n </div>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n );\n};\n\nexport function TrendsPage() {\n useCoolAndLovely();\n const brands = useBrands({ pagination: { limit: 100, offset: 0 } });\n const items = useStyleItems({ pagination: { limit: 100, offset: 0 } });\n const looks = useLooks({ pagination: { limit: 100, offset: 0 } });\n\n const isLoading = brands.isLoading || items.isLoading || looks.isLoading;\n const isError = brands.isError && items.isError && looks.isError;\n\n const analysis = useMemo(() => {\n const brandRows = brands.data?.items ?? [];\n const itemRows = items.data?.items ?? [];\n const lookRows = looks.data?.items ?? [];\n\n const categoryMap = new Map<string, number>();\n const colourMap = new Map<string, number>();\n for (const it of itemRows) {\n categoryMap.set(titleCase(it.category), (categoryMap.get(titleCase(it.category)) ?? 0) + 1);\n for (const c of it.colours) {\n const key = titleCase(c);\n colourMap.set(key, (colourMap.get(key) ?? 0) + 1);\n }\n }\n\n const aestheticMap = new Map<string, number>();\n for (const b of brandRows) {\n for (const a of b.aesthetics) {\n const key = titleCase(a);\n aestheticMap.set(key, (aestheticMap.get(key) ?? 0) + 1);\n }\n }\n\n const occasionEngagement = new Map<string, number>();\n let totalLikes = 0;\n let totalSaves = 0;\n for (const l of lookRows) {\n const eng = l.likeCount + l.saveCount;\n const key = titleCase(l.occasion);\n occasionEngagement.set(key, (occasionEngagement.get(key) ?? 0) + eng);\n totalLikes += l.likeCount;\n totalSaves += l.saveCount;\n }\n\n const topLooks = [...lookRows]\n .sort((a, b) => b.likeCount + b.saveCount - (a.likeCount + a.saveCount))\n .slice(0, 5);\n\n return {\n brandCount: brandRows.length,\n itemCount: itemRows.length,\n lookCount: lookRows.length,\n totalLikes,\n totalSaves,\n topCategories: rank(categoryMap, 8),\n topColours: rank(colourMap, 8),\n topAesthetics: rank(aestheticMap, 8),\n risingOccasions: rank(occasionEngagement, 8),\n topLooks,\n };\n }, [brands.data, items.data, looks.data]);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Trends\">\n <LoadingView label=\"Reading platform signals…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Trends\">\n <ErrorView\n onRetry={() => {\n void brands.refetch();\n void items.refetch();\n void looks.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n const metrics = [\n { icon: <Store className=\"h-5 w-5\" />, value: analysis.brandCount, label: 'Brands sampled' },\n { icon: <Shirt className=\"h-5 w-5\" />, value: analysis.itemCount, label: 'Items sampled' },\n { icon: <Sparkles className=\"h-5 w-5\" />, value: analysis.lookCount, label: 'Looks sampled' },\n {\n icon: <Heart className=\"h-5 w-5\" />,\n value: analysis.totalLikes + analysis.totalSaves,\n label: 'Total engagement',\n },\n ];\n\n return (\n <PageLayout\n title=\"Trends\"\n description=\"Signals from platform activity\"\n hero\n >\n <PagePurpose className=\"mb-6\">\n These are honest, client-side signals computed from the pieces, brands and looks currently\n on CoolAndLovely — the most-listed categories and colours, the aesthetics brands describe\n themselves with, and which occasions are drawing the most likes and saves. Nothing here is\n fabricated; it is a live read of the catalogue and social activity.\n </PagePurpose>\n\n <EmphasisPanel className=\"mb-8\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">At a glance</h2>\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n {metrics.map((m) => (\n <MetricsCard\n key={m.label}\n icon={m.icon}\n value={m.value.toLocaleString()}\n label={m.label}\n />\n ))}\n </div>\n </EmphasisPanel>\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <StatBars\n title=\"Top categories\"\n icon={<Shapes className=\"h-5 w-5\" />}\n items={analysis.topCategories}\n unit=\"items\"\n emptyLabel=\"No style items yet.\"\n />\n <StatBars\n title=\"Most-listed colours\"\n icon={<Palette className=\"h-5 w-5\" />}\n items={analysis.topColours}\n unit=\"items\"\n emptyLabel=\"No colours recorded on items yet.\"\n />\n <StatBars\n title=\"Brand aesthetics\"\n icon={<Store className=\"h-5 w-5\" />}\n items={analysis.topAesthetics}\n unit=\"brands\"\n emptyLabel=\"No brand aesthetics recorded yet.\"\n />\n <StatBars\n title=\"Rising occasions\"\n icon={<CalendarHeart className=\"h-5 w-5\" />}\n items={analysis.risingOccasions}\n unit=\"engagement\"\n emptyLabel=\"No looks published yet.\"\n />\n </div>\n\n <section className=\"mt-8\">\n <h2 className=\"mb-3 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <TrendingUp className=\"h-5 w-5\" /> Most-loved looks\n </h2>\n {analysis.topLooks.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No looks published yet.\n </p>\n ) : (\n <div className=\"divide-y divide-border-seam rounded-lg border border-border-seam bg-bg-surface\">\n {analysis.topLooks.map((look, idx) => (\n <div key={look.id} className=\"flex items-center gap-4 px-4 py-3\">\n <span className=\"w-6 shrink-0 text-center text-sm font-semibold tabular-nums text-text-secondary\">\n {idx + 1}\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <p className=\"text-xs text-text-secondary\">{titleCase(look.occasion)}</p>\n </div>\n <span className=\"flex shrink-0 items-center gap-3 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center gap-1\">\n <Heart className=\"h-3.5 w-3.5\" /> {look.likeCount}\n </span>\n <span className=\"tabular-nums\">{look.saveCount} saves</span>\n </span>\n </div>\n ))}\n </div>\n )}\n </section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1,21 +1,23 @@
1
1
  import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
2
2
  import { PageLayout as t } from "../../components/PageLayout.js";
3
- import { useCreateWardrobeItem as n } from "../../hooks/useCoolAndLovelyApi.js";
3
+ import { COO_FILE_FOLDERS as n } from "../../hooks/useFiles.js";
4
+ import { useCreateWardrobeItem as r } from "../../hooks/useCoolAndLovelyApi.js";
4
5
  import "../../hooks/index.js";
5
- import { parseCsv as r, titleCase as i } from "../../utils/formatters.js";
6
- import { STYLE_CATEGORIES as a } from "../../utils/icons.js";
7
- import { SelectField as o, TextAreaField as s, TextField as c } from "../../components/Field.js";
8
- import { useState as l } from "react";
9
- import { ArrowLeft as u, Heart as d, Loader2 as f, Save as p } from "lucide-react";
10
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
11
- import { GlassCard as g } from "@burdenoff/fe-libs/ui";
6
+ import { parseCsv as i, titleCase as a } from "../../utils/formatters.js";
7
+ import { STYLE_CATEGORIES as o } from "../../utils/icons.js";
8
+ import { SelectField as s, TextAreaField as c, TextField as l } from "../../components/Field.js";
9
+ import { ImageUploadField as u } from "../../components/ImageUploadField.js";
10
+ import { useState as d } from "react";
11
+ import { ArrowLeft as f, Heart as p, Loader2 as m, Save as h } from "lucide-react";
12
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
13
+ import { GlassCard as v } from "@burdenoff/fe-libs/ui";
12
14
  //#region src/coolandlovely/pages/wardrobe/WardrobeFormPage.tsx
13
- var _ = [
15
+ var y = [
14
16
  "OWNED",
15
17
  "WISHLIST",
16
18
  "PURCHASED_ON_PLATFORM",
17
19
  "GIFTED"
18
- ], v = {
20
+ ], b = {
19
21
  name: "",
20
22
  category: "OTHER",
21
23
  source: "OWNED",
@@ -23,143 +25,153 @@ var _ = [
23
25
  colour: "",
24
26
  size: "",
25
27
  notes: "",
26
- tags: ""
28
+ tags: "",
29
+ imageFileId: ""
27
30
  };
28
- function y() {
29
- let { navigateTo: y } = e(), b = n(), [x, S] = l(v), [C, w] = l(), T = (e, t) => S((n) => ({
31
+ function x() {
32
+ let { navigateTo: x } = e(), S = r(), [C, w] = d(b), [T, E] = d(), D = (e, t) => w((n) => ({
30
33
  ...n,
31
34
  [e]: t
32
- })), E = a.map((e) => ({
35
+ })), O = o.map((e) => ({
33
36
  value: e,
34
- label: i(e)
35
- })), D = _.map((e) => ({
37
+ label: a(e)
38
+ })), k = y.map((e) => ({
36
39
  value: e,
37
- label: i(e)
40
+ label: a(e)
38
41
  }));
39
- return /* @__PURE__ */ m(t, {
42
+ return /* @__PURE__ */ g(t, {
40
43
  title: "Add a wardrobe piece",
41
44
  description: "Catalogue something you own or want",
42
- actions: /* @__PURE__ */ h("button", {
45
+ actions: /* @__PURE__ */ _("button", {
43
46
  type: "button",
44
- onClick: () => y("/wardrobe"),
47
+ onClick: () => x("/wardrobe"),
45
48
  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",
46
- children: [/* @__PURE__ */ m(u, { className: "h-4 w-4" }), " Cancel"]
49
+ children: [/* @__PURE__ */ g(f, { className: "h-4 w-4" }), " Cancel"]
47
50
  }),
48
- children: /* @__PURE__ */ m("form", {
51
+ children: /* @__PURE__ */ g("form", {
49
52
  onSubmit: (e) => {
50
- if (e.preventDefault(), !x.name.trim()) {
51
- w("Name is required");
53
+ if (e.preventDefault(), !C.name.trim()) {
54
+ E("Name is required");
52
55
  return;
53
56
  }
54
- w(void 0), b.mutate({
55
- name: x.name.trim(),
56
- category: x.category,
57
- source: x.source,
58
- brandName: x.brandName.trim() || void 0,
59
- colour: x.colour.trim() || void 0,
60
- size: x.size.trim() || void 0,
61
- notes: x.notes.trim() || void 0,
62
- tags: r(x.tags)
63
- }, { onSuccess: () => y("/wardrobe") });
57
+ E(void 0), S.mutate({
58
+ name: C.name.trim(),
59
+ category: C.category,
60
+ source: C.source,
61
+ brandName: C.brandName.trim() || void 0,
62
+ colour: C.colour.trim() || void 0,
63
+ size: C.size.trim() || void 0,
64
+ notes: C.notes.trim() || void 0,
65
+ tags: i(C.tags),
66
+ imageFileId: C.imageFileId || void 0
67
+ }, { onSuccess: () => x("/wardrobe") });
64
68
  },
65
69
  className: "mx-auto max-w-2xl",
66
- children: /* @__PURE__ */ h(g, {
70
+ children: /* @__PURE__ */ _(v, {
67
71
  treatment: "plain",
68
72
  className: "p-6",
69
73
  children: [
70
- /* @__PURE__ */ h("div", {
74
+ /* @__PURE__ */ _("div", {
71
75
  className: "mb-6 flex items-center gap-3",
72
- children: [/* @__PURE__ */ m("div", {
76
+ children: [/* @__PURE__ */ g("div", {
73
77
  className: "flex h-11 w-11 items-center justify-center rounded-lg bg-status-error-bg-subtle text-status-error-text",
74
- children: /* @__PURE__ */ m(d, { className: "h-5 w-5" })
75
- }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h2", {
78
+ children: /* @__PURE__ */ g(p, { className: "h-5 w-5" })
79
+ }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("h2", {
76
80
  className: "text-base font-semibold text-text-primary",
77
81
  children: "Piece details"
78
- }), /* @__PURE__ */ m("p", {
82
+ }), /* @__PURE__ */ g("p", {
79
83
  className: "text-xs text-text-secondary",
80
84
  children: "Only you can see your wardrobe."
81
85
  })] })]
82
86
  }),
83
- /* @__PURE__ */ m(c, {
87
+ /* @__PURE__ */ g(l, {
84
88
  id: "name",
85
89
  label: "Name",
86
- value: x.name,
87
- onChange: (e) => T("name", e),
90
+ value: C.name,
91
+ onChange: (e) => D("name", e),
88
92
  placeholder: "Vintage denim jacket",
89
93
  required: !0,
90
- error: C
94
+ error: T
91
95
  }),
92
- /* @__PURE__ */ h("div", {
96
+ /* @__PURE__ */ _("div", {
93
97
  className: "mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2",
94
- children: [/* @__PURE__ */ m(o, {
98
+ children: [/* @__PURE__ */ g(s, {
95
99
  id: "category",
96
100
  label: "Category",
97
- value: x.category,
98
- onChange: (e) => T("category", e),
99
- options: E
100
- }), /* @__PURE__ */ m(o, {
101
+ value: C.category,
102
+ onChange: (e) => D("category", e),
103
+ options: O
104
+ }), /* @__PURE__ */ g(s, {
101
105
  id: "source",
102
106
  label: "Source",
103
- value: x.source,
104
- onChange: (e) => T("source", e),
105
- options: D
107
+ value: C.source,
108
+ onChange: (e) => D("source", e),
109
+ options: k
106
110
  })]
107
111
  }),
108
- /* @__PURE__ */ h("div", {
112
+ /* @__PURE__ */ _("div", {
109
113
  className: "mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3",
110
114
  children: [
111
- /* @__PURE__ */ m(c, {
115
+ /* @__PURE__ */ g(l, {
112
116
  id: "brandName",
113
117
  label: "Brand",
114
- value: x.brandName,
115
- onChange: (e) => T("brandName", e),
118
+ value: C.brandName,
119
+ onChange: (e) => D("brandName", e),
116
120
  placeholder: "Levi's"
117
121
  }),
118
- /* @__PURE__ */ m(c, {
122
+ /* @__PURE__ */ g(l, {
119
123
  id: "colour",
120
124
  label: "Colour",
121
- value: x.colour,
122
- onChange: (e) => T("colour", e),
125
+ value: C.colour,
126
+ onChange: (e) => D("colour", e),
123
127
  placeholder: "Indigo"
124
128
  }),
125
- /* @__PURE__ */ m(c, {
129
+ /* @__PURE__ */ g(l, {
126
130
  id: "size",
127
131
  label: "Size",
128
- value: x.size,
129
- onChange: (e) => T("size", e),
132
+ value: C.size,
133
+ onChange: (e) => D("size", e),
130
134
  placeholder: "M"
131
135
  })
132
136
  ]
133
137
  }),
134
- /* @__PURE__ */ m(s, {
138
+ /* @__PURE__ */ g(c, {
135
139
  id: "notes",
136
140
  label: "Notes",
137
- value: x.notes,
138
- onChange: (e) => T("notes", e),
141
+ value: C.notes,
142
+ onChange: (e) => D("notes", e),
139
143
  placeholder: "Where you got it, how you wear it…",
140
144
  rows: 3,
141
145
  className: "mt-4"
142
146
  }),
143
- /* @__PURE__ */ m(c, {
147
+ /* @__PURE__ */ g(l, {
144
148
  id: "tags",
145
149
  label: "Tags",
146
- value: x.tags,
147
- onChange: (e) => T("tags", e),
150
+ value: C.tags,
151
+ onChange: (e) => D("tags", e),
148
152
  placeholder: "denim, layering",
149
153
  hint: "Comma-separated",
150
154
  className: "mt-4"
151
155
  }),
152
- b.isError && /* @__PURE__ */ m("p", {
156
+ /* @__PURE__ */ g(u, {
157
+ label: "Photo",
158
+ value: C.imageFileId,
159
+ onChange: (e) => D("imageFileId", e),
160
+ folder: n.wardrobe,
161
+ hint: "Your photo of the piece (private to you)",
162
+ className: "mt-4"
163
+ }),
164
+ S.isError && /* @__PURE__ */ g("p", {
153
165
  className: "mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
154
- children: b.error instanceof Error ? b.error.message : "Something went wrong"
166
+ children: S.error instanceof Error ? S.error.message : "Something went wrong"
155
167
  }),
156
- /* @__PURE__ */ m("div", {
168
+ /* @__PURE__ */ g("div", {
157
169
  className: "mt-6 flex justify-end gap-2",
158
- children: /* @__PURE__ */ h("button", {
170
+ children: /* @__PURE__ */ _("button", {
159
171
  type: "submit",
160
- disabled: b.isPending,
172
+ disabled: S.isPending,
161
173
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50",
162
- children: [b.isPending ? /* @__PURE__ */ m(f, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ m(p, { className: "h-4 w-4" }), "Add to wardrobe"]
174
+ children: [S.isPending ? /* @__PURE__ */ g(m, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ g(h, { className: "h-4 w-4" }), "Add to wardrobe"]
163
175
  })
164
176
  })
165
177
  ]
@@ -168,6 +180,6 @@ function y() {
168
180
  });
169
181
  }
170
182
  //#endregion
171
- export { y as WardrobeFormPage };
183
+ export { x as WardrobeFormPage };
172
184
 
173
185
  //# sourceMappingURL=WardrobeFormPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WardrobeFormPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/wardrobe/WardrobeFormPage.tsx"],"sourcesContent":["/**\n * Wardrobe Item Create Page (self-scoped)\n * @module coolandlovely/pages/wardrobe\n *\n * Drives `cooCreateWardrobeItem`. Belongs to the calling shopper's profile.\n */\n\nimport { useState } from 'react';\nimport { ArrowLeft, Loader2, Save, Heart } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { TextField, TextAreaField, SelectField } from '../../components/Field';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCreateWardrobeItem } from '../../hooks';\nimport { STYLE_CATEGORIES } from '../../utils/icons';\nimport { parseCsv, titleCase } from '../../utils/formatters';\nimport type { CooStyleCategory, CooWardrobeSource } from '../../types';\n\nconst SOURCES: CooWardrobeSource[] = ['OWNED', 'WISHLIST', 'PURCHASED_ON_PLATFORM', 'GIFTED'];\n\ninterface FormState {\n name: string;\n category: CooStyleCategory;\n source: CooWardrobeSource;\n brandName: string;\n colour: string;\n size: string;\n notes: string;\n tags: string;\n}\n\nconst EMPTY: FormState = {\n name: '',\n category: 'OTHER',\n source: 'OWNED',\n brandName: '',\n colour: '',\n size: '',\n notes: '',\n tags: '',\n};\n\nexport function WardrobeFormPage() {\n const { navigateTo } = useCoolAndLovely();\n const createItem = useCreateWardrobeItem();\n\n const [form, setForm] = useState<FormState>(EMPTY);\n const [nameError, setNameError] = useState<string | undefined>();\n\n const setField = <K extends keyof FormState>(key: K, value: FormState[K]) =>\n setForm((f) => ({ ...f, [key]: value }));\n\n const categoryOptions = STYLE_CATEGORIES.map((c) => ({ value: c, label: titleCase(c) }));\n const sourceOptions = SOURCES.map((s) => ({ value: s, label: titleCase(s) }));\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (!form.name.trim()) {\n setNameError('Name is required');\n return;\n }\n setNameError(undefined);\n\n createItem.mutate(\n {\n name: form.name.trim(),\n category: form.category,\n source: form.source,\n brandName: form.brandName.trim() || undefined,\n colour: form.colour.trim() || undefined,\n size: form.size.trim() || undefined,\n notes: form.notes.trim() || undefined,\n tags: parseCsv(form.tags),\n },\n { onSuccess: () => navigateTo('/wardrobe') }\n );\n };\n\n return (\n <PageLayout\n title=\"Add a wardrobe piece\"\n description=\"Catalogue something you own or want\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/wardrobe')}\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\" /> Cancel\n </button>\n }\n >\n <form onSubmit={handleSubmit} className=\"mx-auto max-w-2xl\">\n <GlassCard treatment=\"plain\" className=\"p-6\">\n <div className=\"mb-6 flex items-center gap-3\">\n <div className=\"flex h-11 w-11 items-center justify-center rounded-lg bg-status-error-bg-subtle text-status-error-text\">\n <Heart className=\"h-5 w-5\" />\n </div>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Piece details</h2>\n <p className=\"text-xs text-text-secondary\">Only you can see your wardrobe.</p>\n </div>\n </div>\n\n <TextField\n id=\"name\"\n label=\"Name\"\n value={form.name}\n onChange={(v) => setField('name', v)}\n placeholder=\"Vintage denim jacket\"\n required\n error={nameError}\n />\n\n <div className=\"mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <SelectField\n id=\"category\"\n label=\"Category\"\n value={form.category}\n onChange={(v) => setField('category', v as CooStyleCategory)}\n options={categoryOptions}\n />\n <SelectField\n id=\"source\"\n label=\"Source\"\n value={form.source}\n onChange={(v) => setField('source', v as CooWardrobeSource)}\n options={sourceOptions}\n />\n </div>\n\n <div className=\"mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <TextField\n id=\"brandName\"\n label=\"Brand\"\n value={form.brandName}\n onChange={(v) => setField('brandName', v)}\n placeholder=\"Levi's\"\n />\n <TextField\n id=\"colour\"\n label=\"Colour\"\n value={form.colour}\n onChange={(v) => setField('colour', v)}\n placeholder=\"Indigo\"\n />\n <TextField\n id=\"size\"\n label=\"Size\"\n value={form.size}\n onChange={(v) => setField('size', v)}\n placeholder=\"M\"\n />\n </div>\n\n <TextAreaField\n id=\"notes\"\n label=\"Notes\"\n value={form.notes}\n onChange={(v) => setField('notes', v)}\n placeholder=\"Where you got it, how you wear it…\"\n rows={3}\n className=\"mt-4\"\n />\n\n <TextField\n id=\"tags\"\n label=\"Tags\"\n value={form.tags}\n onChange={(v) => setField('tags', v)}\n placeholder=\"denim, layering\"\n hint=\"Comma-separated\"\n className=\"mt-4\"\n />\n\n {createItem.isError && (\n <p className=\"mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {createItem.error instanceof Error\n ? createItem.error.message\n : 'Something went wrong'}\n </p>\n )}\n\n <div className=\"mt-6 flex justify-end gap-2\">\n <button\n type=\"submit\"\n disabled={createItem.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {createItem.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"h-4 w-4\" />\n )}\n Add to wardrobe\n </button>\n </div>\n </GlassCard>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WardrobeFormPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/wardrobe/WardrobeFormPage.tsx"],"sourcesContent":["/**\n * Wardrobe Item Create Page (self-scoped)\n * @module coolandlovely/pages/wardrobe\n *\n * Drives `cooCreateWardrobeItem`. Belongs to the calling shopper's profile.\n */\n\nimport { useState } from 'react';\nimport { ArrowLeft, Loader2, Save, Heart } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { TextField, TextAreaField, SelectField } from '../../components/Field';\nimport { ImageUploadField } from '../../components/ImageUploadField';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCreateWardrobeItem } from '../../hooks';\nimport { COO_FILE_FOLDERS } from '../../hooks/useFiles';\nimport { STYLE_CATEGORIES } from '../../utils/icons';\nimport { parseCsv, titleCase } from '../../utils/formatters';\nimport type { CooStyleCategory, CooWardrobeSource } from '../../types';\n\nconst SOURCES: CooWardrobeSource[] = ['OWNED', 'WISHLIST', 'PURCHASED_ON_PLATFORM', 'GIFTED'];\n\ninterface FormState {\n name: string;\n category: CooStyleCategory;\n source: CooWardrobeSource;\n brandName: string;\n colour: string;\n size: string;\n notes: string;\n tags: string;\n imageFileId: string;\n}\n\nconst EMPTY: FormState = {\n name: '',\n category: 'OTHER',\n source: 'OWNED',\n brandName: '',\n colour: '',\n size: '',\n notes: '',\n tags: '',\n imageFileId: '',\n};\n\nexport function WardrobeFormPage() {\n const { navigateTo } = useCoolAndLovely();\n const createItem = useCreateWardrobeItem();\n\n const [form, setForm] = useState<FormState>(EMPTY);\n const [nameError, setNameError] = useState<string | undefined>();\n\n const setField = <K extends keyof FormState>(key: K, value: FormState[K]) =>\n setForm((f) => ({ ...f, [key]: value }));\n\n const categoryOptions = STYLE_CATEGORIES.map((c) => ({ value: c, label: titleCase(c) }));\n const sourceOptions = SOURCES.map((s) => ({ value: s, label: titleCase(s) }));\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (!form.name.trim()) {\n setNameError('Name is required');\n return;\n }\n setNameError(undefined);\n\n createItem.mutate(\n {\n name: form.name.trim(),\n category: form.category,\n source: form.source,\n brandName: form.brandName.trim() || undefined,\n colour: form.colour.trim() || undefined,\n size: form.size.trim() || undefined,\n notes: form.notes.trim() || undefined,\n tags: parseCsv(form.tags),\n imageFileId: form.imageFileId || undefined,\n },\n { onSuccess: () => navigateTo('/wardrobe') }\n );\n };\n\n return (\n <PageLayout\n title=\"Add a wardrobe piece\"\n description=\"Catalogue something you own or want\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/wardrobe')}\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\" /> Cancel\n </button>\n }\n >\n <form onSubmit={handleSubmit} className=\"mx-auto max-w-2xl\">\n <GlassCard treatment=\"plain\" className=\"p-6\">\n <div className=\"mb-6 flex items-center gap-3\">\n <div className=\"flex h-11 w-11 items-center justify-center rounded-lg bg-status-error-bg-subtle text-status-error-text\">\n <Heart className=\"h-5 w-5\" />\n </div>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Piece details</h2>\n <p className=\"text-xs text-text-secondary\">Only you can see your wardrobe.</p>\n </div>\n </div>\n\n <TextField\n id=\"name\"\n label=\"Name\"\n value={form.name}\n onChange={(v) => setField('name', v)}\n placeholder=\"Vintage denim jacket\"\n required\n error={nameError}\n />\n\n <div className=\"mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <SelectField\n id=\"category\"\n label=\"Category\"\n value={form.category}\n onChange={(v) => setField('category', v as CooStyleCategory)}\n options={categoryOptions}\n />\n <SelectField\n id=\"source\"\n label=\"Source\"\n value={form.source}\n onChange={(v) => setField('source', v as CooWardrobeSource)}\n options={sourceOptions}\n />\n </div>\n\n <div className=\"mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <TextField\n id=\"brandName\"\n label=\"Brand\"\n value={form.brandName}\n onChange={(v) => setField('brandName', v)}\n placeholder=\"Levi's\"\n />\n <TextField\n id=\"colour\"\n label=\"Colour\"\n value={form.colour}\n onChange={(v) => setField('colour', v)}\n placeholder=\"Indigo\"\n />\n <TextField\n id=\"size\"\n label=\"Size\"\n value={form.size}\n onChange={(v) => setField('size', v)}\n placeholder=\"M\"\n />\n </div>\n\n <TextAreaField\n id=\"notes\"\n label=\"Notes\"\n value={form.notes}\n onChange={(v) => setField('notes', v)}\n placeholder=\"Where you got it, how you wear it…\"\n rows={3}\n className=\"mt-4\"\n />\n\n <TextField\n id=\"tags\"\n label=\"Tags\"\n value={form.tags}\n onChange={(v) => setField('tags', v)}\n placeholder=\"denim, layering\"\n hint=\"Comma-separated\"\n className=\"mt-4\"\n />\n\n <ImageUploadField\n label=\"Photo\"\n value={form.imageFileId}\n onChange={(id) => setField('imageFileId', id)}\n folder={COO_FILE_FOLDERS.wardrobe}\n hint=\"Your photo of the piece (private to you)\"\n className=\"mt-4\"\n />\n\n {createItem.isError && (\n <p className=\"mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {createItem.error instanceof Error\n ? createItem.error.message\n : 'Something went wrong'}\n </p>\n )}\n\n <div className=\"mt-6 flex justify-end gap-2\">\n <button\n type=\"submit\"\n disabled={createItem.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {createItem.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"h-4 w-4\" />\n )}\n Add to wardrobe\n </button>\n </div>\n </GlassCard>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -98,6 +98,8 @@ function w() {
98
98
  children: [/* @__PURE__ */ x(o, {
99
99
  icon: p(e.category, 22),
100
100
  seed: e.id,
101
+ fileId: e.image?.id,
102
+ alt: e.name,
101
103
  className: "h-14 w-14 shrink-0"
102
104
  }), /* @__PURE__ */ S("div", {
103
105
  className: "min-w-0 flex-1",