@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.
- package/dist/coolandlovely/CoolAndLovelyRoutes.js +14 -6
- package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
- package/dist/coolandlovely/components/ActorName.js +29 -0
- package/dist/coolandlovely/components/ActorName.js.map +1 -0
- package/dist/coolandlovely/components/AddToLookbookButton.js +81 -0
- package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -0
- package/dist/coolandlovely/components/Comments.js +109 -0
- package/dist/coolandlovely/components/Comments.js.map +1 -0
- package/dist/coolandlovely/components/Field.js +22 -2
- package/dist/coolandlovely/components/Field.js.map +1 -1
- package/dist/coolandlovely/components/FileImage.js +17 -0
- package/dist/coolandlovely/components/FileImage.js.map +1 -0
- package/dist/coolandlovely/components/FollowButton.js +24 -0
- package/dist/coolandlovely/components/FollowButton.js.map +1 -0
- package/dist/coolandlovely/components/ImageUploadField.js +71 -0
- package/dist/coolandlovely/components/ImageUploadField.js.map +1 -0
- package/dist/coolandlovely/components/Thumbnail.js +20 -13
- package/dist/coolandlovely/components/Thumbnail.js.map +1 -1
- package/dist/coolandlovely/hooks/index.js +2 -0
- package/dist/coolandlovely/hooks/useComments.js +68 -0
- package/dist/coolandlovely/hooks/useComments.js.map +1 -0
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +74 -4
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
- package/dist/coolandlovely/hooks/useFiles.js +94 -0
- package/dist/coolandlovely/hooks/useFiles.js.map +1 -0
- package/dist/coolandlovely/pages/HomePage.js +105 -87
- package/dist/coolandlovely/pages/HomePage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js +144 -122
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandFormPage.js +128 -90
- package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandsListPage.js +2 -0
- package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +5 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionFormPage.js +117 -102
- package/dist/coolandlovely/pages/collections/CollectionFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js +2 -0
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js +223 -0
- package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -0
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +99 -95
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemFormPage.js +144 -130
- package/dist/coolandlovely/pages/items/StyleItemFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemsListPage.js +2 -0
- package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +190 -99
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +81 -68
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookDetailPage.js +195 -155
- package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookFormPage.js +127 -88
- package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LooksListPage.js +2 -0
- package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js +169 -101
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
- package/dist/coolandlovely/pages/trends/TrendsPage.js +249 -0
- package/dist/coolandlovely/pages/trends/TrendsPage.js.map +1 -0
- package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +88 -76
- package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +2 -0
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
|
|
2
|
+
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
|
+
import { ErrorView as n, LoadingView as r } from "../../components/StateViews.js";
|
|
4
|
+
import { Thumbnail as i } from "../../components/Thumbnail.js";
|
|
5
|
+
import { useLooks as a, useMyFollowing as o, useMyStyleProfile as s, useStyleItems as c } from "../../hooks/useCoolAndLovelyApi.js";
|
|
6
|
+
import "../../hooks/index.js";
|
|
7
|
+
import { titleCase as l } from "../../utils/formatters.js";
|
|
8
|
+
import { TagList as u } from "../../components/TagList.js";
|
|
9
|
+
import { EmptyState as d } from "../../components/EmptyState.js";
|
|
10
|
+
import { useMemo as f } from "react";
|
|
11
|
+
import { Compass as p, Heart as m, ShoppingBag as h, Sparkles as g, UserCheck as _, Users as v } from "lucide-react";
|
|
12
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
13
|
+
import { EmphasisPanel as x, PagePurpose as S } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
//#region src/coolandlovely/pages/discover/DiscoverPage.tsx
|
|
15
|
+
function C(e) {
|
|
16
|
+
return new Set(e.map((e) => e.trim().toLowerCase()).filter(Boolean));
|
|
17
|
+
}
|
|
18
|
+
function w(e, t) {
|
|
19
|
+
let n = 0;
|
|
20
|
+
for (let r of e) t.has(r.trim().toLowerCase()) && (n += 1);
|
|
21
|
+
return n;
|
|
22
|
+
}
|
|
23
|
+
var T = ({ title: e, icon: t, sublabel: n, children: r }) => /* @__PURE__ */ b("section", {
|
|
24
|
+
className: "mt-8",
|
|
25
|
+
children: [/* @__PURE__ */ b("div", {
|
|
26
|
+
className: "mb-3",
|
|
27
|
+
children: [/* @__PURE__ */ b("h2", {
|
|
28
|
+
className: "flex items-center gap-2 text-lg font-semibold text-text-primary",
|
|
29
|
+
children: [
|
|
30
|
+
t,
|
|
31
|
+
" ",
|
|
32
|
+
e
|
|
33
|
+
]
|
|
34
|
+
}), n ? /* @__PURE__ */ y("p", {
|
|
35
|
+
className: "mt-0.5 text-sm text-text-secondary",
|
|
36
|
+
children: n
|
|
37
|
+
}) : null]
|
|
38
|
+
}), r]
|
|
39
|
+
});
|
|
40
|
+
function E() {
|
|
41
|
+
let { navigateTo: E } = e(), D = s(), O = a({ pagination: {
|
|
42
|
+
limit: 100,
|
|
43
|
+
offset: 0
|
|
44
|
+
} }), k = c({ pagination: {
|
|
45
|
+
limit: 100,
|
|
46
|
+
offset: 0
|
|
47
|
+
} }), A = o(), j = D.isLoading || O.isLoading || k.isLoading, M = O.isError && k.isError, N = f(() => {
|
|
48
|
+
let e = D.data, t = O.data?.items ?? [], n = k.data?.items ?? [], r = new Set((A.data ?? []).map((e) => e.ownerId)), i = C([
|
|
49
|
+
...e?.stylePreferences ?? [],
|
|
50
|
+
...e?.palette ?? [],
|
|
51
|
+
...e?.favouriteBrands ?? []
|
|
52
|
+
]), a = C(e?.palette ?? []), o = C(e?.favouriteBrands ?? []), s = (e) => w(e.tags, i) * 2 + +!!i.has(e.occasion.toLowerCase()) + e.likeCount * .05 + e.saveCount * .05, c = (e) => w(e.tags, i) * 2 + w(e.colours, a) * 2 + +!!i.has(e.category.toLowerCase()) + (o.size && e.tags.some((e) => o.has(e.toLowerCase())) ? 1 : 0), l = i.size > 0, u = [...t].sort((e, t) => l ? s(t) - s(e) : t.likeCount + t.saveCount - (e.likeCount + e.saveCount)).slice(0, 8), d = [...n].filter((e) => l ? c(e) > 0 : !0).sort((e, t) => c(t) - c(e)).slice(0, 8), f = t.filter((e) => r.has(e.authorId)).sort((e, t) => t.likeCount + t.saveCount - (e.likeCount + e.saveCount)).slice(0, 8);
|
|
53
|
+
return {
|
|
54
|
+
hasProfile: !!e,
|
|
55
|
+
hasTaste: l,
|
|
56
|
+
madeForYou: u,
|
|
57
|
+
inYourPalette: d,
|
|
58
|
+
fromFollowing: f,
|
|
59
|
+
followingProfiles: A.data ?? []
|
|
60
|
+
};
|
|
61
|
+
}, [
|
|
62
|
+
D.data,
|
|
63
|
+
O.data,
|
|
64
|
+
k.data,
|
|
65
|
+
A.data
|
|
66
|
+
]);
|
|
67
|
+
return j ? /* @__PURE__ */ y(t, {
|
|
68
|
+
title: "Discover",
|
|
69
|
+
children: /* @__PURE__ */ y(r, { label: "Curating your feed…" })
|
|
70
|
+
}) : M ? /* @__PURE__ */ y(t, {
|
|
71
|
+
title: "Discover",
|
|
72
|
+
children: /* @__PURE__ */ y(n, { onRetry: () => {
|
|
73
|
+
O.refetch(), k.refetch();
|
|
74
|
+
} })
|
|
75
|
+
}) : /* @__PURE__ */ b(t, {
|
|
76
|
+
title: "Discover",
|
|
77
|
+
description: "Looks and pieces tuned to your taste",
|
|
78
|
+
hero: !0,
|
|
79
|
+
children: [
|
|
80
|
+
/* @__PURE__ */ y(S, {
|
|
81
|
+
className: "mb-6",
|
|
82
|
+
children: "Your personalised feed, computed live from your style profile against the pieces and looks on the platform — the closer a piece matches the aesthetics, palette and brands you follow, the higher it ranks. Nothing here is fabricated."
|
|
83
|
+
}),
|
|
84
|
+
N.hasProfile ? null : /* @__PURE__ */ y(x, {
|
|
85
|
+
className: "mb-8",
|
|
86
|
+
children: /* @__PURE__ */ b("div", {
|
|
87
|
+
className: "flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between",
|
|
88
|
+
children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("h2", {
|
|
89
|
+
className: "text-lg font-semibold text-text-primary",
|
|
90
|
+
children: "Build your style profile"
|
|
91
|
+
}), /* @__PURE__ */ y("p", {
|
|
92
|
+
className: "mt-1 text-sm text-text-secondary",
|
|
93
|
+
children: "Tell us your aesthetics, palette and favourite brands and this feed tunes itself to you."
|
|
94
|
+
})] }), /* @__PURE__ */ b("button", {
|
|
95
|
+
type: "button",
|
|
96
|
+
onClick: () => E("/profile"),
|
|
97
|
+
className: "inline-flex shrink-0 items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90",
|
|
98
|
+
children: [/* @__PURE__ */ y(g, { className: "h-4 w-4" }), " Create profile"]
|
|
99
|
+
})]
|
|
100
|
+
})
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ y(T, {
|
|
103
|
+
title: "Made for you",
|
|
104
|
+
icon: /* @__PURE__ */ y(p, { className: "h-5 w-5" }),
|
|
105
|
+
sublabel: N.hasTaste ? "Ranked to match your style profile" : "Most-loved looks on the platform",
|
|
106
|
+
children: N.madeForYou.length === 0 ? /* @__PURE__ */ y(d, {
|
|
107
|
+
title: "No looks yet",
|
|
108
|
+
description: "Once looks are published they will appear here, tuned to your taste."
|
|
109
|
+
}) : /* @__PURE__ */ y("div", {
|
|
110
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
111
|
+
children: N.madeForYou.map((e) => /* @__PURE__ */ b("button", {
|
|
112
|
+
type: "button",
|
|
113
|
+
onClick: () => E(`/looks/${e.id}`),
|
|
114
|
+
className: "group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md",
|
|
115
|
+
children: [/* @__PURE__ */ y(i, {
|
|
116
|
+
icon: /* @__PURE__ */ y(g, { className: "h-6 w-6" }),
|
|
117
|
+
seed: e.id,
|
|
118
|
+
fileId: e.image?.id,
|
|
119
|
+
alt: e.title,
|
|
120
|
+
className: "aspect-[4/5] w-full rounded-none"
|
|
121
|
+
}), /* @__PURE__ */ b("div", {
|
|
122
|
+
className: "min-w-0 p-3",
|
|
123
|
+
children: [
|
|
124
|
+
/* @__PURE__ */ y("p", {
|
|
125
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
126
|
+
children: e.title
|
|
127
|
+
}),
|
|
128
|
+
/* @__PURE__ */ y("p", {
|
|
129
|
+
className: "mt-0.5 text-xs text-text-secondary",
|
|
130
|
+
children: l(e.occasion)
|
|
131
|
+
}),
|
|
132
|
+
/* @__PURE__ */ b("span", {
|
|
133
|
+
className: "mt-2 inline-flex items-center gap-1 text-xs text-text-secondary",
|
|
134
|
+
children: [
|
|
135
|
+
/* @__PURE__ */ y(m, { className: "h-3.5 w-3.5" }),
|
|
136
|
+
" ",
|
|
137
|
+
e.likeCount
|
|
138
|
+
]
|
|
139
|
+
})
|
|
140
|
+
]
|
|
141
|
+
})]
|
|
142
|
+
}, e.id))
|
|
143
|
+
})
|
|
144
|
+
}),
|
|
145
|
+
N.inYourPalette.length > 0 ? /* @__PURE__ */ y(T, {
|
|
146
|
+
title: "In your palette",
|
|
147
|
+
icon: /* @__PURE__ */ y(h, { className: "h-5 w-5" }),
|
|
148
|
+
sublabel: "Pieces that match your colours, categories and tags",
|
|
149
|
+
children: /* @__PURE__ */ y("div", {
|
|
150
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
151
|
+
children: N.inYourPalette.map((e) => /* @__PURE__ */ b("button", {
|
|
152
|
+
type: "button",
|
|
153
|
+
onClick: () => E(`/items/${e.id}`),
|
|
154
|
+
className: "group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md",
|
|
155
|
+
children: [/* @__PURE__ */ y(i, {
|
|
156
|
+
icon: /* @__PURE__ */ y(h, { className: "h-6 w-6" }),
|
|
157
|
+
seed: e.id,
|
|
158
|
+
fileId: e.image?.id,
|
|
159
|
+
alt: e.name,
|
|
160
|
+
className: "aspect-[4/5] w-full rounded-none"
|
|
161
|
+
}), /* @__PURE__ */ b("div", {
|
|
162
|
+
className: "min-w-0 p-3",
|
|
163
|
+
children: [
|
|
164
|
+
/* @__PURE__ */ y("p", {
|
|
165
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
166
|
+
children: e.name
|
|
167
|
+
}),
|
|
168
|
+
/* @__PURE__ */ y("p", {
|
|
169
|
+
className: "mt-0.5 text-xs text-text-secondary",
|
|
170
|
+
children: l(e.category)
|
|
171
|
+
}),
|
|
172
|
+
/* @__PURE__ */ y(u, {
|
|
173
|
+
tags: e.colours.slice(0, 3),
|
|
174
|
+
className: "mt-2"
|
|
175
|
+
})
|
|
176
|
+
]
|
|
177
|
+
})]
|
|
178
|
+
}, e.id))
|
|
179
|
+
})
|
|
180
|
+
}) : null,
|
|
181
|
+
/* @__PURE__ */ y(T, {
|
|
182
|
+
title: "From people you follow",
|
|
183
|
+
icon: /* @__PURE__ */ y(_, { className: "h-5 w-5" }),
|
|
184
|
+
sublabel: N.followingProfiles.length === 0 ? "Follow creators and shoppers to see their looks here" : `You follow ${N.followingProfiles.length} ${N.followingProfiles.length === 1 ? "person" : "people"}`,
|
|
185
|
+
children: N.followingProfiles.length === 0 ? /* @__PURE__ */ y(d, {
|
|
186
|
+
title: "You are not following anyone yet",
|
|
187
|
+
description: "Open a look or a style profile and tap Follow to build a feed from people whose taste you love.",
|
|
188
|
+
icon: /* @__PURE__ */ y(v, { className: "h-8 w-8" })
|
|
189
|
+
}) : N.fromFollowing.length === 0 ? /* @__PURE__ */ y("div", {
|
|
190
|
+
className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
191
|
+
children: "The people you follow have not published looks visible to you yet."
|
|
192
|
+
}) : /* @__PURE__ */ y("div", {
|
|
193
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
194
|
+
children: N.fromFollowing.map((e) => /* @__PURE__ */ b("button", {
|
|
195
|
+
type: "button",
|
|
196
|
+
onClick: () => E(`/looks/${e.id}`),
|
|
197
|
+
className: "group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md",
|
|
198
|
+
children: [/* @__PURE__ */ y(i, {
|
|
199
|
+
icon: /* @__PURE__ */ y(g, { className: "h-6 w-6" }),
|
|
200
|
+
seed: e.id,
|
|
201
|
+
fileId: e.image?.id,
|
|
202
|
+
alt: e.title,
|
|
203
|
+
className: "aspect-[4/5] w-full rounded-none"
|
|
204
|
+
}), /* @__PURE__ */ b("div", {
|
|
205
|
+
className: "min-w-0 p-3",
|
|
206
|
+
children: [/* @__PURE__ */ y("p", {
|
|
207
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
208
|
+
children: e.title
|
|
209
|
+
}), /* @__PURE__ */ y("p", {
|
|
210
|
+
className: "mt-0.5 text-xs text-text-secondary",
|
|
211
|
+
children: l(e.occasion)
|
|
212
|
+
})]
|
|
213
|
+
})]
|
|
214
|
+
}, e.id))
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
]
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
221
|
+
export { E as DiscoverPage };
|
|
222
|
+
|
|
223
|
+
//# sourceMappingURL=DiscoverPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DiscoverPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/discover/DiscoverPage.tsx"],"sourcesContent":["/**\n * Discover Page\n * @module coolandlovely/pages/discover\n *\n * A profile-tuned discovery feed computed entirely client-side over the REAL\n * catalogue + social lists (cooListLooks / cooListStyleItems) and the caller's\n * own style profile (cooMyStyleProfile) + follow graph (cooMyFollowing). It only\n * ranks what is actually on the platform against the taste the shopper declared\n * — no fabricated recommendations, no black-box \"AI\" (that is roadmap). When the\n * shopper has no profile yet, it invites them to build one.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useMemo } from 'react';\nimport { Compass, Sparkles, Heart, ShoppingBag, UserCheck, Users } from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useMyStyleProfile, useLooks, useStyleItems, useMyFollowing } from '../../hooks';\nimport type { CooLook, CooStyleItem } from '../../types';\nimport { titleCase } from '../../utils/formatters';\n\n/** Lower-cased token set used for overlap scoring. */\nfunction tokenSet(values: string[]): Set<string> {\n return new Set(values.map((v) => v.trim().toLowerCase()).filter(Boolean));\n}\n\n/** Count how many of `candidate`'s tokens appear in the taste set. */\nfunction overlap(candidate: string[], taste: Set<string>): number {\n let n = 0;\n for (const c of candidate) {\n if (taste.has(c.trim().toLowerCase())) n += 1;\n }\n return n;\n}\n\ninterface SectionProps {\n title: string;\n icon: ReactNode;\n children: ReactNode;\n sublabel?: string;\n}\n\nconst Section: FC<SectionProps> = ({ title, icon, sublabel, children }) => (\n <section className=\"mt-8\">\n <div className=\"mb-3\">\n <h2 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n {icon} {title}\n </h2>\n {sublabel ? <p className=\"mt-0.5 text-sm text-text-secondary\">{sublabel}</p> : null}\n </div>\n {children}\n </section>\n);\n\nexport function DiscoverPage() {\n const { navigateTo } = useCoolAndLovely();\n const profile = useMyStyleProfile();\n const looks = useLooks({ pagination: { limit: 100, offset: 0 } });\n const items = useStyleItems({ pagination: { limit: 100, offset: 0 } });\n const following = useMyFollowing();\n\n const isLoading = profile.isLoading || looks.isLoading || items.isLoading;\n const isError = looks.isError && items.isError;\n\n const feed = useMemo(() => {\n const p = profile.data;\n const lookRows = looks.data?.items ?? [];\n const itemRows = items.data?.items ?? [];\n const followingOwners = new Set((following.data ?? []).map((f) => f.ownerId));\n\n // Taste = declared style preferences ∪ palette ∪ favourite brands.\n const taste = tokenSet([\n ...(p?.stylePreferences ?? []),\n ...(p?.palette ?? []),\n ...(p?.favouriteBrands ?? []),\n ]);\n const paletteTokens = tokenSet(p?.palette ?? []);\n const brandTokens = tokenSet(p?.favouriteBrands ?? []);\n\n const scoreLook = (l: CooLook): number =>\n overlap(l.tags, taste) * 2 +\n (taste.has(l.occasion.toLowerCase()) ? 1 : 0) +\n l.likeCount * 0.05 +\n l.saveCount * 0.05;\n\n const scoreItem = (it: CooStyleItem): number =>\n overlap(it.tags, taste) * 2 +\n overlap(it.colours, paletteTokens) * 2 +\n (taste.has(it.category.toLowerCase()) ? 1 : 0) +\n (brandTokens.size && it.tags.some((t) => brandTokens.has(t.toLowerCase())) ? 1 : 0);\n\n const hasTaste = taste.size > 0;\n\n // \"Made for you\": when the shopper has taste, rank by match then engagement;\n // otherwise fall back to most-loved looks so the feed is never empty.\n const madeForYou = [...lookRows]\n .sort((a, b) =>\n hasTaste\n ? scoreLook(b) - scoreLook(a)\n : b.likeCount + b.saveCount - (a.likeCount + a.saveCount)\n )\n .slice(0, 8);\n\n const inYourPalette = [...itemRows]\n .filter((it) => (hasTaste ? scoreItem(it) > 0 : true))\n .sort((a, b) => scoreItem(b) - scoreItem(a))\n .slice(0, 8);\n\n const fromFollowing = lookRows\n .filter((l) => followingOwners.has(l.authorId))\n .sort((a, b) => b.likeCount + b.saveCount - (a.likeCount + a.saveCount))\n .slice(0, 8);\n\n return {\n hasProfile: Boolean(p),\n hasTaste,\n madeForYou,\n inYourPalette,\n fromFollowing,\n followingProfiles: following.data ?? [],\n };\n }, [profile.data, looks.data, items.data, following.data]);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Discover\">\n <LoadingView label=\"Curating your feed…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Discover\">\n <ErrorView\n onRetry={() => {\n void looks.refetch();\n void items.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Discover\" description=\"Looks and pieces tuned to your taste\" hero>\n <PagePurpose className=\"mb-6\">\n Your personalised feed, computed live from your style profile against the pieces and looks on\n the platform — the closer a piece matches the aesthetics, palette and brands you follow, the\n higher it ranks. Nothing here is fabricated.\n </PagePurpose>\n\n {!feed.hasProfile ? (\n <EmphasisPanel className=\"mb-8\">\n <div className=\"flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Build your style profile</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Tell us your aesthetics, palette and favourite brands and this feed tunes itself to you.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('/profile')}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <Sparkles className=\"h-4 w-4\" /> Create profile\n </button>\n </div>\n </EmphasisPanel>\n ) : null}\n\n <Section\n title=\"Made for you\"\n icon={<Compass className=\"h-5 w-5\" />}\n sublabel={feed.hasTaste ? 'Ranked to match your style profile' : 'Most-loved looks on the platform'}\n >\n {feed.madeForYou.length === 0 ? (\n <EmptyState\n title=\"No looks yet\"\n description=\"Once looks are published they will appear here, tuned to your taste.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.madeForYou.map((look) => (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{titleCase(look.occasion)}</p>\n <span className=\"mt-2 inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Heart className=\"h-3.5 w-3.5\" /> {look.likeCount}\n </span>\n </div>\n </button>\n ))}\n </div>\n )}\n </Section>\n\n {feed.inYourPalette.length > 0 ? (\n <Section\n title=\"In your palette\"\n icon={<ShoppingBag className=\"h-5 w-5\" />}\n sublabel=\"Pieces that match your colours, categories and tags\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.inYourPalette.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<ShoppingBag className=\"h-6 w-6\" />}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{titleCase(item.category)}</p>\n <TagList tags={item.colours.slice(0, 3)} className=\"mt-2\" />\n </div>\n </button>\n ))}\n </div>\n </Section>\n ) : null}\n\n <Section\n title=\"From people you follow\"\n icon={<UserCheck className=\"h-5 w-5\" />}\n sublabel={\n feed.followingProfiles.length === 0\n ? 'Follow creators and shoppers to see their looks here'\n : `You follow ${feed.followingProfiles.length} ${feed.followingProfiles.length === 1 ? 'person' : 'people'}`\n }\n >\n {feed.followingProfiles.length === 0 ? (\n <EmptyState\n title=\"You are not following anyone yet\"\n description=\"Open a look or a style profile and tap Follow to build a feed from people whose taste you love.\"\n icon={<Users className=\"h-8 w-8\" />}\n />\n ) : feed.fromFollowing.length === 0 ? (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n The people you follow have not published looks visible to you yet.\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {feed.fromFollowing.map((look) => (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-colors hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"aspect-[4/5] w-full rounded-none\"\n />\n <div className=\"min-w-0 p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{titleCase(look.occasion)}</p>\n </div>\n </button>\n ))}\n </div>\n )}\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -8,113 +8,117 @@ import "../../hooks/index.js";
|
|
|
8
8
|
import { formatDate as c, formatPrice as l, titleCase as u } from "../../utils/formatters.js";
|
|
9
9
|
import { TagList as d } from "../../components/TagList.js";
|
|
10
10
|
import { categoryIcon as f } from "../../utils/icons.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
11
|
+
import { AddToLookbookButton as p } from "../../components/AddToLookbookButton.js";
|
|
12
|
+
import { Archive as m, ArrowLeft as h, Loader2 as g, Pencil as _, Shapes as v, Store as y } from "lucide-react";
|
|
13
|
+
import { useParams as b } from "react-router-dom";
|
|
14
|
+
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
15
|
+
import { GlassCard as C } from "@burdenoff/fe-libs/ui";
|
|
15
16
|
//#region src/coolandlovely/pages/items/StyleItemDetailPage.tsx
|
|
16
|
-
function
|
|
17
|
-
let { itemId:
|
|
18
|
-
if (
|
|
17
|
+
function w() {
|
|
18
|
+
let { itemId: w } = b(), { navigateTo: T } = e(), E = s(w), D = o();
|
|
19
|
+
if (E.isLoading) return /* @__PURE__ */ x(t, {
|
|
19
20
|
title: "Style item",
|
|
20
|
-
children: /* @__PURE__ */
|
|
21
|
+
children: /* @__PURE__ */ x(i, { label: "Loading item…" })
|
|
21
22
|
});
|
|
22
|
-
if (
|
|
23
|
+
if (E.isError || !E.data) return /* @__PURE__ */ x(t, {
|
|
23
24
|
title: "Style item",
|
|
24
|
-
children: /* @__PURE__ */
|
|
25
|
+
children: /* @__PURE__ */ x(r, {
|
|
25
26
|
title: "Item not found",
|
|
26
|
-
onRetry: () => void
|
|
27
|
+
onRetry: () => void E.refetch()
|
|
27
28
|
})
|
|
28
29
|
});
|
|
29
|
-
let
|
|
30
|
-
return /* @__PURE__ */
|
|
31
|
-
title:
|
|
32
|
-
description:
|
|
33
|
-
actions: /* @__PURE__ */
|
|
34
|
-
className: "flex items-center gap-2",
|
|
30
|
+
let O = E.data, k = O.status === "RETIRED";
|
|
31
|
+
return /* @__PURE__ */ x(t, {
|
|
32
|
+
title: O.name,
|
|
33
|
+
description: O.brand?.name ?? void 0,
|
|
34
|
+
actions: /* @__PURE__ */ S("div", {
|
|
35
|
+
className: "flex flex-wrap items-center gap-2",
|
|
35
36
|
children: [
|
|
36
|
-
/* @__PURE__ */
|
|
37
|
+
/* @__PURE__ */ S("button", {
|
|
37
38
|
type: "button",
|
|
38
|
-
onClick: () =>
|
|
39
|
+
onClick: () => T("/items"),
|
|
39
40
|
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",
|
|
40
|
-
children: [/* @__PURE__ */
|
|
41
|
+
children: [/* @__PURE__ */ x(h, { className: "h-4 w-4" }), " Back"]
|
|
41
42
|
}),
|
|
42
|
-
/* @__PURE__ */ x(
|
|
43
|
+
/* @__PURE__ */ x(p, { styleItemId: O.id }),
|
|
44
|
+
/* @__PURE__ */ S("button", {
|
|
43
45
|
type: "button",
|
|
44
|
-
onClick: () =>
|
|
46
|
+
onClick: () => T(`/items/${O.id}/edit`),
|
|
45
47
|
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",
|
|
46
|
-
children: [/* @__PURE__ */
|
|
48
|
+
children: [/* @__PURE__ */ x(_, { className: "h-4 w-4" }), " Edit"]
|
|
47
49
|
}),
|
|
48
|
-
!
|
|
50
|
+
!k && /* @__PURE__ */ S("button", {
|
|
49
51
|
type: "button",
|
|
50
|
-
disabled:
|
|
51
|
-
onClick: () =>
|
|
52
|
+
disabled: D.isPending,
|
|
53
|
+
onClick: () => D.mutate(O.id, { onSuccess: () => T("/items") }),
|
|
52
54
|
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50",
|
|
53
|
-
children: [
|
|
55
|
+
children: [D.isPending ? /* @__PURE__ */ x(g, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ x(m, { className: "h-4 w-4" }), "Archive"]
|
|
54
56
|
})
|
|
55
57
|
]
|
|
56
58
|
}),
|
|
57
|
-
children: /* @__PURE__ */
|
|
59
|
+
children: /* @__PURE__ */ S("div", {
|
|
58
60
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
61
|
+
children: [/* @__PURE__ */ x("div", {
|
|
60
62
|
className: "lg:col-span-2",
|
|
61
|
-
children: /* @__PURE__ */
|
|
63
|
+
children: /* @__PURE__ */ S(C, {
|
|
62
64
|
treatment: "glass",
|
|
63
65
|
className: "overflow-hidden p-0",
|
|
64
|
-
children: [/* @__PURE__ */
|
|
65
|
-
icon: f(
|
|
66
|
-
seed:
|
|
66
|
+
children: [/* @__PURE__ */ x(a, {
|
|
67
|
+
icon: f(O.category, 40),
|
|
68
|
+
seed: O.id,
|
|
69
|
+
fileId: O.image?.id,
|
|
70
|
+
alt: O.name,
|
|
67
71
|
className: "h-52 w-full"
|
|
68
|
-
}), /* @__PURE__ */
|
|
72
|
+
}), /* @__PURE__ */ S("div", {
|
|
69
73
|
className: "p-6",
|
|
70
74
|
children: [
|
|
71
|
-
/* @__PURE__ */
|
|
75
|
+
/* @__PURE__ */ S("div", {
|
|
72
76
|
className: "flex items-center gap-2",
|
|
73
|
-
children: [/* @__PURE__ */
|
|
77
|
+
children: [/* @__PURE__ */ x("h2", {
|
|
74
78
|
className: "text-xl font-semibold text-text-primary",
|
|
75
|
-
children:
|
|
76
|
-
}), /* @__PURE__ */
|
|
77
|
-
status:
|
|
79
|
+
children: O.name
|
|
80
|
+
}), /* @__PURE__ */ x(n, {
|
|
81
|
+
status: O.status,
|
|
78
82
|
className: "ml-auto"
|
|
79
83
|
})]
|
|
80
84
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
85
|
+
/* @__PURE__ */ x("p", {
|
|
82
86
|
className: "mt-1 text-2xl font-bold text-text-primary tabular-nums",
|
|
83
|
-
children: l(
|
|
87
|
+
children: l(O.price, O.currency)
|
|
84
88
|
}),
|
|
85
|
-
|
|
89
|
+
O.description && /* @__PURE__ */ x("p", {
|
|
86
90
|
className: "mt-3 text-sm text-text-secondary",
|
|
87
|
-
children:
|
|
91
|
+
children: O.description
|
|
88
92
|
}),
|
|
89
|
-
/* @__PURE__ */
|
|
93
|
+
/* @__PURE__ */ S("div", {
|
|
90
94
|
className: "mt-5 grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
91
95
|
children: [
|
|
92
|
-
|
|
96
|
+
O.colours.length > 0 && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
93
97
|
className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
94
98
|
children: "Colours"
|
|
95
|
-
}), /* @__PURE__ */
|
|
96
|
-
tags:
|
|
99
|
+
}), /* @__PURE__ */ x(d, {
|
|
100
|
+
tags: O.colours,
|
|
97
101
|
max: 10
|
|
98
102
|
})] }),
|
|
99
|
-
|
|
103
|
+
O.sizes.length > 0 && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
100
104
|
className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
101
105
|
children: "Sizes"
|
|
102
|
-
}), /* @__PURE__ */
|
|
103
|
-
tags:
|
|
106
|
+
}), /* @__PURE__ */ x(d, {
|
|
107
|
+
tags: O.sizes,
|
|
104
108
|
max: 10
|
|
105
109
|
})] }),
|
|
106
|
-
|
|
110
|
+
O.materials.length > 0 && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
107
111
|
className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
108
112
|
children: "Materials"
|
|
109
|
-
}), /* @__PURE__ */
|
|
110
|
-
tags:
|
|
113
|
+
}), /* @__PURE__ */ x(d, {
|
|
114
|
+
tags: O.materials,
|
|
111
115
|
max: 10
|
|
112
116
|
})] }),
|
|
113
|
-
|
|
117
|
+
O.tags.length > 0 && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
114
118
|
className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
115
119
|
children: "Tags"
|
|
116
|
-
}), /* @__PURE__ */
|
|
117
|
-
tags:
|
|
120
|
+
}), /* @__PURE__ */ x(d, {
|
|
121
|
+
tags: O.tags,
|
|
118
122
|
max: 10,
|
|
119
123
|
tone: "accent"
|
|
120
124
|
})] })
|
|
@@ -123,56 +127,56 @@ function C() {
|
|
|
123
127
|
]
|
|
124
128
|
})]
|
|
125
129
|
})
|
|
126
|
-
}), /* @__PURE__ */
|
|
130
|
+
}), /* @__PURE__ */ S("div", {
|
|
127
131
|
className: "space-y-4",
|
|
128
132
|
children: [
|
|
129
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ S(C, {
|
|
130
134
|
treatment: "plain",
|
|
131
135
|
className: "p-5",
|
|
132
|
-
children: [/* @__PURE__ */
|
|
136
|
+
children: [/* @__PURE__ */ x("h3", {
|
|
133
137
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
134
138
|
children: "Details"
|
|
135
|
-
}), /* @__PURE__ */
|
|
139
|
+
}), /* @__PURE__ */ S("dl", {
|
|
136
140
|
className: "space-y-2 text-sm",
|
|
137
141
|
children: [
|
|
138
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ S("div", {
|
|
139
143
|
className: "flex justify-between gap-2",
|
|
140
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ x("dt", {
|
|
141
145
|
className: "text-text-secondary",
|
|
142
146
|
children: "Category"
|
|
143
|
-
}), /* @__PURE__ */
|
|
147
|
+
}), /* @__PURE__ */ x("dd", {
|
|
144
148
|
className: "text-text-primary",
|
|
145
|
-
children: u(
|
|
149
|
+
children: u(O.category)
|
|
146
150
|
})]
|
|
147
151
|
}),
|
|
148
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ S("div", {
|
|
149
153
|
className: "flex justify-between gap-2",
|
|
150
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ x("dt", {
|
|
151
155
|
className: "text-text-secondary",
|
|
152
156
|
children: "SKU"
|
|
153
|
-
}), /* @__PURE__ */
|
|
157
|
+
}), /* @__PURE__ */ x("dd", {
|
|
154
158
|
className: "text-text-primary",
|
|
155
|
-
children:
|
|
159
|
+
children: O.sku ?? "—"
|
|
156
160
|
})]
|
|
157
161
|
}),
|
|
158
|
-
/* @__PURE__ */
|
|
162
|
+
/* @__PURE__ */ S("div", {
|
|
159
163
|
className: "flex justify-between gap-2",
|
|
160
|
-
children: [/* @__PURE__ */
|
|
164
|
+
children: [/* @__PURE__ */ x("dt", {
|
|
161
165
|
className: "text-text-secondary",
|
|
162
166
|
children: "Currency"
|
|
163
|
-
}), /* @__PURE__ */
|
|
167
|
+
}), /* @__PURE__ */ x("dd", {
|
|
164
168
|
className: "text-text-primary",
|
|
165
|
-
children:
|
|
169
|
+
children: O.currency
|
|
166
170
|
})]
|
|
167
171
|
}),
|
|
168
|
-
/* @__PURE__ */
|
|
172
|
+
/* @__PURE__ */ S("div", {
|
|
169
173
|
className: "flex justify-between gap-2",
|
|
170
|
-
children: [/* @__PURE__ */
|
|
174
|
+
children: [/* @__PURE__ */ x("dt", {
|
|
171
175
|
className: "text-text-secondary",
|
|
172
176
|
children: "Created"
|
|
173
|
-
}), /* @__PURE__ */
|
|
177
|
+
}), /* @__PURE__ */ x("dd", {
|
|
174
178
|
className: "text-text-primary",
|
|
175
|
-
children: c(
|
|
179
|
+
children: c(O.createdAt, {
|
|
176
180
|
hour: void 0,
|
|
177
181
|
minute: void 0
|
|
178
182
|
})
|
|
@@ -181,39 +185,39 @@ function C() {
|
|
|
181
185
|
]
|
|
182
186
|
})]
|
|
183
187
|
}),
|
|
184
|
-
|
|
188
|
+
O.brand && /* @__PURE__ */ S("button", {
|
|
185
189
|
type: "button",
|
|
186
|
-
onClick: () =>
|
|
190
|
+
onClick: () => T(`/brands/${O.brand?.id}`),
|
|
187
191
|
className: "flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50",
|
|
188
|
-
children: [/* @__PURE__ */
|
|
189
|
-
icon: /* @__PURE__ */
|
|
190
|
-
seed:
|
|
192
|
+
children: [/* @__PURE__ */ x(a, {
|
|
193
|
+
icon: /* @__PURE__ */ x(y, { className: "h-5 w-5" }),
|
|
194
|
+
seed: O.brand.id,
|
|
191
195
|
className: "h-10 w-10 shrink-0"
|
|
192
|
-
}), /* @__PURE__ */
|
|
196
|
+
}), /* @__PURE__ */ S("div", {
|
|
193
197
|
className: "min-w-0",
|
|
194
|
-
children: [/* @__PURE__ */
|
|
198
|
+
children: [/* @__PURE__ */ x("p", {
|
|
195
199
|
className: "truncate text-sm font-medium text-text-primary",
|
|
196
|
-
children:
|
|
197
|
-
}), /* @__PURE__ */
|
|
200
|
+
children: O.brand.name
|
|
201
|
+
}), /* @__PURE__ */ x("p", {
|
|
198
202
|
className: "truncate text-xs text-text-secondary",
|
|
199
203
|
children: "View brand"
|
|
200
204
|
})]
|
|
201
205
|
})]
|
|
202
206
|
}),
|
|
203
|
-
|
|
207
|
+
O.collection && /* @__PURE__ */ S("button", {
|
|
204
208
|
type: "button",
|
|
205
|
-
onClick: () =>
|
|
209
|
+
onClick: () => T(`/collections/${O.collection?.id}`),
|
|
206
210
|
className: "flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50",
|
|
207
|
-
children: [/* @__PURE__ */
|
|
208
|
-
icon: /* @__PURE__ */
|
|
209
|
-
seed:
|
|
211
|
+
children: [/* @__PURE__ */ x(a, {
|
|
212
|
+
icon: /* @__PURE__ */ x(v, { className: "h-5 w-5" }),
|
|
213
|
+
seed: O.collection.id,
|
|
210
214
|
className: "h-10 w-10 shrink-0"
|
|
211
|
-
}), /* @__PURE__ */
|
|
215
|
+
}), /* @__PURE__ */ S("div", {
|
|
212
216
|
className: "min-w-0",
|
|
213
|
-
children: [/* @__PURE__ */
|
|
217
|
+
children: [/* @__PURE__ */ x("p", {
|
|
214
218
|
className: "truncate text-sm font-medium text-text-primary",
|
|
215
|
-
children:
|
|
216
|
-
}), /* @__PURE__ */
|
|
219
|
+
children: O.collection.name
|
|
220
|
+
}), /* @__PURE__ */ x("p", {
|
|
217
221
|
className: "truncate text-xs text-text-secondary",
|
|
218
222
|
children: "View collection"
|
|
219
223
|
})]
|
|
@@ -225,6 +229,6 @@ function C() {
|
|
|
225
229
|
});
|
|
226
230
|
}
|
|
227
231
|
//#endregion
|
|
228
|
-
export {
|
|
232
|
+
export { w as StyleItemDetailPage };
|
|
229
233
|
|
|
230
234
|
//# sourceMappingURL=StyleItemDetailPage.js.map
|