@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
|
@@ -1,202 +1,242 @@
|
|
|
1
1
|
import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { cn as t } from "../../utils/cn.js";
|
|
3
|
+
import { PageLayout as n } from "../../components/PageLayout.js";
|
|
4
|
+
import { StatusBadge as r } from "../../components/StatusBadge.js";
|
|
5
|
+
import { ErrorView as i, LoadingView as a } from "../../components/StateViews.js";
|
|
6
|
+
import { Thumbnail as o } from "../../components/Thumbnail.js";
|
|
7
|
+
import { useDeleteLook as s, useLikeLook as c, useLook as l, usePublishLook as u, useUpdateLook as d } from "../../hooks/useCoolAndLovelyApi.js";
|
|
7
8
|
import "../../hooks/index.js";
|
|
8
|
-
import { formatDate as
|
|
9
|
-
import { TagList as
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
9
|
+
import { formatDate as f, formatPrice as p, titleCase as m } from "../../utils/formatters.js";
|
|
10
|
+
import { TagList as h } from "../../components/TagList.js";
|
|
11
|
+
import { ActorName as g } from "../../components/ActorName.js";
|
|
12
|
+
import { Comments as _ } from "../../components/Comments.js";
|
|
13
|
+
import { AddToLookbookButton as v } from "../../components/AddToLookbookButton.js";
|
|
14
|
+
import { FollowButton as y } from "../../components/FollowButton.js";
|
|
15
|
+
import { ArrowLeft as b, Bookmark as x, Heart as S, Loader2 as C, Rocket as w, Sparkles as T, Star as E, Trash2 as D } from "lucide-react";
|
|
16
|
+
import { useParams as O } from "react-router-dom";
|
|
17
|
+
import { jsx as k, jsxs as A } from "react/jsx-runtime";
|
|
18
|
+
import { GlassCard as j } from "@burdenoff/fe-libs/ui";
|
|
14
19
|
//#region src/coolandlovely/pages/looks/LookDetailPage.tsx
|
|
15
|
-
function
|
|
16
|
-
let { lookId:
|
|
17
|
-
if (
|
|
20
|
+
function M() {
|
|
21
|
+
let { lookId: M } = O(), { navigateTo: N, currentUser: P } = e(), F = l(M), I = c(), L = u(), R = s(), z = d();
|
|
22
|
+
if (F.isLoading) return /* @__PURE__ */ k(n, {
|
|
18
23
|
title: "Look",
|
|
19
|
-
children: /* @__PURE__ */
|
|
24
|
+
children: /* @__PURE__ */ k(a, { label: "Loading look…" })
|
|
20
25
|
});
|
|
21
|
-
if (
|
|
26
|
+
if (F.isError || !F.data) return /* @__PURE__ */ k(n, {
|
|
22
27
|
title: "Look",
|
|
23
|
-
children: /* @__PURE__ */
|
|
28
|
+
children: /* @__PURE__ */ k(i, {
|
|
24
29
|
title: "Look not found",
|
|
25
|
-
onRetry: () => void
|
|
30
|
+
onRetry: () => void F.refetch()
|
|
26
31
|
})
|
|
27
32
|
});
|
|
28
|
-
let
|
|
29
|
-
return /* @__PURE__ */
|
|
30
|
-
title:
|
|
31
|
-
description:
|
|
32
|
-
actions: /* @__PURE__ */
|
|
33
|
-
className: "flex items-center gap-2",
|
|
33
|
+
let B = F.data, V = B.items ?? [], H = B.publishedAt !== null, U = !!(P?.id && P.id === B.authorId);
|
|
34
|
+
return /* @__PURE__ */ k(n, {
|
|
35
|
+
title: B.title,
|
|
36
|
+
description: m(B.occasion),
|
|
37
|
+
actions: /* @__PURE__ */ A("div", {
|
|
38
|
+
className: "flex flex-wrap items-center gap-2",
|
|
34
39
|
children: [
|
|
35
|
-
/* @__PURE__ */
|
|
40
|
+
/* @__PURE__ */ A("button", {
|
|
36
41
|
type: "button",
|
|
37
|
-
onClick: () =>
|
|
42
|
+
onClick: () => N("/looks"),
|
|
38
43
|
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",
|
|
39
|
-
children: [/* @__PURE__ */
|
|
44
|
+
children: [/* @__PURE__ */ k(b, { className: "h-4 w-4" }), " Back"]
|
|
40
45
|
}),
|
|
41
|
-
|
|
46
|
+
/* @__PURE__ */ k(v, { lookId: B.id }),
|
|
47
|
+
/* @__PURE__ */ A("button", {
|
|
42
48
|
type: "button",
|
|
43
|
-
disabled:
|
|
44
|
-
onClick: () =>
|
|
49
|
+
disabled: z.isPending,
|
|
50
|
+
onClick: () => z.mutate({
|
|
51
|
+
id: B.id,
|
|
52
|
+
input: { isFeatured: !B.isFeatured }
|
|
53
|
+
}),
|
|
54
|
+
"aria-pressed": B.isFeatured,
|
|
55
|
+
className: t("inline-flex items-center gap-1.5 rounded-lg border px-3 py-2 text-sm font-medium transition-colors disabled:opacity-50", B.isFeatured ? "border-status-warning-text/40 bg-status-warning-bg-subtle text-status-warning-text" : "border-border-seam text-text-primary hover:bg-bg-sunken"),
|
|
56
|
+
children: [z.isPending ? /* @__PURE__ */ k(C, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ k(E, { className: t("h-4 w-4", B.isFeatured && "fill-status-warning-text") }), B.isFeatured ? "Featured" : "Feature"]
|
|
57
|
+
}),
|
|
58
|
+
!H && /* @__PURE__ */ A("button", {
|
|
59
|
+
type: "button",
|
|
60
|
+
disabled: L.isPending,
|
|
61
|
+
onClick: () => L.mutate(B.id),
|
|
45
62
|
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 disabled:opacity-50",
|
|
46
|
-
children: [
|
|
63
|
+
children: [L.isPending ? /* @__PURE__ */ k(C, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ k(w, { className: "h-4 w-4" }), "Publish"]
|
|
47
64
|
}),
|
|
48
|
-
/* @__PURE__ */
|
|
65
|
+
/* @__PURE__ */ A("button", {
|
|
49
66
|
type: "button",
|
|
50
|
-
disabled:
|
|
51
|
-
onClick: () =>
|
|
67
|
+
disabled: R.isPending,
|
|
68
|
+
onClick: () => R.mutate(B.id, { onSuccess: () => N("/looks") }),
|
|
52
69
|
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: [
|
|
70
|
+
children: [R.isPending ? /* @__PURE__ */ k(C, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ k(D, { className: "h-4 w-4" }), "Delete"]
|
|
54
71
|
})
|
|
55
72
|
]
|
|
56
73
|
}),
|
|
57
|
-
children: /* @__PURE__ */
|
|
74
|
+
children: /* @__PURE__ */ A("div", {
|
|
58
75
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
76
|
+
children: [/* @__PURE__ */ A("div", {
|
|
60
77
|
className: "lg:col-span-2",
|
|
61
|
-
children: [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
children: M.title
|
|
77
|
-
}),
|
|
78
|
-
M.isFeatured && /* @__PURE__ */ C(b, { className: "h-4 w-4 fill-status-warning-text text-status-warning-text" }),
|
|
79
|
-
/* @__PURE__ */ C(n, {
|
|
80
|
-
status: P ? "published" : "draft",
|
|
81
|
-
className: "ml-auto"
|
|
82
|
-
})
|
|
83
|
-
]
|
|
84
|
-
}),
|
|
85
|
-
M.caption && /* @__PURE__ */ C("p", {
|
|
86
|
-
className: "mt-3 text-sm text-text-secondary",
|
|
87
|
-
children: M.caption
|
|
88
|
-
}),
|
|
89
|
-
M.tags.length > 0 && /* @__PURE__ */ C(p, {
|
|
90
|
-
tags: M.tags,
|
|
91
|
-
className: "mt-4",
|
|
92
|
-
tone: "accent"
|
|
93
|
-
}),
|
|
94
|
-
/* @__PURE__ */ w("div", {
|
|
95
|
-
className: "mt-5 flex items-center gap-3",
|
|
96
|
-
children: [/* @__PURE__ */ w("button", {
|
|
97
|
-
type: "button",
|
|
98
|
-
disabled: k.isPending,
|
|
99
|
-
onClick: () => k.mutate(M.id),
|
|
100
|
-
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-status-error-bg-subtle disabled:opacity-50",
|
|
101
|
-
children: [
|
|
102
|
-
k.isPending ? /* @__PURE__ */ C(_, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ C(g, { className: "h-4 w-4" }),
|
|
103
|
-
"Like · ",
|
|
104
|
-
M.likeCount
|
|
105
|
-
]
|
|
106
|
-
}), /* @__PURE__ */ w("span", {
|
|
107
|
-
className: "inline-flex items-center gap-1.5 text-sm text-text-secondary",
|
|
78
|
+
children: [
|
|
79
|
+
/* @__PURE__ */ A(j, {
|
|
80
|
+
treatment: "glass",
|
|
81
|
+
className: "overflow-hidden p-0",
|
|
82
|
+
children: [/* @__PURE__ */ k(o, {
|
|
83
|
+
icon: /* @__PURE__ */ k(T, { className: "h-14 w-14" }),
|
|
84
|
+
seed: B.id,
|
|
85
|
+
fileId: B.image?.id,
|
|
86
|
+
alt: B.title,
|
|
87
|
+
className: "h-60 w-full"
|
|
88
|
+
}), /* @__PURE__ */ A("div", {
|
|
89
|
+
className: "p-6",
|
|
90
|
+
children: [
|
|
91
|
+
/* @__PURE__ */ A("div", {
|
|
92
|
+
className: "flex items-center gap-2",
|
|
108
93
|
children: [
|
|
109
|
-
/* @__PURE__ */
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
94
|
+
/* @__PURE__ */ k("h2", {
|
|
95
|
+
className: "text-xl font-semibold text-text-primary",
|
|
96
|
+
children: B.title
|
|
97
|
+
}),
|
|
98
|
+
B.isFeatured && /* @__PURE__ */ k(E, { className: "h-4 w-4 fill-status-warning-text text-status-warning-text" }),
|
|
99
|
+
/* @__PURE__ */ k(r, {
|
|
100
|
+
status: H ? "published" : "draft",
|
|
101
|
+
className: "ml-auto"
|
|
102
|
+
})
|
|
113
103
|
]
|
|
114
|
-
})]
|
|
115
|
-
})
|
|
116
|
-
]
|
|
117
|
-
})]
|
|
118
|
-
}), /* @__PURE__ */ w("section", {
|
|
119
|
-
className: "mt-6",
|
|
120
|
-
children: [/* @__PURE__ */ w("h3", {
|
|
121
|
-
className: "mb-3 text-lg font-semibold text-text-primary",
|
|
122
|
-
children: [
|
|
123
|
-
"Shop the look (",
|
|
124
|
-
N.length,
|
|
125
|
-
")"
|
|
126
|
-
]
|
|
127
|
-
}), N.length === 0 ? /* @__PURE__ */ C("p", {
|
|
128
|
-
className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
129
|
-
children: "No items tagged in this look yet."
|
|
130
|
-
}) : /* @__PURE__ */ C("div", {
|
|
131
|
-
className: "divide-y divide-border-seam rounded-lg border border-border-seam bg-bg-surface",
|
|
132
|
-
children: [...N].sort((e, t) => e.position - t.position).map((e) => /* @__PURE__ */ w("button", {
|
|
133
|
-
type: "button",
|
|
134
|
-
onClick: () => e.styleItem && D(`/items/${e.styleItem.id}`),
|
|
135
|
-
className: "flex w-full items-center gap-4 px-4 py-3 text-left transition-colors hover:bg-bg-sunken/50",
|
|
136
|
-
children: [
|
|
137
|
-
/* @__PURE__ */ C(a, {
|
|
138
|
-
icon: /* @__PURE__ */ C(y, { className: "h-5 w-5" }),
|
|
139
|
-
seed: e.id,
|
|
140
|
-
className: "h-11 w-11 shrink-0"
|
|
141
104
|
}),
|
|
142
|
-
/* @__PURE__ */
|
|
143
|
-
className: "
|
|
144
|
-
children:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
105
|
+
B.caption && /* @__PURE__ */ k("p", {
|
|
106
|
+
className: "mt-3 text-sm text-text-secondary",
|
|
107
|
+
children: B.caption
|
|
108
|
+
}),
|
|
109
|
+
B.tags.length > 0 && /* @__PURE__ */ k(h, {
|
|
110
|
+
tags: B.tags,
|
|
111
|
+
className: "mt-4",
|
|
112
|
+
tone: "accent"
|
|
113
|
+
}),
|
|
114
|
+
/* @__PURE__ */ A("div", {
|
|
115
|
+
className: "mt-4 flex flex-wrap items-center gap-2 text-sm text-text-secondary",
|
|
116
|
+
children: [/* @__PURE__ */ A("span", { children: [
|
|
117
|
+
"By",
|
|
118
|
+
" ",
|
|
119
|
+
/* @__PURE__ */ k(g, {
|
|
120
|
+
id: B.authorId,
|
|
121
|
+
className: "font-medium text-text-primary"
|
|
122
|
+
})
|
|
123
|
+
] }), !U && /* @__PURE__ */ k(y, {
|
|
124
|
+
followeeId: B.authorId,
|
|
125
|
+
size: "sm"
|
|
150
126
|
})]
|
|
151
127
|
}),
|
|
152
|
-
|
|
153
|
-
className: "
|
|
154
|
-
children:
|
|
128
|
+
/* @__PURE__ */ A("div", {
|
|
129
|
+
className: "mt-5 flex items-center gap-3",
|
|
130
|
+
children: [/* @__PURE__ */ A("button", {
|
|
131
|
+
type: "button",
|
|
132
|
+
disabled: I.isPending,
|
|
133
|
+
onClick: () => I.mutate(B.id),
|
|
134
|
+
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-status-error-bg-subtle disabled:opacity-50",
|
|
135
|
+
children: [
|
|
136
|
+
I.isPending ? /* @__PURE__ */ k(C, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ k(S, { className: "h-4 w-4" }),
|
|
137
|
+
"Like · ",
|
|
138
|
+
B.likeCount
|
|
139
|
+
]
|
|
140
|
+
}), /* @__PURE__ */ A("span", {
|
|
141
|
+
className: "inline-flex items-center gap-1.5 text-sm text-text-secondary",
|
|
142
|
+
children: [
|
|
143
|
+
/* @__PURE__ */ k(x, { className: "h-4 w-4" }),
|
|
144
|
+
" ",
|
|
145
|
+
B.saveCount,
|
|
146
|
+
" saves"
|
|
147
|
+
]
|
|
148
|
+
})]
|
|
155
149
|
})
|
|
156
150
|
]
|
|
157
|
-
}
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
|
|
151
|
+
})]
|
|
152
|
+
}),
|
|
153
|
+
/* @__PURE__ */ A("section", {
|
|
154
|
+
className: "mt-6",
|
|
155
|
+
children: [/* @__PURE__ */ A("h3", {
|
|
156
|
+
className: "mb-3 text-lg font-semibold text-text-primary",
|
|
157
|
+
children: [
|
|
158
|
+
"Shop the look (",
|
|
159
|
+
V.length,
|
|
160
|
+
")"
|
|
161
|
+
]
|
|
162
|
+
}), V.length === 0 ? /* @__PURE__ */ k("p", {
|
|
163
|
+
className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
164
|
+
children: "No items tagged in this look yet."
|
|
165
|
+
}) : /* @__PURE__ */ k("div", {
|
|
166
|
+
className: "divide-y divide-border-seam rounded-lg border border-border-seam bg-bg-surface",
|
|
167
|
+
children: [...V].sort((e, t) => e.position - t.position).map((e) => /* @__PURE__ */ A("button", {
|
|
168
|
+
type: "button",
|
|
169
|
+
onClick: () => e.styleItem && N(`/items/${e.styleItem.id}`),
|
|
170
|
+
className: "flex w-full items-center gap-4 px-4 py-3 text-left transition-colors hover:bg-bg-sunken/50",
|
|
171
|
+
children: [
|
|
172
|
+
/* @__PURE__ */ k(o, {
|
|
173
|
+
icon: /* @__PURE__ */ k(T, { className: "h-5 w-5" }),
|
|
174
|
+
seed: e.id,
|
|
175
|
+
className: "h-11 w-11 shrink-0"
|
|
176
|
+
}),
|
|
177
|
+
/* @__PURE__ */ A("div", {
|
|
178
|
+
className: "min-w-0 flex-1",
|
|
179
|
+
children: [/* @__PURE__ */ k("p", {
|
|
180
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
181
|
+
children: e.styleItem?.name ?? "Catalogue piece"
|
|
182
|
+
}), e.styling && /* @__PURE__ */ k("p", {
|
|
183
|
+
className: "truncate text-xs text-text-secondary",
|
|
184
|
+
children: e.styling
|
|
185
|
+
})]
|
|
186
|
+
}),
|
|
187
|
+
e.styleItem && /* @__PURE__ */ k("span", {
|
|
188
|
+
className: "shrink-0 text-sm font-semibold text-text-primary",
|
|
189
|
+
children: p(e.styleItem.price, e.styleItem.currency)
|
|
190
|
+
})
|
|
191
|
+
]
|
|
192
|
+
}, e.id))
|
|
193
|
+
})]
|
|
194
|
+
}),
|
|
195
|
+
/* @__PURE__ */ k(_, {
|
|
196
|
+
entityType: "CooLook",
|
|
197
|
+
entityId: B.id
|
|
198
|
+
})
|
|
199
|
+
]
|
|
200
|
+
}), /* @__PURE__ */ A("div", {
|
|
161
201
|
className: "space-y-4",
|
|
162
202
|
children: [
|
|
163
|
-
/* @__PURE__ */
|
|
203
|
+
/* @__PURE__ */ A(j, {
|
|
164
204
|
treatment: "plain",
|
|
165
205
|
className: "p-5",
|
|
166
|
-
children: [/* @__PURE__ */
|
|
206
|
+
children: [/* @__PURE__ */ k("h3", {
|
|
167
207
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
168
208
|
children: "Details"
|
|
169
|
-
}), /* @__PURE__ */
|
|
209
|
+
}), /* @__PURE__ */ A("dl", {
|
|
170
210
|
className: "space-y-2 text-sm",
|
|
171
211
|
children: [
|
|
172
|
-
/* @__PURE__ */
|
|
212
|
+
/* @__PURE__ */ A("div", {
|
|
173
213
|
className: "flex justify-between gap-2",
|
|
174
|
-
children: [/* @__PURE__ */
|
|
214
|
+
children: [/* @__PURE__ */ k("dt", {
|
|
175
215
|
className: "text-text-secondary",
|
|
176
216
|
children: "Occasion"
|
|
177
|
-
}), /* @__PURE__ */
|
|
217
|
+
}), /* @__PURE__ */ k("dd", {
|
|
178
218
|
className: "text-text-primary",
|
|
179
|
-
children:
|
|
219
|
+
children: m(B.occasion)
|
|
180
220
|
})]
|
|
181
221
|
}),
|
|
182
|
-
/* @__PURE__ */
|
|
222
|
+
/* @__PURE__ */ A("div", {
|
|
183
223
|
className: "flex justify-between gap-2",
|
|
184
|
-
children: [/* @__PURE__ */
|
|
224
|
+
children: [/* @__PURE__ */ k("dt", {
|
|
185
225
|
className: "text-text-secondary",
|
|
186
226
|
children: "Visibility"
|
|
187
|
-
}), /* @__PURE__ */
|
|
227
|
+
}), /* @__PURE__ */ k("dd", {
|
|
188
228
|
className: "text-text-primary",
|
|
189
|
-
children:
|
|
229
|
+
children: m(B.visibility)
|
|
190
230
|
})]
|
|
191
231
|
}),
|
|
192
|
-
/* @__PURE__ */
|
|
232
|
+
/* @__PURE__ */ A("div", {
|
|
193
233
|
className: "flex justify-between gap-2",
|
|
194
|
-
children: [/* @__PURE__ */
|
|
234
|
+
children: [/* @__PURE__ */ k("dt", {
|
|
195
235
|
className: "text-text-secondary",
|
|
196
236
|
children: "Published"
|
|
197
|
-
}), /* @__PURE__ */
|
|
237
|
+
}), /* @__PURE__ */ k("dd", {
|
|
198
238
|
className: "text-text-primary",
|
|
199
|
-
children:
|
|
239
|
+
children: B.publishedAt ? f(B.publishedAt, {
|
|
200
240
|
hour: void 0,
|
|
201
241
|
minute: void 0
|
|
202
242
|
}) : "—"
|
|
@@ -205,27 +245,27 @@ function E() {
|
|
|
205
245
|
]
|
|
206
246
|
})]
|
|
207
247
|
}),
|
|
208
|
-
|
|
248
|
+
B.collaborationId && /* @__PURE__ */ A("button", {
|
|
209
249
|
type: "button",
|
|
210
|
-
onClick: () =>
|
|
250
|
+
onClick: () => N(`/collaborations/${B.collaborationId}`),
|
|
211
251
|
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",
|
|
212
|
-
children: [/* @__PURE__ */
|
|
252
|
+
children: [/* @__PURE__ */ k("div", {
|
|
213
253
|
className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-status-warning-bg-subtle text-status-warning-text",
|
|
214
|
-
children: /* @__PURE__ */
|
|
215
|
-
}), /* @__PURE__ */
|
|
254
|
+
children: /* @__PURE__ */ k(T, { className: "h-5 w-5" })
|
|
255
|
+
}), /* @__PURE__ */ A("div", {
|
|
216
256
|
className: "min-w-0",
|
|
217
|
-
children: [/* @__PURE__ */
|
|
257
|
+
children: [/* @__PURE__ */ k("p", {
|
|
218
258
|
className: "truncate text-sm font-medium text-text-primary",
|
|
219
259
|
children: "Part of a collaboration"
|
|
220
|
-
}), /* @__PURE__ */
|
|
260
|
+
}), /* @__PURE__ */ k("p", {
|
|
221
261
|
className: "truncate text-xs text-text-secondary",
|
|
222
262
|
children: "View collaboration"
|
|
223
263
|
})]
|
|
224
264
|
})]
|
|
225
265
|
}),
|
|
226
|
-
(
|
|
266
|
+
(L.isError || R.isError || I.isError) && /* @__PURE__ */ k("p", {
|
|
227
267
|
className: "rounded-lg bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text",
|
|
228
|
-
children: (
|
|
268
|
+
children: (L.error ?? R.error ?? I.error) instanceof Error ? (L.error ?? R.error ?? I.error)?.message : "Action failed"
|
|
229
269
|
})
|
|
230
270
|
]
|
|
231
271
|
})]
|
|
@@ -233,6 +273,6 @@ function E() {
|
|
|
233
273
|
});
|
|
234
274
|
}
|
|
235
275
|
//#endregion
|
|
236
|
-
export {
|
|
276
|
+
export { M as LookDetailPage };
|
|
237
277
|
|
|
238
278
|
//# sourceMappingURL=LookDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LookDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/looks/LookDetailPage.tsx"],"sourcesContent":["/**\n * Look Detail Page\n * @module coolandlovely/pages/looks\n *\n * Single look (`cooLook`) with its look items, like (`cooLikeLook`), publish\n * (`cooPublishLook`) and delete (`cooDeleteLook`) actions.\n */\n\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Heart, Bookmark, Rocket, Trash2, Loader2, Sparkles, Star } 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 { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useLook, useLikeLook, usePublishLook, useDeleteLook } from '../../hooks';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\n\nexport function LookDetailPage() {\n const { lookId } = useParams<{ lookId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useLook(lookId);\n const like = useLikeLook();\n const publish = usePublishLook();\n const remove = useDeleteLook();\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Look\">\n <LoadingView label=\"Loading look…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Look\">\n <ErrorView title=\"Look not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const look = query.data;\n const items = look.items ?? [];\n const isPublished = look.publishedAt !== null;\n\n return (\n <PageLayout\n title={look.title}\n description={titleCase(look.occasion)}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks')}\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 {!isPublished && (\n <button\n type=\"button\"\n disabled={publish.isPending}\n onClick={() => publish.mutate(look.id)}\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 disabled:opacity-50\"\n >\n {publish.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Rocket className=\"h-4 w-4\" />\n )}\n Publish\n </button>\n )}\n <button\n type=\"button\"\n disabled={remove.isPending}\n onClick={() => remove.mutate(look.id, { onSuccess: () => navigateTo('/looks') })}\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 {remove.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=\"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={<Sparkles className=\"h-14 w-14\" />}\n seed={look.id}\n className=\"h-60 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\">{look.title}</h2>\n {look.isFeatured && (\n <Star className=\"h-4 w-4 fill-status-warning-text text-status-warning-text\" />\n )}\n <StatusBadge status={isPublished ? 'published' : 'draft'} className=\"ml-auto\" />\n </div>\n {look.caption && <p className=\"mt-3 text-sm text-text-secondary\">{look.caption}</p>}\n {look.tags.length > 0 && <TagList tags={look.tags} className=\"mt-4\" tone=\"accent\" />}\n\n <div className=\"mt-5 flex items-center gap-3\">\n <button\n type=\"button\"\n disabled={like.isPending}\n onClick={() => like.mutate(look.id)}\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-status-error-bg-subtle disabled:opacity-50\"\n >\n {like.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Heart className=\"h-4 w-4\" />\n )}\n Like · {look.likeCount}\n </button>\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-secondary\">\n <Bookmark className=\"h-4 w-4\" /> {look.saveCount} saves\n </span>\n </div>\n </div>\n </GlassCard>\n\n {/* Shop the look */}\n <section className=\"mt-6\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">\n Shop the look ({items.length})\n </h3>\n {items.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No items tagged in this look yet.\n </p>\n ) : (\n <div className=\"divide-y divide-border-seam rounded-lg border border-border-seam bg-bg-surface\">\n {[...items]\n .sort((a, b) => a.position - b.position)\n .map((li) => (\n <button\n key={li.id}\n type=\"button\"\n onClick={() => li.styleItem && navigateTo(`/items/${li.styleItem.id}`)}\n className=\"flex w-full items-center gap-4 px-4 py-3 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-5 w-5\" />}\n seed={li.id}\n className=\"h-11 w-11 shrink-0\"\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {li.styleItem?.name ?? 'Catalogue piece'}\n </p>\n {li.styling && (\n <p className=\"truncate text-xs text-text-secondary\">{li.styling}</p>\n )}\n </div>\n {li.styleItem && (\n <span className=\"shrink-0 text-sm font-semibold text-text-primary\">\n {formatPrice(li.styleItem.price, li.styleItem.currency)}\n </span>\n )}\n </button>\n ))}\n </div>\n )}\n </section>\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\">Occasion</dt>\n <dd className=\"text-text-primary\">{titleCase(look.occasion)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Visibility</dt>\n <dd className=\"text-text-primary\">{titleCase(look.visibility)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Published</dt>\n <dd className=\"text-text-primary\">\n {look.publishedAt\n ? formatDate(look.publishedAt, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {look.collaborationId && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collaborations/${look.collaborationId}`)}\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 <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-status-warning-bg-subtle text-status-warning-text\">\n <Sparkles className=\"h-5 w-5\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n Part of a collaboration\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View collaboration</p>\n </div>\n </button>\n )}\n\n {(publish.isError || remove.isError || like.isError) && (\n <p className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {(publish.error ?? remove.error ?? like.error) instanceof Error\n ? (publish.error ?? remove.error ?? like.error)?.message\n : 'Action failed'}\n </p>\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LookDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/looks/LookDetailPage.tsx"],"sourcesContent":["/**\n * Look Detail Page\n * @module coolandlovely/pages/looks\n *\n * Single look (`cooLook`) with its look items, like (`cooLikeLook`), publish\n * (`cooPublishLook`) and delete (`cooDeleteLook`) actions.\n */\n\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Heart, Bookmark, Rocket, Trash2, Loader2, Sparkles, Star } 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 { ActorName } from '../../components/ActorName';\nimport { Comments } from '../../components/Comments';\nimport { FollowButton } from '../../components/FollowButton';\nimport { AddToLookbookButton } from '../../components/AddToLookbookButton';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useLook, useLikeLook, usePublishLook, useDeleteLook, useUpdateLook } from '../../hooks';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\n\nexport function LookDetailPage() {\n const { lookId } = useParams<{ lookId: string }>();\n const { navigateTo, currentUser } = useCoolAndLovely();\n const query = useLook(lookId);\n const like = useLikeLook();\n const publish = usePublishLook();\n const remove = useDeleteLook();\n const update = useUpdateLook();\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Look\">\n <LoadingView label=\"Loading look…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Look\">\n <ErrorView title=\"Look not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const look = query.data;\n const items = look.items ?? [];\n const isPublished = look.publishedAt !== null;\n const isOwnLook = Boolean(currentUser?.id && currentUser.id === look.authorId);\n\n return (\n <PageLayout\n title={look.title}\n description={titleCase(look.occasion)}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks')}\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 lookId={look.id} />\n <button\n type=\"button\"\n disabled={update.isPending}\n onClick={() => update.mutate({ id: look.id, input: { isFeatured: !look.isFeatured } })}\n aria-pressed={look.isFeatured}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg border px-3 py-2 text-sm font-medium transition-colors disabled:opacity-50',\n look.isFeatured\n ? 'border-status-warning-text/40 bg-status-warning-bg-subtle text-status-warning-text'\n : 'border-border-seam text-text-primary hover:bg-bg-sunken'\n )}\n >\n {update.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Star className={cn('h-4 w-4', look.isFeatured && 'fill-status-warning-text')} />\n )}\n {look.isFeatured ? 'Featured' : 'Feature'}\n </button>\n {!isPublished && (\n <button\n type=\"button\"\n disabled={publish.isPending}\n onClick={() => publish.mutate(look.id)}\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 disabled:opacity-50\"\n >\n {publish.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Rocket className=\"h-4 w-4\" />\n )}\n Publish\n </button>\n )}\n <button\n type=\"button\"\n disabled={remove.isPending}\n onClick={() => remove.mutate(look.id, { onSuccess: () => navigateTo('/looks') })}\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 {remove.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=\"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={<Sparkles className=\"h-14 w-14\" />}\n seed={look.id}\n fileId={look.image?.id}\n alt={look.title}\n className=\"h-60 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\">{look.title}</h2>\n {look.isFeatured && (\n <Star className=\"h-4 w-4 fill-status-warning-text text-status-warning-text\" />\n )}\n <StatusBadge status={isPublished ? 'published' : 'draft'} className=\"ml-auto\" />\n </div>\n {look.caption && <p className=\"mt-3 text-sm text-text-secondary\">{look.caption}</p>}\n {look.tags.length > 0 && <TagList tags={look.tags} className=\"mt-4\" tone=\"accent\" />}\n\n <div className=\"mt-4 flex flex-wrap items-center gap-2 text-sm text-text-secondary\">\n <span>\n By{' '}\n <ActorName id={look.authorId} className=\"font-medium text-text-primary\" />\n </span>\n {!isOwnLook && <FollowButton followeeId={look.authorId} size=\"sm\" />}\n </div>\n\n <div className=\"mt-5 flex items-center gap-3\">\n <button\n type=\"button\"\n disabled={like.isPending}\n onClick={() => like.mutate(look.id)}\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-status-error-bg-subtle disabled:opacity-50\"\n >\n {like.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Heart className=\"h-4 w-4\" />\n )}\n Like · {look.likeCount}\n </button>\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-secondary\">\n <Bookmark className=\"h-4 w-4\" /> {look.saveCount} saves\n </span>\n </div>\n </div>\n </GlassCard>\n\n {/* Shop the look */}\n <section className=\"mt-6\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">\n Shop the look ({items.length})\n </h3>\n {items.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No items tagged in this look yet.\n </p>\n ) : (\n <div className=\"divide-y divide-border-seam rounded-lg border border-border-seam bg-bg-surface\">\n {[...items]\n .sort((a, b) => a.position - b.position)\n .map((li) => (\n <button\n key={li.id}\n type=\"button\"\n onClick={() => li.styleItem && navigateTo(`/items/${li.styleItem.id}`)}\n className=\"flex w-full items-center gap-4 px-4 py-3 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Sparkles className=\"h-5 w-5\" />}\n seed={li.id}\n className=\"h-11 w-11 shrink-0\"\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {li.styleItem?.name ?? 'Catalogue piece'}\n </p>\n {li.styling && (\n <p className=\"truncate text-xs text-text-secondary\">{li.styling}</p>\n )}\n </div>\n {li.styleItem && (\n <span className=\"shrink-0 text-sm font-semibold text-text-primary\">\n {formatPrice(li.styleItem.price, li.styleItem.currency)}\n </span>\n )}\n </button>\n ))}\n </div>\n )}\n </section>\n\n <Comments entityType=\"CooLook\" entityId={look.id} />\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\">Occasion</dt>\n <dd className=\"text-text-primary\">{titleCase(look.occasion)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Visibility</dt>\n <dd className=\"text-text-primary\">{titleCase(look.visibility)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Published</dt>\n <dd className=\"text-text-primary\">\n {look.publishedAt\n ? formatDate(look.publishedAt, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {look.collaborationId && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collaborations/${look.collaborationId}`)}\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 <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-status-warning-bg-subtle text-status-warning-text\">\n <Sparkles className=\"h-5 w-5\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n Part of a collaboration\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View collaboration</p>\n </div>\n </button>\n )}\n\n {(publish.isError || remove.isError || like.isError) && (\n <p className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {(publish.error ?? remove.error ?? like.error) instanceof Error\n ? (publish.error ?? remove.error ?? like.error)?.message\n : 'Action failed'}\n </p>\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|