@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,180 +3,196 @@ import { PageLayout as t } from "../../components/PageLayout.js";
|
|
|
3
3
|
import { StatusBadge as n } from "../../components/StatusBadge.js";
|
|
4
4
|
import { ErrorView as r, LoadingView as i } from "../../components/StateViews.js";
|
|
5
5
|
import { Thumbnail as a } from "../../components/Thumbnail.js";
|
|
6
|
-
import { useArchiveStyleItem as o,
|
|
6
|
+
import { useArchiveStyleItem as o, useLooksWithItems as s, useStyleItem as c } from "../../hooks/useCoolAndLovelyApi.js";
|
|
7
|
+
import { AddToLookbookButton as l } from "../../components/AddToLookbookButton.js";
|
|
8
|
+
import { formatDate as u, formatPrice as d, titleCase as f } from "../../utils/formatters.js";
|
|
9
|
+
import { LookCard as p } from "../../components/LookCard.js";
|
|
7
10
|
import "../../hooks/index.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { GlassCard as C } from "@burdenoff/fe-libs/ui";
|
|
11
|
+
import { TagList as m } from "../../components/TagList.js";
|
|
12
|
+
import { categoryIcon as h } from "../../utils/icons.js";
|
|
13
|
+
import { ColourSwatchRow as g } from "../../components/ColourSwatchRow.js";
|
|
14
|
+
import { Archive as _, ArrowLeft as v, ChevronRight as y, Loader2 as b, Pencil as x, Shapes as S } from "lucide-react";
|
|
15
|
+
import { useParams as C } from "react-router-dom";
|
|
16
|
+
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
17
|
+
import { GlassCard as E } from "@burdenoff/fe-libs/ui";
|
|
16
18
|
//#region src/coolandlovely/pages/items/StyleItemDetailPage.tsx
|
|
17
|
-
function
|
|
18
|
-
let { itemId:
|
|
19
|
-
|
|
19
|
+
function D() {
|
|
20
|
+
let { itemId: D } = C(), { navigateTo: O } = e(), k = c(D), A = s({ pagination: {
|
|
21
|
+
limit: 100,
|
|
22
|
+
offset: 0
|
|
23
|
+
} }), j = o();
|
|
24
|
+
if (k.isLoading) return /* @__PURE__ */ w(t, {
|
|
20
25
|
title: "Style item",
|
|
21
|
-
children: /* @__PURE__ */
|
|
26
|
+
children: /* @__PURE__ */ w(i, { label: "Loading item…" })
|
|
22
27
|
});
|
|
23
|
-
if (
|
|
28
|
+
if (k.isError || !k.data) return /* @__PURE__ */ w(t, {
|
|
24
29
|
title: "Style item",
|
|
25
|
-
children: /* @__PURE__ */
|
|
30
|
+
children: /* @__PURE__ */ w(r, {
|
|
26
31
|
title: "Item not found",
|
|
27
|
-
onRetry: () => void
|
|
32
|
+
onRetry: () => void k.refetch()
|
|
28
33
|
})
|
|
29
34
|
});
|
|
30
|
-
let
|
|
31
|
-
return /* @__PURE__ */
|
|
32
|
-
title:
|
|
33
|
-
description:
|
|
34
|
-
actions: /* @__PURE__ */
|
|
35
|
+
let M = k.data, N = M.status === "RETIRED", P = (A.data?.items ?? []).filter((e) => e.items?.some((e) => e.styleItemId === M.id)).slice(0, 4);
|
|
36
|
+
return /* @__PURE__ */ T(t, {
|
|
37
|
+
title: M.name,
|
|
38
|
+
description: M.brand?.name ?? void 0,
|
|
39
|
+
actions: /* @__PURE__ */ T("div", {
|
|
35
40
|
className: "flex flex-wrap items-center gap-2",
|
|
36
41
|
children: [
|
|
37
|
-
/* @__PURE__ */
|
|
42
|
+
/* @__PURE__ */ T("button", {
|
|
38
43
|
type: "button",
|
|
39
|
-
onClick: () =>
|
|
44
|
+
onClick: () => O("/items"),
|
|
40
45
|
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",
|
|
41
|
-
children: [/* @__PURE__ */
|
|
46
|
+
children: [/* @__PURE__ */ w(v, { className: "h-4 w-4" }), " Back"]
|
|
42
47
|
}),
|
|
43
|
-
/* @__PURE__ */
|
|
44
|
-
/* @__PURE__ */
|
|
48
|
+
/* @__PURE__ */ w(l, { styleItemId: M.id }),
|
|
49
|
+
/* @__PURE__ */ T("button", {
|
|
45
50
|
type: "button",
|
|
46
|
-
onClick: () =>
|
|
51
|
+
onClick: () => O(`/items/${M.id}/edit`),
|
|
47
52
|
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",
|
|
48
|
-
children: [/* @__PURE__ */ x
|
|
53
|
+
children: [/* @__PURE__ */ w(x, { className: "h-4 w-4" }), " Edit"]
|
|
49
54
|
}),
|
|
50
|
-
!
|
|
55
|
+
!N && /* @__PURE__ */ T("button", {
|
|
51
56
|
type: "button",
|
|
52
|
-
disabled:
|
|
53
|
-
onClick: () =>
|
|
57
|
+
disabled: j.isPending,
|
|
58
|
+
onClick: () => j.mutate(M.id, { onSuccess: () => O("/items") }),
|
|
54
59
|
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",
|
|
55
|
-
children: [
|
|
60
|
+
children: [j.isPending ? /* @__PURE__ */ w(b, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ w(_, { className: "h-4 w-4" }), "Archive"]
|
|
56
61
|
})
|
|
57
62
|
]
|
|
58
63
|
}),
|
|
59
|
-
children: /* @__PURE__ */
|
|
64
|
+
children: [/* @__PURE__ */ T("div", {
|
|
60
65
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
61
|
-
children: [/* @__PURE__ */
|
|
66
|
+
children: [/* @__PURE__ */ w("div", {
|
|
62
67
|
className: "lg:col-span-2",
|
|
63
|
-
children: /* @__PURE__ */
|
|
68
|
+
children: /* @__PURE__ */ T(E, {
|
|
64
69
|
treatment: "glass",
|
|
65
|
-
className: "overflow-hidden p-0",
|
|
66
|
-
children: [/* @__PURE__ */
|
|
67
|
-
icon:
|
|
68
|
-
seed:
|
|
69
|
-
fileId:
|
|
70
|
-
alt:
|
|
71
|
-
className: "
|
|
72
|
-
}), /* @__PURE__ */
|
|
70
|
+
className: "group overflow-hidden p-0",
|
|
71
|
+
children: [/* @__PURE__ */ w(a, {
|
|
72
|
+
icon: h(M.category, 48),
|
|
73
|
+
seed: M.id,
|
|
74
|
+
fileId: M.image?.id,
|
|
75
|
+
alt: M.name,
|
|
76
|
+
className: "aspect-[4/5] w-full"
|
|
77
|
+
}), M.description && /* @__PURE__ */ w("div", {
|
|
73
78
|
className: "p-6",
|
|
74
|
-
children:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
className: "text-xl font-semibold text-text-primary",
|
|
79
|
-
children: O.name
|
|
80
|
-
}), /* @__PURE__ */ x(n, {
|
|
81
|
-
status: O.status,
|
|
82
|
-
className: "ml-auto"
|
|
83
|
-
})]
|
|
84
|
-
}),
|
|
85
|
-
/* @__PURE__ */ x("p", {
|
|
86
|
-
className: "mt-1 text-2xl font-bold text-text-primary tabular-nums",
|
|
87
|
-
children: l(O.price, O.currency)
|
|
88
|
-
}),
|
|
89
|
-
O.description && /* @__PURE__ */ x("p", {
|
|
90
|
-
className: "mt-3 text-sm text-text-secondary",
|
|
91
|
-
children: O.description
|
|
92
|
-
}),
|
|
93
|
-
/* @__PURE__ */ S("div", {
|
|
94
|
-
className: "mt-5 grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
95
|
-
children: [
|
|
96
|
-
O.colours.length > 0 && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
97
|
-
className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
98
|
-
children: "Colours"
|
|
99
|
-
}), /* @__PURE__ */ x(d, {
|
|
100
|
-
tags: O.colours,
|
|
101
|
-
max: 10
|
|
102
|
-
})] }),
|
|
103
|
-
O.sizes.length > 0 && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
104
|
-
className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
105
|
-
children: "Sizes"
|
|
106
|
-
}), /* @__PURE__ */ x(d, {
|
|
107
|
-
tags: O.sizes,
|
|
108
|
-
max: 10
|
|
109
|
-
})] }),
|
|
110
|
-
O.materials.length > 0 && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
111
|
-
className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
112
|
-
children: "Materials"
|
|
113
|
-
}), /* @__PURE__ */ x(d, {
|
|
114
|
-
tags: O.materials,
|
|
115
|
-
max: 10
|
|
116
|
-
})] }),
|
|
117
|
-
O.tags.length > 0 && /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
118
|
-
className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
119
|
-
children: "Tags"
|
|
120
|
-
}), /* @__PURE__ */ x(d, {
|
|
121
|
-
tags: O.tags,
|
|
122
|
-
max: 10,
|
|
123
|
-
tone: "accent"
|
|
124
|
-
})] })
|
|
125
|
-
]
|
|
126
|
-
})
|
|
127
|
-
]
|
|
79
|
+
children: /* @__PURE__ */ w("p", {
|
|
80
|
+
className: "text-sm leading-relaxed text-text-secondary",
|
|
81
|
+
children: M.description
|
|
82
|
+
})
|
|
128
83
|
})]
|
|
129
84
|
})
|
|
130
|
-
}), /* @__PURE__ */
|
|
85
|
+
}), /* @__PURE__ */ T("div", {
|
|
131
86
|
className: "space-y-4",
|
|
132
87
|
children: [
|
|
133
|
-
/* @__PURE__ */
|
|
88
|
+
/* @__PURE__ */ T(E, {
|
|
89
|
+
treatment: "glass",
|
|
90
|
+
className: "space-y-5 p-6",
|
|
91
|
+
children: [
|
|
92
|
+
/* @__PURE__ */ T("div", { children: [
|
|
93
|
+
/* @__PURE__ */ w("h2", {
|
|
94
|
+
className: "text-2xl font-semibold leading-tight text-text-primary",
|
|
95
|
+
children: M.name
|
|
96
|
+
}),
|
|
97
|
+
M.brand && /* @__PURE__ */ T("button", {
|
|
98
|
+
type: "button",
|
|
99
|
+
onClick: () => O(`/brands/${M.brand?.id}`),
|
|
100
|
+
className: "mt-1 inline-flex items-center gap-0.5 text-sm font-medium text-action-primary-bg hover:underline",
|
|
101
|
+
children: [M.brand.name, /* @__PURE__ */ w(y, { className: "h-3.5 w-3.5" })]
|
|
102
|
+
}),
|
|
103
|
+
/* @__PURE__ */ T("div", {
|
|
104
|
+
className: "mt-3 flex flex-wrap items-center justify-between gap-2",
|
|
105
|
+
children: [/* @__PURE__ */ T("p", {
|
|
106
|
+
className: "text-3xl font-bold text-text-primary tabular-nums",
|
|
107
|
+
children: [d(M.price, M.currency), /* @__PURE__ */ w("span", {
|
|
108
|
+
className: "ml-2 text-base font-medium text-text-secondary",
|
|
109
|
+
children: M.currency
|
|
110
|
+
})]
|
|
111
|
+
}), /* @__PURE__ */ w(n, { status: M.status })]
|
|
112
|
+
})
|
|
113
|
+
] }),
|
|
114
|
+
/* @__PURE__ */ w("div", { className: "border-t border-border-seam" }),
|
|
115
|
+
M.colours.length > 0 && /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
116
|
+
className: "mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
117
|
+
children: "Colours"
|
|
118
|
+
}), /* @__PURE__ */ w(g, {
|
|
119
|
+
colours: M.colours,
|
|
120
|
+
max: 12
|
|
121
|
+
})] }),
|
|
122
|
+
M.sizes.length > 0 && /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
123
|
+
className: "mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
124
|
+
children: "Size"
|
|
125
|
+
}), /* @__PURE__ */ w("div", {
|
|
126
|
+
className: "flex flex-wrap gap-2",
|
|
127
|
+
children: M.sizes.map((e) => /* @__PURE__ */ w("span", {
|
|
128
|
+
className: "inline-flex min-w-9 items-center justify-center rounded-full border border-border-seam px-3 py-1 text-sm font-medium text-text-primary",
|
|
129
|
+
children: e
|
|
130
|
+
}, e))
|
|
131
|
+
})] }),
|
|
132
|
+
M.materials.length > 0 && /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
133
|
+
className: "mb-1 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
134
|
+
children: "Materials"
|
|
135
|
+
}), /* @__PURE__ */ w("p", {
|
|
136
|
+
className: "text-sm text-text-primary",
|
|
137
|
+
children: M.materials.join(", ")
|
|
138
|
+
})] }),
|
|
139
|
+
M.tags.length > 0 && /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
140
|
+
className: "mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
141
|
+
children: "Tags"
|
|
142
|
+
}), /* @__PURE__ */ w(m, {
|
|
143
|
+
tags: M.tags,
|
|
144
|
+
max: 12,
|
|
145
|
+
tone: "accent"
|
|
146
|
+
})] })
|
|
147
|
+
]
|
|
148
|
+
}),
|
|
149
|
+
/* @__PURE__ */ T(E, {
|
|
134
150
|
treatment: "plain",
|
|
135
151
|
className: "p-5",
|
|
136
|
-
children: [/* @__PURE__ */
|
|
152
|
+
children: [/* @__PURE__ */ w("h3", {
|
|
137
153
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
138
154
|
children: "Details"
|
|
139
|
-
}), /* @__PURE__ */
|
|
155
|
+
}), /* @__PURE__ */ T("dl", {
|
|
140
156
|
className: "space-y-2 text-sm",
|
|
141
157
|
children: [
|
|
142
|
-
/* @__PURE__ */
|
|
158
|
+
/* @__PURE__ */ T("div", {
|
|
143
159
|
className: "flex justify-between gap-2",
|
|
144
|
-
children: [/* @__PURE__ */
|
|
160
|
+
children: [/* @__PURE__ */ w("dt", {
|
|
145
161
|
className: "text-text-secondary",
|
|
146
162
|
children: "Category"
|
|
147
|
-
}), /* @__PURE__ */
|
|
163
|
+
}), /* @__PURE__ */ w("dd", {
|
|
148
164
|
className: "text-text-primary",
|
|
149
|
-
children:
|
|
165
|
+
children: f(M.category)
|
|
150
166
|
})]
|
|
151
167
|
}),
|
|
152
|
-
/* @__PURE__ */
|
|
168
|
+
/* @__PURE__ */ T("div", {
|
|
153
169
|
className: "flex justify-between gap-2",
|
|
154
|
-
children: [/* @__PURE__ */
|
|
170
|
+
children: [/* @__PURE__ */ w("dt", {
|
|
155
171
|
className: "text-text-secondary",
|
|
156
172
|
children: "SKU"
|
|
157
|
-
}), /* @__PURE__ */
|
|
173
|
+
}), /* @__PURE__ */ w("dd", {
|
|
158
174
|
className: "text-text-primary",
|
|
159
|
-
children:
|
|
175
|
+
children: M.sku ?? "—"
|
|
160
176
|
})]
|
|
161
177
|
}),
|
|
162
|
-
/* @__PURE__ */
|
|
178
|
+
/* @__PURE__ */ T("div", {
|
|
163
179
|
className: "flex justify-between gap-2",
|
|
164
|
-
children: [/* @__PURE__ */
|
|
180
|
+
children: [/* @__PURE__ */ w("dt", {
|
|
165
181
|
className: "text-text-secondary",
|
|
166
182
|
children: "Currency"
|
|
167
|
-
}), /* @__PURE__ */
|
|
183
|
+
}), /* @__PURE__ */ w("dd", {
|
|
168
184
|
className: "text-text-primary",
|
|
169
|
-
children:
|
|
185
|
+
children: M.currency
|
|
170
186
|
})]
|
|
171
187
|
}),
|
|
172
|
-
/* @__PURE__ */
|
|
188
|
+
/* @__PURE__ */ T("div", {
|
|
173
189
|
className: "flex justify-between gap-2",
|
|
174
|
-
children: [/* @__PURE__ */
|
|
190
|
+
children: [/* @__PURE__ */ w("dt", {
|
|
175
191
|
className: "text-text-secondary",
|
|
176
192
|
children: "Created"
|
|
177
|
-
}), /* @__PURE__ */
|
|
193
|
+
}), /* @__PURE__ */ w("dd", {
|
|
178
194
|
className: "text-text-primary",
|
|
179
|
-
children:
|
|
195
|
+
children: u(M.createdAt, {
|
|
180
196
|
hour: void 0,
|
|
181
197
|
minute: void 0
|
|
182
198
|
})
|
|
@@ -185,39 +201,20 @@ function w() {
|
|
|
185
201
|
]
|
|
186
202
|
})]
|
|
187
203
|
}),
|
|
188
|
-
|
|
189
|
-
type: "button",
|
|
190
|
-
onClick: () => T(`/brands/${O.brand?.id}`),
|
|
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",
|
|
192
|
-
children: [/* @__PURE__ */ x(a, {
|
|
193
|
-
icon: /* @__PURE__ */ x(y, { className: "h-5 w-5" }),
|
|
194
|
-
seed: O.brand.id,
|
|
195
|
-
className: "h-10 w-10 shrink-0"
|
|
196
|
-
}), /* @__PURE__ */ S("div", {
|
|
197
|
-
className: "min-w-0",
|
|
198
|
-
children: [/* @__PURE__ */ x("p", {
|
|
199
|
-
className: "truncate text-sm font-medium text-text-primary",
|
|
200
|
-
children: O.brand.name
|
|
201
|
-
}), /* @__PURE__ */ x("p", {
|
|
202
|
-
className: "truncate text-xs text-text-secondary",
|
|
203
|
-
children: "View brand"
|
|
204
|
-
})]
|
|
205
|
-
})]
|
|
206
|
-
}),
|
|
207
|
-
O.collection && /* @__PURE__ */ S("button", {
|
|
204
|
+
M.collection && /* @__PURE__ */ T("button", {
|
|
208
205
|
type: "button",
|
|
209
|
-
onClick: () =>
|
|
206
|
+
onClick: () => O(`/collections/${M.collection?.id}`),
|
|
210
207
|
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",
|
|
211
|
-
children: [/* @__PURE__ */
|
|
212
|
-
icon: /* @__PURE__ */
|
|
213
|
-
seed:
|
|
208
|
+
children: [/* @__PURE__ */ w(a, {
|
|
209
|
+
icon: /* @__PURE__ */ w(S, { className: "h-5 w-5" }),
|
|
210
|
+
seed: M.collection.id,
|
|
214
211
|
className: "h-10 w-10 shrink-0"
|
|
215
|
-
}), /* @__PURE__ */
|
|
212
|
+
}), /* @__PURE__ */ T("div", {
|
|
216
213
|
className: "min-w-0",
|
|
217
|
-
children: [/* @__PURE__ */
|
|
214
|
+
children: [/* @__PURE__ */ w("p", {
|
|
218
215
|
className: "truncate text-sm font-medium text-text-primary",
|
|
219
|
-
children:
|
|
220
|
-
}), /* @__PURE__ */
|
|
216
|
+
children: M.collection.name
|
|
217
|
+
}), /* @__PURE__ */ w("p", {
|
|
221
218
|
className: "truncate text-xs text-text-secondary",
|
|
222
219
|
children: "View collection"
|
|
223
220
|
})]
|
|
@@ -225,10 +222,41 @@ function w() {
|
|
|
225
222
|
})
|
|
226
223
|
]
|
|
227
224
|
})]
|
|
228
|
-
})
|
|
225
|
+
}), /* @__PURE__ */ T("section", {
|
|
226
|
+
className: "mt-8",
|
|
227
|
+
children: [/* @__PURE__ */ T("div", {
|
|
228
|
+
className: "mb-3 flex items-center justify-between gap-3",
|
|
229
|
+
children: [/* @__PURE__ */ w("h3", {
|
|
230
|
+
className: "text-lg font-semibold text-text-primary",
|
|
231
|
+
children: "Appears in looks"
|
|
232
|
+
}), P.length > 0 && /* @__PURE__ */ T("button", {
|
|
233
|
+
type: "button",
|
|
234
|
+
onClick: () => O("/looks"),
|
|
235
|
+
className: "inline-flex items-center gap-1 text-sm font-medium text-action-primary-bg hover:underline",
|
|
236
|
+
children: ["View all ", /* @__PURE__ */ w(y, { className: "h-3.5 w-3.5" })]
|
|
237
|
+
})]
|
|
238
|
+
}), A.isLoading ? /* @__PURE__ */ T("div", {
|
|
239
|
+
className: "flex items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
240
|
+
children: [/* @__PURE__ */ w(b, { className: "h-4 w-4 animate-spin" }), " Loading referenced looks…"]
|
|
241
|
+
}) : P.length === 0 ? /* @__PURE__ */ w("p", {
|
|
242
|
+
className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
243
|
+
children: "This piece has not been tagged in any looks yet."
|
|
244
|
+
}) : /* @__PURE__ */ w("div", {
|
|
245
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
246
|
+
children: P.map((e) => /* @__PURE__ */ w(p, {
|
|
247
|
+
id: e.id,
|
|
248
|
+
title: e.title,
|
|
249
|
+
occasion: e.occasion,
|
|
250
|
+
imageFileId: e.image?.id,
|
|
251
|
+
likeCount: e.likeCount,
|
|
252
|
+
onOpen: () => O(`/looks/${e.id}`),
|
|
253
|
+
showActions: !0
|
|
254
|
+
}, e.id))
|
|
255
|
+
})]
|
|
256
|
+
})]
|
|
229
257
|
});
|
|
230
258
|
}
|
|
231
259
|
//#endregion
|
|
232
|
-
export {
|
|
260
|
+
export { D as StyleItemDetailPage };
|
|
233
261
|
|
|
234
262
|
//# sourceMappingURL=StyleItemDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StyleItemDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/items/StyleItemDetailPage.tsx"],"sourcesContent":["/**\n * Style Item Detail Page\n * @module coolandlovely/pages/items\n *\n * Renders a single catalogue piece (`cooStyleItem`) with edit + archive\n * (`cooArchiveStyleItem`) actions.\n */\n\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Pencil, Archive, Loader2, Store, Shapes } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { AddToLookbookButton } from '../../components/AddToLookbookButton';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useStyleItem, useArchiveStyleItem } from '../../hooks';\nimport { categoryIcon } from '../../utils/icons';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\n\nexport function StyleItemDetailPage() {\n const { itemId } = useParams<{ itemId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useStyleItem(itemId);\n const archive = useArchiveStyleItem();\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Style item\">\n <LoadingView label=\"Loading item…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Style item\">\n <ErrorView title=\"Item not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const item = query.data;\n const isArchived = item.status === 'RETIRED';\n\n return (\n <PageLayout\n title={item.name}\n description={item.brand?.name ?? undefined}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/items')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <AddToLookbookButton styleItemId={item.id} />\n <button\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}/edit`)}\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 <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n {!isArchived && (\n <button\n type=\"button\"\n disabled={archive.isPending}\n onClick={() => archive.mutate(item.id, { onSuccess: () => navigateTo('/items') })}\n 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\"\n >\n {archive.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Archive className=\"h-4 w-4\" />\n )}\n Archive\n </button>\n )}\n </div>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <GlassCard treatment=\"glass\" className=\"overflow-hidden p-0\">\n <Thumbnail\n icon={categoryIcon(item.category, 40)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"h-52 w-full\"\n />\n <div className=\"p-6\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"text-xl font-semibold text-text-primary\">{item.name}</h2>\n <StatusBadge status={item.status} className=\"ml-auto\" />\n </div>\n <p className=\"mt-1 text-2xl font-bold text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n </p>\n {item.description && (\n <p className=\"mt-3 text-sm text-text-secondary\">{item.description}</p>\n )}\n\n <div className=\"mt-5 grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {item.colours.length > 0 && (\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Colours\n </p>\n <TagList tags={item.colours} max={10} />\n </div>\n )}\n {item.sizes.length > 0 && (\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Sizes\n </p>\n <TagList tags={item.sizes} max={10} />\n </div>\n )}\n {item.materials.length > 0 && (\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Materials\n </p>\n <TagList tags={item.materials} max={10} />\n </div>\n )}\n {item.tags.length > 0 && (\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Tags\n </p>\n <TagList tags={item.tags} max={10} tone=\"accent\" />\n </div>\n )}\n </div>\n </div>\n </GlassCard>\n </div>\n\n <div className=\"space-y-4\">\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Details</h3>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Category</dt>\n <dd className=\"text-text-primary\">{titleCase(item.category)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">SKU</dt>\n <dd className=\"text-text-primary\">{item.sku ?? '—'}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Currency</dt>\n <dd className=\"text-text-primary\">{item.currency}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-text-primary\">\n {formatDate(item.createdAt, { hour: undefined, minute: undefined })}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {item.brand && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${item.brand?.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Store className=\"h-5 w-5\" />}\n seed={item.brand.id}\n className=\"h-10 w-10 shrink-0\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.brand.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">View brand</p>\n </div>\n </button>\n )}\n\n {item.collection && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collections/${item.collection?.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Shapes className=\"h-5 w-5\" />}\n seed={item.collection.id}\n className=\"h-10 w-10 shrink-0\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {item.collection.name}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View collection</p>\n </div>\n </button>\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"StyleItemDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/items/StyleItemDetailPage.tsx"],"sourcesContent":["/**\n * Style Item Detail Page\n * @module coolandlovely/pages/items\n *\n * Renders a single catalogue piece (`cooStyleItem`) with edit + archive\n * (`cooArchiveStyleItem`) actions.\n */\n\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Pencil, Archive, Loader2, ChevronRight, Shapes } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { LookCard } from '../../components/LookCard';\nimport { TagList } from '../../components/TagList';\nimport { ColourSwatchRow } from '../../components/ColourSwatchRow';\nimport { AddToLookbookButton } from '../../components/AddToLookbookButton';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useStyleItem, useArchiveStyleItem, useLooksWithItems } from '../../hooks';\nimport { categoryIcon } from '../../utils/icons';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\n\nexport function StyleItemDetailPage() {\n const { itemId } = useParams<{ itemId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useStyleItem(itemId);\n const looksQuery = useLooksWithItems({ pagination: { limit: 100, offset: 0 } });\n const archive = useArchiveStyleItem();\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Style item\">\n <LoadingView label=\"Loading item…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Style item\">\n <ErrorView title=\"Item not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const item = query.data;\n const isArchived = item.status === 'RETIRED';\n const appearsInLooks = (looksQuery.data?.items ?? [])\n .filter((look) => look.items?.some((lookItem) => lookItem.styleItemId === item.id))\n .slice(0, 4);\n\n return (\n <PageLayout\n title={item.name}\n description={item.brand?.name ?? undefined}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/items')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <AddToLookbookButton styleItemId={item.id} />\n <button\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}/edit`)}\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 <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n {!isArchived && (\n <button\n type=\"button\"\n disabled={archive.isPending}\n onClick={() => archive.mutate(item.id, { onSuccess: () => navigateTo('/items') })}\n 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\"\n >\n {archive.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Archive className=\"h-4 w-4\" />\n )}\n Archive\n </button>\n )}\n </div>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Product image */}\n <div className=\"lg:col-span-2\">\n <GlassCard treatment=\"glass\" className=\"group overflow-hidden p-0\">\n <Thumbnail\n icon={categoryIcon(item.category, 48)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[4/5] w-full\"\n />\n {item.description && (\n <div className=\"p-6\">\n <p className=\"text-sm leading-relaxed text-text-secondary\">{item.description}</p>\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Product panel */}\n <div className=\"space-y-4\">\n <GlassCard treatment=\"glass\" className=\"space-y-5 p-6\">\n <div>\n <h2 className=\"text-2xl font-semibold leading-tight text-text-primary\">\n {item.name}\n </h2>\n {item.brand && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${item.brand?.id}`)}\n className=\"mt-1 inline-flex items-center gap-0.5 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n {item.brand.name}\n <ChevronRight className=\"h-3.5 w-3.5\" />\n </button>\n )}\n <div className=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <p className=\"text-3xl font-bold text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n <span className=\"ml-2 text-base font-medium text-text-secondary\">\n {item.currency}\n </span>\n </p>\n <StatusBadge status={item.status} />\n </div>\n </div>\n\n <div className=\"border-t border-border-seam\" />\n\n {item.colours.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Colours\n </p>\n <ColourSwatchRow colours={item.colours} max={12} />\n </div>\n )}\n\n {item.sizes.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Size\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {item.sizes.map((size) => (\n <span\n key={size}\n className=\"inline-flex min-w-9 items-center justify-center rounded-full border border-border-seam px-3 py-1 text-sm font-medium text-text-primary\"\n >\n {size}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {item.materials.length > 0 && (\n <div>\n <p className=\"mb-1 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Materials\n </p>\n <p className=\"text-sm text-text-primary\">{item.materials.join(', ')}</p>\n </div>\n )}\n\n {item.tags.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Tags\n </p>\n <TagList tags={item.tags} max={12} tone=\"accent\" />\n </div>\n )}\n </GlassCard>\n\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Details</h3>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Category</dt>\n <dd className=\"text-text-primary\">{titleCase(item.category)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">SKU</dt>\n <dd className=\"text-text-primary\">{item.sku ?? '—'}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Currency</dt>\n <dd className=\"text-text-primary\">{item.currency}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-text-primary\">\n {formatDate(item.createdAt, { hour: undefined, minute: undefined })}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {item.collection && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collections/${item.collection?.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Shapes className=\"h-5 w-5\" />}\n seed={item.collection.id}\n className=\"h-10 w-10 shrink-0\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {item.collection.name}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View collection</p>\n </div>\n </button>\n )}\n </div>\n </div>\n\n <section className=\"mt-8\">\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Appears in looks</h3>\n {appearsInLooks.length > 0 && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n View all <ChevronRight className=\"h-3.5 w-3.5\" />\n </button>\n )}\n </div>\n {looksQuery.isLoading ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n <Loader2 className=\"h-4 w-4 animate-spin\" /> Loading referenced looks…\n </div>\n ) : appearsInLooks.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n This piece has not been tagged in any looks yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {appearsInLooks.map((look) => (\n <LookCard\n key={look.id}\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 ))}\n </div>\n )}\n </section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ import { PageLayout as t } from "../../components/PageLayout.js";
|
|
|
3
3
|
import { ErrorView as n, LoadingView as r } from "../../components/StateViews.js";
|
|
4
4
|
import { COO_FILE_FOLDERS as i } from "../../hooks/useFiles.js";
|
|
5
5
|
import { useBrands as a, useCollections as o, useCreateStyleItem as s, useStyleItem as c, useUpdateStyleItem as l } from "../../hooks/useCoolAndLovelyApi.js";
|
|
6
|
-
import "../../hooks/index.js";
|
|
7
6
|
import { parseCsv as u, titleCase as d } from "../../utils/formatters.js";
|
|
7
|
+
import "../../hooks/index.js";
|
|
8
8
|
import { STYLE_CATEGORIES as f } from "../../utils/icons.js";
|
|
9
9
|
import { SelectField as p, TextAreaField as m, TextField as h } from "../../components/Field.js";
|
|
10
10
|
import { ImageUploadField as g } from "../../components/ImageUploadField.js";
|