@burdenoff/microfe-coolandlovely 2026.827.1 → 2026.1024.1

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 (71) hide show
  1. package/dist/coolandlovely/components/ActivityTrail.js +7 -7
  2. package/dist/coolandlovely/components/Comments.js +4 -4
  3. package/dist/coolandlovely/components/FeedbackWidget.d.ts.map +1 -1
  4. package/dist/coolandlovely/components/FeedbackWidget.js +72 -70
  5. package/dist/coolandlovely/components/FeedbackWidget.js.map +1 -1
  6. package/dist/coolandlovely/components/LookCard.js +24 -24
  7. package/dist/coolandlovely/components/StateViews.d.ts.map +1 -1
  8. package/dist/coolandlovely/components/StateViews.js +35 -26
  9. package/dist/coolandlovely/components/StateViews.js.map +1 -1
  10. package/dist/coolandlovely/components/StatusBadge.d.ts.map +1 -1
  11. package/dist/coolandlovely/components/StatusBadge.js +45 -15
  12. package/dist/coolandlovely/components/StatusBadge.js.map +1 -1
  13. package/dist/coolandlovely/components/VisibilityChip.d.ts.map +1 -1
  14. package/dist/coolandlovely/components/VisibilityChip.js +22 -17
  15. package/dist/coolandlovely/components/VisibilityChip.js.map +1 -1
  16. package/dist/coolandlovely/hooks/index.d.ts +1 -0
  17. package/dist/coolandlovely/hooks/index.d.ts.map +1 -1
  18. package/dist/coolandlovely/hooks/index.js +2 -1
  19. package/dist/coolandlovely/hooks/useTr.d.ts +2 -0
  20. package/dist/coolandlovely/hooks/useTr.d.ts.map +1 -0
  21. package/dist/coolandlovely/hooks/useTr.js +14 -0
  22. package/dist/coolandlovely/hooks/useTr.js.map +1 -0
  23. package/dist/coolandlovely/pages/HomePage.d.ts.map +1 -1
  24. package/dist/coolandlovely/pages/HomePage.js +172 -132
  25. package/dist/coolandlovely/pages/HomePage.js.map +1 -1
  26. package/dist/coolandlovely/pages/admin/AdminBrandsPage.js +10 -10
  27. package/dist/coolandlovely/pages/admin/AdminCollaborationsPage.js +16 -16
  28. package/dist/coolandlovely/pages/admin/AdminFeaturedItemsPage.js +17 -17
  29. package/dist/coolandlovely/pages/brands/BrandDetailPage.js +22 -22
  30. package/dist/coolandlovely/pages/brands/BrandFormPage.js +9 -9
  31. package/dist/coolandlovely/pages/brands/BrandsListPage.d.ts.map +1 -1
  32. package/dist/coolandlovely/pages/brands/BrandsListPage.js +80 -76
  33. package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
  34. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +21 -21
  35. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +7 -7
  36. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.d.ts.map +1 -1
  37. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js +82 -81
  38. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js.map +1 -1
  39. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +19 -19
  40. package/dist/coolandlovely/pages/collections/CollectionFormPage.js +9 -9
  41. package/dist/coolandlovely/pages/collections/CollectionsListPage.d.ts.map +1 -1
  42. package/dist/coolandlovely/pages/collections/CollectionsListPage.js +54 -55
  43. package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
  44. package/dist/coolandlovely/pages/discover/DiscoverPage.d.ts.map +1 -1
  45. package/dist/coolandlovely/pages/discover/DiscoverPage.js +322 -315
  46. package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -1
  47. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +21 -21
  48. package/dist/coolandlovely/pages/items/StyleItemFormPage.js +10 -10
  49. package/dist/coolandlovely/pages/items/StyleItemsListPage.d.ts.map +1 -1
  50. package/dist/coolandlovely/pages/items/StyleItemsListPage.js +105 -95
  51. package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
  52. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +20 -20
  53. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
  54. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.d.ts.map +1 -1
  55. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +88 -79
  56. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
  57. package/dist/coolandlovely/pages/looks/LookDetailPage.js +18 -18
  58. package/dist/coolandlovely/pages/looks/LookFormPage.js +6 -6
  59. package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
  60. package/dist/coolandlovely/pages/looks/LooksListPage.d.ts.map +1 -1
  61. package/dist/coolandlovely/pages/looks/LooksListPage.js +94 -94
  62. package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
  63. package/dist/coolandlovely/pages/profile/StyleProfilePage.d.ts.map +1 -1
  64. package/dist/coolandlovely/pages/profile/StyleProfilePage.js +226 -199
  65. package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
  66. package/dist/coolandlovely/pages/trends/TrendsPage.js +8 -8
  67. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +5 -5
  68. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.d.ts.map +1 -1
  69. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +71 -69
  70. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
  71. package/package.json +1 -1
@@ -1,109 +1,97 @@
1
1
  import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
2
2
  import { cn as t } from "../../utils/cn.js";
3
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 { useLooks as o } from "../../hooks/useCoolAndLovelyApi.js";
7
- import { LookCard as s } from "../../components/LookCard.js";
4
+ import { useLooks as r } from "../../hooks/useCoolAndLovelyApi.js";
5
+ import { useTr as i } from "../../hooks/useTr.js";
8
6
  import "../../hooks/index.js";
9
- import { EmptyState as c } from "../../components/EmptyState.js";
10
- import { useState as l } from "react";
11
- import { ChevronLeft as u, ChevronRight as d, Plus as f, Sparkles as p, Star as m } from "lucide-react";
12
- import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
7
+ import { StatusBadge as a } from "../../components/StatusBadge.js";
8
+ import { ErrorView as o, LoadingView as s } from "../../components/StateViews.js";
9
+ import { titleCase as c } from "../../utils/formatters.js";
10
+ import { LookCard as l } from "../../components/LookCard.js";
11
+ import { EmptyState as u } from "../../components/EmptyState.js";
12
+ import { useMemo as d, useState as f } from "react";
13
+ import { ChevronLeft as p, ChevronRight as m, Plus as h, Sparkles as g, Star as _ } from "lucide-react";
14
+ import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
13
15
  //#region src/coolandlovely/pages/looks/LooksListPage.tsx
14
- var v = 24, y = [
15
- {
16
- value: "ALL",
17
- label: "All"
18
- },
19
- {
20
- value: "EVERYDAY",
21
- label: "Everyday"
22
- },
23
- {
24
- value: "WORK",
25
- label: "Work"
26
- },
27
- {
28
- value: "EVENING",
29
- label: "Evening"
30
- },
31
- {
32
- value: "WEDDING_GUEST",
33
- label: "Wedding guest"
34
- },
35
- {
36
- value: "VACATION",
37
- label: "Vacation"
38
- },
39
- {
40
- value: "PARTY",
41
- label: "Party"
42
- },
43
- {
44
- value: "ACTIVE",
45
- label: "Active"
46
- },
47
- {
48
- value: "OTHER",
49
- label: "Other"
50
- }
16
+ var x = 24, S = [
17
+ "EVERYDAY",
18
+ "WORK",
19
+ "EVENING",
20
+ "WEDDING_GUEST",
21
+ "VACATION",
22
+ "PARTY",
23
+ "ACTIVE",
24
+ "OTHER"
51
25
  ];
52
- function b() {
53
- let { navigateTo: b } = e(), [x, S] = l("ALL"), [C, w] = l(!1), [T, E] = l(0), D = o({
54
- occasion: x === "ALL" ? void 0 : x,
55
- featured: C ? !0 : void 0,
26
+ function C() {
27
+ let { navigateTo: C } = e(), w = i(), [T, E] = f("ALL"), [D, O] = f(!1), [k, A] = f(0), j = d(() => [{
28
+ value: "ALL",
29
+ label: w("coolandlovely.filters.all", "All")
30
+ }, ...S.map((e) => ({
31
+ value: e,
32
+ label: w(`coolandlovely.occasion.${e.toLowerCase()}`, c(e))
33
+ }))], [w]), M = r({
34
+ occasion: T === "ALL" ? void 0 : T,
35
+ featured: D ? !0 : void 0,
56
36
  pagination: {
57
- limit: v,
58
- offset: T
37
+ limit: x,
38
+ offset: k
59
39
  }
60
- }), O = D.data?.items ?? [], k = D.data?.pageInfo.hasMore ?? !1;
61
- return /* @__PURE__ */ _(n, {
62
- title: "Looks",
63
- description: "Shop-the-look outfits built from real catalogue pieces",
64
- actions: /* @__PURE__ */ _("button", {
40
+ }), N = M.data?.items ?? [], P = M.data?.pageInfo.hasMore ?? !1;
41
+ return /* @__PURE__ */ b(n, {
42
+ title: w("coolandlovely.page.looksTitle", "Looks"),
43
+ description: w("coolandlovely.page.looksSubtitle", "Shop-the-look outfits built from real catalogue pieces"),
44
+ actions: /* @__PURE__ */ b("button", {
65
45
  type: "button",
66
- onClick: () => b("/looks/new"),
46
+ onClick: () => C("/looks/new"),
67
47
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
68
- children: [/* @__PURE__ */ g(f, { className: "h-4 w-4" }), " New look"]
48
+ children: [
49
+ /* @__PURE__ */ y(h, { className: "h-4 w-4" }),
50
+ " ",
51
+ w("coolandlovely.actions.newLook", "New look")
52
+ ]
69
53
  }),
70
- children: [/* @__PURE__ */ _("div", {
54
+ children: [/* @__PURE__ */ b("div", {
71
55
  className: "mb-6 flex flex-wrap items-center gap-2",
72
- children: [y.map((e) => /* @__PURE__ */ g("button", {
56
+ children: [j.map((e) => /* @__PURE__ */ y("button", {
73
57
  type: "button",
74
58
  onClick: () => {
75
- S(e.value), E(0);
59
+ E(e.value), A(0);
76
60
  },
77
- className: t("rounded-full px-3 py-1.5 text-sm font-medium transition-colors", x === e.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
61
+ className: t("rounded-full px-3 py-1.5 text-sm font-medium transition-colors", T === e.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
78
62
  children: e.label
79
- }, e.value)), /* @__PURE__ */ _("button", {
63
+ }, e.value)), /* @__PURE__ */ b("button", {
80
64
  type: "button",
81
65
  onClick: () => {
82
- w((e) => !e), E(0);
66
+ O((e) => !e), A(0);
83
67
  },
84
- className: t("ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors", C ? "bg-status-warning-bg-subtle text-status-warning-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
68
+ className: t("ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors", D ? "bg-status-warning-bg-subtle text-status-warning-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
85
69
  children: [
86
- /* @__PURE__ */ g(m, { className: t("h-3.5 w-3.5", C && "fill-status-warning-text") }),
70
+ /* @__PURE__ */ y(_, { className: t("h-3.5 w-3.5", D && "fill-status-warning-text") }),
87
71
  " ",
88
- "Featured"
72
+ w("coolandlovely.filters.featured", "Featured")
89
73
  ]
90
74
  })]
91
- }), D.isLoading ? /* @__PURE__ */ g(a, { label: "Loading looks…" }) : D.isError ? /* @__PURE__ */ g(i, { onRetry: () => void D.refetch() }) : O.length === 0 ? /* @__PURE__ */ g(c, {
75
+ }), M.isLoading ? /* @__PURE__ */ y(s, { label: w("coolandlovely.loading.looks", "Loading looks…") }) : M.isError ? /* @__PURE__ */ y(o, { onRetry: () => void M.refetch() }) : N.length === 0 ? /* @__PURE__ */ y(u, {
92
76
  illustration: "empty-data",
93
- icon: /* @__PURE__ */ g(p, { className: "h-10 w-10" }),
94
- title: "No looks yet",
95
- description: "Publish a shop-the-look outfit from catalogue pieces.",
96
- action: /* @__PURE__ */ _("button", {
77
+ icon: /* @__PURE__ */ y(g, { className: "h-10 w-10" }),
78
+ title: w("coolandlovely.empty.looksTitle", "No looks yet"),
79
+ description: w("coolandlovely.empty.looksDescription", "Publish a shop-the-look outfit from catalogue pieces."),
80
+ action: /* @__PURE__ */ b("button", {
97
81
  type: "button",
98
- onClick: () => b("/looks/new"),
82
+ onClick: () => C("/looks/new"),
99
83
  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",
100
- children: [/* @__PURE__ */ g(f, { className: "h-4 w-4" }), " New look"]
84
+ children: [
85
+ /* @__PURE__ */ y(h, { className: "h-4 w-4" }),
86
+ " ",
87
+ w("coolandlovely.actions.newLook", "New look")
88
+ ]
101
89
  })
102
- }) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("div", {
90
+ }) : /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ y("div", {
103
91
  className: "grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4",
104
- children: O.map((e) => /* @__PURE__ */ _("div", {
92
+ children: N.map((e) => /* @__PURE__ */ b("div", {
105
93
  className: "relative",
106
- children: [/* @__PURE__ */ g(s, {
94
+ children: [/* @__PURE__ */ y(l, {
107
95
  id: e.id,
108
96
  title: e.title,
109
97
  occasion: e.occasion,
@@ -111,42 +99,54 @@ function b() {
111
99
  likeCount: e.likeCount,
112
100
  isLikedByMe: e.isLikedByMe,
113
101
  isSavedByMe: e.isSavedByMe,
114
- onOpen: () => b(`/looks/${e.id}`),
102
+ onOpen: () => C(`/looks/${e.id}`),
115
103
  showActions: !0
116
- }), (e.isFeatured || e.publishedAt === null) && /* @__PURE__ */ _("div", {
104
+ }), (e.isFeatured || e.publishedAt === null) && /* @__PURE__ */ b("div", {
117
105
  className: "pointer-events-none absolute left-2 top-2 z-10 flex flex-col items-start gap-1",
118
- children: [e.isFeatured && /* @__PURE__ */ _("span", {
106
+ children: [e.isFeatured && /* @__PURE__ */ b("span", {
119
107
  className: "inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs font-medium text-status-warning-text shadow-sm backdrop-blur",
120
- children: [/* @__PURE__ */ g(m, { className: "h-3 w-3 fill-status-warning-text" }), " Featured"]
121
- }), e.publishedAt === null && /* @__PURE__ */ g(r, { status: "draft" })]
108
+ children: [
109
+ /* @__PURE__ */ y(_, { className: "h-3 w-3 fill-status-warning-text" }),
110
+ " ",
111
+ w("coolandlovely.filters.featured", "Featured")
112
+ ]
113
+ }), e.publishedAt === null && /* @__PURE__ */ y(a, { status: "draft" })]
122
114
  })]
123
115
  }, e.id))
124
- }), (T > 0 || k) && /* @__PURE__ */ _("div", {
116
+ }), (k > 0 || P) && /* @__PURE__ */ b("div", {
125
117
  className: "mt-6 flex items-center justify-center gap-2",
126
118
  children: [
127
- /* @__PURE__ */ _("button", {
119
+ /* @__PURE__ */ b("button", {
128
120
  type: "button",
129
- disabled: T === 0,
130
- onClick: () => E((e) => Math.max(0, e - v)),
121
+ disabled: k === 0,
122
+ onClick: () => A((e) => Math.max(0, e - x)),
131
123
  className: "inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40",
132
- children: [/* @__PURE__ */ g(u, { className: "h-4 w-4" }), " Previous"]
124
+ children: [
125
+ /* @__PURE__ */ y(p, { className: "h-4 w-4" }),
126
+ " ",
127
+ w("coolandlovely.pagination.previous", "Previous")
128
+ ]
133
129
  }),
134
- /* @__PURE__ */ _("span", {
130
+ /* @__PURE__ */ y("span", {
135
131
  className: "text-sm text-text-secondary",
136
- children: ["Page ", T / v + 1]
132
+ children: w("coolandlovely.pagination.page", "Page {{page}}", { page: k / x + 1 })
137
133
  }),
138
- /* @__PURE__ */ _("button", {
134
+ /* @__PURE__ */ b("button", {
139
135
  type: "button",
140
- disabled: !k,
141
- onClick: () => E((e) => e + v),
136
+ disabled: !P,
137
+ onClick: () => A((e) => e + x),
142
138
  className: "inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40",
143
- children: ["Next ", /* @__PURE__ */ g(d, { className: "h-4 w-4" })]
139
+ children: [
140
+ w("coolandlovely.pagination.next", "Next"),
141
+ " ",
142
+ /* @__PURE__ */ y(m, { className: "h-4 w-4" })
143
+ ]
144
144
  })
145
145
  ]
146
146
  })] })]
147
147
  });
148
148
  }
149
149
  //#endregion
150
- export { b as LooksListPage };
150
+ export { C as LooksListPage };
151
151
 
152
152
  //# sourceMappingURL=LooksListPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LooksListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/looks/LooksListPage.tsx"],"sourcesContent":["/**\n * Looks List Page\n * @module coolandlovely/pages/looks\n *\n * Cursor-paginated feed of published looks (`cooListLooks`) with occasion &\n * featured filters.\n */\n\nimport { useState } from 'react';\nimport { Plus, Sparkles, ChevronLeft, ChevronRight, Star } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { LookCard } from '../../components/LookCard';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useLooks } from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport type { CooLookOccasion } from '../../types';\n\nconst PAGE_SIZE = 24;\n\nconst OCCASIONS: Array<{ value: CooLookOccasion | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'EVERYDAY', label: 'Everyday' },\n { value: 'WORK', label: 'Work' },\n { value: 'EVENING', label: 'Evening' },\n { value: 'WEDDING_GUEST', label: 'Wedding guest' },\n { value: 'VACATION', label: 'Vacation' },\n { value: 'PARTY', label: 'Party' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'OTHER', label: 'Other' },\n];\n\nexport function LooksListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [occasion, setOccasion] = useState<CooLookOccasion | 'ALL'>('ALL');\n const [featuredOnly, setFeaturedOnly] = useState(false);\n const [offset, setOffset] = useState(0);\n\n const query = useLooks({\n occasion: occasion === 'ALL' ? undefined : occasion,\n featured: featuredOnly ? true : undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const looks = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Looks\"\n description=\"Shop-the-look outfits built from real catalogue pieces\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks/new')}\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 <Plus className=\"h-4 w-4\" /> New look\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n {OCCASIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setOccasion(opt.value);\n setOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n occasion === opt.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n <button\n type=\"button\"\n onClick={() => {\n setFeaturedOnly((v) => !v);\n setOffset(0);\n }}\n className={cn(\n 'ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n featuredOnly\n ? 'bg-status-warning-bg-subtle text-status-warning-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n <Star className={cn('h-3.5 w-3.5', featuredOnly && 'fill-status-warning-text')} />{' '}\n Featured\n </button>\n </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading looks…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : looks.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Sparkles className=\"h-10 w-10\" />}\n title=\"No looks yet\"\n description=\"Publish a shop-the-look outfit from catalogue pieces.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks/new')}\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\"\n >\n <Plus className=\"h-4 w-4\" /> New look\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\n {looks.map((look) => (\n <div key={look.id} className=\"relative\">\n <LookCard\n id={look.id}\n title={look.title}\n occasion={look.occasion}\n imageFileId={look.image?.id}\n likeCount={look.likeCount}\n isLikedByMe={look.isLikedByMe}\n isSavedByMe={look.isSavedByMe}\n onOpen={() => navigateTo(`/looks/${look.id}`)}\n showActions\n />\n {(look.isFeatured || look.publishedAt === null) && (\n <div className=\"pointer-events-none absolute left-2 top-2 z-10 flex flex-col items-start gap-1\">\n {look.isFeatured && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs font-medium text-status-warning-text shadow-sm backdrop-blur\">\n <Star className=\"h-3 w-3 fill-status-warning-text\" /> Featured\n </span>\n )}\n {look.publishedAt === null && <StatusBadge status=\"draft\" />}\n </div>\n )}\n </div>\n ))}\n </div>\n\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" /> Previous\n </button>\n <span className=\"text-sm text-text-secondary\">Page {offset / PAGE_SIZE + 1}</span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n Next <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"LooksListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/looks/LooksListPage.tsx"],"sourcesContent":["/**\n * Looks List Page\n * @module coolandlovely/pages/looks\n *\n * Cursor-paginated feed of published looks (`cooListLooks`) with occasion &\n * featured filters.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Sparkles, ChevronLeft, ChevronRight, Star } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { LookCard } from '../../components/LookCard';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useLooks, useTr } from '../../hooks';\nimport { titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooLookOccasion } from '../../types';\n\nconst PAGE_SIZE = 24;\nconst OCCASION_ORDER: CooLookOccasion[] = [\n 'EVERYDAY',\n 'WORK',\n 'EVENING',\n 'WEDDING_GUEST',\n 'VACATION',\n 'PARTY',\n 'ACTIVE',\n 'OTHER',\n];\n\nexport function LooksListPage() {\n const { navigateTo } = useCoolAndLovely();\n const tr = useTr();\n const [occasion, setOccasion] = useState<CooLookOccasion | 'ALL'>('ALL');\n const [featuredOnly, setFeaturedOnly] = useState(false);\n const [offset, setOffset] = useState(0);\n\n const occasionOptions = useMemo(\n () => [\n { value: 'ALL' as const, label: tr('coolandlovely.filters.all', 'All') },\n ...OCCASION_ORDER.map((value) => ({\n value,\n label: tr(`coolandlovely.occasion.${value.toLowerCase()}`, titleCase(value)),\n })),\n ],\n [tr]\n );\n\n const query = useLooks({\n occasion: occasion === 'ALL' ? undefined : occasion,\n featured: featuredOnly ? true : undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const looks = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title={tr('coolandlovely.page.looksTitle', 'Looks')}\n description={tr(\n 'coolandlovely.page.looksSubtitle',\n 'Shop-the-look outfits built from real catalogue pieces'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks/new')}\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 <Plus className=\"h-4 w-4\" /> {tr('coolandlovely.actions.newLook', 'New look')}\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n {occasionOptions.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setOccasion(opt.value);\n setOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n occasion === opt.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n <button\n type=\"button\"\n onClick={() => {\n setFeaturedOnly((v) => !v);\n setOffset(0);\n }}\n className={cn(\n 'ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n featuredOnly\n ? 'bg-status-warning-bg-subtle text-status-warning-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n <Star className={cn('h-3.5 w-3.5', featuredOnly && 'fill-status-warning-text')} />{' '}\n {tr('coolandlovely.filters.featured', 'Featured')}\n </button>\n </div>\n\n {query.isLoading ? (\n <LoadingView label={tr('coolandlovely.loading.looks', 'Loading looks…')} />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : looks.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Sparkles className=\"h-10 w-10\" />}\n title={tr('coolandlovely.empty.looksTitle', 'No looks yet')}\n description={tr(\n 'coolandlovely.empty.looksDescription',\n 'Publish a shop-the-look outfit from catalogue pieces.'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks/new')}\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\"\n >\n <Plus className=\"h-4 w-4\" /> {tr('coolandlovely.actions.newLook', 'New look')}\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4\">\n {looks.map((look) => (\n <div key={look.id} className=\"relative\">\n <LookCard\n id={look.id}\n title={look.title}\n occasion={look.occasion}\n imageFileId={look.image?.id}\n likeCount={look.likeCount}\n isLikedByMe={look.isLikedByMe}\n isSavedByMe={look.isSavedByMe}\n onOpen={() => navigateTo(`/looks/${look.id}`)}\n showActions\n />\n {(look.isFeatured || look.publishedAt === null) && (\n <div className=\"pointer-events-none absolute left-2 top-2 z-10 flex flex-col items-start gap-1\">\n {look.isFeatured && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs font-medium text-status-warning-text shadow-sm backdrop-blur\">\n <Star className=\"h-3 w-3 fill-status-warning-text\" />{' '}\n {tr('coolandlovely.filters.featured', 'Featured')}\n </span>\n )}\n {look.publishedAt === null && <StatusBadge status=\"draft\" />}\n </div>\n )}\n </div>\n ))}\n </div>\n\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" />{' '}\n {tr('coolandlovely.pagination.previous', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {tr('coolandlovely.pagination.page', 'Page {{page}}', {\n page: offset / PAGE_SIZE + 1,\n })}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {tr('coolandlovely.pagination.next', 'Next')} <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"StyleProfilePage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/profile/StyleProfilePage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA+EH,wBAAgB,gBAAgB,gCAyf/B"}
1
+ {"version":3,"file":"StyleProfilePage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/profile/StyleProfilePage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgFH,wBAAgB,gBAAgB,gCA2jB/B"}