@burdenoff/microfe-coolandlovely 2026.805.1 → 2026.820.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/CoolAndLovelyRoot.d.ts.map +1 -1
- package/dist/coolandlovely/CoolAndLovelyRoot.js +60 -58
- package/dist/coolandlovely/CoolAndLovelyRoot.js.map +1 -1
- package/dist/coolandlovely/components/AddToLookbookButton.d.ts.map +1 -1
- package/dist/coolandlovely/components/AddToLookbookButton.js +1 -0
- package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -1
- package/dist/coolandlovely/components/BrandCard.d.ts +11 -0
- package/dist/coolandlovely/components/BrandCard.d.ts.map +1 -0
- package/dist/coolandlovely/components/BrandCard.js +55 -0
- package/dist/coolandlovely/components/BrandCard.js.map +1 -0
- package/dist/coolandlovely/components/CollectionCard.d.ts +11 -0
- package/dist/coolandlovely/components/CollectionCard.d.ts.map +1 -0
- package/dist/coolandlovely/components/CollectionCard.js +60 -0
- package/dist/coolandlovely/components/CollectionCard.js.map +1 -0
- package/dist/coolandlovely/components/FeedbackWidget.d.ts +4 -0
- package/dist/coolandlovely/components/FeedbackWidget.d.ts.map +1 -0
- package/dist/coolandlovely/components/FeedbackWidget.js +134 -0
- package/dist/coolandlovely/components/FeedbackWidget.js.map +1 -0
- package/dist/coolandlovely/components/LookbookCard.d.ts +11 -0
- package/dist/coolandlovely/components/LookbookCard.d.ts.map +1 -0
- package/dist/coolandlovely/components/LookbookCard.js +60 -0
- package/dist/coolandlovely/components/LookbookCard.js.map +1 -0
- package/dist/coolandlovely/components/WardrobeItemCard.d.ts +14 -0
- package/dist/coolandlovely/components/WardrobeItemCard.d.ts.map +1 -0
- package/dist/coolandlovely/components/WardrobeItemCard.js +92 -0
- package/dist/coolandlovely/components/WardrobeItemCard.js.map +1 -0
- package/dist/coolandlovely/components/index.d.ts +5 -0
- package/dist/coolandlovely/components/index.d.ts.map +1 -1
- package/dist/coolandlovely/components/index.js +26 -0
- package/dist/coolandlovely/pages/HomePage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/HomePage.js +10 -4
- package/dist/coolandlovely/pages/HomePage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js +7 -7
- package/dist/coolandlovely/pages/brands/BrandsListPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandsListPage.js +48 -89
- package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +4 -4
- package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +13 -13
- package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js +4 -4
- package/dist/coolandlovely/pages/collections/CollectionsListPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js +28 -74
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +5 -5
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +66 -112
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js +124 -124
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +46 -120
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
- package/dist/stories/BrandCard.stories.d.ts +10 -0
- package/dist/stories/BrandCard.stories.d.ts.map +1 -0
- package/dist/stories/CollectionCard.stories.d.ts +10 -0
- package/dist/stories/CollectionCard.stories.d.ts.map +1 -0
- package/dist/stories/FeedbackWidget.stories.d.ts +9 -0
- package/dist/stories/FeedbackWidget.stories.d.ts.map +1 -0
- package/dist/stories/LookCard.stories.d.ts +10 -0
- package/dist/stories/LookCard.stories.d.ts.map +1 -0
- package/dist/stories/LookbookCard.stories.d.ts +10 -0
- package/dist/stories/LookbookCard.stories.d.ts.map +1 -0
- package/dist/stories/WardrobeItemCard.stories.d.ts +11 -0
- package/dist/stories/WardrobeItemCard.stories.d.ts.map +1 -0
- package/dist/stories/__fixtures__/coolandlovely.d.ts +13 -0
- package/dist/stories/__fixtures__/coolandlovely.d.ts.map +1 -0
- package/package.json +4 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CoolAndLovelyRoot.d.ts","sourceRoot":"","sources":["../../src/coolandlovely/CoolAndLovelyRoot.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"CoolAndLovelyRoot.d.ts","sourceRoot":"","sources":["../../src/coolandlovely/CoolAndLovelyRoot.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAqBhC,OAAO,KAAK,EAAE,sBAAsB,EAAW,MAAM,SAAS,CAAC;AAY/D,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAoJxD,CAAC"}
|
|
@@ -1,137 +1,139 @@
|
|
|
1
1
|
import { CoolAndLovelyProvider as e } from "./context/CoolAndLovelyContext.js";
|
|
2
2
|
import { CoolAndLovelyRoutes as t } from "./CoolAndLovelyRoutes.js";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
3
|
+
import { FeedbackWidget as n } from "./components/FeedbackWidget.js";
|
|
4
|
+
import "./components/index.js";
|
|
5
|
+
import { useCallback as r, useEffect as i } from "react";
|
|
6
|
+
import { QueryClient as a, QueryClientProvider as o } from "@tanstack/react-query";
|
|
7
|
+
import { useI18n as s } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
|
+
import { BookHeart as c, Compass as l, Handshake as u, Heart as d, Home as f, Shapes as p, Shirt as m, Sparkles as h, Store as g, TrendingUp as _, UserCircle as v } from "lucide-react";
|
|
9
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
10
|
+
import { FeatureFlagProvider as x } from "@burdenoff/fe-libs/shared/feature-flags";
|
|
9
11
|
//#region src/coolandlovely/CoolAndLovelyRoot.tsx
|
|
10
|
-
var
|
|
12
|
+
var S = new a({ defaultOptions: { queries: {
|
|
11
13
|
staleTime: 300 * 1e3,
|
|
12
14
|
retry: 1
|
|
13
|
-
} } }),
|
|
14
|
-
let { registerNavItems:
|
|
15
|
-
let n =
|
|
15
|
+
} } }), C = (a) => {
|
|
16
|
+
let { registerNavItems: C, registerFooterItems: w, basePath: T = "/" } = a, { t: E } = s(), D = r((e, t) => {
|
|
17
|
+
let n = E(e);
|
|
16
18
|
return n === e ? t : n;
|
|
17
|
-
}, [
|
|
18
|
-
return
|
|
19
|
-
if (
|
|
19
|
+
}, [E]), O = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
20
|
+
return i(() => {
|
|
21
|
+
if (C) return C([
|
|
20
22
|
{
|
|
21
23
|
id: "coolandlovely-overview",
|
|
22
|
-
label:
|
|
23
|
-
path:
|
|
24
|
-
icon: /* @__PURE__ */
|
|
24
|
+
label: D("coolandlovely.nav.overview", "Overview"),
|
|
25
|
+
path: O(T, ""),
|
|
26
|
+
icon: /* @__PURE__ */ y(f, { size: 20 }),
|
|
25
27
|
order: 1,
|
|
26
28
|
group: "main"
|
|
27
29
|
},
|
|
28
30
|
{
|
|
29
31
|
id: "coolandlovely-brands",
|
|
30
|
-
label:
|
|
31
|
-
path:
|
|
32
|
-
icon: /* @__PURE__ */
|
|
32
|
+
label: D("coolandlovely.nav.brands", "Brands"),
|
|
33
|
+
path: O(T, "brands"),
|
|
34
|
+
icon: /* @__PURE__ */ y(g, { size: 20 }),
|
|
33
35
|
order: 10,
|
|
34
36
|
group: "catalog"
|
|
35
37
|
},
|
|
36
38
|
{
|
|
37
39
|
id: "coolandlovely-collections",
|
|
38
|
-
label:
|
|
39
|
-
path:
|
|
40
|
-
icon: /* @__PURE__ */
|
|
40
|
+
label: D("coolandlovely.nav.collections", "Collections"),
|
|
41
|
+
path: O(T, "collections"),
|
|
42
|
+
icon: /* @__PURE__ */ y(p, { size: 20 }),
|
|
41
43
|
order: 11,
|
|
42
44
|
group: "catalog"
|
|
43
45
|
},
|
|
44
46
|
{
|
|
45
47
|
id: "coolandlovely-items",
|
|
46
|
-
label:
|
|
47
|
-
path:
|
|
48
|
-
icon: /* @__PURE__ */
|
|
48
|
+
label: D("coolandlovely.nav.items", "Style Items"),
|
|
49
|
+
path: O(T, "items"),
|
|
50
|
+
icon: /* @__PURE__ */ y(m, { size: 20 }),
|
|
49
51
|
order: 12,
|
|
50
52
|
group: "catalog"
|
|
51
53
|
},
|
|
52
54
|
{
|
|
53
55
|
id: "coolandlovely-looks",
|
|
54
|
-
label:
|
|
55
|
-
path:
|
|
56
|
-
icon: /* @__PURE__ */
|
|
56
|
+
label: D("coolandlovely.nav.looks", "Looks"),
|
|
57
|
+
path: O(T, "looks"),
|
|
58
|
+
icon: /* @__PURE__ */ y(h, { size: 20 }),
|
|
57
59
|
order: 20,
|
|
58
60
|
group: "social"
|
|
59
61
|
},
|
|
60
62
|
{
|
|
61
63
|
id: "coolandlovely-collaborations",
|
|
62
|
-
label:
|
|
63
|
-
path:
|
|
64
|
-
icon: /* @__PURE__ */
|
|
64
|
+
label: D("coolandlovely.nav.collaborations", "Collaborations"),
|
|
65
|
+
path: O(T, "collaborations"),
|
|
66
|
+
icon: /* @__PURE__ */ y(u, { size: 20 }),
|
|
65
67
|
order: 21,
|
|
66
68
|
group: "social"
|
|
67
69
|
},
|
|
68
70
|
{
|
|
69
71
|
id: "coolandlovely-wardrobe",
|
|
70
|
-
label:
|
|
71
|
-
path:
|
|
72
|
-
icon: /* @__PURE__ */
|
|
72
|
+
label: D("coolandlovely.nav.wardrobe", "My Wardrobe"),
|
|
73
|
+
path: O(T, "wardrobe"),
|
|
74
|
+
icon: /* @__PURE__ */ y(d, { size: 20 }),
|
|
73
75
|
order: 30,
|
|
74
76
|
group: "my-style"
|
|
75
77
|
},
|
|
76
78
|
{
|
|
77
79
|
id: "coolandlovely-lookbooks",
|
|
78
|
-
label:
|
|
79
|
-
path:
|
|
80
|
-
icon: /* @__PURE__ */
|
|
80
|
+
label: D("coolandlovely.nav.lookbooks", "Lookbooks"),
|
|
81
|
+
path: O(T, "lookbooks"),
|
|
82
|
+
icon: /* @__PURE__ */ y(c, { size: 20 }),
|
|
81
83
|
order: 31,
|
|
82
84
|
group: "my-style"
|
|
83
85
|
},
|
|
84
86
|
{
|
|
85
87
|
id: "coolandlovely-profile",
|
|
86
|
-
label:
|
|
87
|
-
path:
|
|
88
|
-
icon: /* @__PURE__ */ v
|
|
88
|
+
label: D("coolandlovely.nav.profile", "Style Profile"),
|
|
89
|
+
path: O(T, "profile"),
|
|
90
|
+
icon: /* @__PURE__ */ y(v, { size: 20 }),
|
|
89
91
|
order: 32,
|
|
90
92
|
group: "my-style"
|
|
91
93
|
},
|
|
92
94
|
{
|
|
93
95
|
id: "coolandlovely-discover",
|
|
94
|
-
label:
|
|
95
|
-
path:
|
|
96
|
-
icon: /* @__PURE__ */
|
|
96
|
+
label: D("coolandlovely.nav.discover", "Discover"),
|
|
97
|
+
path: O(T, "discover"),
|
|
98
|
+
icon: /* @__PURE__ */ y(l, { size: 20 }),
|
|
97
99
|
order: 40,
|
|
98
100
|
group: "signals"
|
|
99
101
|
},
|
|
100
102
|
{
|
|
101
103
|
id: "coolandlovely-trends",
|
|
102
|
-
label:
|
|
103
|
-
path:
|
|
104
|
-
icon: /* @__PURE__ */
|
|
104
|
+
label: D("coolandlovely.nav.trends", "Trends"),
|
|
105
|
+
path: O(T, "trends"),
|
|
106
|
+
icon: /* @__PURE__ */ y(_, { size: 20 }),
|
|
105
107
|
order: 41,
|
|
106
108
|
group: "signals"
|
|
107
109
|
}
|
|
108
110
|
]);
|
|
109
111
|
}, [
|
|
110
|
-
x,
|
|
111
112
|
C,
|
|
112
|
-
T
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
T,
|
|
114
|
+
D
|
|
115
|
+
]), i(() => {
|
|
116
|
+
if (w) return w([{
|
|
115
117
|
id: "coolandlovely-status",
|
|
116
|
-
label:
|
|
118
|
+
label: D("coolandlovely.footer.ready", "CoolAndLovely"),
|
|
117
119
|
type: "status",
|
|
118
120
|
order: 10,
|
|
119
121
|
section: "left"
|
|
120
122
|
}]);
|
|
121
|
-
}, [
|
|
122
|
-
client:
|
|
123
|
-
children: /* @__PURE__ */
|
|
123
|
+
}, [w, D]), /* @__PURE__ */ y(o, {
|
|
124
|
+
client: S,
|
|
125
|
+
children: /* @__PURE__ */ y(x, {
|
|
124
126
|
workspaceId: null,
|
|
125
127
|
gateway: "global",
|
|
126
128
|
defaultEnabled: !0,
|
|
127
|
-
children: /* @__PURE__ */
|
|
128
|
-
...
|
|
129
|
-
children: /* @__PURE__ */
|
|
129
|
+
children: /* @__PURE__ */ b(e, {
|
|
130
|
+
...a,
|
|
131
|
+
children: [/* @__PURE__ */ y(t, {}), /* @__PURE__ */ y(n, {})]
|
|
130
132
|
})
|
|
131
133
|
})
|
|
132
134
|
});
|
|
133
135
|
};
|
|
134
136
|
//#endregion
|
|
135
|
-
export {
|
|
137
|
+
export { C as CoolAndLovelyRoot };
|
|
136
138
|
|
|
137
139
|
//# sourceMappingURL=CoolAndLovelyRoot.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CoolAndLovelyRoot.js","names":[],"sources":["../../src/coolandlovely/CoolAndLovelyRoot.tsx"],"sourcesContent":["/**\n * CoolAndLovely Root Component\n * @module coolandlovely\n *\n * Single Root export consumed by host application shells. The export name and\n * prop contract (basePath / navigate / currentUser / apiGatewayUrl /\n * registerNavItems / registerFooterItems / workspace context) are stable — the\n * host imports `CoolAndLovelyRoot` the same way regardless of the internal UI.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useEffect } from 'react';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Home,\n Store,\n Shapes,\n Shirt,\n Sparkles,\n Handshake,\n Heart,\n BookHeart,\n UserCircle,\n Compass,\n TrendingUp,\n} from 'lucide-react';\nimport { CoolAndLovelyProvider } from './context/CoolAndLovelyContext';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { CoolAndLovelyRoutes } from './CoolAndLovelyRoutes';\nimport type { CoolAndLovelyRootProps, NavItem } from './types';\n\n// Create a query client for this microfrontend\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000,\n retry: 1,\n },\n },\n});\n\nexport const CoolAndLovelyRoot: FC<CoolAndLovelyRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n // Helper to join paths correctly\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell on mount.\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: 'coolandlovely-overview',\n label: t('coolandlovely.nav.overview', 'Overview'),\n path: joinPath(basePath, ''),\n icon: <Home size={20} />,\n order: 1,\n group: 'main',\n },\n // Catalog\n {\n id: 'coolandlovely-brands',\n label: t('coolandlovely.nav.brands', 'Brands'),\n path: joinPath(basePath, 'brands'),\n icon: <Store size={20} />,\n order: 10,\n group: 'catalog',\n },\n {\n id: 'coolandlovely-collections',\n label: t('coolandlovely.nav.collections', 'Collections'),\n path: joinPath(basePath, 'collections'),\n icon: <Shapes size={20} />,\n order: 11,\n group: 'catalog',\n },\n {\n id: 'coolandlovely-items',\n label: t('coolandlovely.nav.items', 'Style Items'),\n path: joinPath(basePath, 'items'),\n icon: <Shirt size={20} />,\n order: 12,\n group: 'catalog',\n },\n // Social\n {\n id: 'coolandlovely-looks',\n label: t('coolandlovely.nav.looks', 'Looks'),\n path: joinPath(basePath, 'looks'),\n icon: <Sparkles size={20} />,\n order: 20,\n group: 'social',\n },\n {\n id: 'coolandlovely-collaborations',\n label: t('coolandlovely.nav.collaborations', 'Collaborations'),\n path: joinPath(basePath, 'collaborations'),\n icon: <Handshake size={20} />,\n order: 21,\n group: 'social',\n },\n // My style\n {\n id: 'coolandlovely-wardrobe',\n label: t('coolandlovely.nav.wardrobe', 'My Wardrobe'),\n path: joinPath(basePath, 'wardrobe'),\n icon: <Heart size={20} />,\n order: 30,\n group: 'my-style',\n },\n {\n id: 'coolandlovely-lookbooks',\n label: t('coolandlovely.nav.lookbooks', 'Lookbooks'),\n path: joinPath(basePath, 'lookbooks'),\n icon: <BookHeart size={20} />,\n order: 31,\n group: 'my-style',\n },\n {\n id: 'coolandlovely-profile',\n label: t('coolandlovely.nav.profile', 'Style Profile'),\n path: joinPath(basePath, 'profile'),\n icon: <UserCircle size={20} />,\n order: 32,\n group: 'my-style',\n },\n {\n id: 'coolandlovely-discover',\n label: t('coolandlovely.nav.discover', 'Discover'),\n path: joinPath(basePath, 'discover'),\n icon: <Compass size={20} />,\n order: 40,\n group: 'signals',\n },\n {\n id: 'coolandlovely-trends',\n label: t('coolandlovely.nav.trends', 'Trends'),\n path: joinPath(basePath, 'trends'),\n icon: <TrendingUp size={20} />,\n order: 41,\n group: 'signals',\n },\n ];\n\n const cleanup = registerNavItems(navItems);\n return cleanup;\n }, [registerNavItems, basePath, t]);\n\n // Register footer items\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: 'coolandlovely-status',\n label: t('coolandlovely.footer.ready', 'CoolAndLovely'),\n type: 'status' as const,\n order: 10,\n section: 'left' as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, t]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <CoolAndLovelyProvider {...props}>\n <CoolAndLovelyRoutes />\n </CoolAndLovelyProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n );\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CoolAndLovelyRoot.js","names":[],"sources":["../../src/coolandlovely/CoolAndLovelyRoot.tsx"],"sourcesContent":["/**\n * CoolAndLovely Root Component\n * @module coolandlovely\n *\n * Single Root export consumed by host application shells. The export name and\n * prop contract (basePath / navigate / currentUser / apiGatewayUrl /\n * registerNavItems / registerFooterItems / workspace context) are stable — the\n * host imports `CoolAndLovelyRoot` the same way regardless of the internal UI.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useEffect } from 'react';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Home,\n Store,\n Shapes,\n Shirt,\n Sparkles,\n Handshake,\n Heart,\n BookHeart,\n UserCircle,\n Compass,\n TrendingUp,\n} from 'lucide-react';\nimport { CoolAndLovelyProvider } from './context/CoolAndLovelyContext';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { CoolAndLovelyRoutes } from './CoolAndLovelyRoutes';\nimport { FeedbackWidget } from './components';\nimport type { CoolAndLovelyRootProps, NavItem } from './types';\n\n// Create a query client for this microfrontend\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000,\n retry: 1,\n },\n },\n});\n\nexport const CoolAndLovelyRoot: FC<CoolAndLovelyRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n // Helper to join paths correctly\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell on mount.\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: 'coolandlovely-overview',\n label: t('coolandlovely.nav.overview', 'Overview'),\n path: joinPath(basePath, ''),\n icon: <Home size={20} />,\n order: 1,\n group: 'main',\n },\n // Catalog\n {\n id: 'coolandlovely-brands',\n label: t('coolandlovely.nav.brands', 'Brands'),\n path: joinPath(basePath, 'brands'),\n icon: <Store size={20} />,\n order: 10,\n group: 'catalog',\n },\n {\n id: 'coolandlovely-collections',\n label: t('coolandlovely.nav.collections', 'Collections'),\n path: joinPath(basePath, 'collections'),\n icon: <Shapes size={20} />,\n order: 11,\n group: 'catalog',\n },\n {\n id: 'coolandlovely-items',\n label: t('coolandlovely.nav.items', 'Style Items'),\n path: joinPath(basePath, 'items'),\n icon: <Shirt size={20} />,\n order: 12,\n group: 'catalog',\n },\n // Social\n {\n id: 'coolandlovely-looks',\n label: t('coolandlovely.nav.looks', 'Looks'),\n path: joinPath(basePath, 'looks'),\n icon: <Sparkles size={20} />,\n order: 20,\n group: 'social',\n },\n {\n id: 'coolandlovely-collaborations',\n label: t('coolandlovely.nav.collaborations', 'Collaborations'),\n path: joinPath(basePath, 'collaborations'),\n icon: <Handshake size={20} />,\n order: 21,\n group: 'social',\n },\n // My style\n {\n id: 'coolandlovely-wardrobe',\n label: t('coolandlovely.nav.wardrobe', 'My Wardrobe'),\n path: joinPath(basePath, 'wardrobe'),\n icon: <Heart size={20} />,\n order: 30,\n group: 'my-style',\n },\n {\n id: 'coolandlovely-lookbooks',\n label: t('coolandlovely.nav.lookbooks', 'Lookbooks'),\n path: joinPath(basePath, 'lookbooks'),\n icon: <BookHeart size={20} />,\n order: 31,\n group: 'my-style',\n },\n {\n id: 'coolandlovely-profile',\n label: t('coolandlovely.nav.profile', 'Style Profile'),\n path: joinPath(basePath, 'profile'),\n icon: <UserCircle size={20} />,\n order: 32,\n group: 'my-style',\n },\n {\n id: 'coolandlovely-discover',\n label: t('coolandlovely.nav.discover', 'Discover'),\n path: joinPath(basePath, 'discover'),\n icon: <Compass size={20} />,\n order: 40,\n group: 'signals',\n },\n {\n id: 'coolandlovely-trends',\n label: t('coolandlovely.nav.trends', 'Trends'),\n path: joinPath(basePath, 'trends'),\n icon: <TrendingUp size={20} />,\n order: 41,\n group: 'signals',\n },\n ];\n\n const cleanup = registerNavItems(navItems);\n return cleanup;\n }, [registerNavItems, basePath, t]);\n\n // Register footer items\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: 'coolandlovely-status',\n label: t('coolandlovely.footer.ready', 'CoolAndLovely'),\n type: 'status' as const,\n order: 10,\n section: 'left' as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, t]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <CoolAndLovelyProvider {...props}>\n <CoolAndLovelyRoutes />\n <FeedbackWidget />\n </CoolAndLovelyProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n );\n};\n"],"mappings":";;;;;;;;;;;AAkCA,IAAM,IAAc,IAAI,EAAY,EAClC,gBAAgB,EACd,SAAS;CACP,WAAW,MAAS;CACpB,OAAO;CACR,EACF,EACF,CAAC,EAEW,KAAiD,MAAU;CACtE,IAAM,EAAE,qBAAkB,wBAAqB,cAAW,QAAQ,GAC5D,EAAE,GAAG,MAAc,GAAS,EAC5B,IAAI,GACP,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAU,CACZ,EAGK,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AA4HtD,QAvHA,QAAgB;AACT,QAiGL,QADgB,EA9FY;GAC1B;IACE,IAAI;IACJ,OAAO,EAAE,8BAA8B,WAAW;IAClD,MAAM,EAAS,GAAU,GAAG;IAC5B,MAAM,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;IACxB,OAAO;IACP,OAAO;IACR;GAED;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,SAAS;IAC9C,MAAM,EAAS,GAAU,SAAS;IAClC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,iCAAiC,cAAc;IACxD,MAAM,EAAS,GAAU,cAAc;IACvC,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;IAC1B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,2BAA2B,cAAc;IAClD,MAAM,EAAS,GAAU,QAAQ;IACjC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GAED;IACE,IAAI;IACJ,OAAO,EAAE,2BAA2B,QAAQ;IAC5C,MAAM,EAAS,GAAU,QAAQ;IACjC,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;IAC5B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,oCAAoC,iBAAiB;IAC9D,MAAM,EAAS,GAAU,iBAAiB;IAC1C,MAAM,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;IAC7B,OAAO;IACP,OAAO;IACR;GAED;IACE,IAAI;IACJ,OAAO,EAAE,8BAA8B,cAAc;IACrD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,+BAA+B,YAAY;IACpD,MAAM,EAAS,GAAU,YAAY;IACrC,MAAM,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;IAC7B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,6BAA6B,gBAAgB;IACtD,MAAM,EAAS,GAAU,UAAU;IACnC,MAAM,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA;IAC9B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,8BAA8B,WAAW;IAClD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAS,MAAM,IAAM,CAAA;IAC3B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,SAAS;IAC9C,MAAM,EAAS,GAAU,SAAS;IAClC,MAAM,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA;IAC9B,OAAO;IACP,OAAO;IACR;GACF,CAEyC;IAEzC;EAAC;EAAkB;EAAU;EAAE,CAAC,EAGnC,QAAgB;AACT,QAaL,QADgB,EAVI,CAClB;GACE,IAAI;GACJ,OAAO,EAAE,8BAA8B,gBAAgB;GACvD,MAAM;GACN,OAAO;GACP,SAAS;GACV,CACF,CAE+C;IAE/C,CAAC,GAAqB,EAAE,CAAC,EAG1B,kBAAC,GAAD;EAAqB,QAAQ;YAC3B,kBAAC,GAAD;GAAqB,aAAa;GAAM,SAAQ;GAAS,gBAAgB;aACvE,kBAAC,GAAD;IAAuB,GAAI;cAA3B,CACE,kBAAC,GAAD,EAAuB,CAAA,EACvB,kBAAC,GAAD,EAAkB,CAAA,CACI;;GACJ,CAAA;EACF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AddToLookbookButton.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/AddToLookbookButton.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAOhC,UAAU,wBAAwB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,
|
|
1
|
+
{"version":3,"file":"AddToLookbookButton.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/AddToLookbookButton.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAOhC,UAAU,wBAAwB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,CA4G5D,CAAC"}
|
|
@@ -33,6 +33,7 @@ var m = ({ lookId: m, styleItemId: h, className: g }) => {
|
|
|
33
33
|
onClick: () => S((e) => !e),
|
|
34
34
|
"aria-haspopup": "menu",
|
|
35
35
|
"aria-expanded": x,
|
|
36
|
+
"data-tour": "coolandlovely-add-to-lookbook",
|
|
36
37
|
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 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
37
38
|
children: [
|
|
38
39
|
/* @__PURE__ */ f(s, { className: "h-4 w-4" }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AddToLookbookButton.js","names":[],"sources":["../../../src/coolandlovely/components/AddToLookbookButton.tsx"],"sourcesContent":["/**\n * AddToLookbookButton — clip a look or style item into one of the caller's\n * lookbooks (cooAddLookbookEntry).\n * @module coolandlovely/components\n *\n * Exactly one of `lookId` / `styleItemId` should be provided. Opens a small\n * menu of the caller's lookbooks; picking one adds the entry. If the shopper\n * has no lookbooks yet, offers a jump to the lookbooks page.\n */\n\nimport type { FC } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { BookHeart, Check, ChevronDown, Loader2, Plus } from 'lucide-react';\nimport { useCoolAndLovely } from '../context/CoolAndLovelyContext';\nimport { useAddLookbookEntry, useLookbooks } from '../hooks/useCoolAndLovelyApi';\nimport { cn } from '../utils/cn';\n\ninterface AddToLookbookButtonProps {\n lookId?: string;\n styleItemId?: string;\n className?: string;\n}\n\nexport const AddToLookbookButton: FC<AddToLookbookButtonProps> = ({\n lookId,\n styleItemId,\n className,\n}) => {\n const { navigateTo, currentUser } = useCoolAndLovely();\n const lookbooks = useLookbooks(currentUser?.id);\n const addEntry = useAddLookbookEntry();\n const [open, setOpen] = useState(false);\n const [addedTo, setAddedTo] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!open) return;\n const onClick = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener('mousedown', onClick);\n return () => document.removeEventListener('mousedown', onClick);\n }, [open]);\n\n const boards = (lookbooks.data ?? []).filter((lb) => lb.ownerId === currentUser?.id);\n\n const handleAdd = (lookbookId: string) => {\n addEntry.mutate(\n { lookbookId, lookId, styleItemId },\n {\n onSuccess: () => {\n setAddedTo(lookbookId);\n setTimeout(() => {\n setOpen(false);\n setAddedTo(null);\n }, 900);\n },\n }\n );\n };\n\n return (\n <div ref={containerRef} className={cn('relative', className)}>\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n aria-haspopup=\"menu\"\n aria-expanded={open}\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 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <BookHeart className=\"h-4 w-4\" /> Add to lookbook\n <ChevronDown className=\"h-3.5 w-3.5\" />\n </button>\n\n {open && (\n <div\n role=\"menu\"\n className=\"absolute right-0 z-20 mt-1 w-60 overflow-hidden rounded-lg border border-border-seam bg-bg-surface shadow-lg\"\n >\n {lookbooks.isLoading ? (\n <div className=\"flex items-center gap-2 px-3 py-3 text-sm text-text-secondary\">\n <Loader2 className=\"h-4 w-4 animate-spin\" /> Loading lookbooks…\n </div>\n ) : boards.length === 0 ? (\n <button\n type=\"button\"\n onClick={() => {\n setOpen(false);\n navigateTo('/lookbooks');\n }}\n className=\"flex w-full items-center gap-2 px-3 py-3 text-left text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Plus className=\"h-4 w-4\" /> Create your first lookbook\n </button>\n ) : (\n <ul className=\"max-h-64 overflow-auto py-1\">\n {boards.map((lb) => {\n const done = addedTo === lb.id;\n return (\n <li key={lb.id}>\n <button\n type=\"button\"\n role=\"menuitem\"\n disabled={addEntry.isPending}\n onClick={() => handleAdd(lb.id)}\n className=\"flex w-full items-center justify-between gap-2 px-3 py-2 text-left text-sm text-text-primary transition-colors hover:bg-bg-sunken disabled:opacity-50\"\n >\n <span className=\"truncate\">{lb.name}</span>\n {done ? (\n <Check className=\"h-4 w-4 shrink-0 text-status-success-text\" />\n ) : addEntry.isPending ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin text-text-secondary\" />\n ) : null}\n </button>\n </li>\n );\n })}\n </ul>\n )}\n {addEntry.isError && (\n <p className=\"border-t border-border-seam px-3 py-2 text-xs text-status-error-text\">\n {addEntry.error instanceof Error ? addEntry.error.message : 'Could not add'}\n </p>\n )}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;AAuBA,IAAa,KAAqD,EAChE,WACA,gBACA,mBACI;CACJ,IAAM,EAAE,eAAY,mBAAgB,GAAkB,EAChD,IAAY,EAAa,GAAa,GAAG,EACzC,IAAW,GAAqB,EAChC,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,CAAC,GAAS,KAAc,EAAwB,KAAK,EACrD,IAAe,EAA8B,KAAK;AAExD,SAAgB;AACd,MAAI,CAAC,EAAM;EACX,IAAM,KAAW,MAAkB;AACjC,GAAI,EAAa,WAAW,CAAC,EAAa,QAAQ,SAAS,EAAE,OAAe,IAC1E,EAAQ,GAAM;;AAIlB,SADA,SAAS,iBAAiB,aAAa,EAAQ,QAClC,SAAS,oBAAoB,aAAa,EAAQ;IAC9D,CAAC,EAAK,CAAC;CAEV,IAAM,KAAU,EAAU,QAAQ,EAAE,EAAE,QAAQ,MAAO,EAAG,YAAY,GAAa,GAAG,EAE9E,KAAa,MAAuB;AACxC,IAAS,OACP;GAAE;GAAY;GAAQ;GAAa,EACnC,EACE,iBAAiB;AAEf,GADA,EAAW,EAAW,EACtB,iBAAiB;AAEf,IADA,EAAQ,GAAM,EACd,EAAW,KAAK;MACf,IAAI;KAEV,CACF;;AAGH,QACE,kBAAC,OAAD;EAAK,KAAK;EAAc,WAAW,EAAG,YAAY,EAAU;YAA5D,CACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,GAAS,MAAM,CAAC,EAAE;GACjC,iBAAc;GACd,iBAAe;GACf,WAAU;
|
|
1
|
+
{"version":3,"file":"AddToLookbookButton.js","names":[],"sources":["../../../src/coolandlovely/components/AddToLookbookButton.tsx"],"sourcesContent":["/**\n * AddToLookbookButton — clip a look or style item into one of the caller's\n * lookbooks (cooAddLookbookEntry).\n * @module coolandlovely/components\n *\n * Exactly one of `lookId` / `styleItemId` should be provided. Opens a small\n * menu of the caller's lookbooks; picking one adds the entry. If the shopper\n * has no lookbooks yet, offers a jump to the lookbooks page.\n */\n\nimport type { FC } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { BookHeart, Check, ChevronDown, Loader2, Plus } from 'lucide-react';\nimport { useCoolAndLovely } from '../context/CoolAndLovelyContext';\nimport { useAddLookbookEntry, useLookbooks } from '../hooks/useCoolAndLovelyApi';\nimport { cn } from '../utils/cn';\n\ninterface AddToLookbookButtonProps {\n lookId?: string;\n styleItemId?: string;\n className?: string;\n}\n\nexport const AddToLookbookButton: FC<AddToLookbookButtonProps> = ({\n lookId,\n styleItemId,\n className,\n}) => {\n const { navigateTo, currentUser } = useCoolAndLovely();\n const lookbooks = useLookbooks(currentUser?.id);\n const addEntry = useAddLookbookEntry();\n const [open, setOpen] = useState(false);\n const [addedTo, setAddedTo] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!open) return;\n const onClick = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener('mousedown', onClick);\n return () => document.removeEventListener('mousedown', onClick);\n }, [open]);\n\n const boards = (lookbooks.data ?? []).filter((lb) => lb.ownerId === currentUser?.id);\n\n const handleAdd = (lookbookId: string) => {\n addEntry.mutate(\n { lookbookId, lookId, styleItemId },\n {\n onSuccess: () => {\n setAddedTo(lookbookId);\n setTimeout(() => {\n setOpen(false);\n setAddedTo(null);\n }, 900);\n },\n }\n );\n };\n\n return (\n <div ref={containerRef} className={cn('relative', className)}>\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n data-tour=\"coolandlovely-add-to-lookbook\"\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 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <BookHeart className=\"h-4 w-4\" /> Add to lookbook\n <ChevronDown className=\"h-3.5 w-3.5\" />\n </button>\n\n {open && (\n <div\n role=\"menu\"\n className=\"absolute right-0 z-20 mt-1 w-60 overflow-hidden rounded-lg border border-border-seam bg-bg-surface shadow-lg\"\n >\n {lookbooks.isLoading ? (\n <div className=\"flex items-center gap-2 px-3 py-3 text-sm text-text-secondary\">\n <Loader2 className=\"h-4 w-4 animate-spin\" /> Loading lookbooks…\n </div>\n ) : boards.length === 0 ? (\n <button\n type=\"button\"\n onClick={() => {\n setOpen(false);\n navigateTo('/lookbooks');\n }}\n className=\"flex w-full items-center gap-2 px-3 py-3 text-left text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Plus className=\"h-4 w-4\" /> Create your first lookbook\n </button>\n ) : (\n <ul className=\"max-h-64 overflow-auto py-1\">\n {boards.map((lb) => {\n const done = addedTo === lb.id;\n return (\n <li key={lb.id}>\n <button\n type=\"button\"\n role=\"menuitem\"\n disabled={addEntry.isPending}\n onClick={() => handleAdd(lb.id)}\n className=\"flex w-full items-center justify-between gap-2 px-3 py-2 text-left text-sm text-text-primary transition-colors hover:bg-bg-sunken disabled:opacity-50\"\n >\n <span className=\"truncate\">{lb.name}</span>\n {done ? (\n <Check className=\"h-4 w-4 shrink-0 text-status-success-text\" />\n ) : addEntry.isPending ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin text-text-secondary\" />\n ) : null}\n </button>\n </li>\n );\n })}\n </ul>\n )}\n {addEntry.isError && (\n <p className=\"border-t border-border-seam px-3 py-2 text-xs text-status-error-text\">\n {addEntry.error instanceof Error ? addEntry.error.message : 'Could not add'}\n </p>\n )}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;AAuBA,IAAa,KAAqD,EAChE,WACA,gBACA,mBACI;CACJ,IAAM,EAAE,eAAY,mBAAgB,GAAkB,EAChD,IAAY,EAAa,GAAa,GAAG,EACzC,IAAW,GAAqB,EAChC,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,CAAC,GAAS,KAAc,EAAwB,KAAK,EACrD,IAAe,EAA8B,KAAK;AAExD,SAAgB;AACd,MAAI,CAAC,EAAM;EACX,IAAM,KAAW,MAAkB;AACjC,GAAI,EAAa,WAAW,CAAC,EAAa,QAAQ,SAAS,EAAE,OAAe,IAC1E,EAAQ,GAAM;;AAIlB,SADA,SAAS,iBAAiB,aAAa,EAAQ,QAClC,SAAS,oBAAoB,aAAa,EAAQ;IAC9D,CAAC,EAAK,CAAC;CAEV,IAAM,KAAU,EAAU,QAAQ,EAAE,EAAE,QAAQ,MAAO,EAAG,YAAY,GAAa,GAAG,EAE9E,KAAa,MAAuB;AACxC,IAAS,OACP;GAAE;GAAY;GAAQ;GAAa,EACnC,EACE,iBAAiB;AAEf,GADA,EAAW,EAAW,EACtB,iBAAiB;AAEf,IADA,EAAQ,GAAM,EACd,EAAW,KAAK;MACf,IAAI;KAEV,CACF;;AAGH,QACE,kBAAC,OAAD;EAAK,KAAK;EAAc,WAAW,EAAG,YAAY,EAAU;YAA5D,CACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,GAAS,MAAM,CAAC,EAAE;GACjC,iBAAc;GACd,iBAAe;GACf,aAAU;GACV,WAAU;aANZ;IAQE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;;IACjC,kBAAC,GAAD,EAAa,WAAU,eAAgB,CAAA;IAChC;MAER,KACC,kBAAC,OAAD;GACE,MAAK;GACL,WAAU;aAFZ,CAIG,EAAU,YACT,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,EAAA,sBACxC;QACJ,EAAO,WAAW,IACpB,kBAAC,UAAD;IACE,MAAK;IACL,eAAe;AAEb,KADA,EAAQ,GAAM,EACd,EAAW,aAAa;;IAE1B,WAAU;cANZ,CAQE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,8BACrB;QAET,kBAAC,MAAD;IAAI,WAAU;cACX,EAAO,KAAK,MAAO;KAClB,IAAM,IAAO,MAAY,EAAG;AAC5B,YACE,kBAAC,MAAD,EAAA,UACE,kBAAC,UAAD;MACE,MAAK;MACL,MAAK;MACL,UAAU,EAAS;MACnB,eAAe,EAAU,EAAG,GAAG;MAC/B,WAAU;gBALZ,CAOE,kBAAC,QAAD;OAAM,WAAU;iBAAY,EAAG;OAAY,CAAA,EAC1C,IACC,kBAAC,GAAD,EAAO,WAAU,6CAA8C,CAAA,GAC7D,EAAS,YACX,kBAAC,GAAD,EAAS,WAAU,qDAAsD,CAAA,GACvE,KACG;SACN,EAfI,EAAG,GAeP;MAEP;IACC,CAAA,EAEN,EAAS,WACR,kBAAC,KAAD;IAAG,WAAU;cACV,EAAS,iBAAiB,QAAQ,EAAS,MAAM,UAAU;IAC1D,CAAA,CAEF;KAEJ"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { CooBrand } from '../types';
|
|
3
|
+
|
|
4
|
+
interface BrandCardProps {
|
|
5
|
+
brand: CooBrand;
|
|
6
|
+
onClick?: () => void;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const BrandCard: FC<BrandCardProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=BrandCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandCard.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/BrandCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAOhC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,UAAU,cAAc;IACtB,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CAwCxC,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { cn as e } from "../utils/cn.js";
|
|
2
|
+
import { StatusBadge as t } from "./StatusBadge.js";
|
|
3
|
+
import { titleCase as n } from "../utils/formatters.js";
|
|
4
|
+
import { TagList as r } from "./TagList.js";
|
|
5
|
+
import { BrandCover as i } from "./BrandCover.js";
|
|
6
|
+
import { Star as a } from "lucide-react";
|
|
7
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
8
|
+
//#region src/coolandlovely/components/BrandCard.tsx
|
|
9
|
+
var c = ({ brand: c, onClick: l, className: u }) => /* @__PURE__ */ s("button", {
|
|
10
|
+
type: "button",
|
|
11
|
+
onClick: l,
|
|
12
|
+
"aria-label": `Open brand ${c.name}`,
|
|
13
|
+
className: e("group flex flex-col overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--color-focus-ring)]", u),
|
|
14
|
+
children: [/* @__PURE__ */ o(i, {
|
|
15
|
+
coverFileId: c.cover?.id,
|
|
16
|
+
logoFileId: c.logo?.id,
|
|
17
|
+
name: c.name,
|
|
18
|
+
seed: c.id,
|
|
19
|
+
showLogo: !0
|
|
20
|
+
}), /* @__PURE__ */ s("div", {
|
|
21
|
+
className: "px-4 pb-4 pt-3",
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ s("div", {
|
|
24
|
+
className: "flex min-h-[2.5rem] items-start justify-between gap-2 pl-20",
|
|
25
|
+
children: [/* @__PURE__ */ s("div", {
|
|
26
|
+
className: "min-w-0",
|
|
27
|
+
children: [/* @__PURE__ */ s("div", {
|
|
28
|
+
className: "flex items-center gap-1.5",
|
|
29
|
+
children: [/* @__PURE__ */ o("h3", {
|
|
30
|
+
className: "truncate text-base font-semibold text-text-primary",
|
|
31
|
+
children: c.name
|
|
32
|
+
}), c.isFeatured && /* @__PURE__ */ o(a, { className: "h-3.5 w-3.5 shrink-0 fill-status-warning-text text-status-warning-text" })]
|
|
33
|
+
}), /* @__PURE__ */ s("p", {
|
|
34
|
+
className: "truncate text-xs text-text-secondary",
|
|
35
|
+
children: ["@", c.handle]
|
|
36
|
+
})]
|
|
37
|
+
}), /* @__PURE__ */ o(t, { status: c.status })]
|
|
38
|
+
}),
|
|
39
|
+
c.tagline && /* @__PURE__ */ o("p", {
|
|
40
|
+
className: "mt-2 line-clamp-2 text-sm text-text-secondary",
|
|
41
|
+
children: c.tagline
|
|
42
|
+
}),
|
|
43
|
+
c.aesthetics.length > 0 && /* @__PURE__ */ o(r, {
|
|
44
|
+
tags: c.aesthetics.map(n),
|
|
45
|
+
max: 4,
|
|
46
|
+
className: "mt-3",
|
|
47
|
+
tone: "accent"
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
})]
|
|
51
|
+
});
|
|
52
|
+
//#endregion
|
|
53
|
+
export { c as BrandCard };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=BrandCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandCard.js","names":[],"sources":["../../../src/coolandlovely/components/BrandCard.tsx"],"sourcesContent":["/**\n * BrandCard — a clickable brand storefront card for list/grids.\n * @module coolandlovely/components\n *\n * A photographic cover with an overlapping circular logo, name, handle,\n * status badge, tagline and aesthetics. Extracted from BrandsListPage so it\n * can be rendered and tested in isolation (Storybook, tests).\n */\n\nimport type { FC } from 'react';\nimport { Star } from 'lucide-react';\nimport { BrandCover } from './BrandCover';\nimport { StatusBadge } from './StatusBadge';\nimport { TagList } from './TagList';\nimport { titleCase } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { CooBrand } from '../types';\n\ninterface BrandCardProps {\n brand: CooBrand;\n onClick?: () => void;\n className?: string;\n}\n\nexport const BrandCard: FC<BrandCardProps> = ({ brand, onClick, className }) => {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={`Open brand ${brand.name}`}\n className={cn(\n 'group flex flex-col overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--color-focus-ring)]',\n className\n )}\n >\n <BrandCover\n coverFileId={brand.cover?.id}\n logoFileId={brand.logo?.id}\n name={brand.name}\n seed={brand.id}\n showLogo\n />\n <div className=\"px-4 pb-4 pt-3\">\n <div className=\"flex min-h-[2.5rem] items-start justify-between gap-2 pl-20\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">{brand.name}</h3>\n {brand.isFeatured && (\n <Star className=\"h-3.5 w-3.5 shrink-0 fill-status-warning-text text-status-warning-text\" />\n )}\n </div>\n <p className=\"truncate text-xs text-text-secondary\">@{brand.handle}</p>\n </div>\n <StatusBadge status={brand.status} />\n </div>\n {brand.tagline && (\n <p className=\"mt-2 line-clamp-2 text-sm text-text-secondary\">{brand.tagline}</p>\n )}\n {brand.aesthetics.length > 0 && (\n <TagList tags={brand.aesthetics.map(titleCase)} max={4} className=\"mt-3\" tone=\"accent\" />\n )}\n </div>\n </button>\n );\n};\n"],"mappings":";;;;;;;;AAwBA,IAAa,KAAiC,EAAE,UAAO,YAAS,mBAE5D,kBAAC,UAAD;CACE,MAAK;CACI;CACT,cAAY,cAAc,EAAM;CAChC,WAAW,EACT,qSACA,EACD;WAPH,CASE,kBAAC,GAAD;EACE,aAAa,EAAM,OAAO;EAC1B,YAAY,EAAM,MAAM;EACxB,MAAM,EAAM;EACZ,MAAM,EAAM;EACZ,UAAA;EACA,CAAA,EACF,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAsD,EAAM;OAAU,CAAA,EACnF,EAAM,cACL,kBAAC,GAAD,EAAM,WAAU,0EAA2E,CAAA,CAEzF;SACN,kBAAC,KAAD;MAAG,WAAU;gBAAb,CAAoD,KAAE,EAAM,OAAW;QACnE;QACN,kBAAC,GAAD,EAAa,QAAQ,EAAM,QAAU,CAAA,CACjC;;GACL,EAAM,WACL,kBAAC,KAAD;IAAG,WAAU;cAAiD,EAAM;IAAY,CAAA;GAEjF,EAAM,WAAW,SAAS,KACzB,kBAAC,GAAD;IAAS,MAAM,EAAM,WAAW,IAAI,EAAU;IAAE,KAAK;IAAG,WAAU;IAAO,MAAK;IAAW,CAAA;GAEvF;IACC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { CooCollection } from '../types';
|
|
3
|
+
|
|
4
|
+
interface CollectionCardProps {
|
|
5
|
+
collection: CooCollection;
|
|
6
|
+
onClick?: () => void;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const CollectionCard: FC<CollectionCardProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=CollectionCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollectionCard.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/CollectionCard.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAOhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,UAAU,mBAAmB;IAC3B,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAyDlD,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { cn as e } from "../utils/cn.js";
|
|
2
|
+
import { StatusBadge as t } from "./StatusBadge.js";
|
|
3
|
+
import { Thumbnail as n } from "./Thumbnail.js";
|
|
4
|
+
import { formatDate as r, titleCase as i } from "../utils/formatters.js";
|
|
5
|
+
import { TagList as a } from "./TagList.js";
|
|
6
|
+
import { Shapes as o } from "lucide-react";
|
|
7
|
+
import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
8
|
+
//#region src/coolandlovely/components/CollectionCard.tsx
|
|
9
|
+
var u = ({ collection: u, onClick: d, className: f }) => /* @__PURE__ */ l("button", {
|
|
10
|
+
type: "button",
|
|
11
|
+
onClick: d,
|
|
12
|
+
"aria-label": `Open collection ${u.name}`,
|
|
13
|
+
className: e("group overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]", f),
|
|
14
|
+
children: [/* @__PURE__ */ l("div", {
|
|
15
|
+
className: "relative",
|
|
16
|
+
children: [/* @__PURE__ */ c(n, {
|
|
17
|
+
icon: /* @__PURE__ */ c(o, { className: "h-10 w-10" }),
|
|
18
|
+
seed: u.id,
|
|
19
|
+
fileId: u.cover?.id,
|
|
20
|
+
alt: u.name,
|
|
21
|
+
className: "aspect-[16/10] w-full",
|
|
22
|
+
overlay: /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c("div", { className: "pointer-events-none absolute inset-0 bg-gradient-to-t from-bg-canvas via-bg-canvas/55 to-transparent" }), /* @__PURE__ */ l("div", {
|
|
23
|
+
className: "absolute inset-x-0 bottom-0 flex items-end justify-between gap-2 p-4",
|
|
24
|
+
children: [/* @__PURE__ */ l("div", {
|
|
25
|
+
className: "min-w-0",
|
|
26
|
+
children: [/* @__PURE__ */ c("h3", {
|
|
27
|
+
className: "truncate text-lg font-semibold text-text-primary",
|
|
28
|
+
children: u.name
|
|
29
|
+
}), u.brand?.name && /* @__PURE__ */ c("p", {
|
|
30
|
+
className: "truncate text-xs text-text-secondary",
|
|
31
|
+
children: u.brand.name
|
|
32
|
+
})]
|
|
33
|
+
}), /* @__PURE__ */ c(t, {
|
|
34
|
+
status: u.status,
|
|
35
|
+
className: "shrink-0 shadow-sm"
|
|
36
|
+
})]
|
|
37
|
+
})] })
|
|
38
|
+
}), /* @__PURE__ */ c("span", {
|
|
39
|
+
className: "absolute right-3 top-3 rounded-full border border-border-seam bg-bg-surface/85 px-2.5 py-0.5 text-xs font-medium text-text-primary backdrop-blur-sm",
|
|
40
|
+
children: i(u.season)
|
|
41
|
+
})]
|
|
42
|
+
}), (u.publishAt || u.tags.length > 0) && /* @__PURE__ */ l("div", {
|
|
43
|
+
className: "p-4",
|
|
44
|
+
children: [u.publishAt && /* @__PURE__ */ l("p", {
|
|
45
|
+
className: "text-xs text-text-secondary",
|
|
46
|
+
children: ["Publishes ", r(u.publishAt, {
|
|
47
|
+
hour: void 0,
|
|
48
|
+
minute: void 0
|
|
49
|
+
})]
|
|
50
|
+
}), u.tags.length > 0 && /* @__PURE__ */ c(a, {
|
|
51
|
+
tags: u.tags,
|
|
52
|
+
max: 4,
|
|
53
|
+
className: u.publishAt ? "mt-2" : void 0
|
|
54
|
+
})]
|
|
55
|
+
})]
|
|
56
|
+
});
|
|
57
|
+
//#endregion
|
|
58
|
+
export { u as CollectionCard };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=CollectionCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollectionCard.js","names":[],"sources":["../../../src/coolandlovely/components/CollectionCard.tsx"],"sourcesContent":["/**\n * CollectionCard — a seasonal collection drop card for list/grids.\n * @module coolandlovely/components\n *\n * Cover image with a season pill, status badge, brand line, publish date and\n * tags. Extracted from CollectionsListPage for isolated rendering/tests.\n */\n\nimport type { FC } from 'react';\nimport { Shapes } from 'lucide-react';\nimport { Thumbnail } from './Thumbnail';\nimport { StatusBadge } from './StatusBadge';\nimport { TagList } from './TagList';\nimport { titleCase, formatDate } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { CooCollection } from '../types';\n\ninterface CollectionCardProps {\n collection: CooCollection;\n onClick?: () => void;\n className?: string;\n}\n\nexport const CollectionCard: FC<CollectionCardProps> = ({ collection, onClick, className }) => {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={`Open collection ${collection.name}`}\n className={cn(\n 'group overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]',\n className\n )}\n >\n <div className=\"relative\">\n <Thumbnail\n icon={<Shapes className=\"h-10 w-10\" />}\n seed={collection.id}\n fileId={collection.cover?.id}\n alt={collection.name}\n className=\"aspect-[16/10] w-full\"\n overlay={\n <>\n <div className=\"pointer-events-none absolute inset-0 bg-gradient-to-t from-bg-canvas via-bg-canvas/55 to-transparent\" />\n <div className=\"absolute inset-x-0 bottom-0 flex items-end justify-between gap-2 p-4\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-lg font-semibold text-text-primary\">\n {collection.name}\n </h3>\n {collection.brand?.name && (\n <p className=\"truncate text-xs text-text-secondary\">{collection.brand.name}</p>\n )}\n </div>\n <StatusBadge status={collection.status} className=\"shrink-0 shadow-sm\" />\n </div>\n </>\n }\n />\n <span className=\"absolute right-3 top-3 rounded-full border border-border-seam bg-bg-surface/85 px-2.5 py-0.5 text-xs font-medium text-text-primary backdrop-blur-sm\">\n {titleCase(collection.season)}\n </span>\n </div>\n {(collection.publishAt || collection.tags.length > 0) && (\n <div className=\"p-4\">\n {collection.publishAt && (\n <p className=\"text-xs text-text-secondary\">\n Publishes {formatDate(collection.publishAt, { hour: undefined, minute: undefined })}\n </p>\n )}\n {collection.tags.length > 0 && (\n <TagList\n tags={collection.tags}\n max={4}\n className={collection.publishAt ? 'mt-2' : undefined}\n />\n )}\n </div>\n )}\n </button>\n );\n};\n"],"mappings":";;;;;;;;AAuBA,IAAa,KAA2C,EAAE,eAAY,YAAS,mBAE3E,kBAAC,UAAD;CACE,MAAK;CACI;CACT,cAAY,mBAAmB,EAAW;CAC1C,WAAW,EACT,8PACA,EACD;WAPH,CASE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,aAAc,CAAA;GACtC,MAAM,EAAW;GACjB,QAAQ,EAAW,OAAO;GAC1B,KAAK,EAAW;GAChB,WAAU;GACV,SACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD,EAAK,WAAU,wGAAyG,CAAA,EACxH,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAW;MACT,CAAA,EACJ,EAAW,OAAO,QACjB,kBAAC,KAAD;MAAG,WAAU;gBAAwC,EAAW,MAAM;MAAS,CAAA,CAE7E;QACN,kBAAC,GAAD;KAAa,QAAQ,EAAW;KAAQ,WAAU;KAAuB,CAAA,CACrE;MACL,EAAA,CAAA;GAEL,CAAA,EACF,kBAAC,QAAD;GAAM,WAAU;aACb,EAAU,EAAW,OAAO;GACxB,CAAA,CACH;MACJ,EAAW,aAAa,EAAW,KAAK,SAAS,MACjD,kBAAC,OAAD;EAAK,WAAU;YAAf,CACG,EAAW,aACV,kBAAC,KAAD;GAAG,WAAU;aAAb,CAA2C,cAC9B,EAAW,EAAW,WAAW;IAAE,MAAM,KAAA;IAAW,QAAQ,KAAA;IAAW,CAAC,CACjF;MAEL,EAAW,KAAK,SAAS,KACxB,kBAAC,GAAD;GACE,MAAM,EAAW;GACjB,KAAK;GACL,WAAW,EAAW,YAAY,SAAS,KAAA;GAC3C,CAAA,CAEA;IAED"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeedbackWidget.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/FeedbackWidget.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AA6ChC,eAAO,MAAM,cAAc,EAAE,EAwJ5B,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { cn as e } from "../utils/cn.js";
|
|
2
|
+
import { TextAreaField as t } from "./Field.js";
|
|
3
|
+
import { useCallback as n, useEffect as r, useState as i } from "react";
|
|
4
|
+
import { MessageSquarePlus as a, Send as o, X as s } from "lucide-react";
|
|
5
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
6
|
+
import { GlassCard as u } from "@burdenoff/fe-libs/ui";
|
|
7
|
+
//#region src/coolandlovely/components/FeedbackWidget.tsx
|
|
8
|
+
var d = "coolandlovely-feedback-submitted-at", f = 10080 * 60 * 1e3;
|
|
9
|
+
function p() {
|
|
10
|
+
if (typeof window > "u") return !1;
|
|
11
|
+
let e = window.localStorage.getItem(d);
|
|
12
|
+
if (!e) return !1;
|
|
13
|
+
try {
|
|
14
|
+
let t = parseInt(e, 10);
|
|
15
|
+
return Date.now() - t < f;
|
|
16
|
+
} catch {
|
|
17
|
+
return !1;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function m() {
|
|
21
|
+
typeof window > "u" || window.localStorage.setItem(d, String(Date.now()));
|
|
22
|
+
}
|
|
23
|
+
function h(e) {
|
|
24
|
+
typeof window > "u" || window.dispatchEvent(new CustomEvent("coolandlovely:feedback_submitted", {
|
|
25
|
+
detail: e,
|
|
26
|
+
bubbles: !0
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
var g = () => {
|
|
30
|
+
let [d, f] = i(!1), [g, _] = i(null), [v, y] = i(""), [b, x] = i(!1), [S, C] = i(!1);
|
|
31
|
+
r(() => {
|
|
32
|
+
C(p());
|
|
33
|
+
}, []);
|
|
34
|
+
let w = n(() => {
|
|
35
|
+
f((e) => !e);
|
|
36
|
+
}, []), T = n(() => {
|
|
37
|
+
f(!1);
|
|
38
|
+
}, []), E = n(() => {
|
|
39
|
+
g !== null && (h({
|
|
40
|
+
score: g,
|
|
41
|
+
comment: v.trim(),
|
|
42
|
+
path: typeof window < "u" ? window.location.pathname : "",
|
|
43
|
+
submittedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
44
|
+
}), m(), x(!0), C(!0), window.setTimeout(() => {
|
|
45
|
+
f(!1), _(null), y(""), x(!1);
|
|
46
|
+
}, 2500));
|
|
47
|
+
}, [g, v]);
|
|
48
|
+
return S && !d ? null : /* @__PURE__ */ l("div", {
|
|
49
|
+
className: "fixed bottom-4 right-4 z-50 flex flex-col items-end gap-3",
|
|
50
|
+
children: [d && /* @__PURE__ */ l(u, {
|
|
51
|
+
className: "w-[min(92vw,360px)] overflow-hidden p-0 shadow-xl",
|
|
52
|
+
children: [/* @__PURE__ */ l("div", {
|
|
53
|
+
className: "flex items-center justify-between border-b border-border-seam px-4 py-3",
|
|
54
|
+
children: [/* @__PURE__ */ c("h2", {
|
|
55
|
+
className: "text-sm font-semibold text-text-primary",
|
|
56
|
+
children: "How is CoolAndLovely working for you?"
|
|
57
|
+
}), /* @__PURE__ */ c("button", {
|
|
58
|
+
type: "button",
|
|
59
|
+
onClick: T,
|
|
60
|
+
"aria-label": "Close feedback",
|
|
61
|
+
className: "rounded-md p-1 text-text-secondary transition-colors hover:bg-bg-surface hover:text-text-primary",
|
|
62
|
+
children: /* @__PURE__ */ c(s, {
|
|
63
|
+
className: "h-4 w-4",
|
|
64
|
+
"aria-hidden": "true"
|
|
65
|
+
})
|
|
66
|
+
})]
|
|
67
|
+
}), /* @__PURE__ */ c("div", {
|
|
68
|
+
className: "p-4",
|
|
69
|
+
children: b ? /* @__PURE__ */ l("div", {
|
|
70
|
+
className: "py-6 text-center",
|
|
71
|
+
children: [/* @__PURE__ */ c("p", {
|
|
72
|
+
className: "text-sm font-medium text-status-success-text",
|
|
73
|
+
children: "Thank you for your feedback!"
|
|
74
|
+
}), /* @__PURE__ */ c("p", {
|
|
75
|
+
className: "mt-1 text-xs text-text-secondary",
|
|
76
|
+
children: "Your input helps us improve CoolAndLovely."
|
|
77
|
+
})]
|
|
78
|
+
}) : /* @__PURE__ */ l("div", {
|
|
79
|
+
className: "space-y-4",
|
|
80
|
+
children: [
|
|
81
|
+
/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("p", {
|
|
82
|
+
className: "mb-2 text-xs font-medium text-text-secondary",
|
|
83
|
+
children: "Rate your experience (0 = not likely, 10 = very likely)"
|
|
84
|
+
}), /* @__PURE__ */ c("div", {
|
|
85
|
+
className: "flex justify-between gap-1",
|
|
86
|
+
role: "group",
|
|
87
|
+
"aria-label": "NPS score",
|
|
88
|
+
children: Array.from({ length: 11 }, (e, t) => t).map((t) => /* @__PURE__ */ c("button", {
|
|
89
|
+
type: "button",
|
|
90
|
+
onClick: () => _(t),
|
|
91
|
+
"aria-pressed": g === t,
|
|
92
|
+
className: e("flex h-8 w-7 items-center justify-center rounded-md text-xs font-medium transition-colors", g === t ? "bg-action-primary-bg text-action-primary-text" : "border border-border-seam bg-bg-surface text-text-secondary hover:border-action-primary-bg hover:text-text-primary"),
|
|
93
|
+
children: t
|
|
94
|
+
}, t))
|
|
95
|
+
})] }),
|
|
96
|
+
/* @__PURE__ */ c(t, {
|
|
97
|
+
id: "feedback-comment",
|
|
98
|
+
label: "What could be better?",
|
|
99
|
+
value: v,
|
|
100
|
+
onChange: y,
|
|
101
|
+
placeholder: "Tell us what’s working or what we should improve…",
|
|
102
|
+
rows: 3,
|
|
103
|
+
hint: "Optional — your comment is stored with your score and current page."
|
|
104
|
+
}),
|
|
105
|
+
/* @__PURE__ */ l("button", {
|
|
106
|
+
type: "button",
|
|
107
|
+
onClick: E,
|
|
108
|
+
disabled: g === null,
|
|
109
|
+
className: e("inline-flex w-full items-center justify-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors", g === null ? "cursor-not-allowed bg-bg-surface text-text-secondary" : "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90"),
|
|
110
|
+
children: [/* @__PURE__ */ c(o, {
|
|
111
|
+
className: "h-4 w-4",
|
|
112
|
+
"aria-hidden": "true"
|
|
113
|
+
}), "Submit feedback"]
|
|
114
|
+
})
|
|
115
|
+
]
|
|
116
|
+
})
|
|
117
|
+
})]
|
|
118
|
+
}), /* @__PURE__ */ c("button", {
|
|
119
|
+
type: "button",
|
|
120
|
+
onClick: w,
|
|
121
|
+
"aria-label": d ? "Close feedback" : "Give feedback",
|
|
122
|
+
"aria-expanded": d,
|
|
123
|
+
className: e("flex h-12 w-12 items-center justify-center rounded-full shadow-lg transition-transform hover:scale-105 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]", d ? "bg-bg-surface text-text-primary" : "bg-action-primary-bg text-action-primary-text"),
|
|
124
|
+
children: c(d ? s : a, {
|
|
125
|
+
className: "h-5 w-5",
|
|
126
|
+
"aria-hidden": "true"
|
|
127
|
+
})
|
|
128
|
+
})]
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
//#endregion
|
|
132
|
+
export { g as FeedbackWidget };
|
|
133
|
+
|
|
134
|
+
//# sourceMappingURL=FeedbackWidget.js.map
|