@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.
- package/dist/coolandlovely/CoolAndLovelyRoot.js +62 -46
- package/dist/coolandlovely/CoolAndLovelyRoot.js.map +1 -1
- package/dist/coolandlovely/components/AddToLookbookButton.js +22 -22
- package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -1
- package/dist/coolandlovely/components/BrandCover.js +39 -0
- package/dist/coolandlovely/components/BrandCover.js.map +1 -0
- package/dist/coolandlovely/components/BrandCreatorAvatars.js +57 -0
- package/dist/coolandlovely/components/BrandCreatorAvatars.js.map +1 -0
- package/dist/coolandlovely/components/ColourSwatchRow.js +86 -0
- package/dist/coolandlovely/components/ColourSwatchRow.js.map +1 -0
- package/dist/coolandlovely/components/Comments.js +4 -4
- package/dist/coolandlovely/components/Comments.js.map +1 -1
- package/dist/coolandlovely/components/FileImage.js.map +1 -1
- package/dist/coolandlovely/components/ImageUploadField.js +139 -57
- package/dist/coolandlovely/components/ImageUploadField.js.map +1 -1
- package/dist/coolandlovely/components/LookCard.js +77 -0
- package/dist/coolandlovely/components/LookCard.js.map +1 -0
- package/dist/coolandlovely/components/MetricsCard.js +1 -1
- package/dist/coolandlovely/components/MetricsCard.js.map +1 -1
- package/dist/coolandlovely/components/ShopItemCard.js +45 -0
- package/dist/coolandlovely/components/ShopItemCard.js.map +1 -0
- package/dist/coolandlovely/components/StepTracker.js +35 -0
- package/dist/coolandlovely/components/StepTracker.js.map +1 -0
- package/dist/coolandlovely/components/Thumbnail.js +15 -11
- package/dist/coolandlovely/components/Thumbnail.js.map +1 -1
- package/dist/coolandlovely/components/VisibilityChip.js +32 -0
- package/dist/coolandlovely/components/VisibilityChip.js.map +1 -0
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +94 -69
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
- package/dist/coolandlovely/hooks/useFiles.js +49 -32
- package/dist/coolandlovely/hooks/useFiles.js.map +1 -1
- package/dist/coolandlovely/pages/HomePage.js +112 -133
- package/dist/coolandlovely/pages/HomePage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js +253 -242
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandFormPage.js +116 -112
- package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandsListPage.js +13 -13
- package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +117 -95
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js +50 -43
- package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +131 -108
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionFormPage.js +1 -1
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js +59 -56
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +175 -147
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemFormPage.js +1 -1
- package/dist/coolandlovely/pages/items/StyleItemsListPage.js +71 -62
- package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +149 -127
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +69 -53
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookDetailPage.js +135 -113
- package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookFormPage.js +122 -110
- package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LooksListPage.js +60 -97
- package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js +372 -210
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
- package/dist/coolandlovely/pages/trends/TrendsPage.js +1 -1
- package/dist/coolandlovely/pages/trends/TrendsPage.js.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +130 -94
- package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +75 -76
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,16 +3,15 @@ import { cn as t } from "../../utils/cn.js";
|
|
|
3
3
|
import { PageLayout as n } from "../../components/PageLayout.js";
|
|
4
4
|
import { StatusBadge as r } from "../../components/StatusBadge.js";
|
|
5
5
|
import { ErrorView as i, LoadingView as a } from "../../components/StateViews.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { useLooks as o } from "../../hooks/useCoolAndLovelyApi.js";
|
|
7
|
+
import { LookCard as s } from "../../components/LookCard.js";
|
|
8
8
|
import "../../hooks/index.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
9
|
+
import { EmptyState as c } from "../../components/EmptyState.js";
|
|
10
|
+
import { useState as l } from "react";
|
|
11
|
+
import { ChevronLeft as u, ChevronRight as d, Plus as f, Sparkles as p, Star as m } from "lucide-react";
|
|
12
|
+
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
14
13
|
//#region src/coolandlovely/pages/looks/LooksListPage.tsx
|
|
15
|
-
var
|
|
14
|
+
var v = 24, y = [
|
|
16
15
|
{
|
|
17
16
|
value: "ALL",
|
|
18
17
|
label: "All"
|
|
@@ -50,138 +49,102 @@ var x = 24, S = [
|
|
|
50
49
|
label: "Other"
|
|
51
50
|
}
|
|
52
51
|
];
|
|
53
|
-
function
|
|
54
|
-
let { navigateTo:
|
|
55
|
-
occasion:
|
|
56
|
-
featured:
|
|
52
|
+
function b() {
|
|
53
|
+
let { navigateTo: b } = e(), [x, S] = l("ALL"), [C, w] = l(!1), [T, E] = l(0), D = o({
|
|
54
|
+
occasion: x === "ALL" ? void 0 : x,
|
|
55
|
+
featured: C ? !0 : void 0,
|
|
57
56
|
pagination: {
|
|
58
|
-
limit:
|
|
59
|
-
offset:
|
|
57
|
+
limit: v,
|
|
58
|
+
offset: T
|
|
60
59
|
}
|
|
61
|
-
}),
|
|
62
|
-
return /* @__PURE__ */
|
|
60
|
+
}), O = D.data?.items ?? [], k = D.data?.pageInfo.hasMore ?? !1;
|
|
61
|
+
return /* @__PURE__ */ _(n, {
|
|
63
62
|
title: "Looks",
|
|
64
63
|
description: "Shop-the-look outfits built from real catalogue pieces",
|
|
65
|
-
actions: /* @__PURE__ */
|
|
64
|
+
actions: /* @__PURE__ */ _("button", {
|
|
66
65
|
type: "button",
|
|
67
|
-
onClick: () =>
|
|
66
|
+
onClick: () => b("/looks/new"),
|
|
68
67
|
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",
|
|
69
|
-
children: [/* @__PURE__ */
|
|
68
|
+
children: [/* @__PURE__ */ g(f, { className: "h-4 w-4" }), " New look"]
|
|
70
69
|
}),
|
|
71
|
-
children: [/* @__PURE__ */
|
|
70
|
+
children: [/* @__PURE__ */ _("div", {
|
|
72
71
|
className: "mb-6 flex flex-wrap items-center gap-2",
|
|
73
|
-
children: [
|
|
72
|
+
children: [y.map((e) => /* @__PURE__ */ g("button", {
|
|
74
73
|
type: "button",
|
|
75
74
|
onClick: () => {
|
|
76
|
-
|
|
75
|
+
S(e.value), E(0);
|
|
77
76
|
},
|
|
78
|
-
className: t("rounded-full px-3 py-1.5 text-sm font-medium transition-colors",
|
|
77
|
+
className: t("rounded-full px-3 py-1.5 text-sm font-medium transition-colors", x === e.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
|
|
79
78
|
children: e.label
|
|
80
|
-
}, e.value)), /* @__PURE__ */
|
|
79
|
+
}, e.value)), /* @__PURE__ */ _("button", {
|
|
81
80
|
type: "button",
|
|
82
81
|
onClick: () => {
|
|
83
|
-
|
|
82
|
+
w((e) => !e), E(0);
|
|
84
83
|
},
|
|
85
|
-
className: t("ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors",
|
|
84
|
+
className: t("ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors", C ? "bg-status-warning-bg-subtle text-status-warning-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
|
|
86
85
|
children: [
|
|
87
|
-
/* @__PURE__ */
|
|
86
|
+
/* @__PURE__ */ g(m, { className: t("h-3.5 w-3.5", C && "fill-status-warning-text") }),
|
|
88
87
|
" ",
|
|
89
88
|
"Featured"
|
|
90
89
|
]
|
|
91
90
|
})]
|
|
92
|
-
}),
|
|
91
|
+
}), D.isLoading ? /* @__PURE__ */ g(a, { label: "Loading looks…" }) : D.isError ? /* @__PURE__ */ g(i, { onRetry: () => void D.refetch() }) : O.length === 0 ? /* @__PURE__ */ g(c, {
|
|
93
92
|
illustration: "empty-data",
|
|
94
|
-
icon: /* @__PURE__ */
|
|
93
|
+
icon: /* @__PURE__ */ g(p, { className: "h-10 w-10" }),
|
|
95
94
|
title: "No looks yet",
|
|
96
95
|
description: "Publish a shop-the-look outfit from catalogue pieces.",
|
|
97
|
-
action: /* @__PURE__ */
|
|
96
|
+
action: /* @__PURE__ */ _("button", {
|
|
98
97
|
type: "button",
|
|
99
|
-
onClick: () =>
|
|
98
|
+
onClick: () => b("/looks/new"),
|
|
100
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",
|
|
101
|
-
children: [/* @__PURE__ */
|
|
100
|
+
children: [/* @__PURE__ */ g(f, { className: "h-4 w-4" }), " New look"]
|
|
102
101
|
})
|
|
103
|
-
}) : /* @__PURE__ */
|
|
102
|
+
}) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("div", {
|
|
104
103
|
className: "grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4",
|
|
105
|
-
children:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
children: /* @__PURE__ */ b("span", {
|
|
122
|
-
className: "inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs font-medium text-status-warning-text",
|
|
123
|
-
children: [/* @__PURE__ */ y(_, { className: "h-3 w-3 fill-status-warning-text" }), " Featured"]
|
|
124
|
-
})
|
|
125
|
-
}),
|
|
126
|
-
e.publishedAt === null && /* @__PURE__ */ y("div", {
|
|
127
|
-
className: "absolute right-2 top-2",
|
|
128
|
-
children: /* @__PURE__ */ y(r, { status: "draft" })
|
|
129
|
-
})
|
|
130
|
-
]
|
|
131
|
-
}), /* @__PURE__ */ b("div", {
|
|
132
|
-
className: "p-3",
|
|
133
|
-
children: [/* @__PURE__ */ y("p", {
|
|
134
|
-
className: "truncate text-sm font-medium text-text-primary",
|
|
135
|
-
children: e.title
|
|
136
|
-
}), /* @__PURE__ */ b("div", {
|
|
137
|
-
className: "mt-1.5 flex items-center justify-between text-xs text-text-secondary",
|
|
138
|
-
children: [/* @__PURE__ */ y("span", { children: c(e.occasion) }), /* @__PURE__ */ b("span", {
|
|
139
|
-
className: "flex items-center gap-2",
|
|
140
|
-
children: [/* @__PURE__ */ b("span", {
|
|
141
|
-
className: "flex items-center gap-1",
|
|
142
|
-
children: [
|
|
143
|
-
/* @__PURE__ */ y(m, { className: "h-3 w-3" }),
|
|
144
|
-
" ",
|
|
145
|
-
e.likeCount
|
|
146
|
-
]
|
|
147
|
-
}), /* @__PURE__ */ b("span", {
|
|
148
|
-
className: "flex items-center gap-1",
|
|
149
|
-
children: [
|
|
150
|
-
/* @__PURE__ */ y(d, { className: "h-3 w-3" }),
|
|
151
|
-
" ",
|
|
152
|
-
e.saveCount
|
|
153
|
-
]
|
|
154
|
-
})]
|
|
155
|
-
})]
|
|
156
|
-
})]
|
|
104
|
+
children: O.map((e) => /* @__PURE__ */ _("div", {
|
|
105
|
+
className: "relative",
|
|
106
|
+
children: [/* @__PURE__ */ g(s, {
|
|
107
|
+
id: e.id,
|
|
108
|
+
title: e.title,
|
|
109
|
+
occasion: e.occasion,
|
|
110
|
+
imageFileId: e.image?.id,
|
|
111
|
+
likeCount: e.likeCount,
|
|
112
|
+
onOpen: () => b(`/looks/${e.id}`),
|
|
113
|
+
showActions: !0
|
|
114
|
+
}), (e.isFeatured || e.publishedAt === null) && /* @__PURE__ */ _("div", {
|
|
115
|
+
className: "pointer-events-none absolute left-2 top-2 z-10 flex flex-col items-start gap-1",
|
|
116
|
+
children: [e.isFeatured && /* @__PURE__ */ _("span", {
|
|
117
|
+
className: "inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs font-medium text-status-warning-text shadow-sm backdrop-blur",
|
|
118
|
+
children: [/* @__PURE__ */ g(m, { className: "h-3 w-3 fill-status-warning-text" }), " Featured"]
|
|
119
|
+
}), e.publishedAt === null && /* @__PURE__ */ g(r, { status: "draft" })]
|
|
157
120
|
})]
|
|
158
121
|
}, e.id))
|
|
159
|
-
}), (
|
|
122
|
+
}), (T > 0 || k) && /* @__PURE__ */ _("div", {
|
|
160
123
|
className: "mt-6 flex items-center justify-center gap-2",
|
|
161
124
|
children: [
|
|
162
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ _("button", {
|
|
163
126
|
type: "button",
|
|
164
|
-
disabled:
|
|
165
|
-
onClick: () =>
|
|
127
|
+
disabled: T === 0,
|
|
128
|
+
onClick: () => E((e) => Math.max(0, e - v)),
|
|
166
129
|
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",
|
|
167
|
-
children: [/* @__PURE__ */
|
|
130
|
+
children: [/* @__PURE__ */ g(u, { className: "h-4 w-4" }), " Previous"]
|
|
168
131
|
}),
|
|
169
|
-
/* @__PURE__ */
|
|
132
|
+
/* @__PURE__ */ _("span", {
|
|
170
133
|
className: "text-sm text-text-secondary",
|
|
171
|
-
children: ["Page ",
|
|
134
|
+
children: ["Page ", T / v + 1]
|
|
172
135
|
}),
|
|
173
|
-
/* @__PURE__ */
|
|
136
|
+
/* @__PURE__ */ _("button", {
|
|
174
137
|
type: "button",
|
|
175
|
-
disabled: !
|
|
176
|
-
onClick: () =>
|
|
138
|
+
disabled: !k,
|
|
139
|
+
onClick: () => E((e) => e + v),
|
|
177
140
|
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",
|
|
178
|
-
children: ["Next ", /* @__PURE__ */
|
|
141
|
+
children: ["Next ", /* @__PURE__ */ g(d, { className: "h-4 w-4" })]
|
|
179
142
|
})
|
|
180
143
|
]
|
|
181
144
|
})] })]
|
|
182
145
|
});
|
|
183
146
|
}
|
|
184
147
|
//#endregion
|
|
185
|
-
export {
|
|
148
|
+
export { b as LooksListPage };
|
|
186
149
|
|
|
187
150
|
//# sourceMappingURL=LooksListPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LooksListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/looks/LooksListPage.tsx"],"sourcesContent":["/**\n * Looks List Page\n * @module coolandlovely/pages/looks\n *\n * Cursor-paginated feed of published looks (`cooListLooks`) with occasion &\n * featured filters.\n */\n\nimport { useState } from 'react';\nimport { Plus, Heart, Bookmark, Sparkles, ChevronLeft, ChevronRight, Star } 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 { useLooks } from '../../hooks';\nimport { titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooLookOccasion } from '../../types';\n\nconst PAGE_SIZE = 24;\n\nconst OCCASIONS: Array<{ value: CooLookOccasion | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'EVERYDAY', label: 'Everyday' },\n { value: 'WORK', label: 'Work' },\n { value: 'EVENING', label: 'Evening' },\n { value: 'WEDDING_GUEST', label: 'Wedding guest' },\n { value: 'VACATION', label: 'Vacation' },\n { value: 'PARTY', label: 'Party' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'OTHER', label: 'Other' },\n];\n\nexport function LooksListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [occasion, setOccasion] = useState<CooLookOccasion | 'ALL'>('ALL');\n const [featuredOnly, setFeaturedOnly] = useState(false);\n const [offset, setOffset] = useState(0);\n\n const query = useLooks({\n occasion: occasion === 'ALL' ? undefined : occasion,\n featured: featuredOnly ? true : undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const looks = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Looks\"\n description=\"Shop-the-look outfits built from real catalogue pieces\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks/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 look\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n {OCCASIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setOccasion(opt.value);\n setOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n occasion === 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 <button\n type=\"button\"\n onClick={() => {\n setFeaturedOnly((v) => !v);\n setOffset(0);\n }}\n className={cn(\n 'ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n featuredOnly\n ? 'bg-status-warning-bg-subtle text-status-warning-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n <Star className={cn('h-3.5 w-3.5', featuredOnly && 'fill-status-warning-text')} />{' '}\n Featured\n </button>\n </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading looks…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : looks.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Sparkles className=\"h-10 w-10\" />}\n title=\"No looks yet\"\n description=\"Publish a shop-the-look outfit from catalogue pieces.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks/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 look\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\n {looks.map((look) => (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.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={<Sparkles className=\"h-9 w-9\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"h-40 w-full\"\n />\n {look.isFeatured && (\n <div className=\"absolute left-2 top-2\">\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs font-medium text-status-warning-text\">\n <Star className=\"h-3 w-3 fill-status-warning-text\" /> Featured\n </span>\n </div>\n )}\n {look.publishedAt === null && (\n <div className=\"absolute right-2 top-2\">\n <StatusBadge status=\"draft\" />\n </div>\n )}\n </div>\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <div className=\"mt-1.5 flex items-center justify-between text-xs text-text-secondary\">\n <span>{titleCase(look.occasion)}</span>\n <span className=\"flex items-center gap-2\">\n <span className=\"flex items-center gap-1\">\n <Heart className=\"h-3 w-3\" /> {look.likeCount}\n </span>\n <span className=\"flex items-center gap-1\">\n <Bookmark className=\"h-3 w-3\" /> {look.saveCount}\n </span>\n </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":";;;;;;;;;;;;;;AAqBA,IAAM,IAAY,IAEZ,IAAsE;CAC1E;EAAE,OAAO;EAAO,OAAO;EAAO;CAC9B;EAAE,OAAO;EAAY,OAAO;EAAY;CACxC;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAW,OAAO;EAAW;CACtC;EAAE,OAAO;EAAiB,OAAO;EAAiB;CAClD;EAAE,OAAO;EAAY,OAAO;EAAY;CACxC;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAU,OAAO;EAAU;CACpC;EAAE,OAAO;EAAS,OAAO;EAAS;CACnC;AAED,SAAgB,IAAgB;CAC9B,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAU,KAAe,EAAkC,MAAM,EAClE,CAAC,GAAc,KAAmB,EAAS,GAAM,EACjD,CAAC,GAAQ,KAAa,EAAS,EAAE,EAEjC,IAAQ,EAAS;EACrB,UAAU,MAAa,QAAQ,KAAA,IAAY;EAC3C,UAAU,IAAe,KAAO,KAAA;EAChC,YAAY;GAAE,OAAO;GAAW;GAAQ;EACzC,CAAC,EAEI,IAAQ,EAAM,MAAM,SAAS,EAAE,EAC/B,IAAU,EAAM,MAAM,SAAS,WAAW;AAEhD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,aAAa;GACvC,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,YACrB;;YAVb,CAaE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAU,KAAK,MACd,kBAAC,UAAD;IAEE,MAAK;IACL,eAAe;AAEb,KADA,EAAY,EAAI,MAAM,EACtB,EAAU,EAAE;;IAEd,WAAW,EACT,kEACA,MAAa,EAAI,QACb,kDACA,2DACL;cAEA,EAAI;IACE,EAdF,EAAI,MAcF,CACT,EACF,kBAAC,UAAD;IACE,MAAK;IACL,eAAe;AAEb,KADA,GAAiB,MAAM,CAAC,EAAE,EAC1B,EAAU,EAAE;;IAEd,WAAW,EACT,2GACA,IACI,yDACA,2DACL;cAXH;KAaE,kBAAC,GAAD,EAAM,WAAW,EAAG,eAAe,KAAgB,2BAA2B,EAAI,CAAA;KAAC;KAAI;KAEhF;MACL;MAEL,EAAM,YACL,kBAAC,GAAD,EAAa,OAAM,kBAAmB,CAAA,GACpC,EAAM,UACR,kBAAC,GAAD,EAAW,eAAe,KAAK,EAAM,SAAS,EAAI,CAAA,GAChD,EAAM,WAAW,IACnB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GACxC,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,aAAa;IACvC,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,YACrB;;GAEX,CAAA,GAEF,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,MACV,kBAAC,UAAD;IAEE,MAAK;IACL,eAAe,EAAW,UAAU,EAAK,KAAK;IAC9C,WAAU;cAJZ,CAME,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;OACtC,MAAM,EAAK;OACX,QAAQ,EAAK,OAAO;OACpB,KAAK,EAAK;OACV,WAAU;OACV,CAAA;MACD,EAAK,cACJ,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CACE,kBAAC,GAAD,EAAM,WAAU,oCAAqC,CAAA,EAAA,YAChD;;OACH,CAAA;MAEP,EAAK,gBAAgB,QACpB,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD,EAAa,QAAO,SAAU,CAAA;OAC1B,CAAA;MAEJ;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAkD,EAAK;MAAU,CAAA,EAC9E,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD,EAAA,UAAO,EAAU,EAAK,SAAS,EAAQ,CAAA,EACvC,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;;SAAE,EAAK;SAC/B;WACP,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;;SAAE,EAAK;SAClC;UACF;SACH;QACF;OACC;MAxCF,EAAK,GAwCH,CACT;GACE,CAAA,GAEJ,IAAS,KAAK,MACd,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,MAAW;KACrB,eAAe,GAAW,MAAM,KAAK,IAAI,GAAG,IAAI,EAAU,CAAC;KAC3D,WAAU;eAJZ,CAME,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA,EAAA,YAC5B;;IACT,kBAAC,QAAD;KAAM,WAAU;eAAhB,CAA8C,SAAM,IAAS,IAAY,EAAS;;IAClF,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,CAAC;KACX,eAAe,GAAW,MAAM,IAAI,EAAU;KAC9C,WAAU;eAJZ,CAKC,SACM,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA,CAClC;;IACL;KAEP,EAAA,CAAA,CAEM"}
|
|
1
|
+
{"version":3,"file":"LooksListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/looks/LooksListPage.tsx"],"sourcesContent":["/**\n * Looks List Page\n * @module coolandlovely/pages/looks\n *\n * Cursor-paginated feed of published looks (`cooListLooks`) with occasion &\n * featured filters.\n */\n\nimport { useState } from 'react';\nimport { Plus, Sparkles, ChevronLeft, ChevronRight, Star } 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 { LookCard } from '../../components/LookCard';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useLooks } from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport type { CooLookOccasion } from '../../types';\n\nconst PAGE_SIZE = 24;\n\nconst OCCASIONS: Array<{ value: CooLookOccasion | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'EVERYDAY', label: 'Everyday' },\n { value: 'WORK', label: 'Work' },\n { value: 'EVENING', label: 'Evening' },\n { value: 'WEDDING_GUEST', label: 'Wedding guest' },\n { value: 'VACATION', label: 'Vacation' },\n { value: 'PARTY', label: 'Party' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'OTHER', label: 'Other' },\n];\n\nexport function LooksListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [occasion, setOccasion] = useState<CooLookOccasion | 'ALL'>('ALL');\n const [featuredOnly, setFeaturedOnly] = useState(false);\n const [offset, setOffset] = useState(0);\n\n const query = useLooks({\n occasion: occasion === 'ALL' ? undefined : occasion,\n featured: featuredOnly ? true : undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const looks = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Looks\"\n description=\"Shop-the-look outfits built from real catalogue pieces\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks/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 look\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n {OCCASIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setOccasion(opt.value);\n setOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n occasion === 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 <button\n type=\"button\"\n onClick={() => {\n setFeaturedOnly((v) => !v);\n setOffset(0);\n }}\n className={cn(\n 'ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n featuredOnly\n ? 'bg-status-warning-bg-subtle text-status-warning-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n <Star className={cn('h-3.5 w-3.5', featuredOnly && 'fill-status-warning-text')} />{' '}\n Featured\n </button>\n </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading looks…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : looks.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Sparkles className=\"h-10 w-10\" />}\n title=\"No looks yet\"\n description=\"Publish a shop-the-look outfit from catalogue pieces.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks/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 look\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\n {looks.map((look) => (\n <div key={look.id} className=\"relative\">\n <LookCard\n id={look.id}\n title={look.title}\n occasion={look.occasion}\n imageFileId={look.image?.id}\n likeCount={look.likeCount}\n onOpen={() => navigateTo(`/looks/${look.id}`)}\n showActions\n />\n {(look.isFeatured || look.publishedAt === null) && (\n <div className=\"pointer-events-none absolute left-2 top-2 z-10 flex flex-col items-start gap-1\">\n {look.isFeatured && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs font-medium text-status-warning-text shadow-sm backdrop-blur\">\n <Star className=\"h-3 w-3 fill-status-warning-text\" /> Featured\n </span>\n )}\n {look.publishedAt === null && <StatusBadge status=\"draft\" />}\n </div>\n )}\n </div>\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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"}
|