@burdenoff/microfe-coolandlovely 2026.720.1 → 2026.720.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.d.ts.map +1 -1
- package/dist/coolandlovely/CoolAndLovelyRoutes.js +8 -0
- package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
- package/dist/coolandlovely/components/Field.d.ts +3 -0
- package/dist/coolandlovely/components/Field.d.ts.map +1 -1
- package/dist/coolandlovely/components/Field.js +12 -9
- package/dist/coolandlovely/components/Field.js.map +1 -1
- package/dist/coolandlovely/components/MetricsCard.d.ts +7 -0
- package/dist/coolandlovely/components/MetricsCard.d.ts.map +1 -1
- package/dist/coolandlovely/components/MetricsCard.js +37 -13
- package/dist/coolandlovely/components/MetricsCard.js.map +1 -1
- package/dist/coolandlovely/hooks/index.d.ts +1 -1
- package/dist/coolandlovely/hooks/index.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.d.ts +54 -4
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +197 -79
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
- package/dist/coolandlovely/pages/HomePage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/HomePage.js +112 -101
- package/dist/coolandlovely/pages/HomePage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js +9 -9
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +135 -111
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.d.ts +5 -4
- package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +201 -107
- package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +110 -99
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js +7 -6
- package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +4 -4
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +116 -104
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/looks/LookDetailPage.js +15 -13
- package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/profile/StyleProfilePage.d.ts +11 -6
- package/dist/coolandlovely/pages/profile/StyleProfilePage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js +195 -176
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
- package/dist/coolandlovely/types/index.d.ts +40 -0
- package/dist/coolandlovely/types/index.d.ts.map +1 -1
- package/dist/coolandlovely/utils/index.d.ts +1 -0
- package/dist/coolandlovely/utils/index.d.ts.map +1 -1
- package/dist/coolandlovely/utils/index.js +5 -0
- package/dist/coolandlovely/utils/sparkline.d.ts +31 -0
- package/dist/coolandlovely/utils/sparkline.d.ts.map +1 -0
- package/dist/coolandlovely/utils/sparkline.js +29 -0
- package/dist/coolandlovely/utils/sparkline.js.map +1 -0
- package/dist/utils/pageContext.d.ts +8 -1
- package/dist/utils/pageContext.d.ts.map +1 -1
- package/dist/utils/pageContext.js +22 -27
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,226 +2,238 @@ import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
|
|
|
2
2
|
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
3
|
import { ErrorView as n, LoadingView as r } from "../../components/StateViews.js";
|
|
4
4
|
import { Thumbnail as i } from "../../components/Thumbnail.js";
|
|
5
|
-
import { useAddLookbookEntry as a,
|
|
5
|
+
import { useAddLookbookEntry as a, useDeleteLookbook as o, useLookbook as s, useLooks as c, useRemoveLookbookEntry as l, useStyleItems as ee } from "../../hooks/useCoolAndLovelyApi.js";
|
|
6
6
|
import { formatRelativeTime as u } from "../../utils/formatters.js";
|
|
7
7
|
import "../../hooks/index.js";
|
|
8
8
|
import { TagList as d } from "../../components/TagList.js";
|
|
9
9
|
import { SelectField as f, TextField as p } from "../../components/Field.js";
|
|
10
10
|
import { VisibilityChip as m } from "../../components/VisibilityChip.js";
|
|
11
11
|
import { useMemo as h, useState as g } from "react";
|
|
12
|
-
import { ArrowLeft as _, BookHeart as v, Clock as y, Loader2 as b, Plus as x, Sparkles as S, Tag as C,
|
|
13
|
-
import { useParams as
|
|
14
|
-
import { jsx as
|
|
15
|
-
import { GlassCard as
|
|
12
|
+
import { ArrowLeft as _, BookHeart as v, Clock as y, Loader2 as b, Plus as x, Sparkles as S, Tag as C, Trash2 as w, X as T } from "lucide-react";
|
|
13
|
+
import { useParams as E } from "react-router-dom";
|
|
14
|
+
import { jsx as D, jsxs as O } from "react/jsx-runtime";
|
|
15
|
+
import { GlassCard as k } from "@burdenoff/fe-libs/ui";
|
|
16
16
|
//#region src/coolandlovely/pages/lookbooks/LookbookDetailPage.tsx
|
|
17
|
-
var
|
|
17
|
+
var A = [
|
|
18
18
|
"aspect-[3/4]",
|
|
19
19
|
"aspect-square",
|
|
20
20
|
"aspect-[4/5]"
|
|
21
21
|
];
|
|
22
|
-
function
|
|
23
|
-
let { lookbookId:
|
|
22
|
+
function j() {
|
|
23
|
+
let { lookbookId: j } = E(), { navigateTo: M } = e(), N = s(j), P = l(), F = a(), I = o(), [L, R] = g(!1), [z, B] = g("look"), [V, H] = g(""), [U, W] = g(""), G = c({ pagination: {
|
|
24
24
|
limit: 100,
|
|
25
25
|
offset: 0
|
|
26
|
-
} }),
|
|
26
|
+
} }), K = ee({ pagination: {
|
|
27
27
|
limit: 100,
|
|
28
28
|
offset: 0
|
|
29
|
-
} }),
|
|
29
|
+
} }), q = h(() => new Map((G.data?.items ?? []).map((e) => [e.id, e])), [G.data]), J = h(() => new Map((K.data?.items ?? []).map((e) => [e.id, e])), [K.data]), Y = h(() => (K.data?.items ?? []).filter((e) => e.status !== "RETIRED"), [K.data]), X = h(() => (G.data?.items ?? []).map((e) => ({
|
|
30
30
|
value: e.id,
|
|
31
31
|
label: e.title
|
|
32
|
-
})), [
|
|
32
|
+
})), [G.data]), Z = h(() => Y.map((e) => ({
|
|
33
33
|
value: e.id,
|
|
34
34
|
label: `${e.name}${e.brand?.name ? ` · ${e.brand.name}` : ""}`
|
|
35
|
-
})), [
|
|
36
|
-
if (
|
|
35
|
+
})), [Y]);
|
|
36
|
+
if (N.isLoading) return /* @__PURE__ */ D(t, {
|
|
37
37
|
title: "Lookbook",
|
|
38
|
-
children: /* @__PURE__ */
|
|
38
|
+
children: /* @__PURE__ */ D(r, { label: "Loading lookbook…" })
|
|
39
39
|
});
|
|
40
|
-
if (
|
|
40
|
+
if (N.isError || !N.data) return /* @__PURE__ */ D(t, {
|
|
41
41
|
title: "Lookbook",
|
|
42
|
-
children: /* @__PURE__ */
|
|
42
|
+
children: /* @__PURE__ */ D(n, {
|
|
43
43
|
title: "Lookbook not found",
|
|
44
|
-
onRetry: () => void
|
|
44
|
+
onRetry: () => void N.refetch()
|
|
45
45
|
})
|
|
46
46
|
});
|
|
47
|
-
let
|
|
48
|
-
return /* @__PURE__ */
|
|
49
|
-
title:
|
|
50
|
-
description:
|
|
51
|
-
actions: /* @__PURE__ */
|
|
47
|
+
let Q = N.data, $ = [...Q.entries ?? []].sort((e, t) => e.position - t.position);
|
|
48
|
+
return /* @__PURE__ */ D(t, {
|
|
49
|
+
title: Q.name,
|
|
50
|
+
description: Q.description ?? void 0,
|
|
51
|
+
actions: /* @__PURE__ */ O("div", {
|
|
52
52
|
className: "flex flex-wrap items-center gap-2",
|
|
53
|
-
children: [
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
53
|
+
children: [
|
|
54
|
+
/* @__PURE__ */ O("button", {
|
|
55
|
+
type: "button",
|
|
56
|
+
onClick: () => M("/lookbooks"),
|
|
57
|
+
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",
|
|
58
|
+
children: [/* @__PURE__ */ D(_, { className: "h-4 w-4" }), " Back"]
|
|
59
|
+
}),
|
|
60
|
+
/* @__PURE__ */ O("button", {
|
|
61
|
+
type: "button",
|
|
62
|
+
onClick: () => {
|
|
63
|
+
R((e) => !e), H("");
|
|
64
|
+
},
|
|
65
|
+
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",
|
|
66
|
+
children: [D(L ? T : x, { className: "h-4 w-4" }), L ? "Close" : "Add entry"]
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ O("button", {
|
|
69
|
+
type: "button",
|
|
70
|
+
disabled: I.isPending,
|
|
71
|
+
onClick: () => {
|
|
72
|
+
j && I.mutate(j, { onSuccess: () => M("/lookbooks") });
|
|
73
|
+
},
|
|
74
|
+
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",
|
|
75
|
+
children: [I.isPending ? /* @__PURE__ */ D(b, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ D(w, { className: "h-4 w-4" }), "Delete"]
|
|
76
|
+
})
|
|
77
|
+
]
|
|
66
78
|
}),
|
|
67
|
-
children: /* @__PURE__ */
|
|
79
|
+
children: /* @__PURE__ */ O("div", {
|
|
68
80
|
className: "mx-auto max-w-5xl",
|
|
69
81
|
children: [
|
|
70
|
-
/* @__PURE__ */
|
|
82
|
+
/* @__PURE__ */ O(k, {
|
|
71
83
|
treatment: "glass",
|
|
72
84
|
className: "p-6",
|
|
73
|
-
children: [/* @__PURE__ */
|
|
85
|
+
children: [/* @__PURE__ */ O("div", {
|
|
74
86
|
className: "flex items-center gap-3",
|
|
75
|
-
children: [/* @__PURE__ */
|
|
87
|
+
children: [/* @__PURE__ */ D("div", {
|
|
76
88
|
className: "flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-accent-purple-subtle text-text-primary",
|
|
77
|
-
children: /* @__PURE__ */
|
|
78
|
-
}), /* @__PURE__ */
|
|
89
|
+
children: /* @__PURE__ */ D(v, { className: "h-6 w-6" })
|
|
90
|
+
}), /* @__PURE__ */ O("div", {
|
|
79
91
|
className: "min-w-0 flex-1",
|
|
80
|
-
children: [/* @__PURE__ */
|
|
92
|
+
children: [/* @__PURE__ */ D("h2", {
|
|
81
93
|
className: "truncate text-xl font-semibold text-text-primary",
|
|
82
|
-
children:
|
|
83
|
-
}), /* @__PURE__ */
|
|
94
|
+
children: Q.name
|
|
95
|
+
}), /* @__PURE__ */ O("div", {
|
|
84
96
|
className: "mt-1.5 flex flex-wrap items-center gap-2",
|
|
85
97
|
children: [
|
|
86
|
-
/* @__PURE__ */
|
|
87
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ D(m, { visibility: Q.visibility }),
|
|
99
|
+
/* @__PURE__ */ O("span", {
|
|
88
100
|
className: "inline-flex items-center gap-1 text-xs text-text-secondary",
|
|
89
101
|
children: [
|
|
90
|
-
/* @__PURE__ */
|
|
102
|
+
/* @__PURE__ */ D(y, { className: "h-3.5 w-3.5" }),
|
|
91
103
|
" Updated ",
|
|
92
|
-
u(
|
|
104
|
+
u(Q.updatedAt)
|
|
93
105
|
]
|
|
94
106
|
}),
|
|
95
|
-
/* @__PURE__ */
|
|
107
|
+
/* @__PURE__ */ O("span", {
|
|
96
108
|
className: "text-xs text-text-secondary tabular-nums",
|
|
97
109
|
children: [
|
|
98
110
|
"· ",
|
|
99
|
-
|
|
111
|
+
$.length,
|
|
100
112
|
" ",
|
|
101
|
-
|
|
113
|
+
$.length === 1 ? "item" : "items"
|
|
102
114
|
]
|
|
103
115
|
})
|
|
104
116
|
]
|
|
105
117
|
})]
|
|
106
118
|
})]
|
|
107
|
-
}),
|
|
108
|
-
tags:
|
|
119
|
+
}), Q.tags.length > 0 && /* @__PURE__ */ D(d, {
|
|
120
|
+
tags: Q.tags,
|
|
109
121
|
className: "mt-4"
|
|
110
122
|
})]
|
|
111
123
|
}),
|
|
112
|
-
|
|
124
|
+
L && /* @__PURE__ */ D("form", {
|
|
113
125
|
onSubmit: (e) => {
|
|
114
|
-
e.preventDefault(), !(!
|
|
115
|
-
lookbookId:
|
|
116
|
-
lookId:
|
|
117
|
-
styleItemId:
|
|
118
|
-
note:
|
|
126
|
+
e.preventDefault(), !(!j || !V) && F.mutate({
|
|
127
|
+
lookbookId: j,
|
|
128
|
+
lookId: z === "look" ? V : void 0,
|
|
129
|
+
styleItemId: z === "item" ? V : void 0,
|
|
130
|
+
note: U.trim() || void 0
|
|
119
131
|
}, { onSuccess: () => {
|
|
120
|
-
|
|
132
|
+
H(""), W(""), R(!1);
|
|
121
133
|
} });
|
|
122
134
|
},
|
|
123
135
|
className: "mt-6",
|
|
124
|
-
children: /* @__PURE__ */
|
|
136
|
+
children: /* @__PURE__ */ O(k, {
|
|
125
137
|
treatment: "plain",
|
|
126
138
|
className: "p-5",
|
|
127
139
|
children: [
|
|
128
|
-
/* @__PURE__ */
|
|
140
|
+
/* @__PURE__ */ O("h3", {
|
|
129
141
|
className: "mb-4 flex items-center gap-2 text-base font-semibold text-text-primary",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
142
|
+
children: [/* @__PURE__ */ D(x, { className: "h-5 w-5" }), " Add to this lookbook"]
|
|
131
143
|
}),
|
|
132
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ D("div", {
|
|
133
145
|
className: "mb-4 flex flex-wrap gap-2",
|
|
134
|
-
children: ["look", "item"].map((e) => /* @__PURE__ */
|
|
146
|
+
children: ["look", "item"].map((e) => /* @__PURE__ */ D("button", {
|
|
135
147
|
type: "button",
|
|
136
148
|
onClick: () => {
|
|
137
|
-
|
|
149
|
+
B(e), H("");
|
|
138
150
|
},
|
|
139
|
-
className:
|
|
151
|
+
className: z === e ? "rounded-full bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text" : "rounded-full bg-bg-sunken px-3 py-1.5 text-sm font-medium text-text-secondary hover:text-text-primary",
|
|
140
152
|
children: e === "look" ? "Save a look" : "Clip a piece"
|
|
141
153
|
}, e))
|
|
142
154
|
}),
|
|
143
|
-
/* @__PURE__ */
|
|
144
|
-
label:
|
|
145
|
-
value: z,
|
|
146
|
-
onChange: B,
|
|
147
|
-
options: L === "look" ? J : Y,
|
|
148
|
-
placeholder: L === "look" ? U.isLoading ? "Loading looks…" : "Select a look" : W.isLoading ? "Loading items…" : "Select a style item"
|
|
149
|
-
}),
|
|
150
|
-
/* @__PURE__ */ E(p, {
|
|
151
|
-
label: "Note (optional)",
|
|
155
|
+
/* @__PURE__ */ D(f, {
|
|
156
|
+
label: z === "look" ? "Look" : "Style item",
|
|
152
157
|
value: V,
|
|
153
158
|
onChange: H,
|
|
159
|
+
options: z === "look" ? X : Z,
|
|
160
|
+
placeholder: z === "look" ? G.isLoading ? "Loading looks…" : "Select a look" : K.isLoading ? "Loading items…" : "Select a style item"
|
|
161
|
+
}),
|
|
162
|
+
/* @__PURE__ */ D(p, {
|
|
163
|
+
label: "Note (optional)",
|
|
164
|
+
value: U,
|
|
165
|
+
onChange: W,
|
|
154
166
|
placeholder: "Why you saved it…",
|
|
155
167
|
className: "mt-4"
|
|
156
168
|
}),
|
|
157
|
-
|
|
169
|
+
F.isError && /* @__PURE__ */ D("p", {
|
|
158
170
|
className: "mt-3 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
159
|
-
children:
|
|
171
|
+
children: F.error instanceof Error ? F.error.message : "Could not add entry"
|
|
160
172
|
}),
|
|
161
|
-
/* @__PURE__ */
|
|
173
|
+
/* @__PURE__ */ D("div", {
|
|
162
174
|
className: "mt-4 flex justify-end",
|
|
163
|
-
children: /* @__PURE__ */
|
|
175
|
+
children: /* @__PURE__ */ O("button", {
|
|
164
176
|
type: "submit",
|
|
165
|
-
disabled: !
|
|
177
|
+
disabled: !V || F.isPending,
|
|
166
178
|
className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50",
|
|
167
|
-
children: [
|
|
179
|
+
children: [F.isPending ? /* @__PURE__ */ D(b, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ D(x, { className: "h-4 w-4" }), "Add entry"]
|
|
168
180
|
})
|
|
169
181
|
})
|
|
170
182
|
]
|
|
171
183
|
})
|
|
172
184
|
}),
|
|
173
|
-
/* @__PURE__ */
|
|
185
|
+
/* @__PURE__ */ O("section", {
|
|
174
186
|
className: "mt-6",
|
|
175
|
-
children: [/* @__PURE__ */
|
|
187
|
+
children: [/* @__PURE__ */ O("h3", {
|
|
176
188
|
className: "mb-3 text-lg font-semibold text-text-primary",
|
|
177
189
|
children: [
|
|
178
190
|
"Board (",
|
|
179
|
-
|
|
191
|
+
$.length,
|
|
180
192
|
")"
|
|
181
193
|
]
|
|
182
|
-
}),
|
|
194
|
+
}), $.length === 0 ? /* @__PURE__ */ D("p", {
|
|
183
195
|
className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
184
196
|
children: "This lookbook has no entries yet. Clip a catalogue piece or save a look to add one."
|
|
185
|
-
}) : /* @__PURE__ */
|
|
197
|
+
}) : /* @__PURE__ */ D("div", {
|
|
186
198
|
className: "columns-2 gap-4 md:columns-3",
|
|
187
|
-
children:
|
|
188
|
-
let n = !!e.lookId, r = e.lookId ?
|
|
189
|
-
return /* @__PURE__ */
|
|
199
|
+
children: $.map((e, t) => {
|
|
200
|
+
let n = !!e.lookId, r = e.lookId ? q.get(e.lookId) : void 0, a = e.styleItemId ? J.get(e.styleItemId) : void 0, o = n ? r?.title ?? "Saved look" : a?.name ?? "Clipped piece", s = n ? r?.image?.id : a?.image?.id, c = P.isPending && P.variables === e.id;
|
|
201
|
+
return /* @__PURE__ */ O("div", {
|
|
190
202
|
className: "group relative mb-4 break-inside-avoid overflow-hidden rounded-xl border border-border-seam bg-bg-surface shadow-sm transition-shadow hover:shadow-lg",
|
|
191
|
-
children: [/* @__PURE__ */
|
|
203
|
+
children: [/* @__PURE__ */ D("button", {
|
|
192
204
|
type: "button",
|
|
193
205
|
onClick: () => {
|
|
194
|
-
n && e.lookId ?
|
|
206
|
+
n && e.lookId ? M(`/looks/${e.lookId}`) : e.styleItemId && M(`/items/${e.styleItemId}`);
|
|
195
207
|
},
|
|
196
208
|
"aria-label": `Open ${o}`,
|
|
197
209
|
className: "block w-full text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--color-focus-ring)]",
|
|
198
|
-
children: /* @__PURE__ */
|
|
199
|
-
icon:
|
|
210
|
+
children: /* @__PURE__ */ D(i, {
|
|
211
|
+
icon: D(n ? S : C, { className: "h-8 w-8" }),
|
|
200
212
|
seed: e.id,
|
|
201
213
|
fileId: s,
|
|
202
214
|
alt: o,
|
|
203
|
-
className: `w-full rounded-none ${
|
|
204
|
-
overlay: /* @__PURE__ */
|
|
215
|
+
className: `w-full rounded-none ${A[t % A.length]}`,
|
|
216
|
+
overlay: /* @__PURE__ */ O("div", {
|
|
205
217
|
className: "pointer-events-none absolute inset-x-0 bottom-0 flex flex-col gap-1.5 bg-gradient-to-t from-bg-canvas/90 via-bg-canvas/40 to-transparent p-3 pt-10",
|
|
206
|
-
children: [e.note && /* @__PURE__ */
|
|
218
|
+
children: [e.note && /* @__PURE__ */ D("span", {
|
|
207
219
|
className: "inline-flex w-fit max-w-full items-center rounded-md bg-bg-canvas/80 px-2 py-0.5 text-[11px] font-medium text-text-primary backdrop-blur",
|
|
208
|
-
children: /* @__PURE__ */
|
|
220
|
+
children: /* @__PURE__ */ D("span", {
|
|
209
221
|
className: "truncate",
|
|
210
222
|
children: e.note
|
|
211
223
|
})
|
|
212
|
-
}), /* @__PURE__ */
|
|
224
|
+
}), /* @__PURE__ */ D("p", {
|
|
213
225
|
className: "truncate text-sm font-semibold text-text-primary",
|
|
214
226
|
children: o
|
|
215
227
|
})]
|
|
216
228
|
})
|
|
217
229
|
})
|
|
218
|
-
}), /* @__PURE__ */
|
|
230
|
+
}), /* @__PURE__ */ D("button", {
|
|
219
231
|
type: "button",
|
|
220
|
-
disabled:
|
|
221
|
-
onClick: () =>
|
|
232
|
+
disabled: P.isPending,
|
|
233
|
+
onClick: () => P.mutate(e.id),
|
|
222
234
|
"aria-label": `Remove ${o}`,
|
|
223
235
|
className: "absolute right-2 top-2 z-10 inline-flex h-7 w-7 items-center justify-center rounded-full bg-bg-surface/90 text-text-secondary opacity-100 shadow-sm backdrop-blur transition-opacity hover:text-status-error-text sm:opacity-0 sm:focus-visible:opacity-100 sm:group-hover:opacity-100 disabled:opacity-60",
|
|
224
|
-
children: c ? /* @__PURE__ */
|
|
236
|
+
children: c ? /* @__PURE__ */ D(b, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ D(T, { className: "h-3.5 w-3.5" })
|
|
225
237
|
})]
|
|
226
238
|
}, e.id);
|
|
227
239
|
})
|
|
@@ -232,6 +244,6 @@ function A() {
|
|
|
232
244
|
});
|
|
233
245
|
}
|
|
234
246
|
//#endregion
|
|
235
|
-
export {
|
|
247
|
+
export { j as LookbookDetailPage };
|
|
236
248
|
|
|
237
249
|
//# sourceMappingURL=LookbookDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LookbookDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/lookbooks/LookbookDetailPage.tsx"],"sourcesContent":["/**\n * Lookbook Detail Page\n * @module coolandlovely/pages/lookbooks\n *\n * Single lookbook (`cooLookbook`) rendered as a Pinterest-style masonry board.\n * Each entry's `lookId` / `styleItemId` is resolved client-side against the\n * already-fetched looks/items lists to a real title + image, with an optional\n * note badge and a hover X-remove (`cooRemoveLookbookEntry`). New entries are\n * added inline (`cooAddLookbookEntry`).\n */\n\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, BookHeart, Sparkles, Tag, Loader2, Plus, X, Clock } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { VisibilityChip } from '../../components/VisibilityChip';\nimport { SelectField, TextField } from '../../components/Field';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport {\n useLookbook,\n useRemoveLookbookEntry,\n useAddLookbookEntry,\n useLooks,\n useStyleItems,\n} from '../../hooks';\nimport { formatRelativeTime } from '../../utils/formatters';\n\ntype EntryKind = 'look' | 'item';\n\n/** Alternating aspect ratios give the board its masonry rhythm. */\nconst TILE_ASPECTS = ['aspect-[3/4]', 'aspect-square', 'aspect-[4/5]'];\n\nexport function LookbookDetailPage() {\n const { lookbookId } = useParams<{ lookbookId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useLookbook(lookbookId);\n const removeEntry = useRemoveLookbookEntry();\n const addEntry = useAddLookbookEntry();\n\n const [adding, setAdding] = useState(false);\n const [entryKind, setEntryKind] = useState<EntryKind>('look');\n const [selectedId, setSelectedId] = useState('');\n const [note, setNote] = useState('');\n\n const looks = useLooks({ pagination: { limit: 100, offset: 0 } });\n const items = useStyleItems({ pagination: { limit: 100, offset: 0 } });\n\n const lookById = useMemo(\n () => new Map((looks.data?.items ?? []).map((l) => [l.id, l])),\n [looks.data]\n );\n const itemById = useMemo(\n () => new Map((items.data?.items ?? []).map((i) => [i.id, i])),\n [items.data]\n );\n const usableItems = useMemo(\n () => (items.data?.items ?? []).filter((i) => i.status !== 'RETIRED'),\n [items.data]\n );\n\n const lookOptions = useMemo(\n () => (looks.data?.items ?? []).map((l) => ({ value: l.id, label: l.title })),\n [looks.data]\n );\n const itemOptions = useMemo(\n () =>\n usableItems.map((i) => ({\n value: i.id,\n label: `${i.name}${i.brand?.name ? ` · ${i.brand.name}` : ''}`,\n })),\n [usableItems]\n );\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Lookbook\">\n <LoadingView label=\"Loading lookbook…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Lookbook\">\n <ErrorView title=\"Lookbook not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const lookbook = query.data;\n const entries = [...(lookbook.entries ?? [])].sort((a, b) => a.position - b.position);\n\n const handleAddEntry = (e: React.FormEvent) => {\n e.preventDefault();\n if (!lookbookId || !selectedId) return;\n addEntry.mutate(\n {\n lookbookId,\n lookId: entryKind === 'look' ? selectedId : undefined,\n styleItemId: entryKind === 'item' ? selectedId : undefined,\n note: note.trim() || undefined,\n },\n {\n onSuccess: () => {\n setSelectedId('');\n setNote('');\n setAdding(false);\n },\n }\n );\n };\n\n return (\n <PageLayout\n title={lookbook.name}\n description={lookbook.description ?? undefined}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/lookbooks')}\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 <button\n type=\"button\"\n onClick={() => {\n setAdding((v) => !v);\n setSelectedId('');\n }}\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 {adding ? <X className=\"h-4 w-4\" /> : <Plus className=\"h-4 w-4\" />}\n {adding ? 'Close' : 'Add entry'}\n </button>\n </div>\n }\n >\n <div className=\"mx-auto max-w-5xl\">\n <GlassCard treatment=\"glass\" className=\"p-6\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-accent-purple-subtle text-text-primary\">\n <BookHeart className=\"h-6 w-6\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"truncate text-xl font-semibold text-text-primary\">{lookbook.name}</h2>\n <div className=\"mt-1.5 flex flex-wrap items-center gap-2\">\n <VisibilityChip visibility={lookbook.visibility} />\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" /> Updated {formatRelativeTime(lookbook.updatedAt)}\n </span>\n <span className=\"text-xs text-text-secondary tabular-nums\">\n · {entries.length} {entries.length === 1 ? 'item' : 'items'}\n </span>\n </div>\n </div>\n </div>\n {lookbook.tags.length > 0 && <TagList tags={lookbook.tags} className=\"mt-4\" />}\n </GlassCard>\n\n {adding && (\n <form onSubmit={handleAddEntry} className=\"mt-6\">\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <h3 className=\"mb-4 flex items-center gap-2 text-base font-semibold text-text-primary\">\n <Plus className=\"h-5 w-5\" /> Add to this lookbook\n </h3>\n <div className=\"mb-4 flex flex-wrap gap-2\">\n {(['look', 'item'] as EntryKind[]).map((k) => (\n <button\n key={k}\n type=\"button\"\n onClick={() => {\n setEntryKind(k);\n setSelectedId('');\n }}\n className={\n entryKind === k\n ? 'rounded-full bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text'\n : 'rounded-full bg-bg-sunken px-3 py-1.5 text-sm font-medium text-text-secondary hover:text-text-primary'\n }\n >\n {k === 'look' ? 'Save a look' : 'Clip a piece'}\n </button>\n ))}\n </div>\n <SelectField\n label={entryKind === 'look' ? 'Look' : 'Style item'}\n value={selectedId}\n onChange={setSelectedId}\n options={entryKind === 'look' ? lookOptions : itemOptions}\n placeholder={\n entryKind === 'look'\n ? looks.isLoading\n ? 'Loading looks…'\n : 'Select a look'\n : items.isLoading\n ? 'Loading items…'\n : 'Select a style item'\n }\n />\n <TextField\n label=\"Note (optional)\"\n value={note}\n onChange={setNote}\n placeholder=\"Why you saved it…\"\n className=\"mt-4\"\n />\n {addEntry.isError && (\n <p className=\"mt-3 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {addEntry.error instanceof Error ? addEntry.error.message : 'Could not add entry'}\n </p>\n )}\n <div className=\"mt-4 flex justify-end\">\n <button\n type=\"submit\"\n disabled={!selectedId || addEntry.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {addEntry.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Plus className=\"h-4 w-4\" />\n )}\n Add entry\n </button>\n </div>\n </GlassCard>\n </form>\n )}\n\n <section className=\"mt-6\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">Board ({entries.length})</h3>\n {entries.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n This lookbook has no entries yet. Clip a catalogue piece or save a look to add one.\n </p>\n ) : (\n <div className=\"columns-2 gap-4 md:columns-3\">\n {entries.map((entry, idx) => {\n const isLook = Boolean(entry.lookId);\n const look = entry.lookId ? lookById.get(entry.lookId) : undefined;\n const item = entry.styleItemId ? itemById.get(entry.styleItemId) : undefined;\n const title = isLook\n ? (look?.title ?? 'Saved look')\n : (item?.name ?? 'Clipped piece');\n const imageFileId = isLook ? look?.image?.id : item?.image?.id;\n const removing = removeEntry.isPending && removeEntry.variables === entry.id;\n const onOpen = () => {\n if (isLook && entry.lookId) navigateTo(`/looks/${entry.lookId}`);\n else if (entry.styleItemId) navigateTo(`/items/${entry.styleItemId}`);\n };\n return (\n <div\n key={entry.id}\n className=\"group relative mb-4 break-inside-avoid overflow-hidden rounded-xl border border-border-seam bg-bg-surface shadow-sm transition-shadow hover:shadow-lg\"\n >\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${title}`}\n className=\"block w-full text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <Thumbnail\n icon={\n isLook ? <Sparkles className=\"h-8 w-8\" /> : <Tag className=\"h-8 w-8\" />\n }\n seed={entry.id}\n fileId={imageFileId}\n alt={title}\n className={`w-full rounded-none ${TILE_ASPECTS[idx % TILE_ASPECTS.length]}`}\n overlay={\n <div className=\"pointer-events-none absolute inset-x-0 bottom-0 flex flex-col gap-1.5 bg-gradient-to-t from-bg-canvas/90 via-bg-canvas/40 to-transparent p-3 pt-10\">\n {entry.note && (\n <span className=\"inline-flex w-fit max-w-full items-center rounded-md bg-bg-canvas/80 px-2 py-0.5 text-[11px] font-medium text-text-primary backdrop-blur\">\n <span className=\"truncate\">{entry.note}</span>\n </span>\n )}\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {title}\n </p>\n </div>\n }\n />\n </button>\n <button\n type=\"button\"\n disabled={removeEntry.isPending}\n onClick={() => removeEntry.mutate(entry.id)}\n aria-label={`Remove ${title}`}\n className=\"absolute right-2 top-2 z-10 inline-flex h-7 w-7 items-center justify-center rounded-full bg-bg-surface/90 text-text-secondary opacity-100 shadow-sm backdrop-blur transition-opacity hover:text-status-error-text sm:opacity-0 sm:focus-visible:opacity-100 sm:group-hover:opacity-100 disabled:opacity-60\"\n >\n {removing ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <X className=\"h-3.5 w-3.5\" />\n )}\n </button>\n </div>\n );\n })}\n </div>\n )}\n </section>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LookbookDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/lookbooks/LookbookDetailPage.tsx"],"sourcesContent":["/**\n * Lookbook Detail Page\n * @module coolandlovely/pages/lookbooks\n *\n * Single lookbook (`cooLookbook`) rendered as a Pinterest-style masonry board.\n * Each entry's `lookId` / `styleItemId` is resolved client-side against the\n * already-fetched looks/items lists to a real title + image, with an optional\n * note badge and a hover X-remove (`cooRemoveLookbookEntry`). New entries are\n * added inline (`cooAddLookbookEntry`).\n */\n\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, BookHeart, Sparkles, Tag, Loader2, Plus, Trash2, X, Clock } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { VisibilityChip } from '../../components/VisibilityChip';\nimport { SelectField, TextField } from '../../components/Field';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport {\n useLookbook,\n useRemoveLookbookEntry,\n useAddLookbookEntry,\n useDeleteLookbook,\n useLooks,\n useStyleItems,\n} from '../../hooks';\nimport { formatRelativeTime } from '../../utils/formatters';\n\ntype EntryKind = 'look' | 'item';\n\n/** Alternating aspect ratios give the board its masonry rhythm. */\nconst TILE_ASPECTS = ['aspect-[3/4]', 'aspect-square', 'aspect-[4/5]'];\n\nexport function LookbookDetailPage() {\n const { lookbookId } = useParams<{ lookbookId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useLookbook(lookbookId);\n const removeEntry = useRemoveLookbookEntry();\n const addEntry = useAddLookbookEntry();\n const deleteLookbook = useDeleteLookbook();\n\n const [adding, setAdding] = useState(false);\n const [entryKind, setEntryKind] = useState<EntryKind>('look');\n const [selectedId, setSelectedId] = useState('');\n const [note, setNote] = useState('');\n\n const looks = useLooks({ pagination: { limit: 100, offset: 0 } });\n const items = useStyleItems({ pagination: { limit: 100, offset: 0 } });\n\n const lookById = useMemo(\n () => new Map((looks.data?.items ?? []).map((l) => [l.id, l])),\n [looks.data]\n );\n const itemById = useMemo(\n () => new Map((items.data?.items ?? []).map((i) => [i.id, i])),\n [items.data]\n );\n const usableItems = useMemo(\n () => (items.data?.items ?? []).filter((i) => i.status !== 'RETIRED'),\n [items.data]\n );\n\n const lookOptions = useMemo(\n () => (looks.data?.items ?? []).map((l) => ({ value: l.id, label: l.title })),\n [looks.data]\n );\n const itemOptions = useMemo(\n () =>\n usableItems.map((i) => ({\n value: i.id,\n label: `${i.name}${i.brand?.name ? ` · ${i.brand.name}` : ''}`,\n })),\n [usableItems]\n );\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Lookbook\">\n <LoadingView label=\"Loading lookbook…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Lookbook\">\n <ErrorView title=\"Lookbook not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const lookbook = query.data;\n const entries = [...(lookbook.entries ?? [])].sort((a, b) => a.position - b.position);\n\n const handleAddEntry = (e: React.FormEvent) => {\n e.preventDefault();\n if (!lookbookId || !selectedId) return;\n addEntry.mutate(\n {\n lookbookId,\n lookId: entryKind === 'look' ? selectedId : undefined,\n styleItemId: entryKind === 'item' ? selectedId : undefined,\n note: note.trim() || undefined,\n },\n {\n onSuccess: () => {\n setSelectedId('');\n setNote('');\n setAdding(false);\n },\n }\n );\n };\n\n return (\n <PageLayout\n title={lookbook.name}\n description={lookbook.description ?? undefined}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/lookbooks')}\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 <button\n type=\"button\"\n onClick={() => {\n setAdding((v) => !v);\n setSelectedId('');\n }}\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 {adding ? <X className=\"h-4 w-4\" /> : <Plus className=\"h-4 w-4\" />}\n {adding ? 'Close' : 'Add entry'}\n </button>\n <button\n type=\"button\"\n disabled={deleteLookbook.isPending}\n onClick={() => {\n if (!lookbookId) return;\n deleteLookbook.mutate(lookbookId, { onSuccess: () => navigateTo('/lookbooks') });\n }}\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 {deleteLookbook.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Trash2 className=\"h-4 w-4\" />\n )}\n Delete\n </button>\n </div>\n }\n >\n <div className=\"mx-auto max-w-5xl\">\n <GlassCard treatment=\"glass\" className=\"p-6\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-accent-purple-subtle text-text-primary\">\n <BookHeart className=\"h-6 w-6\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"truncate text-xl font-semibold text-text-primary\">{lookbook.name}</h2>\n <div className=\"mt-1.5 flex flex-wrap items-center gap-2\">\n <VisibilityChip visibility={lookbook.visibility} />\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" /> Updated {formatRelativeTime(lookbook.updatedAt)}\n </span>\n <span className=\"text-xs text-text-secondary tabular-nums\">\n · {entries.length} {entries.length === 1 ? 'item' : 'items'}\n </span>\n </div>\n </div>\n </div>\n {lookbook.tags.length > 0 && <TagList tags={lookbook.tags} className=\"mt-4\" />}\n </GlassCard>\n\n {adding && (\n <form onSubmit={handleAddEntry} className=\"mt-6\">\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <h3 className=\"mb-4 flex items-center gap-2 text-base font-semibold text-text-primary\">\n <Plus className=\"h-5 w-5\" /> Add to this lookbook\n </h3>\n <div className=\"mb-4 flex flex-wrap gap-2\">\n {(['look', 'item'] as EntryKind[]).map((k) => (\n <button\n key={k}\n type=\"button\"\n onClick={() => {\n setEntryKind(k);\n setSelectedId('');\n }}\n className={\n entryKind === k\n ? 'rounded-full bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text'\n : 'rounded-full bg-bg-sunken px-3 py-1.5 text-sm font-medium text-text-secondary hover:text-text-primary'\n }\n >\n {k === 'look' ? 'Save a look' : 'Clip a piece'}\n </button>\n ))}\n </div>\n <SelectField\n label={entryKind === 'look' ? 'Look' : 'Style item'}\n value={selectedId}\n onChange={setSelectedId}\n options={entryKind === 'look' ? lookOptions : itemOptions}\n placeholder={\n entryKind === 'look'\n ? looks.isLoading\n ? 'Loading looks…'\n : 'Select a look'\n : items.isLoading\n ? 'Loading items…'\n : 'Select a style item'\n }\n />\n <TextField\n label=\"Note (optional)\"\n value={note}\n onChange={setNote}\n placeholder=\"Why you saved it…\"\n className=\"mt-4\"\n />\n {addEntry.isError && (\n <p className=\"mt-3 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {addEntry.error instanceof Error ? addEntry.error.message : 'Could not add entry'}\n </p>\n )}\n <div className=\"mt-4 flex justify-end\">\n <button\n type=\"submit\"\n disabled={!selectedId || addEntry.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {addEntry.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Plus className=\"h-4 w-4\" />\n )}\n Add entry\n </button>\n </div>\n </GlassCard>\n </form>\n )}\n\n <section className=\"mt-6\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">Board ({entries.length})</h3>\n {entries.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n This lookbook has no entries yet. Clip a catalogue piece or save a look to add one.\n </p>\n ) : (\n <div className=\"columns-2 gap-4 md:columns-3\">\n {entries.map((entry, idx) => {\n const isLook = Boolean(entry.lookId);\n const look = entry.lookId ? lookById.get(entry.lookId) : undefined;\n const item = entry.styleItemId ? itemById.get(entry.styleItemId) : undefined;\n const title = isLook\n ? (look?.title ?? 'Saved look')\n : (item?.name ?? 'Clipped piece');\n const imageFileId = isLook ? look?.image?.id : item?.image?.id;\n const removing = removeEntry.isPending && removeEntry.variables === entry.id;\n const onOpen = () => {\n if (isLook && entry.lookId) navigateTo(`/looks/${entry.lookId}`);\n else if (entry.styleItemId) navigateTo(`/items/${entry.styleItemId}`);\n };\n return (\n <div\n key={entry.id}\n className=\"group relative mb-4 break-inside-avoid overflow-hidden rounded-xl border border-border-seam bg-bg-surface shadow-sm transition-shadow hover:shadow-lg\"\n >\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${title}`}\n className=\"block w-full text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <Thumbnail\n icon={\n isLook ? <Sparkles className=\"h-8 w-8\" /> : <Tag className=\"h-8 w-8\" />\n }\n seed={entry.id}\n fileId={imageFileId}\n alt={title}\n className={`w-full rounded-none ${TILE_ASPECTS[idx % TILE_ASPECTS.length]}`}\n overlay={\n <div className=\"pointer-events-none absolute inset-x-0 bottom-0 flex flex-col gap-1.5 bg-gradient-to-t from-bg-canvas/90 via-bg-canvas/40 to-transparent p-3 pt-10\">\n {entry.note && (\n <span className=\"inline-flex w-fit max-w-full items-center rounded-md bg-bg-canvas/80 px-2 py-0.5 text-[11px] font-medium text-text-primary backdrop-blur\">\n <span className=\"truncate\">{entry.note}</span>\n </span>\n )}\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {title}\n </p>\n </div>\n }\n />\n </button>\n <button\n type=\"button\"\n disabled={removeEntry.isPending}\n onClick={() => removeEntry.mutate(entry.id)}\n aria-label={`Remove ${title}`}\n className=\"absolute right-2 top-2 z-10 inline-flex h-7 w-7 items-center justify-center rounded-full bg-bg-surface/90 text-text-secondary opacity-100 shadow-sm backdrop-blur transition-opacity hover:text-status-error-text sm:opacity-0 sm:focus-visible:opacity-100 sm:group-hover:opacity-100 disabled:opacity-60\"\n >\n {removing ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <X className=\"h-3.5 w-3.5\" />\n )}\n </button>\n </div>\n );\n })}\n </div>\n )}\n </section>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LookDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/looks/LookDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"LookDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/looks/LookDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuFH,wBAAgB,cAAc,gCA2R7B"}
|
|
@@ -24,33 +24,35 @@ function L(e) {
|
|
|
24
24
|
return t.length === 0 ? "?" : t.length === 1 ? t[0].slice(0, 2).toUpperCase() : (t[0][0] + t[t.length - 1][0]).toUpperCase();
|
|
25
25
|
}
|
|
26
26
|
function R({ authorId: t }) {
|
|
27
|
-
let { apiGatewayUrl: n, authToken: r, workspaceId: i } = e(), [
|
|
27
|
+
let { apiGatewayUrl: n, authToken: r, workspaceId: i, navigateTo: a } = e(), [o, s] = C(!1), c = I(S(() => [{
|
|
28
28
|
actorId: t,
|
|
29
29
|
actorType: "user"
|
|
30
30
|
}], [t]), {
|
|
31
31
|
apiGatewayUrl: n,
|
|
32
32
|
authToken: r,
|
|
33
33
|
workspaceId: i
|
|
34
|
-
})[t],
|
|
35
|
-
return /* @__PURE__ */ P("
|
|
36
|
-
|
|
34
|
+
})[t], l = c?.displayName ?? "Creator", u = c?.avatarUrl;
|
|
35
|
+
return /* @__PURE__ */ P("button", {
|
|
36
|
+
type: "button",
|
|
37
|
+
onClick: () => a(`/profile/${t}`),
|
|
38
|
+
className: "inline-flex items-center gap-2 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
37
39
|
children: [/* @__PURE__ */ N("span", {
|
|
38
|
-
title:
|
|
40
|
+
title: l,
|
|
39
41
|
className: "relative flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-bg-sunken ring-1 ring-border-seam",
|
|
40
|
-
children:
|
|
41
|
-
src:
|
|
42
|
-
alt:
|
|
42
|
+
children: u && !o ? /* @__PURE__ */ N("img", {
|
|
43
|
+
src: u,
|
|
44
|
+
alt: l,
|
|
43
45
|
loading: "lazy",
|
|
44
|
-
onError: () =>
|
|
46
|
+
onError: () => s(!0),
|
|
45
47
|
className: "h-full w-full object-cover"
|
|
46
48
|
}) : /* @__PURE__ */ N("span", {
|
|
47
49
|
className: "text-[10px] font-semibold text-text-secondary",
|
|
48
|
-
children: L(
|
|
50
|
+
children: L(l)
|
|
49
51
|
})
|
|
50
52
|
}), /* @__PURE__ */ N("span", {
|
|
51
|
-
className: "font-medium text-text-primary",
|
|
52
|
-
title:
|
|
53
|
-
children:
|
|
53
|
+
className: "font-medium text-text-primary hover:underline",
|
|
54
|
+
title: c?.email ?? t,
|
|
55
|
+
children: l
|
|
54
56
|
})]
|
|
55
57
|
});
|
|
56
58
|
}
|