@burdenoff/microfe-coolandlovely 2026.706.2 → 2026.706.3

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 (75) hide show
  1. package/dist/coolandlovely/CoolAndLovelyRoot.js +62 -46
  2. package/dist/coolandlovely/CoolAndLovelyRoot.js.map +1 -1
  3. package/dist/coolandlovely/components/AddToLookbookButton.js +22 -22
  4. package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -1
  5. package/dist/coolandlovely/components/BrandCover.js +39 -0
  6. package/dist/coolandlovely/components/BrandCover.js.map +1 -0
  7. package/dist/coolandlovely/components/BrandCreatorAvatars.js +57 -0
  8. package/dist/coolandlovely/components/BrandCreatorAvatars.js.map +1 -0
  9. package/dist/coolandlovely/components/ColourSwatchRow.js +86 -0
  10. package/dist/coolandlovely/components/ColourSwatchRow.js.map +1 -0
  11. package/dist/coolandlovely/components/Comments.js +4 -4
  12. package/dist/coolandlovely/components/Comments.js.map +1 -1
  13. package/dist/coolandlovely/components/FileImage.js.map +1 -1
  14. package/dist/coolandlovely/components/ImageUploadField.js +139 -57
  15. package/dist/coolandlovely/components/ImageUploadField.js.map +1 -1
  16. package/dist/coolandlovely/components/LookCard.js +77 -0
  17. package/dist/coolandlovely/components/LookCard.js.map +1 -0
  18. package/dist/coolandlovely/components/MetricsCard.js +1 -1
  19. package/dist/coolandlovely/components/MetricsCard.js.map +1 -1
  20. package/dist/coolandlovely/components/ShopItemCard.js +45 -0
  21. package/dist/coolandlovely/components/ShopItemCard.js.map +1 -0
  22. package/dist/coolandlovely/components/StepTracker.js +35 -0
  23. package/dist/coolandlovely/components/StepTracker.js.map +1 -0
  24. package/dist/coolandlovely/components/Thumbnail.js +15 -11
  25. package/dist/coolandlovely/components/Thumbnail.js.map +1 -1
  26. package/dist/coolandlovely/components/VisibilityChip.js +32 -0
  27. package/dist/coolandlovely/components/VisibilityChip.js.map +1 -0
  28. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +94 -69
  29. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
  30. package/dist/coolandlovely/hooks/useFiles.js +49 -32
  31. package/dist/coolandlovely/hooks/useFiles.js.map +1 -1
  32. package/dist/coolandlovely/pages/HomePage.js +112 -133
  33. package/dist/coolandlovely/pages/HomePage.js.map +1 -1
  34. package/dist/coolandlovely/pages/brands/BrandDetailPage.js +253 -242
  35. package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
  36. package/dist/coolandlovely/pages/brands/BrandFormPage.js +116 -112
  37. package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -1
  38. package/dist/coolandlovely/pages/brands/BrandsListPage.js +13 -13
  39. package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
  40. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +117 -95
  41. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js.map +1 -1
  42. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +1 -1
  43. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js +50 -43
  44. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js.map +1 -1
  45. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +131 -108
  46. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
  47. package/dist/coolandlovely/pages/collections/CollectionFormPage.js +1 -1
  48. package/dist/coolandlovely/pages/collections/CollectionsListPage.js +59 -56
  49. package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
  50. package/dist/coolandlovely/pages/discover/DiscoverPage.js +1 -1
  51. package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -1
  52. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +175 -147
  53. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
  54. package/dist/coolandlovely/pages/items/StyleItemFormPage.js +1 -1
  55. package/dist/coolandlovely/pages/items/StyleItemsListPage.js +71 -62
  56. package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
  57. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +149 -127
  58. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
  59. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +69 -53
  60. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
  61. package/dist/coolandlovely/pages/looks/LookDetailPage.js +135 -113
  62. package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
  63. package/dist/coolandlovely/pages/looks/LookFormPage.js +122 -110
  64. package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
  65. package/dist/coolandlovely/pages/looks/LooksListPage.js +60 -97
  66. package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
  67. package/dist/coolandlovely/pages/profile/StyleProfilePage.js +372 -210
  68. package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
  69. package/dist/coolandlovely/pages/trends/TrendsPage.js +1 -1
  70. package/dist/coolandlovely/pages/trends/TrendsPage.js.map +1 -1
  71. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +130 -94
  72. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -1
  73. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +75 -76
  74. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
  75. package/package.json +1 -1
@@ -5,15 +5,16 @@ 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 { useStyleItems as s } from "../../hooks/useCoolAndLovelyApi.js";
8
- import "../../hooks/index.js";
9
8
  import { formatPrice as c, titleCase as l } from "../../utils/formatters.js";
9
+ import "../../hooks/index.js";
10
10
  import { STYLE_CATEGORIES as u, categoryIcon as d } from "../../utils/icons.js";
11
11
  import { EmptyState as f } from "../../components/EmptyState.js";
12
- import { useState as p } from "react";
13
- import { ChevronLeft as m, ChevronRight as h, Plus as g, Shirt as _ } from "lucide-react";
14
- import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
12
+ import { ColourSwatchRow as p } from "../../components/ColourSwatchRow.js";
13
+ import { useState as m } from "react";
14
+ import { ChevronLeft as h, ChevronRight as g, Plus as _, Shirt as v } from "lucide-react";
15
+ import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
15
16
  //#region src/coolandlovely/pages/items/StyleItemsListPage.tsx
16
- var x = 24, S = [
17
+ var S = 24, C = [
17
18
  {
18
19
  value: "ALL",
19
20
  label: "All"
@@ -35,51 +36,51 @@ var x = 24, S = [
35
36
  label: "Retired"
36
37
  }
37
38
  ];
38
- function C() {
39
- let { navigateTo: C } = e(), [w, T] = p("ALL"), [E, D] = p("ALL"), [O, k] = p(0), A = s({
40
- category: w === "ALL" ? void 0 : w,
41
- status: E === "ALL" ? void 0 : E,
39
+ function w() {
40
+ let { navigateTo: w } = e(), [T, E] = m("ALL"), [D, O] = m("ALL"), [k, A] = m(0), j = s({
41
+ category: T === "ALL" ? void 0 : T,
42
+ status: D === "ALL" ? void 0 : D,
42
43
  pagination: {
43
- limit: x,
44
- offset: O
44
+ limit: S,
45
+ offset: k
45
46
  }
46
- }), j = A.data?.items ?? [], M = A.data?.pageInfo.hasMore ?? !1;
47
- return /* @__PURE__ */ b(n, {
47
+ }), M = j.data?.items ?? [], N = j.data?.pageInfo.hasMore ?? !1;
48
+ return /* @__PURE__ */ x(n, {
48
49
  title: "Style Items",
49
50
  description: "The shoppable catalogue across every brand",
50
- actions: /* @__PURE__ */ b("button", {
51
+ actions: /* @__PURE__ */ x("button", {
51
52
  type: "button",
52
- onClick: () => C("/items/new"),
53
+ onClick: () => w("/items/new"),
53
54
  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",
54
- children: [/* @__PURE__ */ y(g, { className: "h-4 w-4" }), " New item"]
55
+ children: [/* @__PURE__ */ b(_, { className: "h-4 w-4" }), " New item"]
55
56
  }),
56
57
  children: [
57
- /* @__PURE__ */ y("div", {
58
+ /* @__PURE__ */ b("div", {
58
59
  className: "mb-3 flex flex-wrap items-center gap-2",
59
- children: S.map((e) => /* @__PURE__ */ y("button", {
60
+ children: C.map((e) => /* @__PURE__ */ b("button", {
60
61
  type: "button",
61
62
  onClick: () => {
62
- D(e.value), k(0);
63
+ O(e.value), A(0);
63
64
  },
64
- className: t("rounded-full px-3 py-1.5 text-sm font-medium transition-colors", E === e.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
65
+ className: t("rounded-full px-3 py-1.5 text-sm font-medium transition-colors", D === e.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
65
66
  children: e.label
66
67
  }, e.value))
67
68
  }),
68
- /* @__PURE__ */ b("div", {
69
+ /* @__PURE__ */ x("div", {
69
70
  className: "mb-6 flex flex-wrap items-center gap-2",
70
- children: [/* @__PURE__ */ y("button", {
71
+ children: [/* @__PURE__ */ b("button", {
71
72
  type: "button",
72
73
  onClick: () => {
73
- T("ALL"), k(0);
74
+ E("ALL"), A(0);
74
75
  },
75
- className: t("rounded-full px-3 py-1.5 text-xs font-medium transition-colors", w === "ALL" ? "bg-accent-purple-subtle text-text-primary" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
76
+ className: t("rounded-full px-3 py-1.5 text-xs font-medium transition-colors", T === "ALL" ? "bg-accent-purple-subtle text-text-primary" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
76
77
  children: "All categories"
77
- }), u.map((e) => /* @__PURE__ */ b("button", {
78
+ }), u.map((e) => /* @__PURE__ */ x("button", {
78
79
  type: "button",
79
80
  onClick: () => {
80
- T(e), k(0);
81
+ E(e), A(0);
81
82
  },
82
- className: t("inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-xs font-medium transition-colors", w === e ? "bg-accent-purple-subtle text-text-primary" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
83
+ className: t("inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-xs font-medium transition-colors", T === e ? "bg-accent-purple-subtle text-text-primary" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
83
84
  children: [
84
85
  d(e, 14),
85
86
  " ",
@@ -87,79 +88,87 @@ function C() {
87
88
  ]
88
89
  }, e))]
89
90
  }),
90
- A.isLoading ? /* @__PURE__ */ y(a, { label: "Loading catalogue…" }) : A.isError ? /* @__PURE__ */ y(i, { onRetry: () => void A.refetch() }) : j.length === 0 ? /* @__PURE__ */ y(f, {
91
+ j.isLoading ? /* @__PURE__ */ b(a, { label: "Loading catalogue…" }) : j.isError ? /* @__PURE__ */ b(i, { onRetry: () => void j.refetch() }) : M.length === 0 ? /* @__PURE__ */ b(f, {
91
92
  illustration: "empty-data",
92
- icon: /* @__PURE__ */ y(_, { className: "h-10 w-10" }),
93
+ icon: /* @__PURE__ */ b(v, { className: "h-10 w-10" }),
93
94
  title: "No items found",
94
95
  description: "No style items match these filters yet.",
95
- action: /* @__PURE__ */ b("button", {
96
+ action: /* @__PURE__ */ x("button", {
96
97
  type: "button",
97
- onClick: () => C("/items/new"),
98
+ onClick: () => w("/items/new"),
98
99
  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",
99
- children: [/* @__PURE__ */ y(g, { className: "h-4 w-4" }), " New item"]
100
+ children: [/* @__PURE__ */ b(_, { className: "h-4 w-4" }), " New item"]
100
101
  })
101
- }) : /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ y("div", {
102
+ }) : /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b("div", {
102
103
  className: "grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4",
103
- children: j.map((e) => /* @__PURE__ */ b("button", {
104
+ children: M.map((e) => /* @__PURE__ */ x("button", {
104
105
  type: "button",
105
- onClick: () => C(`/items/${e.id}`),
106
- 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",
107
- children: [/* @__PURE__ */ b("div", {
106
+ onClick: () => w(`/items/${e.id}`),
107
+ className: "group 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",
108
+ children: [/* @__PURE__ */ x("div", {
108
109
  className: "relative",
109
- children: [/* @__PURE__ */ y(o, {
110
- icon: d(e.category, 28),
110
+ children: [/* @__PURE__ */ b(o, {
111
+ icon: d(e.category, 32),
111
112
  seed: e.id,
112
113
  fileId: e.image?.id,
113
114
  alt: e.name,
114
- className: "h-36 w-full"
115
- }), /* @__PURE__ */ y("div", {
115
+ className: "aspect-[3/4] w-full"
116
+ }), /* @__PURE__ */ b("div", {
116
117
  className: "absolute right-2 top-2",
117
- children: /* @__PURE__ */ y(r, { status: e.status })
118
+ children: /* @__PURE__ */ b(r, {
119
+ status: e.status,
120
+ className: "shadow-sm"
121
+ })
118
122
  })]
119
- }), /* @__PURE__ */ b("div", {
123
+ }), /* @__PURE__ */ x("div", {
120
124
  className: "p-3",
121
125
  children: [
122
- /* @__PURE__ */ y("p", {
126
+ /* @__PURE__ */ b("p", {
123
127
  className: "truncate text-sm font-medium text-text-primary",
124
128
  children: e.name
125
129
  }),
126
- e.brand?.name && /* @__PURE__ */ y("p", {
130
+ e.brand?.name && /* @__PURE__ */ b("p", {
127
131
  className: "truncate text-xs text-text-secondary",
128
132
  children: e.brand.name
129
133
  }),
130
- /* @__PURE__ */ b("div", {
131
- className: "mt-1.5 flex items-center justify-between",
132
- children: [/* @__PURE__ */ y("span", {
133
- className: "text-sm font-semibold text-text-primary",
134
+ /* @__PURE__ */ x("div", {
135
+ className: "mt-1.5 flex items-center justify-between gap-2",
136
+ children: [/* @__PURE__ */ b("span", {
137
+ className: "text-sm font-semibold text-text-primary tabular-nums",
134
138
  children: c(e.price, e.currency)
135
- }), /* @__PURE__ */ y("span", {
139
+ }), /* @__PURE__ */ b("span", {
136
140
  className: "text-xs text-text-secondary",
137
141
  children: l(e.category)
138
142
  })]
143
+ }),
144
+ e.colours.length > 0 && /* @__PURE__ */ b(p, {
145
+ colours: e.colours,
146
+ max: 5,
147
+ className: "mt-2"
139
148
  })
140
149
  ]
141
150
  })]
142
151
  }, e.id))
143
- }), (O > 0 || M) && /* @__PURE__ */ b("div", {
152
+ }), (k > 0 || N) && /* @__PURE__ */ x("div", {
144
153
  className: "mt-6 flex items-center justify-center gap-2",
145
154
  children: [
146
- /* @__PURE__ */ b("button", {
155
+ /* @__PURE__ */ x("button", {
147
156
  type: "button",
148
- disabled: O === 0,
149
- onClick: () => k((e) => Math.max(0, e - x)),
157
+ disabled: k === 0,
158
+ onClick: () => A((e) => Math.max(0, e - S)),
150
159
  className: "inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40",
151
- children: [/* @__PURE__ */ y(m, { className: "h-4 w-4" }), " Previous"]
160
+ children: [/* @__PURE__ */ b(h, { className: "h-4 w-4" }), " Previous"]
152
161
  }),
153
- /* @__PURE__ */ b("span", {
162
+ /* @__PURE__ */ x("span", {
154
163
  className: "text-sm text-text-secondary",
155
- children: ["Page ", O / x + 1]
164
+ children: ["Page ", k / S + 1]
156
165
  }),
157
- /* @__PURE__ */ b("button", {
166
+ /* @__PURE__ */ x("button", {
158
167
  type: "button",
159
- disabled: !M,
160
- onClick: () => k((e) => e + x),
168
+ disabled: !N,
169
+ onClick: () => A((e) => e + S),
161
170
  className: "inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40",
162
- children: ["Next ", /* @__PURE__ */ y(h, { className: "h-4 w-4" })]
171
+ children: ["Next ", /* @__PURE__ */ b(g, { className: "h-4 w-4" })]
163
172
  })
164
173
  ]
165
174
  })] })
@@ -167,6 +176,6 @@ function C() {
167
176
  });
168
177
  }
169
178
  //#endregion
170
- export { C as StyleItemsListPage };
179
+ export { w as StyleItemsListPage };
171
180
 
172
181
  //# sourceMappingURL=StyleItemsListPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StyleItemsListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/items/StyleItemsListPage.tsx"],"sourcesContent":["/**\n * Style Items List Page\n * @module coolandlovely/pages/items\n *\n * Cursor-paginated catalogue (`cooListStyleItems`) with category & status\n * filters. Cards link to the item detail page.\n */\n\nimport { useState } from 'react';\nimport { Plus, ChevronLeft, ChevronRight, Shirt } 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 { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useStyleItems } from '../../hooks';\nimport { categoryIcon, STYLE_CATEGORIES } from '../../utils/icons';\nimport { formatPrice, titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooStyleCategory, CooStyleItemStatus } from '../../types';\n\nconst PAGE_SIZE = 24;\n\nconst STATUS_OPTIONS: Array<{ value: CooStyleItemStatus | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'OUT_OF_STOCK', label: 'Out of stock' },\n { value: 'RETIRED', label: 'Retired' },\n];\n\nexport function StyleItemsListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [category, setCategory] = useState<CooStyleCategory | 'ALL'>('ALL');\n const [status, setStatus] = useState<CooStyleItemStatus | 'ALL'>('ALL');\n const [offset, setOffset] = useState(0);\n\n const query = useStyleItems({\n category: category === 'ALL' ? undefined : category,\n status: status === 'ALL' ? undefined : status,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const items = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Style Items\"\n description=\"The shoppable catalogue across every brand\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/items/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 item\n </button>\n }\n >\n {/* Status filter */}\n <div className=\"mb-3 flex flex-wrap items-center gap-2\">\n {STATUS_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setStatus(opt.value);\n setOffset(0);\n }}\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 {/* Category filter */}\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setCategory('ALL');\n setOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-xs font-medium transition-colors',\n category === 'ALL'\n ? 'bg-accent-purple-subtle text-text-primary'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n All categories\n </button>\n {STYLE_CATEGORIES.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => {\n setCategory(c);\n setOffset(0);\n }}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-xs font-medium transition-colors',\n category === c\n ? 'bg-accent-purple-subtle text-text-primary'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {categoryIcon(c, 14)} {titleCase(c)}\n </button>\n ))}\n </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading catalogue…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Shirt className=\"h-10 w-10\" />}\n title=\"No items found\"\n description=\"No style items match these filters yet.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/items/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 item\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\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 shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <div className=\"relative\">\n <Thumbnail\n icon={categoryIcon(item.category, 28)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"h-36 w-full\"\n />\n <div className=\"absolute right-2 top-2\">\n <StatusBadge status={item.status} />\n </div>\n </div>\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n {item.brand?.name && (\n <p className=\"truncate text-xs text-text-secondary\">{item.brand.name}</p>\n )}\n <div className=\"mt-1.5 flex items-center justify-between\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {formatPrice(item.price, item.currency)}\n </span>\n <span className=\"text-xs text-text-secondary\">{titleCase(item.category)}</span>\n </div>\n </div>\n </button>\n ))}\n </div>\n\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" /> Previous\n </button>\n <span className=\"text-sm text-text-secondary\">Page {offset / PAGE_SIZE + 1}</span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n Next <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"StyleItemsListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/items/StyleItemsListPage.tsx"],"sourcesContent":["/**\n * Style Items List Page\n * @module coolandlovely/pages/items\n *\n * Cursor-paginated catalogue (`cooListStyleItems`) with category & status\n * filters. Cards link to the item detail page.\n */\n\nimport { useState } from 'react';\nimport { Plus, ChevronLeft, ChevronRight, Shirt } 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 { ColourSwatchRow } from '../../components/ColourSwatchRow';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useStyleItems } from '../../hooks';\nimport { categoryIcon, STYLE_CATEGORIES } from '../../utils/icons';\nimport { formatPrice, titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooStyleCategory, CooStyleItemStatus } from '../../types';\n\nconst PAGE_SIZE = 24;\n\nconst STATUS_OPTIONS: Array<{ value: CooStyleItemStatus | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'OUT_OF_STOCK', label: 'Out of stock' },\n { value: 'RETIRED', label: 'Retired' },\n];\n\nexport function StyleItemsListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [category, setCategory] = useState<CooStyleCategory | 'ALL'>('ALL');\n const [status, setStatus] = useState<CooStyleItemStatus | 'ALL'>('ALL');\n const [offset, setOffset] = useState(0);\n\n const query = useStyleItems({\n category: category === 'ALL' ? undefined : category,\n status: status === 'ALL' ? undefined : status,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const items = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Style Items\"\n description=\"The shoppable catalogue across every brand\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/items/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 item\n </button>\n }\n >\n {/* Status filter */}\n <div className=\"mb-3 flex flex-wrap items-center gap-2\">\n {STATUS_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setStatus(opt.value);\n setOffset(0);\n }}\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 {/* Category filter */}\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setCategory('ALL');\n setOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-xs font-medium transition-colors',\n category === 'ALL'\n ? 'bg-accent-purple-subtle text-text-primary'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n All categories\n </button>\n {STYLE_CATEGORIES.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => {\n setCategory(c);\n setOffset(0);\n }}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-xs font-medium transition-colors',\n category === c\n ? 'bg-accent-purple-subtle text-text-primary'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {categoryIcon(c, 14)} {titleCase(c)}\n </button>\n ))}\n </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading catalogue…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Shirt className=\"h-10 w-10\" />}\n title=\"No items found\"\n description=\"No style items match these filters yet.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/items/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 item\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\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 shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <div className=\"relative\">\n <Thumbnail\n icon={categoryIcon(item.category, 32)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[3/4] w-full\"\n />\n <div className=\"absolute right-2 top-2\">\n <StatusBadge status={item.status} className=\"shadow-sm\" />\n </div>\n </div>\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n {item.brand?.name && (\n <p className=\"truncate text-xs text-text-secondary\">{item.brand.name}</p>\n )}\n <div className=\"mt-1.5 flex items-center justify-between gap-2\">\n <span className=\"text-sm font-semibold text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n </span>\n <span className=\"text-xs text-text-secondary\">{titleCase(item.category)}</span>\n </div>\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 {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" /> Previous\n </button>\n <span className=\"text-sm text-text-secondary\">Page {offset / PAGE_SIZE + 1}</span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n Next <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}