@burdenoff/microfe-coolandlovely 2026.1101.8 → 2026.1102.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.
Files changed (108) hide show
  1. package/README.md +15 -0
  2. package/dist/coolandlovely/CoolAndLovelyRoot.d.ts.map +1 -1
  3. package/dist/coolandlovely/CoolAndLovelyRoot.js +8 -0
  4. package/dist/coolandlovely/CoolAndLovelyRoot.js.map +1 -1
  5. package/dist/coolandlovely/CoolAndLovelyRoutes.d.ts.map +1 -1
  6. package/dist/coolandlovely/CoolAndLovelyRoutes.js +20 -16
  7. package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
  8. package/dist/coolandlovely/components/WardrobeItemCard.d.ts +2 -1
  9. package/dist/coolandlovely/components/WardrobeItemCard.d.ts.map +1 -1
  10. package/dist/coolandlovely/components/WardrobeItemCard.js +4 -3
  11. package/dist/coolandlovely/components/WardrobeItemCard.js.map +1 -1
  12. package/dist/coolandlovely/components/prices/BestPriceBadge.d.ts +7 -0
  13. package/dist/coolandlovely/components/prices/BestPriceBadge.d.ts.map +1 -0
  14. package/dist/coolandlovely/components/prices/BestPriceBadge.js +22 -0
  15. package/dist/coolandlovely/components/prices/BestPriceBadge.js.map +1 -0
  16. package/dist/coolandlovely/components/prices/LookbookPriceBoard.d.ts +10 -0
  17. package/dist/coolandlovely/components/prices/LookbookPriceBoard.d.ts.map +1 -0
  18. package/dist/coolandlovely/components/prices/LookbookPriceBoard.js +120 -0
  19. package/dist/coolandlovely/components/prices/LookbookPriceBoard.js.map +1 -0
  20. package/dist/coolandlovely/components/prices/PriceComparison.d.ts +5 -0
  21. package/dist/coolandlovely/components/prices/PriceComparison.d.ts.map +1 -0
  22. package/dist/coolandlovely/components/prices/PriceComparison.js +95 -0
  23. package/dist/coolandlovely/components/prices/PriceComparison.js.map +1 -0
  24. package/dist/coolandlovely/components/prices/PriceCurrencySelect.d.ts +6 -0
  25. package/dist/coolandlovely/components/prices/PriceCurrencySelect.d.ts.map +1 -0
  26. package/dist/coolandlovely/components/prices/PriceCurrencySelect.js +38 -0
  27. package/dist/coolandlovely/components/prices/PriceCurrencySelect.js.map +1 -0
  28. package/dist/coolandlovely/components/prices/PricePanel.d.ts +6 -0
  29. package/dist/coolandlovely/components/prices/PricePanel.d.ts.map +1 -0
  30. package/dist/coolandlovely/components/prices/PricePanel.js +105 -0
  31. package/dist/coolandlovely/components/prices/PricePanel.js.map +1 -0
  32. package/dist/coolandlovely/components/prices/PriceWatchDisclosure.d.ts +2 -0
  33. package/dist/coolandlovely/components/prices/PriceWatchDisclosure.d.ts.map +1 -0
  34. package/dist/coolandlovely/components/prices/PriceWatchDisclosure.js +28 -0
  35. package/dist/coolandlovely/components/prices/PriceWatchDisclosure.js.map +1 -0
  36. package/dist/coolandlovely/components/prices/PriceWatchForm.d.ts +5 -0
  37. package/dist/coolandlovely/components/prices/PriceWatchForm.d.ts.map +1 -0
  38. package/dist/coolandlovely/components/prices/PriceWatchForm.js +89 -0
  39. package/dist/coolandlovely/components/prices/PriceWatchForm.js.map +1 -0
  40. package/dist/coolandlovely/components/prices/PriceWatches.d.ts +3 -0
  41. package/dist/coolandlovely/components/prices/PriceWatches.d.ts.map +1 -0
  42. package/dist/coolandlovely/components/prices/PriceWatches.js +189 -0
  43. package/dist/coolandlovely/components/prices/PriceWatches.js.map +1 -0
  44. package/dist/coolandlovely/components/prices/RetailerOfferLink.d.ts +6 -0
  45. package/dist/coolandlovely/components/prices/RetailerOfferLink.d.ts.map +1 -0
  46. package/dist/coolandlovely/components/prices/RetailerOfferLink.js +28 -0
  47. package/dist/coolandlovely/components/prices/RetailerOfferLink.js.map +1 -0
  48. package/dist/coolandlovely/components/prices/money.d.ts +6 -0
  49. package/dist/coolandlovely/components/prices/money.d.ts.map +1 -0
  50. package/dist/coolandlovely/components/prices/money.js +42 -0
  51. package/dist/coolandlovely/components/prices/money.js.map +1 -0
  52. package/dist/coolandlovely/hooks/useContextNavigation.d.ts +3 -0
  53. package/dist/coolandlovely/hooks/useContextNavigation.d.ts.map +1 -0
  54. package/dist/coolandlovely/hooks/useContextNavigation.js +31 -0
  55. package/dist/coolandlovely/hooks/useContextNavigation.js.map +1 -0
  56. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.d.ts.map +1 -1
  57. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +1 -1
  58. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
  59. package/dist/coolandlovely/hooks/useCreatorMarketplace.d.ts +118 -0
  60. package/dist/coolandlovely/hooks/useCreatorMarketplace.d.ts.map +1 -0
  61. package/dist/coolandlovely/hooks/useCreatorMarketplace.js +120 -0
  62. package/dist/coolandlovely/hooks/useCreatorMarketplace.js.map +1 -0
  63. package/dist/coolandlovely/hooks/usePriceApi.d.ts +57 -0
  64. package/dist/coolandlovely/hooks/usePriceApi.d.ts.map +1 -0
  65. package/dist/coolandlovely/hooks/usePriceApi.js +111 -0
  66. package/dist/coolandlovely/hooks/usePriceApi.js.map +1 -0
  67. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.d.ts.map +1 -1
  68. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +139 -121
  69. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js.map +1 -1
  70. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.d.ts.map +1 -1
  71. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +140 -137
  72. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js.map +1 -1
  73. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.d.ts.map +1 -1
  74. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js +104 -95
  75. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js.map +1 -1
  76. package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.d.ts.map +1 -1
  77. package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.js +49 -40
  78. package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.js.map +1 -1
  79. package/dist/coolandlovely/pages/items/StoreListedPieceView.d.ts.map +1 -1
  80. package/dist/coolandlovely/pages/items/StoreListedPieceView.js +130 -123
  81. package/dist/coolandlovely/pages/items/StoreListedPieceView.js.map +1 -1
  82. package/dist/coolandlovely/pages/items/StyleItemDetailPage.d.ts.map +1 -1
  83. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +241 -230
  84. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
  85. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.d.ts.map +1 -1
  86. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +64 -119
  87. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
  88. package/dist/coolandlovely/pages/marketplace/CreatorMarketplacePage.d.ts +2 -0
  89. package/dist/coolandlovely/pages/marketplace/CreatorMarketplacePage.d.ts.map +1 -0
  90. package/dist/coolandlovely/pages/marketplace/CreatorMarketplacePage.js +714 -0
  91. package/dist/coolandlovely/pages/marketplace/CreatorMarketplacePage.js.map +1 -0
  92. package/dist/coolandlovely/pages/profile/StyleProfilePage.d.ts.map +1 -1
  93. package/dist/coolandlovely/pages/profile/StyleProfilePage.js +214 -209
  94. package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
  95. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.d.ts.map +1 -1
  96. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +83 -49
  97. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
  98. package/dist/coolandlovely/types/index.d.ts +5 -0
  99. package/dist/coolandlovely/types/index.d.ts.map +1 -1
  100. package/dist/generated/wspace-operations.d.ts +931 -2
  101. package/dist/generated/wspace-operations.d.ts.map +1 -1
  102. package/dist/generated/wspace-operations.js +221 -1
  103. package/dist/generated/wspace-operations.js.map +1 -1
  104. package/dist/generated/wspace-types.d.ts +539 -1
  105. package/dist/generated/wspace-types.d.ts.map +1 -1
  106. package/dist/generated/wspace-types.js +14 -0
  107. package/dist/generated/wspace-types.js.map +1 -0
  108. package/package.json +4 -3
@@ -3,79 +3,74 @@ import { PageLayout as t } from "../../components/PageLayout.js";
3
3
  import { useAddLookbookEntry as n, useDeleteLookbook as r, useLookbook as i, useLooks as a, useRemoveLookbookEntry as o, useStyleItems as s } from "../../hooks/useCoolAndLovelyApi.js";
4
4
  import { useAssistantEntityName as c } from "../../hooks/useAssistantEntity.js";
5
5
  import "../../hooks/index.js";
6
- import { ErrorView as ee, LoadingView as l } from "../../components/StateViews.js";
7
- import { Thumbnail as u } from "../../components/Thumbnail.js";
6
+ import { ErrorView as l, LoadingView as u } from "../../components/StateViews.js";
8
7
  import { formatRelativeTime as d } from "../../utils/formatters.js";
9
8
  import { SelectField as f, TextField as p } from "../../components/Field.js";
10
9
  import { TagList as m } from "../../components/TagList.js";
11
10
  import { VisibilityChip as h } from "../../components/VisibilityChip.js";
12
- import { useMemo as g, useState as _ } from "react";
13
- import { ArrowLeft as te, 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";
11
+ import { LookbookPriceBoard as g } from "../../components/prices/LookbookPriceBoard.js";
12
+ import { useMemo as _, useState as v } from "react";
13
+ import { ArrowLeft as y, BookHeart as b, Clock as x, Loader2 as S, Plus as C, Trash2 as w, X as T } from "lucide-react";
14
14
  import { useParams as E } from "react-router";
15
15
  import { jsx as D, jsxs as O } from "react/jsx-runtime";
16
16
  import { GlassCard as k } from "@burdenoff/fe-libs/ui";
17
17
  //#region src/coolandlovely/pages/lookbooks/LookbookDetailPage.tsx
18
- var A = [
19
- "aspect-[3/4]",
20
- "aspect-square",
21
- "aspect-[4/5]"
22
- ];
23
- function j() {
24
- let { lookbookId: j } = E(), { navigateTo: M } = e(), N = i(j), P = o(), F = n(), I = r();
25
- c(j, N.data?.name);
26
- let [L, R] = _(!1), [z, B] = _("look"), [V, H] = _(""), [U, W] = _(""), G = a({ pagination: {
18
+ function A() {
19
+ let { lookbookId: A } = E(), { navigateTo: j } = e(), M = i(A), N = o(), P = n(), F = r();
20
+ c(A, M.data?.name);
21
+ let [I, L] = v(!1), [R, z] = v("look"), [B, V] = v(""), [H, U] = v(""), W = a({ pagination: {
27
22
  limit: 100,
28
23
  offset: 0
29
- } }), K = s({ pagination: {
24
+ } }), G = s({ pagination: {
30
25
  limit: 100,
31
26
  offset: 0
32
- } }), q = g(() => new Map((G.data?.items ?? []).map((e) => [e.id, e])), [G.data]), J = g(() => new Map((K.data?.items ?? []).map((e) => [e.id, e])), [K.data]), Y = g(() => (K.data?.items ?? []).filter((e) => e.status !== "RETIRED"), [K.data]), X = g(() => (G.data?.items ?? []).map((e) => ({
27
+ } }), K = _(() => (G.data?.items ?? []).filter((e) => e.status !== "RETIRED"), [G.data]), q = _(() => (W.data?.items ?? []).map((e) => ({
33
28
  value: e.id,
34
29
  label: e.title
35
- })), [G.data]), Z = g(() => Y.map((e) => ({
30
+ })), [W.data]), J = _(() => K.map((e) => ({
36
31
  value: e.id,
37
32
  label: `${e.name}${e.brand?.name ? ` · ${e.brand.name}` : ""}`
38
- })), [Y]);
39
- if (N.isLoading) return /* @__PURE__ */ D(t, {
33
+ })), [K]), Y = _(() => [...M.data?.entries ?? []].sort((e, t) => e.position - t.position), [M.data?.entries]);
34
+ if (M.isLoading) return /* @__PURE__ */ D(t, {
40
35
  title: "Lookbook",
41
- children: /* @__PURE__ */ D(l, { label: "Loading lookbook…" })
36
+ children: /* @__PURE__ */ D(u, { label: "Loading lookbook…" })
42
37
  });
43
- if (N.isError || !N.data) return /* @__PURE__ */ D(t, {
38
+ if (M.isError || !M.data) return /* @__PURE__ */ D(t, {
44
39
  title: "Lookbook",
45
- children: /* @__PURE__ */ D(ee, {
40
+ children: /* @__PURE__ */ D(l, {
46
41
  title: "Lookbook not found",
47
- onRetry: () => void N.refetch()
42
+ onRetry: () => void M.refetch()
48
43
  })
49
44
  });
50
- let Q = N.data, $ = [...Q.entries ?? []].sort((e, t) => e.position - t.position);
45
+ let X = M.data;
51
46
  return /* @__PURE__ */ D(t, {
52
- title: Q.name,
53
- description: Q.description ?? void 0,
47
+ title: X.name,
48
+ description: X.description ?? void 0,
54
49
  actions: /* @__PURE__ */ O("div", {
55
50
  className: "flex flex-wrap items-center gap-2",
56
51
  children: [
57
52
  /* @__PURE__ */ O("button", {
58
53
  type: "button",
59
- onClick: () => M("/lookbooks"),
54
+ onClick: () => j("/lookbooks"),
60
55
  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",
61
- children: [/* @__PURE__ */ D(te, { className: "h-4 w-4" }), " Back"]
56
+ children: [/* @__PURE__ */ D(y, { className: "h-4 w-4" }), " Back"]
62
57
  }),
63
58
  /* @__PURE__ */ O("button", {
64
59
  type: "button",
65
60
  onClick: () => {
66
- R((e) => !e), H("");
61
+ L((e) => !e), V("");
67
62
  },
68
63
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
69
- children: [D(L ? T : x, { className: "h-4 w-4" }), L ? "Close" : "Add entry"]
64
+ children: [D(I ? T : C, { className: "h-4 w-4" }), I ? "Close" : "Add entry"]
70
65
  }),
71
66
  /* @__PURE__ */ O("button", {
72
67
  type: "button",
73
- disabled: I.isPending,
68
+ disabled: F.isPending,
74
69
  onClick: () => {
75
- j && I.mutate(j, { onSuccess: () => M("/lookbooks") });
70
+ A && F.mutate(A, { onSuccess: () => j("/lookbooks") });
76
71
  },
77
72
  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",
78
- children: [I.isPending ? /* @__PURE__ */ D(b, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ D(w, { className: "h-4 w-4" }), "Delete"]
73
+ children: [F.isPending ? /* @__PURE__ */ D(S, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ D(w, { className: "h-4 w-4" }), "Delete"]
79
74
  })
80
75
  ]
81
76
  }),
@@ -89,50 +84,50 @@ function j() {
89
84
  className: "flex items-center gap-3",
90
85
  children: [/* @__PURE__ */ D("div", {
91
86
  className: "flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-accent-purple-subtle text-text-primary",
92
- children: /* @__PURE__ */ D(v, { className: "h-6 w-6" })
87
+ children: /* @__PURE__ */ D(b, { className: "h-6 w-6" })
93
88
  }), /* @__PURE__ */ O("div", {
94
89
  className: "min-w-0 flex-1",
95
90
  children: [/* @__PURE__ */ D("h2", {
96
91
  className: "truncate text-xl font-semibold text-text-primary",
97
- children: Q.name
92
+ children: X.name
98
93
  }), /* @__PURE__ */ O("div", {
99
94
  className: "mt-1.5 flex flex-wrap items-center gap-2",
100
95
  children: [
101
- /* @__PURE__ */ D(h, { visibility: Q.visibility }),
96
+ /* @__PURE__ */ D(h, { visibility: X.visibility }),
102
97
  /* @__PURE__ */ O("span", {
103
98
  className: "inline-flex items-center gap-1 text-xs text-text-secondary",
104
99
  children: [
105
- /* @__PURE__ */ D(y, { className: "h-3.5 w-3.5" }),
100
+ /* @__PURE__ */ D(x, { className: "h-3.5 w-3.5" }),
106
101
  " Updated ",
107
- d(Q.updatedAt)
102
+ d(X.updatedAt)
108
103
  ]
109
104
  }),
110
105
  /* @__PURE__ */ O("span", {
111
106
  className: "text-xs text-text-secondary tabular-nums",
112
107
  children: [
113
108
  "· ",
114
- $.length,
109
+ Y.length,
115
110
  " ",
116
- $.length === 1 ? "item" : "items"
111
+ Y.length === 1 ? "item" : "items"
117
112
  ]
118
113
  })
119
114
  ]
120
115
  })]
121
116
  })]
122
- }), Q.tags.length > 0 && /* @__PURE__ */ D(m, {
123
- tags: Q.tags,
117
+ }), X.tags.length > 0 && /* @__PURE__ */ D(m, {
118
+ tags: X.tags,
124
119
  className: "mt-4"
125
120
  })]
126
121
  }),
127
- L && /* @__PURE__ */ D("form", {
122
+ I && /* @__PURE__ */ D("form", {
128
123
  onSubmit: (e) => {
129
- e.preventDefault(), !(!j || !V) && F.mutate({
130
- lookbookId: j,
131
- lookId: z === "look" ? V : void 0,
132
- styleItemId: z === "item" ? V : void 0,
133
- note: U.trim() || void 0
124
+ e.preventDefault(), !(!A || !B) && P.mutate({
125
+ lookbookId: A,
126
+ lookId: R === "look" ? B : void 0,
127
+ styleItemId: R === "item" ? B : void 0,
128
+ note: H.trim() || void 0
134
129
  }, { onSuccess: () => {
135
- H(""), W(""), R(!1);
130
+ V(""), U(""), L(!1);
136
131
  } });
137
132
  },
138
133
  className: "mt-6",
@@ -142,111 +137,61 @@ function j() {
142
137
  children: [
143
138
  /* @__PURE__ */ O("h3", {
144
139
  className: "mb-4 flex items-center gap-2 text-base font-semibold text-text-primary",
145
- children: [/* @__PURE__ */ D(x, { className: "h-5 w-5" }), " Add to this lookbook"]
140
+ children: [/* @__PURE__ */ D(C, { className: "h-5 w-5" }), " Add to this lookbook"]
146
141
  }),
147
142
  /* @__PURE__ */ D("div", {
148
143
  className: "mb-4 flex flex-wrap gap-2",
149
144
  children: ["look", "item"].map((e) => /* @__PURE__ */ D("button", {
150
145
  type: "button",
151
146
  onClick: () => {
152
- B(e), H("");
147
+ z(e), V("");
153
148
  },
154
- 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",
149
+ className: R === 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",
155
150
  children: e === "look" ? "Save a look" : "Clip a piece"
156
151
  }, e))
157
152
  }),
158
153
  /* @__PURE__ */ D(f, {
159
- label: z === "look" ? "Look" : "Style item",
160
- value: V,
161
- onChange: H,
162
- options: z === "look" ? X : Z,
163
- placeholder: z === "look" ? G.isLoading ? "Loading looks…" : "Select a look" : K.isLoading ? "Loading items…" : "Select a style item"
154
+ label: R === "look" ? "Look" : "Style item",
155
+ value: B,
156
+ onChange: V,
157
+ options: R === "look" ? q : J,
158
+ placeholder: R === "look" ? W.isLoading ? "Loading looks…" : "Select a look" : G.isLoading ? "Loading items…" : "Select a style item"
164
159
  }),
165
160
  /* @__PURE__ */ D(p, {
166
161
  label: "Note (optional)",
167
- value: U,
168
- onChange: W,
162
+ value: H,
163
+ onChange: U,
169
164
  placeholder: "Why you saved it…",
170
165
  className: "mt-4"
171
166
  }),
172
- F.isError && /* @__PURE__ */ D("p", {
167
+ P.isError && /* @__PURE__ */ D("p", {
173
168
  className: "mt-3 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
174
- children: F.error instanceof Error ? F.error.message : "Could not add entry"
169
+ children: P.error instanceof Error ? P.error.message : "Could not add entry"
175
170
  }),
176
171
  /* @__PURE__ */ D("div", {
177
172
  className: "mt-4 flex justify-end",
178
173
  children: /* @__PURE__ */ O("button", {
179
174
  type: "submit",
180
- disabled: !V || F.isPending,
175
+ disabled: !B || P.isPending,
181
176
  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",
182
- children: [F.isPending ? /* @__PURE__ */ D(b, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ D(x, { className: "h-4 w-4" }), "Add entry"]
177
+ children: [P.isPending ? /* @__PURE__ */ D(S, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ D(C, { className: "h-4 w-4" }), "Add entry"]
183
178
  })
184
179
  })
185
180
  ]
186
181
  })
187
182
  }),
188
- /* @__PURE__ */ O("section", {
189
- className: "mt-6",
190
- children: [/* @__PURE__ */ O("h3", {
191
- className: "mb-3 text-lg font-semibold text-text-primary",
192
- children: [
193
- "Board (",
194
- $.length,
195
- ")"
196
- ]
197
- }), $.length === 0 ? /* @__PURE__ */ D("p", {
198
- className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
199
- children: "This lookbook has no entries yet. Clip a catalogue piece or save a look to add one."
200
- }) : /* @__PURE__ */ D("div", {
201
- className: "columns-2 gap-4 md:columns-3",
202
- children: $.map((e, t) => {
203
- let n = !!e.lookId, r = e.lookId ? q.get(e.lookId) : void 0, i = e.styleItemId ? J.get(e.styleItemId) : void 0, a = n ? r?.title ?? "Saved look" : i?.name ?? "Clipped piece", o = n ? r?.image?.id : i?.image?.id, s = P.isPending && P.variables === e.id;
204
- return /* @__PURE__ */ O("div", {
205
- 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",
206
- children: [/* @__PURE__ */ D("button", {
207
- type: "button",
208
- onClick: () => {
209
- n && e.lookId ? M(`/looks/${e.lookId}`) : e.styleItemId && M(`/items/${e.styleItemId}`);
210
- },
211
- "aria-label": `Open ${a}`,
212
- 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)]",
213
- children: /* @__PURE__ */ D(u, {
214
- icon: D(n ? S : C, { className: "h-8 w-8" }),
215
- seed: e.id,
216
- fileId: o,
217
- alt: a,
218
- className: `w-full rounded-none ${A[t % A.length]}`,
219
- overlay: /* @__PURE__ */ O("div", {
220
- 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",
221
- children: [e.note && /* @__PURE__ */ D("span", {
222
- 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",
223
- children: /* @__PURE__ */ D("span", {
224
- className: "truncate",
225
- children: e.note
226
- })
227
- }), /* @__PURE__ */ D("p", {
228
- className: "truncate text-sm font-semibold text-text-primary",
229
- children: a
230
- })]
231
- })
232
- })
233
- }), /* @__PURE__ */ D("button", {
234
- type: "button",
235
- disabled: P.isPending,
236
- onClick: () => P.mutate(e.id),
237
- "aria-label": `Remove ${a}`,
238
- 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",
239
- children: s ? /* @__PURE__ */ D(b, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ D(T, { className: "h-3.5 w-3.5" })
240
- })]
241
- }, e.id);
242
- })
243
- })]
183
+ /* @__PURE__ */ D(g, {
184
+ entries: Y,
185
+ looks: W.data?.items ?? [],
186
+ items: G.data?.items ?? [],
187
+ removingEntryId: N.isPending ? N.variables : void 0,
188
+ onRemove: (e) => N.mutate(e)
244
189
  })
245
190
  ]
246
191
  })
247
192
  });
248
193
  }
249
194
  //#endregion
250
- export { j as LookbookDetailPage };
195
+ export { A as LookbookDetailPage };
251
196
 
252
197
  //# 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';\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 useAssistantEntityName,\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 // Name the board for the assistant's screen context.\n useAssistantEntityName(lookbookId, query.data?.name);\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
+ {"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 { LookbookPriceBoard } from '../../components/prices/LookbookPriceBoard';\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router';\nimport { ArrowLeft, BookHeart, 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 { 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 useAssistantEntityName,\n} from '../../hooks';\nimport { formatRelativeTime } from '../../utils/formatters';\n\ntype EntryKind = 'look' | 'item';\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 // Name the board for the assistant's screen context.\n useAssistantEntityName(lookbookId, query.data?.name);\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 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 const entries = useMemo(\n () => [...(query.data?.entries ?? [])].sort((a, b) => a.position - b.position),\n [query.data?.entries]\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\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 <LookbookPriceBoard\n entries={entries}\n looks={looks.data?.items ?? []}\n items={items.data?.items ?? []}\n removingEntryId={removeEntry.isPending ? removeEntry.variables : undefined}\n onRemove={(id) => removeEntry.mutate(id)}\n />\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function CreatorMarketplacePage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=CreatorMarketplacePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreatorMarketplacePage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/marketplace/CreatorMarketplacePage.tsx"],"names":[],"mappings":"AAyhCA,wBAAgB,sBAAsB,gCAOrC"}