@blinkdotnew/mobile-ui 2.0.0-alpha.8 → 2.0.0
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/index.d.mts +580 -103
- package/dist/index.d.ts +580 -103
- package/dist/index.js +2731 -439
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2707 -459
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -4
package/dist/index.mjs
CHANGED
|
@@ -5,73 +5,286 @@ var blinkConfig = createTamagui({
|
|
|
5
5
|
...defaultConfig
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
+
// src/index.ts
|
|
9
|
+
import { defaultConfig as defaultConfig2 } from "@tamagui/config/v5";
|
|
10
|
+
|
|
11
|
+
// src/config/design-themes.ts
|
|
12
|
+
var BLINK_DESIGN_THEMES = {
|
|
13
|
+
"mono": {
|
|
14
|
+
id: "mono",
|
|
15
|
+
name: "Mono",
|
|
16
|
+
description: "Black/white neutral",
|
|
17
|
+
palette: { primary: "#18181B", primary_foreground: "#FAFAFA", secondary: "#F4F4F5", secondary_foreground: "#27272A", accent: "#3F3F46", background: "#FFFFFF", dark_mode: "#09090B" }
|
|
18
|
+
},
|
|
19
|
+
"ocean-teal": {
|
|
20
|
+
id: "ocean-teal",
|
|
21
|
+
name: "Ocean Teal",
|
|
22
|
+
description: "SaaS, fintech, healthcare",
|
|
23
|
+
palette: { primary: "#0D9488", primary_foreground: "#FFFFFF", secondary: "#F0FDFA", secondary_foreground: "#134E4A", accent: "#2DD4BF", background: "#FFFFFF", dark_mode: "#042F2E" }
|
|
24
|
+
},
|
|
25
|
+
"warm-amber": {
|
|
26
|
+
id: "warm-amber",
|
|
27
|
+
name: "Warm Amber",
|
|
28
|
+
description: "E-commerce, food, hospitality",
|
|
29
|
+
palette: { primary: "#D97706", primary_foreground: "#FFFFFF", secondary: "#FFFBEB", secondary_foreground: "#78350F", accent: "#FBBF24", background: "#FFFEF7", dark_mode: "#451A03" }
|
|
30
|
+
},
|
|
31
|
+
"rose-coral": {
|
|
32
|
+
id: "rose-coral",
|
|
33
|
+
name: "Rose Coral",
|
|
34
|
+
description: "Lifestyle, beauty, fashion",
|
|
35
|
+
palette: { primary: "#E11D48", primary_foreground: "#FFFFFF", secondary: "#FFF1F2", secondary_foreground: "#881337", accent: "#FB7185", background: "#FFFAFA", dark_mode: "#4C0519" }
|
|
36
|
+
},
|
|
37
|
+
"lavender": {
|
|
38
|
+
id: "lavender",
|
|
39
|
+
name: "Lavender",
|
|
40
|
+
description: "Creative, wellness, meditation",
|
|
41
|
+
palette: { primary: "#7C3AED", primary_foreground: "#FFFFFF", secondary: "#F5F3FF", secondary_foreground: "#4C1D95", accent: "#A78BFA", background: "#FEFEFF", dark_mode: "#2E1065" }
|
|
42
|
+
},
|
|
43
|
+
"glacier": {
|
|
44
|
+
id: "glacier",
|
|
45
|
+
name: "Glacier",
|
|
46
|
+
description: "Professional, corporate, analytics",
|
|
47
|
+
palette: { primary: "#0EA5E9", primary_foreground: "#FFFFFF", secondary: "#F0F9FF", secondary_foreground: "#0C4A6E", accent: "#38BDF8", background: "#FFFFFF", dark_mode: "#082F49" }
|
|
48
|
+
},
|
|
49
|
+
"forest": {
|
|
50
|
+
id: "forest",
|
|
51
|
+
name: "Forest",
|
|
52
|
+
description: "Sustainability, nature, outdoor",
|
|
53
|
+
palette: { primary: "#16A34A", primary_foreground: "#FFFFFF", secondary: "#F0FDF4", secondary_foreground: "#14532D", accent: "#4ADE80", background: "#FEFFFE", dark_mode: "#052E16" }
|
|
54
|
+
},
|
|
55
|
+
"obsidian": {
|
|
56
|
+
id: "obsidian",
|
|
57
|
+
name: "Obsidian",
|
|
58
|
+
description: "Developer tools, gaming, tech",
|
|
59
|
+
palette: { primary: "#475569", primary_foreground: "#FFFFFF", secondary: "#F1F5F9", secondary_foreground: "#1E293B", accent: "#64748B", background: "#FFFFFF", dark_mode: "#0F172A" }
|
|
60
|
+
},
|
|
61
|
+
"solar": {
|
|
62
|
+
id: "solar",
|
|
63
|
+
name: "Solar",
|
|
64
|
+
description: "Energy, optimistic, kid-friendly",
|
|
65
|
+
palette: { primary: "#CA8A04", primary_foreground: "#FFFFFF", secondary: "#FEFCE8", secondary_foreground: "#713F12", accent: "#FACC15", background: "#FFFEF5", dark_mode: "#422006" }
|
|
66
|
+
},
|
|
67
|
+
"orchid": {
|
|
68
|
+
id: "orchid",
|
|
69
|
+
name: "Orchid",
|
|
70
|
+
description: "Beauty, fashion, luxury",
|
|
71
|
+
palette: { primary: "#C026D3", primary_foreground: "#FFFFFF", secondary: "#FDF4FF", secondary_foreground: "#701A75", accent: "#E879F9", background: "#FFFEFF", dark_mode: "#4A044E" }
|
|
72
|
+
},
|
|
73
|
+
"indigo": {
|
|
74
|
+
id: "indigo",
|
|
75
|
+
name: "Indigo",
|
|
76
|
+
description: "Enterprise, fintech, trust",
|
|
77
|
+
palette: { primary: "#4F46E5", primary_foreground: "#FFFFFF", secondary: "#EEF2FF", secondary_foreground: "#312E81", accent: "#818CF8", background: "#FEFEFF", dark_mode: "#1E1B4B" }
|
|
78
|
+
},
|
|
79
|
+
"cosmic-night": {
|
|
80
|
+
id: "cosmic-night",
|
|
81
|
+
name: "Cosmic Night",
|
|
82
|
+
description: "Dark mode, futuristic, gaming",
|
|
83
|
+
palette: { primary: "#6366F1", primary_foreground: "#FFFFFF", secondary: "#1E1B4B", secondary_foreground: "#E0E7FF", accent: "#A855F7", background: "#0F0D1A", dark_mode: "#030014" }
|
|
84
|
+
},
|
|
85
|
+
"soft-pop": {
|
|
86
|
+
id: "soft-pop",
|
|
87
|
+
name: "Soft Pop",
|
|
88
|
+
description: "Playful, modern, creative",
|
|
89
|
+
palette: { primary: "#14B8A6", primary_foreground: "#FFFFFF", secondary: "#FDF2F8", secondary_foreground: "#134E4A", accent: "#F472B6", background: "#FFFBFE", dark_mode: "#0D1117" }
|
|
90
|
+
},
|
|
91
|
+
"neo-brutalism": {
|
|
92
|
+
id: "neo-brutalism",
|
|
93
|
+
name: "Neo Brutalism",
|
|
94
|
+
description: "Bold, striking, artistic",
|
|
95
|
+
palette: { primary: "#FF6B35", primary_foreground: "#000000", secondary: "#FFE66D", secondary_foreground: "#1A1A1A", accent: "#FF3366", background: "#FFFEF0", dark_mode: "#1A1A1A" }
|
|
96
|
+
},
|
|
97
|
+
"vintage-paper": {
|
|
98
|
+
id: "vintage-paper",
|
|
99
|
+
name: "Vintage Paper",
|
|
100
|
+
description: "Classic, warm, nostalgic",
|
|
101
|
+
palette: { primary: "#B45309", primary_foreground: "#FFFFFF", secondary: "#FEF3C7", secondary_foreground: "#78350F", accent: "#92400E", background: "#FFFDF7", dark_mode: "#292524" }
|
|
102
|
+
},
|
|
103
|
+
"modern-minimal": {
|
|
104
|
+
id: "modern-minimal",
|
|
105
|
+
name: "Modern Minimal",
|
|
106
|
+
description: "Clean, professional, corporate",
|
|
107
|
+
palette: { primary: "#2563EB", primary_foreground: "#FFFFFF", secondary: "#F8FAFC", secondary_foreground: "#1E40AF", accent: "#3B82F6", background: "#FFFFFF", dark_mode: "#0F172A" }
|
|
108
|
+
},
|
|
109
|
+
"bubblegum": {
|
|
110
|
+
id: "bubblegum",
|
|
111
|
+
name: "Bubblegum",
|
|
112
|
+
description: "Fun, feminine, youthful",
|
|
113
|
+
palette: { primary: "#EC4899", primary_foreground: "#FFFFFF", secondary: "#FDF4FF", secondary_foreground: "#9D174D", accent: "#F472B6", background: "#FFFBFF", dark_mode: "#500724" }
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
function hexToRgb(hex) {
|
|
117
|
+
const h = hex.replace("#", "");
|
|
118
|
+
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
|
|
119
|
+
}
|
|
120
|
+
function rgbToHex(r, g, b) {
|
|
121
|
+
return "#" + [r, g, b].map((v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0")).join("");
|
|
122
|
+
}
|
|
123
|
+
function mixColors(c1, c2, t) {
|
|
124
|
+
const [r1, g1, b1] = hexToRgb(c1);
|
|
125
|
+
const [r2, g2, b2] = hexToRgb(c2);
|
|
126
|
+
return rgbToHex(r1 + (r2 - r1) * t, g1 + (g2 - g1) * t, b1 + (b2 - b1) * t);
|
|
127
|
+
}
|
|
128
|
+
function generateLightPalette(p) {
|
|
129
|
+
return [
|
|
130
|
+
p.background,
|
|
131
|
+
p.secondary,
|
|
132
|
+
mixColors(p.secondary, p.accent, 0.15),
|
|
133
|
+
mixColors(p.secondary, p.accent, 0.3),
|
|
134
|
+
mixColors(p.accent, p.primary, 0.1),
|
|
135
|
+
mixColors(p.accent, p.primary, 0.3),
|
|
136
|
+
mixColors(p.accent, p.primary, 0.5),
|
|
137
|
+
mixColors(p.accent, p.primary, 0.7),
|
|
138
|
+
p.primary,
|
|
139
|
+
mixColors(p.primary, p.secondary_foreground, 0.3),
|
|
140
|
+
p.secondary_foreground,
|
|
141
|
+
p.dark_mode
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
function generateDarkPalette(p) {
|
|
145
|
+
return [
|
|
146
|
+
p.dark_mode,
|
|
147
|
+
mixColors(p.dark_mode, p.secondary_foreground, 0.15),
|
|
148
|
+
mixColors(p.dark_mode, p.secondary_foreground, 0.25),
|
|
149
|
+
mixColors(p.dark_mode, p.secondary_foreground, 0.35),
|
|
150
|
+
mixColors(p.secondary_foreground, p.accent, 0.2),
|
|
151
|
+
mixColors(p.secondary_foreground, p.accent, 0.4),
|
|
152
|
+
mixColors(p.secondary_foreground, p.accent, 0.6),
|
|
153
|
+
mixColors(p.accent, p.primary, 0.5),
|
|
154
|
+
p.primary,
|
|
155
|
+
p.accent,
|
|
156
|
+
mixColors(p.accent, p.primary_foreground, 0.5),
|
|
157
|
+
p.primary_foreground
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
function getBlinkThemePalettes(themeId) {
|
|
161
|
+
const theme = BLINK_DESIGN_THEMES[themeId];
|
|
162
|
+
if (!theme) throw new Error(`Unknown theme: ${themeId}`);
|
|
163
|
+
const p = theme.palette;
|
|
164
|
+
return {
|
|
165
|
+
base: {
|
|
166
|
+
light: generateLightPalette(p),
|
|
167
|
+
dark: generateDarkPalette(p)
|
|
168
|
+
},
|
|
169
|
+
accent: {
|
|
170
|
+
light: generateDarkPalette(p),
|
|
171
|
+
dark: generateLightPalette(p)
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
var BLINK_DESIGN_THEME_IDS = Object.keys(BLINK_DESIGN_THEMES);
|
|
176
|
+
function getBlinkDesignTheme(themeId) {
|
|
177
|
+
return BLINK_DESIGN_THEMES[themeId];
|
|
178
|
+
}
|
|
179
|
+
|
|
8
180
|
// src/index.ts
|
|
9
181
|
import {
|
|
10
|
-
View as
|
|
11
|
-
|
|
12
|
-
|
|
182
|
+
View as View7,
|
|
183
|
+
Stack,
|
|
184
|
+
SizableStack,
|
|
185
|
+
ThemeableStack,
|
|
186
|
+
Frame,
|
|
187
|
+
XStack as XStack44,
|
|
188
|
+
YStack as YStack49,
|
|
13
189
|
ZStack,
|
|
14
|
-
ScrollView as
|
|
15
|
-
Circle as
|
|
190
|
+
ScrollView as ScrollView6,
|
|
191
|
+
Circle as Circle12,
|
|
16
192
|
Square,
|
|
193
|
+
Spacer,
|
|
194
|
+
EnsureFlexed,
|
|
195
|
+
Group,
|
|
17
196
|
XGroup,
|
|
18
197
|
YGroup,
|
|
198
|
+
Header,
|
|
199
|
+
Footer,
|
|
200
|
+
Main,
|
|
201
|
+
Nav,
|
|
202
|
+
Article,
|
|
203
|
+
Aside,
|
|
19
204
|
H1 as H12,
|
|
20
205
|
H2 as H22,
|
|
21
206
|
H3 as H32,
|
|
22
207
|
H4 as H42,
|
|
23
208
|
H5 as H52,
|
|
24
209
|
H6 as H62,
|
|
210
|
+
Heading,
|
|
25
211
|
Paragraph,
|
|
26
|
-
SizableText as
|
|
212
|
+
SizableText as SizableText51,
|
|
27
213
|
Text,
|
|
28
214
|
Label,
|
|
29
|
-
Button as
|
|
30
|
-
Input as
|
|
215
|
+
Button as Button13,
|
|
216
|
+
Input as Input5,
|
|
31
217
|
TextArea,
|
|
32
|
-
Switch as
|
|
218
|
+
Switch as Switch3,
|
|
33
219
|
Checkbox,
|
|
34
|
-
Slider,
|
|
220
|
+
Slider as Slider2,
|
|
35
221
|
RadioGroup,
|
|
36
|
-
Select,
|
|
222
|
+
Select as Select2,
|
|
37
223
|
Fieldset,
|
|
224
|
+
Form,
|
|
38
225
|
Card as Card2,
|
|
39
226
|
Avatar as Avatar2,
|
|
40
|
-
Separator as
|
|
41
|
-
Image as
|
|
227
|
+
Separator as Separator7,
|
|
228
|
+
Image as Image9,
|
|
42
229
|
Progress,
|
|
43
230
|
Spinner as Spinner2,
|
|
44
231
|
ListItem as ListItem2,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
232
|
+
Anchor,
|
|
233
|
+
Sheet as Sheet5,
|
|
234
|
+
Dialog as Dialog2,
|
|
235
|
+
AlertDialog as AlertDialog3,
|
|
236
|
+
Popover as Popover3,
|
|
49
237
|
Tooltip,
|
|
50
238
|
TooltipSimple,
|
|
239
|
+
Portal,
|
|
240
|
+
PortalHost,
|
|
241
|
+
PortalItem,
|
|
242
|
+
PortalProvider,
|
|
51
243
|
Tabs,
|
|
52
244
|
Accordion,
|
|
53
245
|
ToggleGroup,
|
|
54
|
-
|
|
55
|
-
|
|
246
|
+
AnimatePresence,
|
|
247
|
+
Adapt as Adapt4,
|
|
56
248
|
VisuallyHidden,
|
|
57
249
|
Unspaced,
|
|
58
|
-
|
|
59
|
-
Form,
|
|
60
|
-
Theme,
|
|
250
|
+
Theme as Theme2,
|
|
61
251
|
TamaguiProvider,
|
|
62
|
-
|
|
252
|
+
TamaguiProvider as TamaguiProvider2,
|
|
253
|
+
createTamagui as createTamagui2,
|
|
254
|
+
createFont,
|
|
255
|
+
createMedia,
|
|
256
|
+
createTheme,
|
|
257
|
+
createTokens,
|
|
258
|
+
createVariable,
|
|
259
|
+
createStyledContext,
|
|
260
|
+
addTheme,
|
|
261
|
+
updateTheme,
|
|
262
|
+
replaceTheme,
|
|
263
|
+
styled as styled14,
|
|
63
264
|
withStaticProperties as withStaticProperties2,
|
|
265
|
+
isWeb,
|
|
266
|
+
isClient,
|
|
267
|
+
getConfig,
|
|
268
|
+
getToken,
|
|
269
|
+
getTokens,
|
|
270
|
+
getTokenValue,
|
|
271
|
+
composeRefs,
|
|
272
|
+
composeEventHandlers,
|
|
64
273
|
useTheme,
|
|
65
|
-
useMedia,
|
|
66
|
-
useThemeName
|
|
274
|
+
useMedia as useMedia2,
|
|
275
|
+
useThemeName,
|
|
276
|
+
useControllableState,
|
|
277
|
+
useEvent,
|
|
278
|
+
useForceUpdate,
|
|
279
|
+
useIsomorphicLayoutEffect,
|
|
280
|
+
useComposedRefs,
|
|
281
|
+
useWindowDimensions,
|
|
282
|
+
useDidFinishSSR,
|
|
283
|
+
useDebounce,
|
|
284
|
+
useDebounceValue,
|
|
285
|
+
usePresence,
|
|
286
|
+
useIsPresent
|
|
67
287
|
} from "tamagui";
|
|
68
|
-
import {
|
|
69
|
-
Toast,
|
|
70
|
-
ToastProvider,
|
|
71
|
-
ToastViewport,
|
|
72
|
-
useToastController,
|
|
73
|
-
useToastState
|
|
74
|
-
} from "@tamagui/toast";
|
|
75
288
|
|
|
76
289
|
// src/primitives/Button.tsx
|
|
77
290
|
import { Button as TamaguiButton, styled } from "tamagui";
|
|
@@ -708,26 +921,34 @@ function BlinkToggleGroup({ options, value, onValueChange, size = "md" }) {
|
|
|
708
921
|
|
|
709
922
|
// src/interface/BlinkToast.tsx
|
|
710
923
|
import { useState as useState4, useCallback, useEffect as useEffect2, createContext, useContext } from "react";
|
|
711
|
-
import { SizableText as SizableText10, YStack as YStack5 } from "tamagui";
|
|
924
|
+
import { SizableText as SizableText10, XStack as XStack6, YStack as YStack5 } from "tamagui";
|
|
712
925
|
import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
713
926
|
var ToastContext = createContext(null);
|
|
714
|
-
var
|
|
715
|
-
default: "$
|
|
716
|
-
success: "$
|
|
717
|
-
error: "$
|
|
718
|
-
warning: "$
|
|
927
|
+
var variantStyles = {
|
|
928
|
+
default: { bg: "$color3", border: "$color6", icon: "\u2139" },
|
|
929
|
+
success: { bg: "$green2", border: "$green7", icon: "\u2713" },
|
|
930
|
+
error: { bg: "$red2", border: "$red7", icon: "\u2715" },
|
|
931
|
+
warning: { bg: "$yellow2", border: "$yellow7", icon: "!" }
|
|
719
932
|
};
|
|
720
933
|
var globalToastShow = null;
|
|
721
|
-
var toast = (
|
|
722
|
-
|
|
934
|
+
var toast = (title, options) => {
|
|
935
|
+
const opts = typeof options === "string" ? { variant: options } : options;
|
|
936
|
+
if (globalToastShow) globalToastShow(title, opts);
|
|
723
937
|
else console.warn("BlinkToastProvider not mounted");
|
|
724
938
|
};
|
|
725
939
|
function BlinkToastProvider({ children }) {
|
|
726
940
|
const [toasts, setToasts] = useState4([]);
|
|
727
|
-
const show = useCallback((
|
|
941
|
+
const show = useCallback((title, options) => {
|
|
728
942
|
const id = Math.random().toString(36).slice(2, 9);
|
|
729
|
-
|
|
730
|
-
|
|
943
|
+
const entry = {
|
|
944
|
+
id,
|
|
945
|
+
title,
|
|
946
|
+
message: options?.message,
|
|
947
|
+
variant: options?.variant ?? "default",
|
|
948
|
+
duration: options?.duration ?? 3e3
|
|
949
|
+
};
|
|
950
|
+
setToasts((prev) => [...prev, entry]);
|
|
951
|
+
setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), entry.duration);
|
|
731
952
|
}, []);
|
|
732
953
|
useEffect2(() => {
|
|
733
954
|
globalToastShow = show;
|
|
@@ -735,24 +956,72 @@ function BlinkToastProvider({ children }) {
|
|
|
735
956
|
globalToastShow = null;
|
|
736
957
|
};
|
|
737
958
|
}, [show]);
|
|
959
|
+
const dismiss = useCallback((id) => {
|
|
960
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
961
|
+
}, []);
|
|
738
962
|
return /* @__PURE__ */ jsxs5(ToastContext.Provider, { value: { show }, children: [
|
|
739
963
|
children,
|
|
740
|
-
/* @__PURE__ */ jsx10(
|
|
964
|
+
/* @__PURE__ */ jsx10(
|
|
741
965
|
YStack5,
|
|
742
966
|
{
|
|
743
|
-
|
|
967
|
+
position: "absolute",
|
|
968
|
+
top: 50,
|
|
969
|
+
left: 0,
|
|
970
|
+
right: 0,
|
|
971
|
+
alignItems: "center",
|
|
972
|
+
gap: "$2",
|
|
973
|
+
pointerEvents: "box-none",
|
|
974
|
+
zIndex: 1e5,
|
|
744
975
|
paddingHorizontal: "$4",
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
976
|
+
children: toasts.map((t) => {
|
|
977
|
+
const style = variantStyles[t.variant ?? "default"];
|
|
978
|
+
return /* @__PURE__ */ jsxs5(
|
|
979
|
+
XStack6,
|
|
980
|
+
{
|
|
981
|
+
width: "100%",
|
|
982
|
+
maxWidth: 400,
|
|
983
|
+
backgroundColor: style.bg,
|
|
984
|
+
borderWidth: 1,
|
|
985
|
+
borderColor: style.border,
|
|
986
|
+
borderRadius: "$4",
|
|
987
|
+
paddingHorizontal: "$4",
|
|
988
|
+
paddingVertical: "$3",
|
|
989
|
+
gap: "$3",
|
|
990
|
+
alignItems: "flex-start",
|
|
991
|
+
enterStyle: { opacity: 0, y: -20, scale: 0.95 },
|
|
992
|
+
exitStyle: { opacity: 0, y: -20, scale: 0.95 },
|
|
993
|
+
opacity: 1,
|
|
994
|
+
y: 0,
|
|
995
|
+
scale: 1,
|
|
996
|
+
animation: "quick",
|
|
997
|
+
pointerEvents: "auto",
|
|
998
|
+
elevation: 4,
|
|
999
|
+
children: [
|
|
1000
|
+
/* @__PURE__ */ jsx10(SizableText10, { size: "$4", fontWeight: "700", marginTop: "$0.5", children: style.icon }),
|
|
1001
|
+
/* @__PURE__ */ jsxs5(YStack5, { flex: 1, gap: "$1", children: [
|
|
1002
|
+
/* @__PURE__ */ jsx10(SizableText10, { size: "$4", fontWeight: "600", color: "$color12", children: t.title }),
|
|
1003
|
+
t.message && /* @__PURE__ */ jsx10(SizableText10, { size: "$3", color: "$color10", children: t.message })
|
|
1004
|
+
] }),
|
|
1005
|
+
/* @__PURE__ */ jsx10(
|
|
1006
|
+
SizableText10,
|
|
1007
|
+
{
|
|
1008
|
+
size: "$3",
|
|
1009
|
+
color: "$color8",
|
|
1010
|
+
fontWeight: "600",
|
|
1011
|
+
pressStyle: { opacity: 0.5 },
|
|
1012
|
+
onPress: () => dismiss(t.id),
|
|
1013
|
+
cursor: "pointer",
|
|
1014
|
+
marginTop: "$0.5",
|
|
1015
|
+
children: "\u2715"
|
|
1016
|
+
}
|
|
1017
|
+
)
|
|
1018
|
+
]
|
|
1019
|
+
},
|
|
1020
|
+
t.id
|
|
1021
|
+
);
|
|
1022
|
+
})
|
|
1023
|
+
}
|
|
1024
|
+
)
|
|
756
1025
|
] });
|
|
757
1026
|
}
|
|
758
1027
|
function useBlinkToast() {
|
|
@@ -804,17 +1073,43 @@ function BlinkTooltip({ content, children, side = "top" }) {
|
|
|
804
1073
|
] });
|
|
805
1074
|
}
|
|
806
1075
|
|
|
1076
|
+
// src/interface/BrandIcons.tsx
|
|
1077
|
+
import Svg, { Path, Rect } from "react-native-svg";
|
|
1078
|
+
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1079
|
+
function GoogleLogo({ size = 20 }) {
|
|
1080
|
+
return /* @__PURE__ */ jsxs8(Svg, { width: size, height: size, viewBox: "0 0 24 24", children: [
|
|
1081
|
+
/* @__PURE__ */ jsx13(Path, { fill: "#4285F4", d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" }),
|
|
1082
|
+
/* @__PURE__ */ jsx13(Path, { fill: "#34A853", d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" }),
|
|
1083
|
+
/* @__PURE__ */ jsx13(Path, { fill: "#FBBC05", d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l3.66-2.84z" }),
|
|
1084
|
+
/* @__PURE__ */ jsx13(Path, { fill: "#EA4335", d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" })
|
|
1085
|
+
] });
|
|
1086
|
+
}
|
|
1087
|
+
function AppleLogo({ size = 20, color = "#000" }) {
|
|
1088
|
+
return /* @__PURE__ */ jsx13(Svg, { width: size, height: size, viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13(Path, { fill: color, d: "M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" }) });
|
|
1089
|
+
}
|
|
1090
|
+
function GitHubLogo({ size = 20, color = "#fff" }) {
|
|
1091
|
+
return /* @__PURE__ */ jsx13(Svg, { width: size, height: size, viewBox: "0 0 98 96", children: /* @__PURE__ */ jsx13(Path, { fillRule: "evenodd", clipRule: "evenodd", fill: color, d: "M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" }) });
|
|
1092
|
+
}
|
|
1093
|
+
function MicrosoftLogo({ size = 20 }) {
|
|
1094
|
+
return /* @__PURE__ */ jsxs8(Svg, { width: size, height: size, viewBox: "0 0 21 21", children: [
|
|
1095
|
+
/* @__PURE__ */ jsx13(Rect, { width: "10", height: "10", fill: "#F25022" }),
|
|
1096
|
+
/* @__PURE__ */ jsx13(Rect, { x: "11", width: "10", height: "10", fill: "#7FBA00" }),
|
|
1097
|
+
/* @__PURE__ */ jsx13(Rect, { y: "11", width: "10", height: "10", fill: "#00A4EF" }),
|
|
1098
|
+
/* @__PURE__ */ jsx13(Rect, { x: "11", y: "11", width: "10", height: "10", fill: "#FFB900" })
|
|
1099
|
+
] });
|
|
1100
|
+
}
|
|
1101
|
+
|
|
807
1102
|
// src/layouts/StepPageLayout.tsx
|
|
808
1103
|
import { SizableText as SizableText13, YStack as YStack7 } from "tamagui";
|
|
809
|
-
import { jsx as
|
|
1104
|
+
import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
810
1105
|
function StepPageLayout({ title, description, children, bottom }) {
|
|
811
|
-
return /* @__PURE__ */
|
|
812
|
-
/* @__PURE__ */
|
|
813
|
-
/* @__PURE__ */
|
|
814
|
-
description && /* @__PURE__ */
|
|
1106
|
+
return /* @__PURE__ */ jsxs9(YStack7, { flex: 1, padding: "$4", maxWidth: 500, marginHorizontal: "auto", width: "100%", children: [
|
|
1107
|
+
/* @__PURE__ */ jsx14(YStack7, { gap: "$5", children: /* @__PURE__ */ jsxs9(YStack7, { gap: "$2", children: [
|
|
1108
|
+
/* @__PURE__ */ jsx14(SizableText13, { size: "$8", fontWeight: "700", children: title }),
|
|
1109
|
+
description && /* @__PURE__ */ jsx14(SizableText13, { size: "$5", fontWeight: "400", color: "$color10", children: description })
|
|
815
1110
|
] }) }),
|
|
816
|
-
/* @__PURE__ */
|
|
817
|
-
bottom && /* @__PURE__ */
|
|
1111
|
+
/* @__PURE__ */ jsx14(YStack7, { paddingTop: "$5", gap: "$4", children }),
|
|
1112
|
+
bottom && /* @__PURE__ */ jsx14(YStack7, { paddingTop: "$4", children: bottom })
|
|
818
1113
|
] });
|
|
819
1114
|
}
|
|
820
1115
|
|
|
@@ -839,21 +1134,21 @@ var ScreenLayout = styled10(YStack8, {
|
|
|
839
1134
|
|
|
840
1135
|
// src/layouts/Section.tsx
|
|
841
1136
|
import { SizableText as SizableText14, YStack as YStack9 } from "tamagui";
|
|
842
|
-
import { jsx as
|
|
1137
|
+
import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
843
1138
|
function Section({ title, description, children, gap = "$3" }) {
|
|
844
|
-
return /* @__PURE__ */
|
|
845
|
-
title && /* @__PURE__ */
|
|
846
|
-
/* @__PURE__ */
|
|
847
|
-
description && /* @__PURE__ */
|
|
1139
|
+
return /* @__PURE__ */ jsxs10(YStack9, { gap, children: [
|
|
1140
|
+
title && /* @__PURE__ */ jsxs10(YStack9, { gap: "$1", children: [
|
|
1141
|
+
/* @__PURE__ */ jsx15(SizableText14, { size: "$5", fontWeight: "600", color: "$color12", children: title }),
|
|
1142
|
+
description && /* @__PURE__ */ jsx15(SizableText14, { size: "$3", color: "$color9", children: description })
|
|
848
1143
|
] }),
|
|
849
1144
|
children
|
|
850
1145
|
] });
|
|
851
1146
|
}
|
|
852
1147
|
|
|
853
1148
|
// src/layouts/ListItem.tsx
|
|
854
|
-
import { styled as styled11, SizableText as SizableText15, XStack as
|
|
855
|
-
import { jsx as
|
|
856
|
-
var ListItemFrame = styled11(
|
|
1149
|
+
import { styled as styled11, SizableText as SizableText15, XStack as XStack7, YStack as YStack10, View as View5 } from "tamagui";
|
|
1150
|
+
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1151
|
+
var ListItemFrame = styled11(XStack7, {
|
|
857
1152
|
name: "BlinkListItem",
|
|
858
1153
|
alignItems: "center",
|
|
859
1154
|
gap: "$3",
|
|
@@ -870,40 +1165,40 @@ var ListItemFrame = styled11(XStack6, {
|
|
|
870
1165
|
}
|
|
871
1166
|
});
|
|
872
1167
|
function ListItem({ icon, title, subtitle, right, onPress }) {
|
|
873
|
-
return /* @__PURE__ */
|
|
874
|
-
icon && /* @__PURE__ */
|
|
875
|
-
/* @__PURE__ */
|
|
876
|
-
/* @__PURE__ */
|
|
877
|
-
subtitle && /* @__PURE__ */
|
|
1168
|
+
return /* @__PURE__ */ jsxs11(ListItemFrame, { pressable: !!onPress, onPress, children: [
|
|
1169
|
+
icon && /* @__PURE__ */ jsx16(View5, { children: icon }),
|
|
1170
|
+
/* @__PURE__ */ jsxs11(YStack10, { flex: 1, gap: "$1", children: [
|
|
1171
|
+
/* @__PURE__ */ jsx16(SizableText15, { size: "$4", fontWeight: "500", color: "$color12", children: title }),
|
|
1172
|
+
subtitle && /* @__PURE__ */ jsx16(SizableText15, { size: "$2", color: "$color9", children: subtitle })
|
|
878
1173
|
] }),
|
|
879
1174
|
right
|
|
880
1175
|
] });
|
|
881
1176
|
}
|
|
882
1177
|
|
|
883
1178
|
// src/layouts/Divider.tsx
|
|
884
|
-
import { Separator as Separator3, SizableText as SizableText16, XStack as
|
|
885
|
-
import { jsx as
|
|
1179
|
+
import { Separator as Separator3, SizableText as SizableText16, XStack as XStack8 } from "tamagui";
|
|
1180
|
+
import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
886
1181
|
function Divider({ label }) {
|
|
887
|
-
if (!label) return /* @__PURE__ */
|
|
888
|
-
return /* @__PURE__ */
|
|
889
|
-
/* @__PURE__ */
|
|
890
|
-
/* @__PURE__ */
|
|
891
|
-
/* @__PURE__ */
|
|
1182
|
+
if (!label) return /* @__PURE__ */ jsx17(Separator3, { borderColor: "$color4" });
|
|
1183
|
+
return /* @__PURE__ */ jsxs12(XStack8, { alignItems: "center", gap: "$3", children: [
|
|
1184
|
+
/* @__PURE__ */ jsx17(Separator3, { flex: 1, borderColor: "$color4" }),
|
|
1185
|
+
/* @__PURE__ */ jsx17(SizableText16, { size: "$2", color: "$color9", children: label }),
|
|
1186
|
+
/* @__PURE__ */ jsx17(Separator3, { flex: 1, borderColor: "$color4" })
|
|
892
1187
|
] });
|
|
893
1188
|
}
|
|
894
1189
|
|
|
895
1190
|
// src/layouts/KeyboardStickyFooter.tsx
|
|
896
1191
|
import { YStack as YStack11 } from "tamagui";
|
|
897
|
-
import { jsx as
|
|
1192
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
898
1193
|
function KeyboardStickyFooter({ children, offset }) {
|
|
899
|
-
return /* @__PURE__ */
|
|
1194
|
+
return /* @__PURE__ */ jsx18(YStack11, { maxWidth: 500, alignSelf: "center", paddingTop: "$8", paddingBottom: "$4", style: { paddingBottom: offset }, children });
|
|
900
1195
|
}
|
|
901
1196
|
|
|
902
1197
|
// src/layouts/SafeArea.tsx
|
|
903
1198
|
import { YStack as YStack12 } from "tamagui";
|
|
904
|
-
import { jsx as
|
|
1199
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
905
1200
|
function SafeArea({ children, edges = ["top", "bottom"] }) {
|
|
906
|
-
return /* @__PURE__ */
|
|
1201
|
+
return /* @__PURE__ */ jsx19(
|
|
907
1202
|
YStack12,
|
|
908
1203
|
{
|
|
909
1204
|
flex: 1,
|
|
@@ -919,159 +1214,357 @@ function SafeArea({ children, edges = ["top", "bottom"] }) {
|
|
|
919
1214
|
|
|
920
1215
|
// src/layouts/Grid.tsx
|
|
921
1216
|
import { Children } from "react";
|
|
922
|
-
import { XStack as
|
|
923
|
-
import { jsx as
|
|
1217
|
+
import { XStack as XStack9, YStack as YStack13 } from "tamagui";
|
|
1218
|
+
import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
924
1219
|
function Grid({ children, columns = 2, gap = "$3" }) {
|
|
925
1220
|
const items = Children.toArray(children);
|
|
926
1221
|
const rows = [];
|
|
927
1222
|
for (let i = 0; i < items.length; i += columns) {
|
|
928
1223
|
rows.push(items.slice(i, i + columns));
|
|
929
1224
|
}
|
|
930
|
-
return /* @__PURE__ */
|
|
931
|
-
row.map((item, ci) => /* @__PURE__ */
|
|
932
|
-
row.length < columns && Array.from({ length: columns - row.length }).map((_, i) => /* @__PURE__ */
|
|
1225
|
+
return /* @__PURE__ */ jsx20(YStack13, { gap, children: rows.map((row, ri) => /* @__PURE__ */ jsxs13(XStack9, { gap, children: [
|
|
1226
|
+
row.map((item, ci) => /* @__PURE__ */ jsx20(YStack13, { flex: 1, children: item }, ci)),
|
|
1227
|
+
row.length < columns && Array.from({ length: columns - row.length }).map((_, i) => /* @__PURE__ */ jsx20(YStack13, { flex: 1 }, `pad-${i}`))
|
|
933
1228
|
] }, ri)) });
|
|
934
1229
|
}
|
|
935
1230
|
function Container({ children, maxWidth = 500, centered = true, padding = "$4" }) {
|
|
936
|
-
return /* @__PURE__ */
|
|
1231
|
+
return /* @__PURE__ */ jsx20(YStack13, { width: "100%", maxWidth, alignSelf: centered ? "center" : void 0, padding, children });
|
|
937
1232
|
}
|
|
938
1233
|
|
|
939
1234
|
// src/patterns/PaywallScreen.tsx
|
|
940
|
-
import {
|
|
941
|
-
import {
|
|
1235
|
+
import { useState as useState5, useEffect as useEffect3 } from "react";
|
|
1236
|
+
import { Button as Button3, Circle as Circle2, SizableText as SizableText17, XStack as XStack10, YStack as YStack14, ScrollView as ScrollView2 } from "tamagui";
|
|
1237
|
+
import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1238
|
+
function useCountdown(minutes) {
|
|
1239
|
+
const [seconds, setSeconds] = useState5((minutes ?? 0) * 60);
|
|
1240
|
+
useEffect3(() => {
|
|
1241
|
+
if (!minutes) return;
|
|
1242
|
+
setSeconds(minutes * 60);
|
|
1243
|
+
const id = setInterval(() => setSeconds((s) => s > 0 ? s - 1 : 0), 1e3);
|
|
1244
|
+
return () => clearInterval(id);
|
|
1245
|
+
}, [minutes]);
|
|
1246
|
+
const mm = String(Math.floor(seconds / 60)).padStart(2, "0");
|
|
1247
|
+
const ss = String(seconds % 60).padStart(2, "0");
|
|
1248
|
+
return { display: `${mm}:${ss}`, expired: seconds <= 0 };
|
|
1249
|
+
}
|
|
1250
|
+
function normalizeFeature(f) {
|
|
1251
|
+
return typeof f === "string" ? { title: f } : f;
|
|
1252
|
+
}
|
|
1253
|
+
function BenefitRow({ feature, tone, muted }) {
|
|
1254
|
+
const f = normalizeFeature(feature);
|
|
1255
|
+
return /* @__PURE__ */ jsxs14(XStack10, { gap: "$3", alignItems: "center", children: [
|
|
1256
|
+
/* @__PURE__ */ jsx21(Circle2, { size: 40, backgroundColor: "$color3", children: f.icon ?? /* @__PURE__ */ jsx21(SizableText17, { size: "$5", color: "$color9", children: "\u2726" }) }),
|
|
1257
|
+
/* @__PURE__ */ jsxs14(YStack14, { flex: 1, gap: "$0.5", children: [
|
|
1258
|
+
/* @__PURE__ */ jsx21(SizableText17, { size: "$4", fontWeight: "700", color: tone, children: f.title }),
|
|
1259
|
+
f.description ? /* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: muted, children: f.description }) : null
|
|
1260
|
+
] })
|
|
1261
|
+
] });
|
|
1262
|
+
}
|
|
1263
|
+
function PlanRow({ plan, selected, onPress }) {
|
|
1264
|
+
return /* @__PURE__ */ jsxs14(
|
|
1265
|
+
XStack10,
|
|
1266
|
+
{
|
|
1267
|
+
width: "100%",
|
|
1268
|
+
padding: "$3",
|
|
1269
|
+
paddingHorizontal: "$3.5",
|
|
1270
|
+
borderRadius: "$5",
|
|
1271
|
+
borderWidth: 2,
|
|
1272
|
+
borderColor: selected ? "$color9" : "$color5",
|
|
1273
|
+
backgroundColor: selected ? "$color3" : "$color1",
|
|
1274
|
+
pressStyle: { scale: 0.98, opacity: 0.9 },
|
|
1275
|
+
animation: "quick",
|
|
1276
|
+
onPress,
|
|
1277
|
+
cursor: "pointer",
|
|
1278
|
+
alignItems: "center",
|
|
1279
|
+
gap: "$3",
|
|
1280
|
+
position: "relative",
|
|
1281
|
+
children: [
|
|
1282
|
+
plan.popular && /* @__PURE__ */ jsx21(YStack14, { position: "absolute", top: -10, right: 12, backgroundColor: "$color9", paddingHorizontal: "$2", paddingVertical: 2, borderRadius: "$10", children: /* @__PURE__ */ jsx21(SizableText17, { size: "$1", color: "white", fontWeight: "700", children: "BEST VALUE" }) }),
|
|
1283
|
+
/* @__PURE__ */ jsx21(Circle2, { size: 22, borderWidth: 2, borderColor: selected ? "$color9" : "$color7", backgroundColor: selected ? "$color9" : "transparent", children: selected && /* @__PURE__ */ jsx21(Circle2, { size: 8, backgroundColor: "white" }) }),
|
|
1284
|
+
/* @__PURE__ */ jsxs14(YStack14, { flex: 1, gap: "$0.5", children: [
|
|
1285
|
+
/* @__PURE__ */ jsxs14(XStack10, { gap: "$2", alignItems: "center", children: [
|
|
1286
|
+
/* @__PURE__ */ jsx21(SizableText17, { size: "$4", fontWeight: "700", children: plan.name }),
|
|
1287
|
+
plan.trial && /* @__PURE__ */ jsx21(YStack14, { backgroundColor: "$green3", paddingHorizontal: "$1.5", paddingVertical: 2, borderRadius: "$10", children: /* @__PURE__ */ jsx21(SizableText17, { size: "$1", color: "$green9", fontWeight: "700", children: plan.trial }) })
|
|
1288
|
+
] }),
|
|
1289
|
+
plan.tagline ? /* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: "$color10", children: plan.tagline }) : null
|
|
1290
|
+
] }),
|
|
1291
|
+
/* @__PURE__ */ jsxs14(YStack14, { alignItems: "flex-end", gap: "$0.5", children: [
|
|
1292
|
+
/* @__PURE__ */ jsxs14(XStack10, { alignItems: "baseline", gap: "$1", children: [
|
|
1293
|
+
/* @__PURE__ */ jsx21(SizableText17, { size: "$5", fontWeight: "800", children: plan.price }),
|
|
1294
|
+
/* @__PURE__ */ jsxs14(SizableText17, { size: "$2", color: "$color10", children: [
|
|
1295
|
+
"/",
|
|
1296
|
+
plan.period
|
|
1297
|
+
] })
|
|
1298
|
+
] }),
|
|
1299
|
+
plan.savings && /* @__PURE__ */ jsx21(YStack14, { backgroundColor: "$green3", paddingHorizontal: "$1.5", paddingVertical: 1, borderRadius: "$10", children: /* @__PURE__ */ jsx21(SizableText17, { size: "$1", color: "$green9", fontWeight: "700", children: plan.savings }) }),
|
|
1300
|
+
plan.pricePerWeek && /* @__PURE__ */ jsx21(SizableText17, { size: "$1", color: "$color10", children: plan.pricePerWeek })
|
|
1301
|
+
] })
|
|
1302
|
+
]
|
|
1303
|
+
}
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
function ComparisonIcon({ enabled }) {
|
|
1307
|
+
return /* @__PURE__ */ jsx21(Circle2, { size: 24, backgroundColor: enabled ? "$green3" : "$color4", children: /* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: enabled ? "$green10" : "$color8", fontWeight: "700", children: enabled ? "\u2713" : "\u2715" }) });
|
|
1308
|
+
}
|
|
1309
|
+
function TestimonialCard({ t }) {
|
|
1310
|
+
return /* @__PURE__ */ jsxs14(YStack14, { minWidth: 240, backgroundColor: "$color2", borderRadius: "$6", padding: "$3.5", gap: "$2.5", children: [
|
|
1311
|
+
/* @__PURE__ */ jsxs14(SizableText17, { size: "$3", color: "$color11", fontStyle: "italic", children: [
|
|
1312
|
+
"\u201C",
|
|
1313
|
+
t.quote,
|
|
1314
|
+
"\u201D"
|
|
1315
|
+
] }),
|
|
1316
|
+
/* @__PURE__ */ jsxs14(XStack10, { gap: "$2", alignItems: "center", children: [
|
|
1317
|
+
/* @__PURE__ */ jsx21(Circle2, { size: 32, backgroundColor: "$color5", children: /* @__PURE__ */ jsx21(SizableText17, { size: "$2", fontWeight: "700", children: t.author[0] }) }),
|
|
1318
|
+
/* @__PURE__ */ jsxs14(YStack14, { children: [
|
|
1319
|
+
/* @__PURE__ */ jsx21(SizableText17, { size: "$2", fontWeight: "700", children: t.author }),
|
|
1320
|
+
t.meta ? /* @__PURE__ */ jsx21(SizableText17, { size: "$1", color: "$color10", children: t.meta }) : null
|
|
1321
|
+
] })
|
|
1322
|
+
] })
|
|
1323
|
+
] });
|
|
1324
|
+
}
|
|
1325
|
+
function CreatorHeader({ c }) {
|
|
1326
|
+
return /* @__PURE__ */ jsxs14(XStack10, { alignItems: "center", justifyContent: "center", gap: "$3", children: [
|
|
1327
|
+
c.avatar && /* @__PURE__ */ jsx21(Circle2, { size: 72, overflow: "hidden", backgroundColor: "$color3", children: c.avatar }),
|
|
1328
|
+
/* @__PURE__ */ jsxs14(YStack14, { alignItems: "center", gap: "$1", children: [
|
|
1329
|
+
/* @__PURE__ */ jsx21(SizableText17, { size: "$6", fontWeight: "800", children: c.name }),
|
|
1330
|
+
c.meta ? /* @__PURE__ */ jsx21(SizableText17, { size: "$3", color: "$color10", children: c.meta }) : null
|
|
1331
|
+
] })
|
|
1332
|
+
] });
|
|
1333
|
+
}
|
|
1334
|
+
function TrustBadges({ badges }) {
|
|
1335
|
+
return /* @__PURE__ */ jsx21(XStack10, { justifyContent: "center", gap: "$4", paddingTop: "$1", children: badges.map((b, i) => /* @__PURE__ */ jsxs14(YStack14, { alignItems: "center", gap: "$1", children: [
|
|
1336
|
+
/* @__PURE__ */ jsx21(Circle2, { size: 28, backgroundColor: "$color3", children: b.icon ?? /* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: "$color9", children: "\u2726" }) }),
|
|
1337
|
+
/* @__PURE__ */ jsx21(SizableText17, { size: "$1", color: "$color10", textAlign: "center", children: b.label })
|
|
1338
|
+
] }, i)) });
|
|
1339
|
+
}
|
|
942
1340
|
function PaywallScreen({
|
|
943
|
-
|
|
944
|
-
|
|
1341
|
+
variant = "default",
|
|
1342
|
+
eyebrow,
|
|
1343
|
+
title = "Unlock Premium",
|
|
1344
|
+
subtitle,
|
|
1345
|
+
features = [],
|
|
945
1346
|
plans,
|
|
946
1347
|
selectedPlan,
|
|
947
1348
|
onSelectPlan,
|
|
948
1349
|
onContinue,
|
|
1350
|
+
onClose,
|
|
949
1351
|
onRestore,
|
|
950
|
-
|
|
1352
|
+
onTerms,
|
|
1353
|
+
onPrivacy,
|
|
1354
|
+
continueLabel = "Continue",
|
|
1355
|
+
reassurance = "Cancel anytime",
|
|
1356
|
+
hero,
|
|
1357
|
+
socialProof,
|
|
1358
|
+
countdownMinutes,
|
|
1359
|
+
badge,
|
|
1360
|
+
comparisonRows = [],
|
|
1361
|
+
testimonials = [],
|
|
1362
|
+
creator,
|
|
1363
|
+
topSlot,
|
|
1364
|
+
footerSlot,
|
|
1365
|
+
trustBadges
|
|
951
1366
|
}) {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1367
|
+
const selected = selectedPlan ?? plans.find((p) => p.popular)?.id ?? plans[0]?.id;
|
|
1368
|
+
const countdown = useCountdown(countdownMinutes);
|
|
1369
|
+
const dark = variant === "immersive-dark";
|
|
1370
|
+
const bg = dark ? "$color1" : "$background";
|
|
1371
|
+
const tone = dark ? "$color12" : "$color11";
|
|
1372
|
+
const muted = "$color10";
|
|
1373
|
+
return /* @__PURE__ */ jsxs14(YStack14, { flex: 1, backgroundColor: bg, children: [
|
|
1374
|
+
onClose && /* @__PURE__ */ jsx21(XStack10, { position: "absolute", top: "$4", right: "$4", zIndex: 10, children: /* @__PURE__ */ jsx21(Button3, { size: "$3", circular: true, chromeless: true, onPress: onClose, pressStyle: { opacity: 0.6 }, children: /* @__PURE__ */ jsx21(SizableText17, { size: "$5", color: muted, children: "\u2715" }) }) }),
|
|
1375
|
+
/* @__PURE__ */ jsx21(ScrollView2, { flex: 1, contentContainerStyle: { paddingBottom: 240 }, children: /* @__PURE__ */ jsxs14(YStack14, { paddingHorizontal: "$5", paddingTop: "$8", gap: "$5", children: [
|
|
1376
|
+
topSlot,
|
|
1377
|
+
creator && variant === "creator-sheet" ? /* @__PURE__ */ jsx21(CreatorHeader, { c: creator }) : null,
|
|
1378
|
+
hero && /* @__PURE__ */ jsx21(YStack14, { alignItems: "center", paddingVertical: "$3", children: hero }),
|
|
1379
|
+
badge && /* @__PURE__ */ jsx21(XStack10, { justifyContent: "center", children: /* @__PURE__ */ jsx21(YStack14, { backgroundColor: "$color9", paddingHorizontal: "$3", paddingVertical: "$1", borderRadius: "$10", children: /* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: "white", fontWeight: "700", children: badge }) }) }),
|
|
1380
|
+
/* @__PURE__ */ jsxs14(YStack14, { gap: "$1.5", alignItems: "center", children: [
|
|
1381
|
+
eyebrow ? /* @__PURE__ */ jsx21(SizableText17, { size: "$2", fontWeight: "700", color: "$color9", textTransform: "uppercase", children: eyebrow }) : null,
|
|
1382
|
+
/* @__PURE__ */ jsx21(SizableText17, { size: "$9", fontWeight: "800", textAlign: "center", color: tone, children: title }),
|
|
1383
|
+
subtitle && /* @__PURE__ */ jsx21(SizableText17, { size: "$4", color: muted, textAlign: "center", children: subtitle }),
|
|
1384
|
+
socialProof && /* @__PURE__ */ jsx21(SizableText17, { size: "$3", color: "$color9", fontWeight: "600", textAlign: "center", paddingTop: "$1", children: socialProof })
|
|
1385
|
+
] }),
|
|
1386
|
+
countdownMinutes && !countdown.expired ? /* @__PURE__ */ jsxs14(XStack10, { justifyContent: "center", padding: "$2", backgroundColor: "$red3", borderRadius: "$4", alignSelf: "center", paddingHorizontal: "$4", gap: "$2", alignItems: "center", children: [
|
|
1387
|
+
/* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: "$red9", fontWeight: "600", children: "Offer ends in" }),
|
|
1388
|
+
/* @__PURE__ */ jsx21(SizableText17, { size: "$5", color: "$red9", fontWeight: "800", fontFamily: "$mono", children: countdown.display })
|
|
1389
|
+
] }) : null,
|
|
1390
|
+
features.length > 0 && /* @__PURE__ */ jsx21(YStack14, { gap: "$3.5", children: features.map((feature, i) => /* @__PURE__ */ jsx21(BenefitRow, { feature, tone, muted }, i)) }),
|
|
1391
|
+
variant === "social-proof" && testimonials.length > 0 ? /* @__PURE__ */ jsx21(ScrollView2, { horizontal: true, showsHorizontalScrollIndicator: false, children: /* @__PURE__ */ jsx21(XStack10, { gap: "$3", paddingRight: "$4", children: testimonials.map((t, i) => /* @__PURE__ */ jsx21(TestimonialCard, { t }, `${t.author}-${i}`)) }) }) : null,
|
|
1392
|
+
variant === "comparison" && comparisonRows.length > 0 ? /* @__PURE__ */ jsxs14(YStack14, { backgroundColor: dark ? "$color2" : "$color1", borderRadius: "$6", padding: "$3.5", gap: "$2", borderWidth: 1, borderColor: "$color4", children: [
|
|
1393
|
+
/* @__PURE__ */ jsxs14(XStack10, { alignItems: "center", children: [
|
|
1394
|
+
/* @__PURE__ */ jsx21(SizableText17, { flex: 1, size: "$2", fontWeight: "700", color: muted, children: "Feature" }),
|
|
1395
|
+
/* @__PURE__ */ jsx21(SizableText17, { width: 64, size: "$2", fontWeight: "700", textAlign: "center", color: muted, children: "Free" }),
|
|
1396
|
+
/* @__PURE__ */ jsx21(SizableText17, { width: 84, size: "$2", fontWeight: "700", textAlign: "center", color: "$color9", children: "Premium" })
|
|
1397
|
+
] }),
|
|
1398
|
+
comparisonRows.map((row) => /* @__PURE__ */ jsxs14(XStack10, { alignItems: "center", paddingVertical: "$1.5", children: [
|
|
1399
|
+
/* @__PURE__ */ jsx21(SizableText17, { flex: 1, size: "$3", color: tone, children: row.label }),
|
|
1400
|
+
/* @__PURE__ */ jsx21(XStack10, { width: 64, justifyContent: "center", children: /* @__PURE__ */ jsx21(ComparisonIcon, { enabled: row.free }) }),
|
|
1401
|
+
/* @__PURE__ */ jsx21(XStack10, { width: 84, justifyContent: "center", children: /* @__PURE__ */ jsx21(ComparisonIcon, { enabled: row.premium }) })
|
|
1402
|
+
] }, row.label))
|
|
1403
|
+
] }) : null,
|
|
1404
|
+
/* @__PURE__ */ jsx21(YStack14, { gap: "$3", children: plans.map((plan) => /* @__PURE__ */ jsx21(
|
|
1405
|
+
PlanRow,
|
|
1406
|
+
{
|
|
1407
|
+
plan,
|
|
1408
|
+
selected: selected === plan.id,
|
|
1409
|
+
onPress: () => onSelectPlan?.(plan.id)
|
|
1410
|
+
},
|
|
1411
|
+
plan.id
|
|
1412
|
+
)) })
|
|
1413
|
+
] }) }),
|
|
1414
|
+
/* @__PURE__ */ jsxs14(
|
|
958
1415
|
YStack14,
|
|
959
1416
|
{
|
|
1417
|
+
position: "absolute",
|
|
1418
|
+
bottom: 0,
|
|
1419
|
+
left: 0,
|
|
1420
|
+
right: 0,
|
|
960
1421
|
padding: "$4",
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
onPress: () => onSelectPlan?.(plan.id),
|
|
967
|
-
cursor: "pointer",
|
|
1422
|
+
paddingBottom: "$6",
|
|
1423
|
+
backgroundColor: bg,
|
|
1424
|
+
borderTopWidth: 1,
|
|
1425
|
+
borderTopColor: "$color4",
|
|
1426
|
+
gap: "$2.5",
|
|
968
1427
|
children: [
|
|
969
|
-
/* @__PURE__ */
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1428
|
+
/* @__PURE__ */ jsx21(
|
|
1429
|
+
Button3,
|
|
1430
|
+
{
|
|
1431
|
+
size: "$5",
|
|
1432
|
+
backgroundColor: "$color9",
|
|
1433
|
+
color: "$color1",
|
|
1434
|
+
onPress: onContinue,
|
|
1435
|
+
pressStyle: { backgroundColor: "$color8", scale: 0.98 },
|
|
1436
|
+
animation: "quick",
|
|
1437
|
+
borderRadius: "$10",
|
|
1438
|
+
fontWeight: "700",
|
|
1439
|
+
children: continueLabel
|
|
1440
|
+
}
|
|
1441
|
+
),
|
|
1442
|
+
reassurance && /* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: "$color9", textAlign: "center", children: reassurance }),
|
|
1443
|
+
/* @__PURE__ */ jsxs14(XStack10, { justifyContent: "center", gap: "$3", children: [
|
|
1444
|
+
onRestore && /* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: "$color8", onPress: onRestore, pressStyle: { opacity: 0.6 }, children: "Restore" }),
|
|
1445
|
+
onTerms && /* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: "$color8", onPress: onTerms, pressStyle: { opacity: 0.6 }, children: "Terms" }),
|
|
1446
|
+
onPrivacy && /* @__PURE__ */ jsx21(SizableText17, { size: "$2", color: "$color8", onPress: onPrivacy, pressStyle: { opacity: 0.6 }, children: "Privacy" })
|
|
981
1447
|
] }),
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
/* @__PURE__ */ jsx20(SizableText17, { size: "$3", color: "$color11", children: feature })
|
|
985
|
-
] }, i)) })
|
|
1448
|
+
trustBadges && trustBadges.length > 0 && /* @__PURE__ */ jsx21(TrustBadges, { badges: trustBadges }),
|
|
1449
|
+
footerSlot
|
|
986
1450
|
]
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
)) }),
|
|
990
|
-
/* @__PURE__ */ jsxs13(YStack14, { gap: "$3", paddingBottom: "$4", children: [
|
|
991
|
-
/* @__PURE__ */ jsx20(
|
|
992
|
-
Button3,
|
|
993
|
-
{
|
|
994
|
-
size: "$5",
|
|
995
|
-
backgroundColor: "$color9",
|
|
996
|
-
color: "$color1",
|
|
997
|
-
onPress: onContinue,
|
|
998
|
-
hoverStyle: { backgroundColor: "$color10" },
|
|
999
|
-
pressStyle: { backgroundColor: "$color8" },
|
|
1000
|
-
borderRadius: "$5",
|
|
1001
|
-
children: continueLabel
|
|
1002
|
-
}
|
|
1003
|
-
),
|
|
1004
|
-
onRestore && /* @__PURE__ */ jsx20(Button3, { size: "$3", chromeless: true, onPress: onRestore, children: /* @__PURE__ */ jsx20(SizableText17, { size: "$3", color: "$color9", children: "Restore Purchases" }) })
|
|
1005
|
-
] })
|
|
1451
|
+
}
|
|
1452
|
+
)
|
|
1006
1453
|
] });
|
|
1007
1454
|
}
|
|
1008
1455
|
|
|
1009
1456
|
// src/patterns/OnboardingCarousel.tsx
|
|
1010
|
-
import { useState as
|
|
1011
|
-
import { Button as Button4, SizableText as SizableText18, XStack as
|
|
1012
|
-
import { jsx as
|
|
1457
|
+
import { useState as useState6 } from "react";
|
|
1458
|
+
import { Button as Button4, SizableText as SizableText18, XStack as XStack11, YStack as YStack15, Circle as Circle3 } from "tamagui";
|
|
1459
|
+
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1013
1460
|
function OnboardingCarousel({
|
|
1014
1461
|
steps,
|
|
1462
|
+
variant = "default",
|
|
1463
|
+
brand,
|
|
1464
|
+
topLeading,
|
|
1015
1465
|
onComplete,
|
|
1016
1466
|
onSkip,
|
|
1017
1467
|
completeLabel = "Get Started",
|
|
1018
1468
|
skipLabel = "Skip",
|
|
1019
|
-
nextLabel = "Next"
|
|
1469
|
+
nextLabel = "Next",
|
|
1470
|
+
footerSlot
|
|
1020
1471
|
}) {
|
|
1021
|
-
const [current, setCurrent] =
|
|
1472
|
+
const [current, setCurrent] = useState6(0);
|
|
1473
|
+
if (steps.length === 0) {
|
|
1474
|
+
return /* @__PURE__ */ jsx22(YStack15, { flex: 1, backgroundColor: "$background", padding: "$4", alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsx22(SizableText18, { size: "$5", color: "$color10", textAlign: "center", children: "Add at least one onboarding step." }) });
|
|
1475
|
+
}
|
|
1022
1476
|
const isLast = current === steps.length - 1;
|
|
1023
1477
|
const step = steps[current];
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1478
|
+
const hero = step?.hero ?? step?.icon;
|
|
1479
|
+
const isEditorial = variant === "editorial";
|
|
1480
|
+
const isSelection = variant === "selection-step";
|
|
1481
|
+
const isPermission = variant === "permission-prompt";
|
|
1482
|
+
const topPadding = isEditorial ? "$6" : "$4";
|
|
1483
|
+
const titleSize = isEditorial ? "$10" : "$9";
|
|
1484
|
+
const backgroundColor = variant === "calm-gradient" ? "$color2" : "$background";
|
|
1485
|
+
const heroBackground = isPermission ? "$color3" : isSelection ? "$color1" : "$color2";
|
|
1486
|
+
const heroRadius = variant === "card-tilt" || isSelection ? "$8" : "$10";
|
|
1487
|
+
const buttonTone = variant === "editorial" ? "$color12" : "$color9";
|
|
1488
|
+
return /* @__PURE__ */ jsxs15(YStack15, { flex: 1, backgroundColor, padding: "$4", justifyContent: "space-between", children: [
|
|
1489
|
+
step?.background ? /* @__PURE__ */ jsx22(YStack15, { position: "absolute", left: 0, right: 0, top: 0, bottom: 0, children: step.background }) : null,
|
|
1490
|
+
/* @__PURE__ */ jsxs15(XStack11, { justifyContent: "space-between", alignItems: "center", paddingTop: topPadding, children: [
|
|
1491
|
+
/* @__PURE__ */ jsx22(XStack11, { minWidth: 40, children: topLeading }),
|
|
1492
|
+
brand ? /* @__PURE__ */ jsx22(YStack15, { alignItems: "center", flex: 1, children: brand }) : /* @__PURE__ */ jsx22(YStack15, { flex: 1 }),
|
|
1493
|
+
!isLast && onSkip && /* @__PURE__ */ jsx22(Button4, { chromeless: true, onPress: onSkip, children: /* @__PURE__ */ jsx22(SizableText18, { size: "$4", color: "$color9", children: skipLabel }) })
|
|
1494
|
+
] }),
|
|
1495
|
+
/* @__PURE__ */ jsxs15(YStack15, { flex: 1, alignItems: "center", justifyContent: "center", gap: "$5", paddingHorizontal: "$4", children: [
|
|
1496
|
+
hero ? variant === "card-tilt" || isSelection ? /* @__PURE__ */ jsx22(
|
|
1497
|
+
YStack15,
|
|
1498
|
+
{
|
|
1499
|
+
width: "100%",
|
|
1500
|
+
maxWidth: 340,
|
|
1501
|
+
minHeight: 260,
|
|
1502
|
+
borderRadius: heroRadius,
|
|
1503
|
+
backgroundColor: heroBackground,
|
|
1504
|
+
padding: "$3",
|
|
1505
|
+
alignItems: "center",
|
|
1506
|
+
justifyContent: "center",
|
|
1507
|
+
borderWidth: variant === "card-tilt" ? 3 : 1,
|
|
1508
|
+
borderColor: "$color4",
|
|
1509
|
+
shadowColor: "$shadowColor",
|
|
1510
|
+
shadowOpacity: 0.14,
|
|
1511
|
+
shadowRadius: 18,
|
|
1512
|
+
shadowOffset: { width: 0, height: 10 },
|
|
1513
|
+
style: variant === "card-tilt" ? { transform: [{ rotate: "-5deg" }] } : void 0,
|
|
1514
|
+
children: hero
|
|
1515
|
+
}
|
|
1516
|
+
) : /* @__PURE__ */ jsx22(Circle3, { size: isPermission ? 140 : 120, backgroundColor: heroBackground, alignItems: "center", justifyContent: "center", children: hero }) : null,
|
|
1517
|
+
/* @__PURE__ */ jsxs15(YStack15, { gap: "$3", alignItems: "center", children: [
|
|
1518
|
+
step?.eyebrow ? /* @__PURE__ */ jsx22(SizableText18, { size: "$2", color: "$color9", fontWeight: "700", textTransform: "uppercase", children: step.eyebrow }) : null,
|
|
1519
|
+
/* @__PURE__ */ jsx22(SizableText18, { size: titleSize, fontWeight: "700", textAlign: "center", children: step?.title }),
|
|
1520
|
+
/* @__PURE__ */ jsx22(SizableText18, { size: "$4", color: "$color10", textAlign: "center", maxWidth: 300, children: step?.description })
|
|
1031
1521
|
] })
|
|
1032
1522
|
] }),
|
|
1033
|
-
/* @__PURE__ */
|
|
1034
|
-
/* @__PURE__ */
|
|
1523
|
+
/* @__PURE__ */ jsxs15(YStack15, { gap: "$3", paddingBottom: "$2", children: [
|
|
1524
|
+
/* @__PURE__ */ jsx22(XStack11, { justifyContent: "center", gap: "$2", children: steps.map((_, i) => /* @__PURE__ */ jsx22(
|
|
1035
1525
|
Circle3,
|
|
1036
1526
|
{
|
|
1037
|
-
size: 8,
|
|
1527
|
+
size: variant === "card-tilt" ? 10 : 8,
|
|
1528
|
+
width: i === current && variant !== "default" ? 24 : void 0,
|
|
1038
1529
|
backgroundColor: i === current ? "$color9" : "$color4",
|
|
1530
|
+
borderRadius: "$10",
|
|
1039
1531
|
animation: "quick"
|
|
1040
1532
|
},
|
|
1041
1533
|
i
|
|
1042
1534
|
)) }),
|
|
1043
|
-
/* @__PURE__ */
|
|
1535
|
+
/* @__PURE__ */ jsx22(
|
|
1044
1536
|
Button4,
|
|
1045
1537
|
{
|
|
1046
1538
|
size: "$5",
|
|
1047
|
-
backgroundColor:
|
|
1539
|
+
backgroundColor: buttonTone,
|
|
1048
1540
|
color: "$color1",
|
|
1049
|
-
borderRadius: "$5",
|
|
1050
|
-
hoverStyle: { backgroundColor: "$color10" },
|
|
1541
|
+
borderRadius: variant === "editorial" ? "$10" : "$5",
|
|
1542
|
+
hoverStyle: { backgroundColor: variant === "editorial" ? "$color11" : "$color10" },
|
|
1051
1543
|
pressStyle: { backgroundColor: "$color8" },
|
|
1052
1544
|
onPress: () => isLast ? onComplete?.() : setCurrent((c) => c + 1),
|
|
1053
|
-
children: isLast ? completeLabel : nextLabel
|
|
1545
|
+
children: isLast ? step?.ctaLabel ?? completeLabel : step?.ctaLabel ?? nextLabel
|
|
1054
1546
|
}
|
|
1055
|
-
)
|
|
1547
|
+
),
|
|
1548
|
+
footerSlot
|
|
1056
1549
|
] })
|
|
1057
1550
|
] });
|
|
1058
1551
|
}
|
|
1059
1552
|
|
|
1060
1553
|
// src/patterns/ChatBubble.tsx
|
|
1061
|
-
import { SizableText as SizableText19, XStack as
|
|
1062
|
-
import { jsx as
|
|
1554
|
+
import { SizableText as SizableText19, XStack as XStack12, YStack as YStack16, Circle as Circle4, Image as Image3 } from "tamagui";
|
|
1555
|
+
import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1063
1556
|
function ChatBubble({ message, showAvatar = true }) {
|
|
1064
1557
|
const isUser = message.sender === "user";
|
|
1065
|
-
return /* @__PURE__ */
|
|
1066
|
-
|
|
1558
|
+
return /* @__PURE__ */ jsxs16(
|
|
1559
|
+
XStack12,
|
|
1067
1560
|
{
|
|
1068
1561
|
alignSelf: isUser ? "flex-end" : "flex-start",
|
|
1069
1562
|
maxWidth: "75%",
|
|
1070
1563
|
gap: "$2",
|
|
1071
1564
|
flexDirection: isUser ? "row-reverse" : "row",
|
|
1072
1565
|
children: [
|
|
1073
|
-
showAvatar && !isUser && /* @__PURE__ */
|
|
1074
|
-
/* @__PURE__ */
|
|
1566
|
+
showAvatar && !isUser && /* @__PURE__ */ jsx23(Circle4, { size: 32, backgroundColor: "$color4", overflow: "hidden", children: message.avatar ? /* @__PURE__ */ jsx23(Image3, { source: { uri: message.avatar }, width: 32, height: 32, objectFit: "cover" }) : /* @__PURE__ */ jsx23(SizableText19, { size: "$2", fontWeight: "600", color: "$color11", children: message.senderName?.[0]?.toUpperCase() ?? "?" }) }),
|
|
1567
|
+
/* @__PURE__ */ jsxs16(
|
|
1075
1568
|
YStack16,
|
|
1076
1569
|
{
|
|
1077
1570
|
backgroundColor: isUser ? "$color9" : "$color3",
|
|
@@ -1082,8 +1575,8 @@ function ChatBubble({ message, showAvatar = true }) {
|
|
|
1082
1575
|
borderBottomLeftRadius: isUser ? "$5" : "$2",
|
|
1083
1576
|
gap: "$1",
|
|
1084
1577
|
children: [
|
|
1085
|
-
/* @__PURE__ */
|
|
1086
|
-
message.timestamp && /* @__PURE__ */
|
|
1578
|
+
/* @__PURE__ */ jsx23(SizableText19, { size: "$3", color: isUser ? "$color1" : "$color12", children: message.text }),
|
|
1579
|
+
message.timestamp && /* @__PURE__ */ jsx23(SizableText19, { size: "$1", color: isUser ? "$color3" : "$color9", alignSelf: "flex-end", children: message.timestamp })
|
|
1087
1580
|
]
|
|
1088
1581
|
}
|
|
1089
1582
|
)
|
|
@@ -1093,11 +1586,11 @@ function ChatBubble({ message, showAvatar = true }) {
|
|
|
1093
1586
|
}
|
|
1094
1587
|
|
|
1095
1588
|
// src/patterns/SettingsScreen.tsx
|
|
1096
|
-
import { Separator as Separator4, SizableText as SizableText20, Switch, XStack as
|
|
1097
|
-
import { jsx as
|
|
1589
|
+
import { Separator as Separator4, SizableText as SizableText20, Switch, XStack as XStack13, YStack as YStack17 } from "tamagui";
|
|
1590
|
+
import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1098
1591
|
function SettingsItemRow({ item }) {
|
|
1099
|
-
return /* @__PURE__ */
|
|
1100
|
-
|
|
1592
|
+
return /* @__PURE__ */ jsxs17(
|
|
1593
|
+
XStack13,
|
|
1101
1594
|
{
|
|
1102
1595
|
alignItems: "center",
|
|
1103
1596
|
gap: "$3",
|
|
@@ -1108,21 +1601,21 @@ function SettingsItemRow({ item }) {
|
|
|
1108
1601
|
onPress: item.onPress,
|
|
1109
1602
|
cursor: item.onPress ? "pointer" : void 0,
|
|
1110
1603
|
children: [
|
|
1111
|
-
item.icon && /* @__PURE__ */
|
|
1112
|
-
/* @__PURE__ */
|
|
1113
|
-
/* @__PURE__ */
|
|
1114
|
-
item.subtitle && /* @__PURE__ */
|
|
1604
|
+
item.icon && /* @__PURE__ */ jsx24(YStack17, { width: 24, alignItems: "center", children: item.icon }),
|
|
1605
|
+
/* @__PURE__ */ jsxs17(YStack17, { flex: 1, gap: "$1", children: [
|
|
1606
|
+
/* @__PURE__ */ jsx24(SizableText20, { size: "$4", fontWeight: "500", children: item.title }),
|
|
1607
|
+
item.subtitle && /* @__PURE__ */ jsx24(SizableText20, { size: "$2", color: "$color9", children: item.subtitle })
|
|
1115
1608
|
] }),
|
|
1116
|
-
item.type === "toggle" ? /* @__PURE__ */
|
|
1609
|
+
item.type === "toggle" ? /* @__PURE__ */ jsx24(Switch, { size: "$3", checked: item.value, onCheckedChange: item.onValueChange, children: /* @__PURE__ */ jsx24(Switch.Thumb, { animation: "quick" }) }) : item.right ? item.right : item.onPress && /* @__PURE__ */ jsx24(SizableText20, { size: "$5", color: "$color8", children: "\u203A" })
|
|
1117
1610
|
]
|
|
1118
1611
|
}
|
|
1119
1612
|
);
|
|
1120
1613
|
}
|
|
1121
1614
|
function SettingsScreen({ sections, header }) {
|
|
1122
|
-
return /* @__PURE__ */
|
|
1615
|
+
return /* @__PURE__ */ jsxs17(YStack17, { flex: 1, backgroundColor: "$background", children: [
|
|
1123
1616
|
header,
|
|
1124
|
-
/* @__PURE__ */
|
|
1125
|
-
section.title && /* @__PURE__ */
|
|
1617
|
+
/* @__PURE__ */ jsx24(YStack17, { gap: "$4", paddingVertical: "$2", children: sections.map((section, si) => /* @__PURE__ */ jsxs17(YStack17, { children: [
|
|
1618
|
+
section.title && /* @__PURE__ */ jsx24(
|
|
1126
1619
|
SizableText20,
|
|
1127
1620
|
{
|
|
1128
1621
|
size: "$2",
|
|
@@ -1134,9 +1627,9 @@ function SettingsScreen({ sections, header }) {
|
|
|
1134
1627
|
children: section.title
|
|
1135
1628
|
}
|
|
1136
1629
|
),
|
|
1137
|
-
/* @__PURE__ */
|
|
1138
|
-
/* @__PURE__ */
|
|
1139
|
-
ii < section.items.length - 1 && /* @__PURE__ */
|
|
1630
|
+
/* @__PURE__ */ jsx24(YStack17, { backgroundColor: "$color1", borderRadius: "$4", marginHorizontal: "$3", overflow: "hidden", children: section.items.map((item, ii) => /* @__PURE__ */ jsxs17(YStack17, { children: [
|
|
1631
|
+
/* @__PURE__ */ jsx24(SettingsItemRow, { item }),
|
|
1632
|
+
ii < section.items.length - 1 && /* @__PURE__ */ jsx24(Separator4, { borderColor: "$color3", marginLeft: "$12" })
|
|
1140
1633
|
] }, item.id)) })
|
|
1141
1634
|
] }, si)) })
|
|
1142
1635
|
] });
|
|
@@ -1144,15 +1637,15 @@ function SettingsScreen({ sections, header }) {
|
|
|
1144
1637
|
|
|
1145
1638
|
// src/patterns/EmptyState.tsx
|
|
1146
1639
|
import { Button as Button5, SizableText as SizableText21, YStack as YStack18 } from "tamagui";
|
|
1147
|
-
import { jsx as
|
|
1640
|
+
import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1148
1641
|
function EmptyState({ icon, title, description, actionLabel, onAction }) {
|
|
1149
|
-
return /* @__PURE__ */
|
|
1642
|
+
return /* @__PURE__ */ jsxs18(YStack18, { flex: 1, alignItems: "center", justifyContent: "center", gap: "$4", padding: "$6", children: [
|
|
1150
1643
|
icon,
|
|
1151
|
-
/* @__PURE__ */
|
|
1152
|
-
/* @__PURE__ */
|
|
1153
|
-
description && /* @__PURE__ */
|
|
1644
|
+
/* @__PURE__ */ jsxs18(YStack18, { gap: "$2", alignItems: "center", children: [
|
|
1645
|
+
/* @__PURE__ */ jsx25(SizableText21, { size: "$6", fontWeight: "600", textAlign: "center", children: title }),
|
|
1646
|
+
description && /* @__PURE__ */ jsx25(SizableText21, { size: "$4", color: "$color9", textAlign: "center", maxWidth: 280, children: description })
|
|
1154
1647
|
] }),
|
|
1155
|
-
actionLabel && onAction && /* @__PURE__ */
|
|
1648
|
+
actionLabel && onAction && /* @__PURE__ */ jsx25(
|
|
1156
1649
|
Button5,
|
|
1157
1650
|
{
|
|
1158
1651
|
size: "$4",
|
|
@@ -1169,46 +1662,46 @@ function EmptyState({ icon, title, description, actionLabel, onAction }) {
|
|
|
1169
1662
|
}
|
|
1170
1663
|
|
|
1171
1664
|
// src/patterns/ProfileHeader.tsx
|
|
1172
|
-
import { Circle as Circle5, Image as Image4, SizableText as SizableText22, XStack as
|
|
1173
|
-
import { jsx as
|
|
1665
|
+
import { Circle as Circle5, Image as Image4, SizableText as SizableText22, XStack as XStack14, YStack as YStack19 } from "tamagui";
|
|
1666
|
+
import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1174
1667
|
function ProfileHeader({ name, subtitle, avatar, stats, actions }) {
|
|
1175
|
-
return /* @__PURE__ */
|
|
1176
|
-
/* @__PURE__ */
|
|
1177
|
-
/* @__PURE__ */
|
|
1178
|
-
/* @__PURE__ */
|
|
1179
|
-
subtitle && /* @__PURE__ */
|
|
1668
|
+
return /* @__PURE__ */ jsxs19(YStack19, { alignItems: "center", gap: "$4", paddingVertical: "$6", paddingHorizontal: "$4", children: [
|
|
1669
|
+
/* @__PURE__ */ jsx26(Circle5, { size: 80, backgroundColor: "$color4", overflow: "hidden", children: avatar ? /* @__PURE__ */ jsx26(Image4, { source: { uri: avatar }, width: 80, height: 80, objectFit: "cover" }) : /* @__PURE__ */ jsx26(SizableText22, { size: "$9", fontWeight: "700", color: "$color11", children: name[0]?.toUpperCase() ?? "?" }) }),
|
|
1670
|
+
/* @__PURE__ */ jsxs19(YStack19, { alignItems: "center", gap: "$1", children: [
|
|
1671
|
+
/* @__PURE__ */ jsx26(SizableText22, { size: "$7", fontWeight: "700", children: name }),
|
|
1672
|
+
subtitle && /* @__PURE__ */ jsx26(SizableText22, { size: "$4", color: "$color10", children: subtitle })
|
|
1180
1673
|
] }),
|
|
1181
|
-
stats && stats.length > 0 && /* @__PURE__ */
|
|
1182
|
-
/* @__PURE__ */
|
|
1183
|
-
/* @__PURE__ */
|
|
1674
|
+
stats && stats.length > 0 && /* @__PURE__ */ jsx26(XStack14, { gap: "$6", children: stats.map((stat, i) => /* @__PURE__ */ jsxs19(YStack19, { alignItems: "center", gap: "$1", children: [
|
|
1675
|
+
/* @__PURE__ */ jsx26(SizableText22, { size: "$6", fontWeight: "700", children: stat.value }),
|
|
1676
|
+
/* @__PURE__ */ jsx26(SizableText22, { size: "$2", color: "$color9", children: stat.label })
|
|
1184
1677
|
] }, i)) }),
|
|
1185
1678
|
actions
|
|
1186
1679
|
] });
|
|
1187
1680
|
}
|
|
1188
1681
|
|
|
1189
1682
|
// src/patterns/AppHeader.tsx
|
|
1190
|
-
import { SizableText as SizableText23, XStack as
|
|
1191
|
-
import { jsx as
|
|
1683
|
+
import { SizableText as SizableText23, XStack as XStack15, YStack as YStack20 } from "tamagui";
|
|
1684
|
+
import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1192
1685
|
function AppHeader({ title, subtitle, variant = "simple", onBack, avatar, left, right, transparent, borderless }) {
|
|
1193
1686
|
const leftContent = (() => {
|
|
1194
|
-
if (variant === "back") return /* @__PURE__ */
|
|
1195
|
-
if (variant === "profile") return /* @__PURE__ */
|
|
1687
|
+
if (variant === "back") return /* @__PURE__ */ jsx27(SizableText23, { size: "$6", paddingRight: "$2", onPress: onBack, pressStyle: { opacity: 0.6 }, cursor: "pointer", children: "\u2039" });
|
|
1688
|
+
if (variant === "profile") return /* @__PURE__ */ jsx27(Avatar, { uri: avatar, name: title, size: "sm" });
|
|
1196
1689
|
if (variant === "centered") return left ?? null;
|
|
1197
1690
|
return null;
|
|
1198
1691
|
})();
|
|
1199
1692
|
const rightContent = variant === "profile" || variant === "centered" ? right ?? null : null;
|
|
1200
|
-
return /* @__PURE__ */
|
|
1693
|
+
return /* @__PURE__ */ jsx27(
|
|
1201
1694
|
YStack20,
|
|
1202
1695
|
{
|
|
1203
1696
|
paddingTop: "$6",
|
|
1204
1697
|
backgroundColor: transparent ? "transparent" : "$background",
|
|
1205
1698
|
borderBottomWidth: borderless ? 0 : 1,
|
|
1206
1699
|
borderBottomColor: "$borderColor",
|
|
1207
|
-
children: /* @__PURE__ */
|
|
1700
|
+
children: /* @__PURE__ */ jsxs20(XStack15, { height: 56, alignItems: "center", paddingHorizontal: "$4", gap: "$3", children: [
|
|
1208
1701
|
leftContent,
|
|
1209
|
-
/* @__PURE__ */
|
|
1210
|
-
/* @__PURE__ */
|
|
1211
|
-
subtitle && /* @__PURE__ */
|
|
1702
|
+
/* @__PURE__ */ jsxs20(YStack20, { flex: 1, alignItems: variant === "centered" ? "center" : "flex-start", children: [
|
|
1703
|
+
/* @__PURE__ */ jsx27(SizableText23, { size: "$6", fontWeight: "700", numberOfLines: 1, children: title }),
|
|
1704
|
+
subtitle && /* @__PURE__ */ jsx27(SizableText23, { size: "$2", color: "$color9", numberOfLines: 1, children: subtitle })
|
|
1212
1705
|
] }),
|
|
1213
1706
|
rightContent
|
|
1214
1707
|
] })
|
|
@@ -1217,107 +1710,183 @@ function AppHeader({ title, subtitle, variant = "simple", onBack, avatar, left,
|
|
|
1217
1710
|
}
|
|
1218
1711
|
|
|
1219
1712
|
// src/patterns/BottomSheet.tsx
|
|
1220
|
-
import { Sheet, SizableText as SizableText24, XStack as
|
|
1221
|
-
import { ScrollView as
|
|
1222
|
-
import { jsx as
|
|
1223
|
-
function BottomSheet({ open, onOpenChange, title, children, snapPoints = [85], dismissOnSnapToBottom = true, showHandle = true, showClose = false }) {
|
|
1224
|
-
return /* @__PURE__ */
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1713
|
+
import { Sheet, SizableText as SizableText24, XStack as XStack16, YStack as YStack21 } from "tamagui";
|
|
1714
|
+
import { ScrollView as ScrollView3 } from "react-native";
|
|
1715
|
+
import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1716
|
+
function BottomSheet({ open, onOpenChange, title, children, snapPoints = [85], dismissOnSnapToBottom = true, showHandle = true, showClose = false, zIndex = 1e5 }) {
|
|
1717
|
+
return /* @__PURE__ */ jsxs21(
|
|
1718
|
+
Sheet,
|
|
1719
|
+
{
|
|
1720
|
+
modal: true,
|
|
1721
|
+
forceRemoveScrollEnabled: open,
|
|
1722
|
+
open,
|
|
1723
|
+
onOpenChange,
|
|
1724
|
+
snapPoints,
|
|
1725
|
+
dismissOnSnapToBottom,
|
|
1726
|
+
zIndex,
|
|
1727
|
+
animation: "medium",
|
|
1728
|
+
children: [
|
|
1729
|
+
/* @__PURE__ */ jsx28(Sheet.Overlay, { animation: "lazy", enterStyle: { opacity: 0 }, exitStyle: { opacity: 0 } }),
|
|
1730
|
+
showHandle && /* @__PURE__ */ jsx28(Sheet.Handle, {}),
|
|
1731
|
+
/* @__PURE__ */ jsxs21(Sheet.Frame, { children: [
|
|
1732
|
+
(title || showClose) && /* @__PURE__ */ jsxs21(XStack16, { paddingHorizontal: "$4", paddingTop: "$3", paddingBottom: "$2", alignItems: "center", justifyContent: "space-between", children: [
|
|
1733
|
+
/* @__PURE__ */ jsx28(SizableText24, { size: "$6", fontWeight: "600", flexShrink: 1, children: title }),
|
|
1734
|
+
showClose && /* @__PURE__ */ jsx28(
|
|
1735
|
+
XStack16,
|
|
1736
|
+
{
|
|
1737
|
+
width: 28,
|
|
1738
|
+
height: 28,
|
|
1739
|
+
borderRadius: "$10",
|
|
1740
|
+
backgroundColor: "$color4",
|
|
1741
|
+
alignItems: "center",
|
|
1742
|
+
justifyContent: "center",
|
|
1743
|
+
pressStyle: { opacity: 0.7 },
|
|
1744
|
+
onPress: () => onOpenChange(false),
|
|
1745
|
+
children: /* @__PURE__ */ jsx28(SizableText24, { size: "$3", color: "$color10", fontWeight: "600", children: "\u2715" })
|
|
1746
|
+
}
|
|
1747
|
+
)
|
|
1748
|
+
] }),
|
|
1749
|
+
/* @__PURE__ */ jsx28(ScrollView3, { contentContainerStyle: { paddingBottom: 40 }, children: /* @__PURE__ */ jsx28(YStack21, { padding: "$4", children }) })
|
|
1750
|
+
] })
|
|
1751
|
+
]
|
|
1752
|
+
}
|
|
1753
|
+
);
|
|
1248
1754
|
}
|
|
1249
1755
|
|
|
1250
1756
|
// src/patterns/LoginScreen.tsx
|
|
1251
|
-
import { useState as
|
|
1252
|
-
import { Button as Button6, SizableText as SizableText25, Spinner, XStack as
|
|
1253
|
-
import { jsx as
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1757
|
+
import { useState as useState7 } from "react";
|
|
1758
|
+
import { Button as Button6, Circle as Circle6, SizableText as SizableText25, Spinner, XStack as XStack17, YStack as YStack22 } from "tamagui";
|
|
1759
|
+
import { Fragment as Fragment2, jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1760
|
+
var BRAND_ICON_MAP = {
|
|
1761
|
+
google: ({ size }) => /* @__PURE__ */ jsx29(GoogleLogo, { size }),
|
|
1762
|
+
apple: ({ size, color }) => /* @__PURE__ */ jsx29(AppleLogo, { size, color }),
|
|
1763
|
+
github: ({ size, color }) => /* @__PURE__ */ jsx29(GitHubLogo, { size, color }),
|
|
1764
|
+
microsoft: ({ size }) => /* @__PURE__ */ jsx29(MicrosoftLogo, { size }),
|
|
1765
|
+
custom: ({ size = 20 }) => /* @__PURE__ */ jsx29(Circle6, { size, backgroundColor: "$color4", alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsx29(SizableText25, { fontSize: size * 0.6, color: "$color10", children: "\u2022" }) })
|
|
1766
|
+
};
|
|
1767
|
+
var BRAND_STYLES = {
|
|
1768
|
+
google: { backgroundColor: "$color1", borderColor: "$color5", textColor: "$color12" },
|
|
1769
|
+
apple: { backgroundColor: "$color12", borderColor: "$color12", textColor: "$color1" },
|
|
1770
|
+
github: { backgroundColor: "$color12", borderColor: "$color12", textColor: "$color1" },
|
|
1771
|
+
microsoft: { backgroundColor: "$color1", borderColor: "$color5", textColor: "$color12" },
|
|
1772
|
+
custom: { backgroundColor: "$color1", borderColor: "$color5", textColor: "$color12" }
|
|
1773
|
+
};
|
|
1774
|
+
function ProviderBadge({ provider }) {
|
|
1775
|
+
const brand = provider.brand ?? "custom";
|
|
1776
|
+
if (provider.icon) return /* @__PURE__ */ jsx29(Fragment2, { children: provider.icon });
|
|
1777
|
+
const renderIcon = BRAND_ICON_MAP[brand];
|
|
1778
|
+
const iconColor = brand === "apple" || brand === "github" ? "#fff" : void 0;
|
|
1779
|
+
return renderIcon({ size: 20, color: iconColor });
|
|
1780
|
+
}
|
|
1781
|
+
function LoginScreen({
|
|
1782
|
+
variant = "default",
|
|
1783
|
+
title = "Welcome",
|
|
1784
|
+
subtitle = "Sign in to continue",
|
|
1785
|
+
logo,
|
|
1786
|
+
providers = [],
|
|
1787
|
+
hero,
|
|
1788
|
+
backgroundSlot,
|
|
1789
|
+
footerSlot,
|
|
1790
|
+
providerButtonStyle = "brand",
|
|
1791
|
+
onProviderPress,
|
|
1792
|
+
showEmailForm,
|
|
1793
|
+
onEmailSubmit,
|
|
1794
|
+
onForgotPassword,
|
|
1795
|
+
onCreateAccount,
|
|
1796
|
+
onTerms,
|
|
1797
|
+
onPrivacy,
|
|
1798
|
+
loading
|
|
1799
|
+
}) {
|
|
1800
|
+
const [email, setEmail] = useState7("");
|
|
1801
|
+
const [password, setPassword] = useState7("");
|
|
1802
|
+
const isEditorial = variant === "editorial";
|
|
1803
|
+
const isCenteredCard = variant === "centered-card";
|
|
1804
|
+
return /* @__PURE__ */ jsxs22(YStack22, { flex: 1, padding: "$4", gap: "$5", backgroundColor: "$background", justifyContent: "center", children: [
|
|
1805
|
+
backgroundSlot ? /* @__PURE__ */ jsx29(YStack22, { position: "absolute", left: 0, right: 0, top: 0, bottom: 0, children: backgroundSlot }) : null,
|
|
1806
|
+
/* @__PURE__ */ jsxs22(
|
|
1807
|
+
YStack22,
|
|
1265
1808
|
{
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1809
|
+
gap: "$5",
|
|
1810
|
+
backgroundColor: isCenteredCard ? "$color1" : "transparent",
|
|
1811
|
+
borderRadius: isCenteredCard ? "$7" : void 0,
|
|
1812
|
+
padding: isCenteredCard ? "$4" : void 0,
|
|
1813
|
+
borderWidth: isCenteredCard ? 1 : 0,
|
|
1814
|
+
borderColor: isCenteredCard ? "$color4" : void 0,
|
|
1815
|
+
children: [
|
|
1816
|
+
/* @__PURE__ */ jsxs22(YStack22, { alignItems: "center", gap: "$2", children: [
|
|
1817
|
+
logo && /* @__PURE__ */ jsx29(YStack22, { paddingBottom: "$3", children: logo }),
|
|
1818
|
+
hero ? /* @__PURE__ */ jsx29(YStack22, { paddingBottom: "$2", children: hero }) : null,
|
|
1819
|
+
/* @__PURE__ */ jsx29(SizableText25, { size: isEditorial ? "$10" : "$9", fontWeight: "700", textAlign: "center", fontFamily: isEditorial ? "$heading" : void 0, children: title }),
|
|
1820
|
+
/* @__PURE__ */ jsx29(SizableText25, { size: "$4", color: "$color10", textAlign: "center", children: subtitle })
|
|
1821
|
+
] }),
|
|
1822
|
+
providers.length > 0 && /* @__PURE__ */ jsx29(YStack22, { gap: "$2.5", children: providers.map((p) => /* @__PURE__ */ jsx29(
|
|
1823
|
+
Button6,
|
|
1824
|
+
{
|
|
1825
|
+
size: "$5",
|
|
1826
|
+
borderWidth: 1.5,
|
|
1827
|
+
borderColor: providerButtonStyle === "brand" ? BRAND_STYLES[p.brand ?? "custom"].borderColor : "$color5",
|
|
1828
|
+
backgroundColor: providerButtonStyle === "brand" ? BRAND_STYLES[p.brand ?? "custom"].backgroundColor : "$color1",
|
|
1829
|
+
borderRadius: isEditorial ? "$6" : "$4",
|
|
1830
|
+
disabled: loading,
|
|
1831
|
+
onPress: () => onProviderPress?.(p.id),
|
|
1832
|
+
hoverStyle: { backgroundColor: providerButtonStyle === "brand" ? BRAND_STYLES[p.brand ?? "custom"].backgroundColor : "$color2" },
|
|
1833
|
+
pressStyle: { backgroundColor: "$color3" },
|
|
1834
|
+
children: /* @__PURE__ */ jsxs22(XStack17, { alignItems: "center", justifyContent: "space-between", width: "100%", gap: "$2", children: [
|
|
1835
|
+
/* @__PURE__ */ jsxs22(XStack17, { alignItems: "center", gap: "$2.5", children: [
|
|
1836
|
+
/* @__PURE__ */ jsx29(ProviderBadge, { provider: p }),
|
|
1837
|
+
/* @__PURE__ */ jsxs22(YStack22, { alignItems: "flex-start", children: [
|
|
1838
|
+
/* @__PURE__ */ jsx29(SizableText25, { size: "$4", fontWeight: "600", color: providerButtonStyle === "brand" ? BRAND_STYLES[p.brand ?? "custom"].textColor : void 0, children: p.name }),
|
|
1839
|
+
p.description ? /* @__PURE__ */ jsx29(SizableText25, { size: "$2", color: "$color10", children: p.description }) : null
|
|
1840
|
+
] })
|
|
1841
|
+
] }),
|
|
1842
|
+
/* @__PURE__ */ jsx29(SizableText25, { size: "$4", color: providerButtonStyle === "brand" ? BRAND_STYLES[p.brand ?? "custom"].textColor : "$color9", children: "\u2192" })
|
|
1843
|
+
] })
|
|
1844
|
+
},
|
|
1845
|
+
p.id
|
|
1846
|
+
)) }),
|
|
1847
|
+
showEmailForm && providers.length > 0 && /* @__PURE__ */ jsx29(Divider, { label: "or" }),
|
|
1848
|
+
showEmailForm && /* @__PURE__ */ jsxs22(YStack22, { gap: "$3", children: [
|
|
1849
|
+
/* @__PURE__ */ jsx29(Input, { label: "Email", placeholder: "your@email.com", value: email, onChangeText: setEmail, keyboardType: "email-address", autoCapitalize: "none" }),
|
|
1850
|
+
/* @__PURE__ */ jsx29(Input, { label: "Password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChangeText: setPassword, secureTextEntry: true }),
|
|
1851
|
+
onForgotPassword && /* @__PURE__ */ jsx29(XStack17, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx29(SizableText25, { size: "$3", color: "$color9", onPress: onForgotPassword, children: "Forgot password?" }) }),
|
|
1852
|
+
/* @__PURE__ */ jsx29(
|
|
1853
|
+
Button6,
|
|
1854
|
+
{
|
|
1855
|
+
size: "$5",
|
|
1856
|
+
backgroundColor: "$color9",
|
|
1857
|
+
color: "$color1",
|
|
1858
|
+
borderRadius: "$5",
|
|
1859
|
+
disabled: loading,
|
|
1860
|
+
onPress: () => onEmailSubmit?.(email, password),
|
|
1861
|
+
hoverStyle: { backgroundColor: "$color10" },
|
|
1862
|
+
pressStyle: { backgroundColor: "$color8" },
|
|
1863
|
+
icon: loading ? /* @__PURE__ */ jsx29(Spinner, { size: "small", color: "$color1" }) : void 0,
|
|
1864
|
+
children: "Sign In"
|
|
1865
|
+
}
|
|
1866
|
+
),
|
|
1867
|
+
onCreateAccount && /* @__PURE__ */ jsx29(Button6, { size: "$3", chromeless: true, onPress: onCreateAccount, children: /* @__PURE__ */ jsx29(SizableText25, { size: "$3", color: "$color9", children: "Create Account" }) })
|
|
1868
|
+
] }),
|
|
1869
|
+
(onTerms || onPrivacy) && /* @__PURE__ */ jsx29(YStack22, { paddingTop: "$2", alignItems: "center", children: /* @__PURE__ */ jsxs22(SizableText25, { size: "$2", color: "$color8", textAlign: "center", children: [
|
|
1870
|
+
"By continuing you agree to our",
|
|
1871
|
+
" ",
|
|
1872
|
+
onTerms && /* @__PURE__ */ jsx29(SizableText25, { size: "$2", color: "$color9", onPress: onTerms, children: "Terms of Service" }),
|
|
1873
|
+
onTerms && onPrivacy && " & ",
|
|
1874
|
+
onPrivacy && /* @__PURE__ */ jsx29(SizableText25, { size: "$2", color: "$color9", onPress: onPrivacy, children: "Privacy Policy" })
|
|
1875
|
+
] }) }),
|
|
1876
|
+
footerSlot
|
|
1877
|
+
]
|
|
1878
|
+
}
|
|
1879
|
+
)
|
|
1311
1880
|
] });
|
|
1312
1881
|
}
|
|
1313
1882
|
|
|
1314
1883
|
// src/patterns/TabBar.tsx
|
|
1315
|
-
import { SizableText as SizableText26, XStack as
|
|
1316
|
-
import { jsx as
|
|
1884
|
+
import { SizableText as SizableText26, XStack as XStack18, YStack as YStack23 } from "tamagui";
|
|
1885
|
+
import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1317
1886
|
function TabBar({ tabs, activeTab, onTabPress, showLabels = true }) {
|
|
1318
|
-
return /* @__PURE__ */
|
|
1887
|
+
return /* @__PURE__ */ jsx30(XStack18, { height: 56, borderTopWidth: 1, borderTopColor: "$borderColor", backgroundColor: "$background", paddingBottom: "$2", children: tabs.map((tab) => {
|
|
1319
1888
|
const active = tab.id === activeTab;
|
|
1320
|
-
return /* @__PURE__ */
|
|
1889
|
+
return /* @__PURE__ */ jsxs23(
|
|
1321
1890
|
YStack23,
|
|
1322
1891
|
{
|
|
1323
1892
|
flex: 1,
|
|
@@ -1327,8 +1896,8 @@ function TabBar({ tabs, activeTab, onTabPress, showLabels = true }) {
|
|
|
1327
1896
|
pressStyle: { opacity: 0.6 },
|
|
1328
1897
|
onPress: () => onTabPress(tab.id),
|
|
1329
1898
|
children: [
|
|
1330
|
-
tab.icon && /* @__PURE__ */
|
|
1331
|
-
showLabels && /* @__PURE__ */
|
|
1899
|
+
tab.icon && /* @__PURE__ */ jsx30(SizableText26, { size: "$5", color: active ? "$color9" : "$color8", children: tab.icon }),
|
|
1900
|
+
showLabels && /* @__PURE__ */ jsx30(SizableText26, { size: "$1", color: active ? "$color9" : "$color8", fontWeight: active ? "600" : "400", children: tab.label })
|
|
1332
1901
|
]
|
|
1333
1902
|
},
|
|
1334
1903
|
tab.id
|
|
@@ -1337,12 +1906,12 @@ function TabBar({ tabs, activeTab, onTabPress, showLabels = true }) {
|
|
|
1337
1906
|
}
|
|
1338
1907
|
|
|
1339
1908
|
// src/patterns/SearchBar.tsx
|
|
1340
|
-
import { Input as Input2, SizableText as SizableText27, XStack as
|
|
1341
|
-
import { jsx as
|
|
1909
|
+
import { Input as Input2, SizableText as SizableText27, XStack as XStack19 } from "tamagui";
|
|
1910
|
+
import { jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1342
1911
|
function SearchBar({ value, onChangeText, placeholder = "Search\u2026", onFilter, onCancel, autoFocus }) {
|
|
1343
|
-
return /* @__PURE__ */
|
|
1344
|
-
/* @__PURE__ */
|
|
1345
|
-
/* @__PURE__ */
|
|
1912
|
+
return /* @__PURE__ */ jsxs24(XStack19, { height: 44, borderRadius: "$10", backgroundColor: "$color2", alignItems: "center", paddingHorizontal: "$3", gap: "$2", children: [
|
|
1913
|
+
/* @__PURE__ */ jsx31(SizableText27, { size: "$4", color: "$color8", children: "\u2315" }),
|
|
1914
|
+
/* @__PURE__ */ jsx31(
|
|
1346
1915
|
Input2,
|
|
1347
1916
|
{
|
|
1348
1917
|
flex: 1,
|
|
@@ -1356,14 +1925,14 @@ function SearchBar({ value, onChangeText, placeholder = "Search\u2026", onFilter
|
|
|
1356
1925
|
autoFocus
|
|
1357
1926
|
}
|
|
1358
1927
|
),
|
|
1359
|
-
onFilter && /* @__PURE__ */
|
|
1360
|
-
onCancel && /* @__PURE__ */
|
|
1928
|
+
onFilter && /* @__PURE__ */ jsx31(SizableText27, { size: "$4", color: "$color9", pressStyle: { opacity: 0.6 }, onPress: onFilter, children: "\u2ACF" }),
|
|
1929
|
+
onCancel && /* @__PURE__ */ jsx31(SizableText27, { size: "$3", color: "$color9", pressStyle: { opacity: 0.6 }, onPress: onCancel, children: "Cancel" })
|
|
1361
1930
|
] });
|
|
1362
1931
|
}
|
|
1363
1932
|
|
|
1364
1933
|
// src/patterns/FloatingActionButton.tsx
|
|
1365
|
-
import { SizableText as SizableText28, XStack as
|
|
1366
|
-
import { jsx as
|
|
1934
|
+
import { SizableText as SizableText28, XStack as XStack20 } from "tamagui";
|
|
1935
|
+
import { jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1367
1936
|
var sizes = { sm: 44, md: 56, lg: 68 };
|
|
1368
1937
|
var positionStyles = {
|
|
1369
1938
|
"bottom-right": { right: 20 },
|
|
@@ -1372,8 +1941,8 @@ var positionStyles = {
|
|
|
1372
1941
|
};
|
|
1373
1942
|
function FloatingActionButton({ icon, label, onPress, position = "bottom-right", size = "md" }) {
|
|
1374
1943
|
const dim = sizes[size];
|
|
1375
|
-
return /* @__PURE__ */
|
|
1376
|
-
|
|
1944
|
+
return /* @__PURE__ */ jsxs25(
|
|
1945
|
+
XStack20,
|
|
1377
1946
|
{
|
|
1378
1947
|
position: "absolute",
|
|
1379
1948
|
bottom: 32,
|
|
@@ -1390,91 +1959,104 @@ function FloatingActionButton({ icon, label, onPress, position = "bottom-right",
|
|
|
1390
1959
|
pressStyle: { scale: 0.95, opacity: 0.9 },
|
|
1391
1960
|
onPress,
|
|
1392
1961
|
children: [
|
|
1393
|
-
icon && /* @__PURE__ */
|
|
1394
|
-
label && /* @__PURE__ */
|
|
1962
|
+
icon && /* @__PURE__ */ jsx32(SizableText28, { color: "$color1", children: icon }),
|
|
1963
|
+
label && /* @__PURE__ */ jsx32(SizableText28, { color: "$color1", size: "$4", fontWeight: "600", children: label })
|
|
1395
1964
|
]
|
|
1396
1965
|
}
|
|
1397
1966
|
);
|
|
1398
1967
|
}
|
|
1399
1968
|
|
|
1400
1969
|
// src/patterns/ActionSheet.tsx
|
|
1401
|
-
import { Sheet as Sheet2, SizableText as SizableText29, XStack as
|
|
1402
|
-
import { jsx as
|
|
1403
|
-
function ActionSheet({ open, onOpenChange, title, items, onSelect, cancelLabel = "Cancel" }) {
|
|
1404
|
-
return /* @__PURE__ */
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1970
|
+
import { Sheet as Sheet2, SizableText as SizableText29, XStack as XStack21, YStack as YStack24 } from "tamagui";
|
|
1971
|
+
import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1972
|
+
function ActionSheet({ open, onOpenChange, title, items, onSelect, cancelLabel = "Cancel", zIndex = 1e5 }) {
|
|
1973
|
+
return /* @__PURE__ */ jsxs26(
|
|
1974
|
+
Sheet2,
|
|
1975
|
+
{
|
|
1976
|
+
modal: true,
|
|
1977
|
+
forceRemoveScrollEnabled: open,
|
|
1978
|
+
open,
|
|
1979
|
+
onOpenChange,
|
|
1980
|
+
snapPoints: [50],
|
|
1981
|
+
dismissOnSnapToBottom: true,
|
|
1982
|
+
zIndex,
|
|
1983
|
+
animation: "medium",
|
|
1984
|
+
children: [
|
|
1985
|
+
/* @__PURE__ */ jsx33(Sheet2.Overlay, { animation: "lazy", enterStyle: { opacity: 0 }, exitStyle: { opacity: 0 } }),
|
|
1986
|
+
/* @__PURE__ */ jsx33(Sheet2.Handle, {}),
|
|
1987
|
+
/* @__PURE__ */ jsxs26(Sheet2.Frame, { children: [
|
|
1988
|
+
title && /* @__PURE__ */ jsx33(SizableText29, { size: "$3", color: "$color8", textAlign: "center", paddingTop: "$3", paddingBottom: "$1", children: title }),
|
|
1989
|
+
/* @__PURE__ */ jsx33(YStack24, { paddingHorizontal: "$3", paddingTop: "$2", children: items.map((item) => /* @__PURE__ */ jsxs26(
|
|
1990
|
+
XStack21,
|
|
1991
|
+
{
|
|
1992
|
+
height: 52,
|
|
1993
|
+
alignItems: "center",
|
|
1994
|
+
gap: "$3",
|
|
1995
|
+
paddingHorizontal: "$3",
|
|
1996
|
+
borderRadius: "$4",
|
|
1997
|
+
pressStyle: { backgroundColor: "$color3" },
|
|
1998
|
+
onPress: () => {
|
|
1999
|
+
onSelect(item.id);
|
|
2000
|
+
onOpenChange(false);
|
|
2001
|
+
},
|
|
2002
|
+
children: [
|
|
2003
|
+
item.icon && /* @__PURE__ */ jsx33(SizableText29, { size: "$5", children: item.icon }),
|
|
2004
|
+
/* @__PURE__ */ jsx33(
|
|
2005
|
+
SizableText29,
|
|
2006
|
+
{
|
|
2007
|
+
size: "$5",
|
|
2008
|
+
flex: 1,
|
|
2009
|
+
color: item.destructive ? "$red9" : "$color12",
|
|
2010
|
+
fontWeight: item.destructive ? "600" : "400",
|
|
2011
|
+
children: item.label
|
|
2012
|
+
}
|
|
2013
|
+
)
|
|
2014
|
+
]
|
|
2015
|
+
},
|
|
2016
|
+
item.id
|
|
2017
|
+
)) }),
|
|
2018
|
+
/* @__PURE__ */ jsx33(YStack24, { paddingHorizontal: "$3", paddingVertical: "$3", borderTopWidth: 1, borderTopColor: "$borderColor", marginTop: "$2", children: /* @__PURE__ */ jsx33(
|
|
2019
|
+
XStack21,
|
|
2020
|
+
{
|
|
2021
|
+
height: 48,
|
|
2022
|
+
alignItems: "center",
|
|
2023
|
+
justifyContent: "center",
|
|
2024
|
+
borderRadius: "$4",
|
|
2025
|
+
pressStyle: { backgroundColor: "$color3" },
|
|
2026
|
+
onPress: () => onOpenChange(false),
|
|
2027
|
+
children: /* @__PURE__ */ jsx33(SizableText29, { size: "$5", fontWeight: "600", color: "$color9", children: cancelLabel })
|
|
2028
|
+
}
|
|
2029
|
+
) })
|
|
2030
|
+
] })
|
|
2031
|
+
]
|
|
2032
|
+
}
|
|
2033
|
+
);
|
|
1452
2034
|
}
|
|
1453
2035
|
|
|
1454
2036
|
// src/patterns/Skeleton.tsx
|
|
1455
2037
|
import { YStack as YStack25 } from "tamagui";
|
|
1456
|
-
import { jsx as
|
|
2038
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
1457
2039
|
function Skeleton({ width, height, borderRadius, variant = "rectangular" }) {
|
|
1458
2040
|
const size = variant === "circular" ? height ?? 40 : height;
|
|
1459
2041
|
const w = variant === "text" ? width ?? "100%" : width;
|
|
1460
2042
|
const h = variant === "text" ? height ?? 16 : size;
|
|
1461
2043
|
const r = variant === "circular" ? 9999 : borderRadius ?? 8;
|
|
1462
|
-
return /* @__PURE__ */
|
|
2044
|
+
return /* @__PURE__ */ jsx34(YStack25, { width: w, height: h, borderRadius: r, backgroundColor: "$color3", opacity: 0.6, animation: "slow", enterStyle: { opacity: 0.3 }, exitStyle: { opacity: 0.3 } });
|
|
1463
2045
|
}
|
|
1464
2046
|
|
|
1465
2047
|
// src/patterns/NotificationBanner.tsx
|
|
1466
|
-
import { SizableText as SizableText30, XStack as
|
|
1467
|
-
import { jsx as
|
|
1468
|
-
var
|
|
1469
|
-
info: { bg: "$blue3", text: "$blue11" },
|
|
2048
|
+
import { SizableText as SizableText30, XStack as XStack22, YStack as YStack26 } from "tamagui";
|
|
2049
|
+
import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2050
|
+
var variantColors = {
|
|
2051
|
+
info: { bg: "$blue3", text: "$blue11" },
|
|
1470
2052
|
success: { bg: "$green3", text: "$green11" },
|
|
1471
2053
|
warning: { bg: "$yellow3", text: "$yellow11" },
|
|
1472
2054
|
error: { bg: "$red3", text: "$red11" }
|
|
1473
2055
|
};
|
|
1474
2056
|
function NotificationBanner({ title, message, variant = "info", onPress, onDismiss, icon }) {
|
|
1475
|
-
const colors =
|
|
1476
|
-
return /* @__PURE__ */
|
|
1477
|
-
|
|
2057
|
+
const colors = variantColors[variant];
|
|
2058
|
+
return /* @__PURE__ */ jsxs27(
|
|
2059
|
+
XStack22,
|
|
1478
2060
|
{
|
|
1479
2061
|
backgroundColor: colors.bg,
|
|
1480
2062
|
padding: "$3",
|
|
@@ -1484,48 +2066,48 @@ function NotificationBanner({ title, message, variant = "info", onPress, onDismi
|
|
|
1484
2066
|
onPress,
|
|
1485
2067
|
pressStyle: onPress ? { opacity: 0.8 } : void 0,
|
|
1486
2068
|
children: [
|
|
1487
|
-
icon && /* @__PURE__ */
|
|
1488
|
-
/* @__PURE__ */
|
|
1489
|
-
/* @__PURE__ */
|
|
1490
|
-
message && /* @__PURE__ */
|
|
2069
|
+
icon && /* @__PURE__ */ jsx35(YStack26, { paddingTop: "$0.5", children: icon }),
|
|
2070
|
+
/* @__PURE__ */ jsxs27(YStack26, { flex: 1, gap: "$1", children: [
|
|
2071
|
+
/* @__PURE__ */ jsx35(SizableText30, { size: "$4", fontWeight: "600", color: colors.text, children: title }),
|
|
2072
|
+
message && /* @__PURE__ */ jsx35(SizableText30, { size: "$3", color: colors.text, opacity: 0.8, children: message })
|
|
1491
2073
|
] }),
|
|
1492
|
-
onDismiss && /* @__PURE__ */
|
|
2074
|
+
onDismiss && /* @__PURE__ */ jsx35(SizableText30, { size: "$3", color: colors.text, opacity: 0.6, onPress: onDismiss, padding: "$1", children: "\u2715" })
|
|
1493
2075
|
]
|
|
1494
2076
|
}
|
|
1495
2077
|
);
|
|
1496
2078
|
}
|
|
1497
2079
|
|
|
1498
2080
|
// src/patterns/ProgressSteps.tsx
|
|
1499
|
-
import { Circle as
|
|
1500
|
-
import { jsx as
|
|
2081
|
+
import { Circle as Circle7, SizableText as SizableText31, XStack as XStack23, YStack as YStack27 } from "tamagui";
|
|
2082
|
+
import { jsx as jsx36, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
1501
2083
|
function ProgressSteps({ steps, currentStep, variant = "dots" }) {
|
|
1502
2084
|
if (variant === "bar") {
|
|
1503
2085
|
const progress = steps.length > 1 ? currentStep / (steps.length - 1) * 100 : 100;
|
|
1504
|
-
return /* @__PURE__ */
|
|
1505
|
-
/* @__PURE__ */
|
|
1506
|
-
/* @__PURE__ */
|
|
2086
|
+
return /* @__PURE__ */ jsxs28(YStack27, { gap: "$2", children: [
|
|
2087
|
+
/* @__PURE__ */ jsx36(YStack27, { height: 4, backgroundColor: "$color4", borderRadius: 2, overflow: "hidden", children: /* @__PURE__ */ jsx36(YStack27, { height: 4, width: `${progress}%`, backgroundColor: "$color9", borderRadius: 2, animation: "quick" }) }),
|
|
2088
|
+
/* @__PURE__ */ jsx36(XStack23, { justifyContent: "space-between", children: steps.map((label, i) => /* @__PURE__ */ jsx36(SizableText31, { size: "$2", color: i <= currentStep ? "$color9" : "$color8", children: label }, i)) })
|
|
1507
2089
|
] });
|
|
1508
2090
|
}
|
|
1509
|
-
return /* @__PURE__ */
|
|
1510
|
-
/* @__PURE__ */
|
|
1511
|
-
/* @__PURE__ */
|
|
1512
|
-
/* @__PURE__ */
|
|
2091
|
+
return /* @__PURE__ */ jsx36(XStack23, { alignItems: "center", justifyContent: "center", gap: "$0", children: steps.map((label, i) => /* @__PURE__ */ jsxs28(XStack23, { alignItems: "center", gap: "$0", children: [
|
|
2092
|
+
/* @__PURE__ */ jsxs28(YStack27, { alignItems: "center", gap: "$1.5", children: [
|
|
2093
|
+
/* @__PURE__ */ jsx36(Circle7, { size: variant === "numbered" ? 28 : 10, backgroundColor: i <= currentStep ? "$color9" : "$color4", animation: "quick", children: variant === "numbered" && /* @__PURE__ */ jsx36(SizableText31, { size: "$2", fontWeight: "600", color: i <= currentStep ? "$color1" : "$color8", children: i + 1 }) }),
|
|
2094
|
+
/* @__PURE__ */ jsx36(SizableText31, { size: "$1", color: i <= currentStep ? "$color11" : "$color8", numberOfLines: 1, children: label })
|
|
1513
2095
|
] }),
|
|
1514
|
-
i < steps.length - 1 && /* @__PURE__ */
|
|
2096
|
+
i < steps.length - 1 && /* @__PURE__ */ jsx36(YStack27, { height: 2, width: 32, backgroundColor: i < currentStep ? "$color9" : "$color4", marginBottom: "$4" })
|
|
1515
2097
|
] }, i)) });
|
|
1516
2098
|
}
|
|
1517
2099
|
|
|
1518
2100
|
// src/patterns/SwipeableRow.tsx
|
|
1519
|
-
import { useState as
|
|
1520
|
-
import { Button as Button7, SizableText as SizableText32, XStack as
|
|
1521
|
-
import { Fragment as
|
|
2101
|
+
import { useState as useState8 } from "react";
|
|
2102
|
+
import { Button as Button7, SizableText as SizableText32, XStack as XStack24, YStack as YStack28 } from "tamagui";
|
|
2103
|
+
import { Fragment as Fragment3, jsx as jsx37, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
1522
2104
|
function SwipeableRow({ children, leftActions, rightActions }) {
|
|
1523
|
-
const [showActions, setShowActions] =
|
|
2105
|
+
const [showActions, setShowActions] = useState8(false);
|
|
1524
2106
|
const actions = [...leftActions ?? [], ...rightActions ?? []];
|
|
1525
|
-
if (actions.length === 0) return /* @__PURE__ */
|
|
1526
|
-
return /* @__PURE__ */
|
|
1527
|
-
/* @__PURE__ */
|
|
1528
|
-
showActions && /* @__PURE__ */
|
|
2107
|
+
if (actions.length === 0) return /* @__PURE__ */ jsx37(Fragment3, { children });
|
|
2108
|
+
return /* @__PURE__ */ jsxs29(YStack28, { children: [
|
|
2109
|
+
/* @__PURE__ */ jsx37(YStack28, { onLongPress: () => setShowActions((v) => !v), pressStyle: { opacity: 0.9 }, children }),
|
|
2110
|
+
showActions && /* @__PURE__ */ jsx37(XStack24, { gap: "$2", padding: "$2", animation: "quick", enterStyle: { opacity: 0, scale: 0.95 }, children: actions.map((action) => /* @__PURE__ */ jsx37(
|
|
1529
2111
|
Button7,
|
|
1530
2112
|
{
|
|
1531
2113
|
flex: 1,
|
|
@@ -1536,7 +2118,7 @@ function SwipeableRow({ children, leftActions, rightActions }) {
|
|
|
1536
2118
|
action.onPress();
|
|
1537
2119
|
setShowActions(false);
|
|
1538
2120
|
},
|
|
1539
|
-
children: /* @__PURE__ */
|
|
2121
|
+
children: /* @__PURE__ */ jsx37(SizableText32, { size: "$2", fontWeight: "600", color: "white", children: action.label })
|
|
1540
2122
|
},
|
|
1541
2123
|
action.id
|
|
1542
2124
|
)) })
|
|
@@ -1544,11 +2126,11 @@ function SwipeableRow({ children, leftActions, rightActions }) {
|
|
|
1544
2126
|
}
|
|
1545
2127
|
|
|
1546
2128
|
// src/patterns/MediaCard.tsx
|
|
1547
|
-
import { Image as Image5, SizableText as SizableText33, XStack as
|
|
2129
|
+
import { Image as Image5, SizableText as SizableText33, XStack as XStack25, YStack as YStack29 } from "tamagui";
|
|
1548
2130
|
import { LinearGradient } from "tamagui/linear-gradient";
|
|
1549
|
-
import { jsx as
|
|
2131
|
+
import { jsx as jsx38, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
1550
2132
|
function MediaCard({ image, title, subtitle, overlay = "gradient", aspectRatio = 16 / 9, onPress, badge }) {
|
|
1551
|
-
return /* @__PURE__ */
|
|
2133
|
+
return /* @__PURE__ */ jsx38(
|
|
1552
2134
|
YStack29,
|
|
1553
2135
|
{
|
|
1554
2136
|
borderRadius: "$4",
|
|
@@ -1556,9 +2138,9 @@ function MediaCard({ image, title, subtitle, overlay = "gradient", aspectRatio =
|
|
|
1556
2138
|
onPress,
|
|
1557
2139
|
pressStyle: onPress ? { scale: 0.98, opacity: 0.9 } : void 0,
|
|
1558
2140
|
animation: "quick",
|
|
1559
|
-
children: /* @__PURE__ */
|
|
1560
|
-
/* @__PURE__ */
|
|
1561
|
-
overlay === "gradient" && /* @__PURE__ */
|
|
2141
|
+
children: /* @__PURE__ */ jsxs30(YStack29, { aspectRatio, children: [
|
|
2142
|
+
/* @__PURE__ */ jsx38(Image5, { source: { uri: image }, width: "100%", height: "100%", objectFit: "cover" }),
|
|
2143
|
+
overlay === "gradient" && /* @__PURE__ */ jsx38(
|
|
1562
2144
|
LinearGradient,
|
|
1563
2145
|
{
|
|
1564
2146
|
colors: ["transparent", "rgba(0,0,0,0.7)"],
|
|
@@ -1571,9 +2153,9 @@ function MediaCard({ image, title, subtitle, overlay = "gradient", aspectRatio =
|
|
|
1571
2153
|
height: "60%"
|
|
1572
2154
|
}
|
|
1573
2155
|
),
|
|
1574
|
-
overlay === "dark" && /* @__PURE__ */
|
|
1575
|
-
badge && /* @__PURE__ */
|
|
1576
|
-
|
|
2156
|
+
overlay === "dark" && /* @__PURE__ */ jsx38(YStack29, { position: "absolute", fullscreen: true, backgroundColor: "rgba(0,0,0,0.4)" }),
|
|
2157
|
+
badge && /* @__PURE__ */ jsx38(
|
|
2158
|
+
XStack25,
|
|
1577
2159
|
{
|
|
1578
2160
|
position: "absolute",
|
|
1579
2161
|
top: "$2",
|
|
@@ -1582,12 +2164,12 @@ function MediaCard({ image, title, subtitle, overlay = "gradient", aspectRatio =
|
|
|
1582
2164
|
paddingHorizontal: "$2",
|
|
1583
2165
|
paddingVertical: "$1",
|
|
1584
2166
|
borderRadius: "$2",
|
|
1585
|
-
children: /* @__PURE__ */
|
|
2167
|
+
children: /* @__PURE__ */ jsx38(SizableText33, { size: "$1", fontWeight: "600", color: "$color1", children: badge })
|
|
1586
2168
|
}
|
|
1587
2169
|
),
|
|
1588
|
-
/* @__PURE__ */
|
|
1589
|
-
/* @__PURE__ */
|
|
1590
|
-
subtitle && /* @__PURE__ */
|
|
2170
|
+
/* @__PURE__ */ jsxs30(YStack29, { position: "absolute", bottom: 0, left: 0, right: 0, padding: "$3", gap: "$1", children: [
|
|
2171
|
+
/* @__PURE__ */ jsx38(SizableText33, { size: "$5", fontWeight: "600", color: "white", children: title }),
|
|
2172
|
+
subtitle && /* @__PURE__ */ jsx38(SizableText33, { size: "$3", color: "rgba(255,255,255,0.8)", children: subtitle })
|
|
1591
2173
|
] })
|
|
1592
2174
|
] })
|
|
1593
2175
|
}
|
|
@@ -1595,17 +2177,17 @@ function MediaCard({ image, title, subtitle, overlay = "gradient", aspectRatio =
|
|
|
1595
2177
|
}
|
|
1596
2178
|
|
|
1597
2179
|
// src/patterns/Carousel.tsx
|
|
1598
|
-
import { Children as Children2, useState as
|
|
1599
|
-
import { Circle as
|
|
1600
|
-
import { ScrollView as
|
|
1601
|
-
import { jsx as
|
|
2180
|
+
import { Children as Children2, useState as useState9 } from "react";
|
|
2181
|
+
import { Circle as Circle8, XStack as XStack26, YStack as YStack30 } from "tamagui";
|
|
2182
|
+
import { ScrollView as ScrollView4 } from "react-native";
|
|
2183
|
+
import { jsx as jsx39, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
1602
2184
|
function Carousel({ children, gap = "$3", snapToInterval, showIndicators = false }) {
|
|
1603
|
-
const [activeIndex, setActiveIndex] =
|
|
2185
|
+
const [activeIndex, setActiveIndex] = useState9(0);
|
|
1604
2186
|
const count = Children2.count(children);
|
|
1605
2187
|
const gapPx = gap === "$2" ? 8 : gap === "$3" ? 12 : 16;
|
|
1606
|
-
return /* @__PURE__ */
|
|
1607
|
-
/* @__PURE__ */
|
|
1608
|
-
|
|
2188
|
+
return /* @__PURE__ */ jsxs31(YStack30, { gap: "$3", children: [
|
|
2189
|
+
/* @__PURE__ */ jsx39(
|
|
2190
|
+
ScrollView4,
|
|
1609
2191
|
{
|
|
1610
2192
|
horizontal: true,
|
|
1611
2193
|
showsHorizontalScrollIndicator: false,
|
|
@@ -1618,84 +2200,1715 @@ function Carousel({ children, gap = "$3", snapToInterval, showIndicators = false
|
|
|
1618
2200
|
children
|
|
1619
2201
|
}
|
|
1620
2202
|
),
|
|
1621
|
-
showIndicators && count > 1 && /* @__PURE__ */
|
|
2203
|
+
showIndicators && count > 1 && /* @__PURE__ */ jsx39(XStack26, { justifyContent: "center", gap: "$1.5", children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx39(Circle8, { size: 6, backgroundColor: i === activeIndex ? "$color9" : "$color4", animation: "quick" }, i)) })
|
|
1622
2204
|
] });
|
|
1623
2205
|
}
|
|
1624
2206
|
|
|
1625
2207
|
// src/patterns/PullToRefresh.tsx
|
|
1626
2208
|
import { YStack as YStack31 } from "tamagui";
|
|
1627
|
-
import { RefreshControl, ScrollView as
|
|
1628
|
-
import { jsx as
|
|
2209
|
+
import { RefreshControl, ScrollView as ScrollView5 } from "react-native";
|
|
2210
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
1629
2211
|
function PullToRefresh({ children, onRefresh, refreshing = false }) {
|
|
1630
|
-
return /* @__PURE__ */
|
|
1631
|
-
|
|
2212
|
+
return /* @__PURE__ */ jsx40(
|
|
2213
|
+
ScrollView5,
|
|
1632
2214
|
{
|
|
1633
2215
|
contentContainerStyle: { flexGrow: 1 },
|
|
1634
|
-
refreshControl: /* @__PURE__ */
|
|
1635
|
-
children: /* @__PURE__ */
|
|
2216
|
+
refreshControl: /* @__PURE__ */ jsx40(RefreshControl, { refreshing, onRefresh }),
|
|
2217
|
+
children: /* @__PURE__ */ jsx40(YStack31, { flex: 1, children })
|
|
2218
|
+
}
|
|
2219
|
+
);
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
// src/patterns/ProductCard.tsx
|
|
2223
|
+
import { Button as Button8, Image as Image6, SizableText as SizableText34, XStack as XStack27, YStack as YStack32 } from "tamagui";
|
|
2224
|
+
import { jsx as jsx41, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2225
|
+
function Stars({ rating = 0 }) {
|
|
2226
|
+
return /* @__PURE__ */ jsx41(XStack27, { gap: "$0.5", children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx41(SizableText34, { size: "$2", color: i < Math.round(rating) ? "$yellow9" : "$color5", children: "\u2605" }, i)) });
|
|
2227
|
+
}
|
|
2228
|
+
function CardContent2({ title, price, originalPrice, rating, reviewCount, onAddToCart }) {
|
|
2229
|
+
return /* @__PURE__ */ jsxs32(YStack32, { flex: 1, gap: "$1.5", justifyContent: "space-between", children: [
|
|
2230
|
+
/* @__PURE__ */ jsxs32(YStack32, { gap: "$1", children: [
|
|
2231
|
+
/* @__PURE__ */ jsx41(SizableText34, { size: "$4", fontWeight: "600", numberOfLines: 2, children: title }),
|
|
2232
|
+
rating !== void 0 && /* @__PURE__ */ jsxs32(XStack27, { gap: "$1.5", alignItems: "center", children: [
|
|
2233
|
+
/* @__PURE__ */ jsx41(Stars, { rating }),
|
|
2234
|
+
reviewCount !== void 0 && /* @__PURE__ */ jsxs32(SizableText34, { size: "$2", color: "$color9", children: [
|
|
2235
|
+
"(",
|
|
2236
|
+
reviewCount,
|
|
2237
|
+
")"
|
|
2238
|
+
] })
|
|
2239
|
+
] })
|
|
2240
|
+
] }),
|
|
2241
|
+
/* @__PURE__ */ jsxs32(XStack27, { alignItems: "center", justifyContent: "space-between", children: [
|
|
2242
|
+
/* @__PURE__ */ jsxs32(XStack27, { gap: "$2", alignItems: "baseline", children: [
|
|
2243
|
+
/* @__PURE__ */ jsx41(SizableText34, { size: "$6", fontWeight: "700", children: price }),
|
|
2244
|
+
originalPrice && /* @__PURE__ */ jsx41(SizableText34, { size: "$3", color: "$color8", textDecorationLine: "line-through", children: originalPrice })
|
|
2245
|
+
] }),
|
|
2246
|
+
onAddToCart && /* @__PURE__ */ jsx41(
|
|
2247
|
+
Button8,
|
|
2248
|
+
{
|
|
2249
|
+
size: "$3",
|
|
2250
|
+
backgroundColor: "$color9",
|
|
2251
|
+
color: "$color1",
|
|
2252
|
+
borderRadius: "$10",
|
|
2253
|
+
onPress: (e) => {
|
|
2254
|
+
e.stopPropagation?.();
|
|
2255
|
+
onAddToCart();
|
|
2256
|
+
},
|
|
2257
|
+
pressStyle: { backgroundColor: "$color8", scale: 0.95 },
|
|
2258
|
+
animation: "quick",
|
|
2259
|
+
children: "+ Cart"
|
|
2260
|
+
}
|
|
2261
|
+
)
|
|
2262
|
+
] })
|
|
2263
|
+
] });
|
|
2264
|
+
}
|
|
2265
|
+
function ProductCard({ image, title, price, originalPrice, rating, reviewCount, badge, onPress, onAddToCart, variant = "vertical" }) {
|
|
2266
|
+
const isHorizontal = variant === "horizontal";
|
|
2267
|
+
const Wrapper = isHorizontal ? XStack27 : YStack32;
|
|
2268
|
+
return /* @__PURE__ */ jsxs32(
|
|
2269
|
+
Wrapper,
|
|
2270
|
+
{
|
|
2271
|
+
backgroundColor: "$color1",
|
|
2272
|
+
borderRadius: "$5",
|
|
2273
|
+
overflow: "hidden",
|
|
2274
|
+
borderWidth: 1,
|
|
2275
|
+
borderColor: "$color4",
|
|
2276
|
+
onPress,
|
|
2277
|
+
animation: "quick",
|
|
2278
|
+
pressStyle: onPress ? { scale: 0.98, opacity: 0.9 } : void 0,
|
|
2279
|
+
...isHorizontal ? { height: 140 } : {},
|
|
2280
|
+
children: [
|
|
2281
|
+
/* @__PURE__ */ jsxs32(YStack32, { ...isHorizontal ? { width: 140 } : { aspectRatio: 4 / 3 }, position: "relative", children: [
|
|
2282
|
+
/* @__PURE__ */ jsx41(Image6, { source: { uri: image }, width: "100%", height: "100%", objectFit: "cover" }),
|
|
2283
|
+
badge && /* @__PURE__ */ jsx41(
|
|
2284
|
+
XStack27,
|
|
2285
|
+
{
|
|
2286
|
+
position: "absolute",
|
|
2287
|
+
top: "$2",
|
|
2288
|
+
left: "$2",
|
|
2289
|
+
backgroundColor: "$red9",
|
|
2290
|
+
paddingHorizontal: "$2",
|
|
2291
|
+
paddingVertical: "$1",
|
|
2292
|
+
borderRadius: "$10",
|
|
2293
|
+
children: /* @__PURE__ */ jsx41(SizableText34, { size: "$1", fontWeight: "700", color: "white", children: badge })
|
|
2294
|
+
}
|
|
2295
|
+
)
|
|
2296
|
+
] }),
|
|
2297
|
+
/* @__PURE__ */ jsx41(YStack32, { flex: 1, padding: "$3", children: /* @__PURE__ */ jsx41(CardContent2, { ...{ title, price, originalPrice, rating, reviewCount, onAddToCart } }) })
|
|
2298
|
+
]
|
|
2299
|
+
}
|
|
2300
|
+
);
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
// src/patterns/PricingTable.tsx
|
|
2304
|
+
import { Button as Button9, Circle as Circle9, SizableText as SizableText35, XStack as XStack28, YStack as YStack33 } from "tamagui";
|
|
2305
|
+
import { jsx as jsx42, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2306
|
+
function BillingToggle({ annual, onToggle }) {
|
|
2307
|
+
return /* @__PURE__ */ jsx42(XStack28, { alignSelf: "center", backgroundColor: "$color3", borderRadius: "$10", padding: "$1", gap: "$0.5", children: ["Monthly", "Annual"].map((label, i) => {
|
|
2308
|
+
const active = i === 1 ? annual : !annual;
|
|
2309
|
+
return /* @__PURE__ */ jsx42(
|
|
2310
|
+
XStack28,
|
|
2311
|
+
{
|
|
2312
|
+
paddingHorizontal: "$4",
|
|
2313
|
+
paddingVertical: "$2",
|
|
2314
|
+
borderRadius: "$10",
|
|
2315
|
+
backgroundColor: active ? "$color9" : "transparent",
|
|
2316
|
+
onPress: () => onToggle(i === 1),
|
|
2317
|
+
pressStyle: { opacity: 0.8 },
|
|
2318
|
+
animation: "quick",
|
|
2319
|
+
children: /* @__PURE__ */ jsx42(SizableText35, { size: "$3", fontWeight: "600", color: active ? "$color1" : "$color10", children: label })
|
|
2320
|
+
},
|
|
2321
|
+
label
|
|
2322
|
+
);
|
|
2323
|
+
}) });
|
|
2324
|
+
}
|
|
2325
|
+
function PlanRow2({ plan, selected, onSelect }) {
|
|
2326
|
+
return /* @__PURE__ */ jsxs33(
|
|
2327
|
+
XStack28,
|
|
2328
|
+
{
|
|
2329
|
+
padding: "$4",
|
|
2330
|
+
borderRadius: "$6",
|
|
2331
|
+
borderWidth: 2,
|
|
2332
|
+
borderColor: selected ? "$color9" : "$color4",
|
|
2333
|
+
backgroundColor: selected ? "$color2" : "$color1",
|
|
2334
|
+
alignItems: "center",
|
|
2335
|
+
gap: "$3",
|
|
2336
|
+
onPress: onSelect,
|
|
2337
|
+
pressStyle: { scale: 0.98, opacity: 0.9 },
|
|
2338
|
+
animation: "quick",
|
|
2339
|
+
cursor: "pointer",
|
|
2340
|
+
position: "relative",
|
|
2341
|
+
children: [
|
|
2342
|
+
plan.popular && /* @__PURE__ */ jsx42(XStack28, { position: "absolute", top: -10, right: 12, backgroundColor: "$color9", paddingHorizontal: "$2.5", paddingVertical: 2, borderRadius: "$10", children: /* @__PURE__ */ jsx42(SizableText35, { size: "$1", fontWeight: "700", color: "$color1", children: "BEST VALUE" }) }),
|
|
2343
|
+
/* @__PURE__ */ jsx42(
|
|
2344
|
+
Circle9,
|
|
2345
|
+
{
|
|
2346
|
+
size: 22,
|
|
2347
|
+
borderWidth: 2,
|
|
2348
|
+
borderColor: selected ? "$color9" : "$color6",
|
|
2349
|
+
backgroundColor: selected ? "$color9" : "transparent",
|
|
2350
|
+
children: selected && /* @__PURE__ */ jsx42(Circle9, { size: 8, backgroundColor: "$color1" })
|
|
2351
|
+
}
|
|
2352
|
+
),
|
|
2353
|
+
/* @__PURE__ */ jsxs33(YStack33, { flex: 1, gap: "$0.5", children: [
|
|
2354
|
+
/* @__PURE__ */ jsxs33(XStack28, { alignItems: "center", gap: "$2", children: [
|
|
2355
|
+
/* @__PURE__ */ jsx42(SizableText35, { size: "$5", fontWeight: "700", children: plan.name }),
|
|
2356
|
+
plan.trial && /* @__PURE__ */ jsx42(XStack28, { backgroundColor: "$green3", paddingHorizontal: "$2", paddingVertical: 2, borderRadius: "$10", children: /* @__PURE__ */ jsx42(SizableText35, { size: "$1", fontWeight: "700", color: "$green9", children: plan.trial }) })
|
|
2357
|
+
] }),
|
|
2358
|
+
plan.description && /* @__PURE__ */ jsx42(SizableText35, { size: "$2", color: "$color10", children: plan.description })
|
|
2359
|
+
] }),
|
|
2360
|
+
/* @__PURE__ */ jsx42(SizableText35, { size: "$5", fontWeight: "800", children: plan.price })
|
|
2361
|
+
]
|
|
2362
|
+
}
|
|
2363
|
+
);
|
|
2364
|
+
}
|
|
2365
|
+
function FeatureList({ features }) {
|
|
2366
|
+
return /* @__PURE__ */ jsx42(YStack33, { gap: "$2.5", paddingHorizontal: "$1", children: features.map((f, i) => /* @__PURE__ */ jsxs33(XStack28, { gap: "$2.5", alignItems: "center", children: [
|
|
2367
|
+
/* @__PURE__ */ jsx42(Circle9, { size: 20, backgroundColor: f.included ? "$green3" : "$color3", children: /* @__PURE__ */ jsx42(SizableText35, { size: "$1", fontWeight: "700", color: f.included ? "$green9" : "$color8", children: f.included ? "\u2713" : "\u2014" }) }),
|
|
2368
|
+
/* @__PURE__ */ jsx42(SizableText35, { size: "$3", color: f.included ? "$color11" : "$color8", flex: 1, children: f.label })
|
|
2369
|
+
] }, i)) });
|
|
2370
|
+
}
|
|
2371
|
+
function PricingTable({ plans, selectedPlan, onSelectPlan, annual = false, onToggleBilling, onContinue, continueLabel, reassurance }) {
|
|
2372
|
+
const selected = selectedPlan ?? plans.find((p) => p.popular)?.id ?? plans[0]?.id;
|
|
2373
|
+
const activePlan = plans.find((p) => p.id === selected);
|
|
2374
|
+
return /* @__PURE__ */ jsxs33(YStack33, { gap: "$4", children: [
|
|
2375
|
+
onToggleBilling && /* @__PURE__ */ jsx42(BillingToggle, { annual, onToggle: onToggleBilling }),
|
|
2376
|
+
activePlan && activePlan.features.length > 0 && /* @__PURE__ */ jsx42(YStack33, { backgroundColor: "$color1", borderRadius: "$6", padding: "$4", gap: "$3", borderWidth: 1, borderColor: "$color4", children: /* @__PURE__ */ jsx42(FeatureList, { features: activePlan.features }) }),
|
|
2377
|
+
/* @__PURE__ */ jsx42(YStack33, { gap: "$3", children: plans.map((plan) => /* @__PURE__ */ jsx42(
|
|
2378
|
+
PlanRow2,
|
|
2379
|
+
{
|
|
2380
|
+
plan,
|
|
2381
|
+
selected: selected === plan.id,
|
|
2382
|
+
onSelect: () => onSelectPlan?.(plan.id)
|
|
2383
|
+
},
|
|
2384
|
+
plan.id
|
|
2385
|
+
)) }),
|
|
2386
|
+
reassurance && /* @__PURE__ */ jsx42(SizableText35, { size: "$2", color: "$color10", textAlign: "center", children: reassurance }),
|
|
2387
|
+
onContinue && /* @__PURE__ */ jsx42(
|
|
2388
|
+
Button9,
|
|
2389
|
+
{
|
|
2390
|
+
size: "$5",
|
|
2391
|
+
backgroundColor: "$color9",
|
|
2392
|
+
color: "$color1",
|
|
2393
|
+
borderRadius: "$10",
|
|
2394
|
+
fontWeight: "700",
|
|
2395
|
+
onPress: onContinue,
|
|
2396
|
+
pressStyle: { scale: 0.97, backgroundColor: "$color8" },
|
|
2397
|
+
animation: "quick",
|
|
2398
|
+
children: continueLabel ?? activePlan?.cta ?? "Get Started"
|
|
2399
|
+
}
|
|
2400
|
+
)
|
|
2401
|
+
] });
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
// src/patterns/CountdownBanner.tsx
|
|
2405
|
+
import { useState as useState10, useEffect as useEffect4, useRef, useCallback as useCallback2 } from "react";
|
|
2406
|
+
import { SizableText as SizableText36, XStack as XStack29, YStack as YStack34 } from "tamagui";
|
|
2407
|
+
import { jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2408
|
+
function useCountdown2(endTime, minutes, onExpire) {
|
|
2409
|
+
const getRemaining = useCallback2(() => {
|
|
2410
|
+
if (endTime) return Math.max(0, Math.floor((endTime.getTime() - Date.now()) / 1e3));
|
|
2411
|
+
return 0;
|
|
2412
|
+
}, [endTime]);
|
|
2413
|
+
const [seconds, setSeconds] = useState10(() => endTime ? getRemaining() : (minutes ?? 0) * 60);
|
|
2414
|
+
const firedRef = useRef(false);
|
|
2415
|
+
useEffect4(() => {
|
|
2416
|
+
if (endTime) setSeconds(getRemaining());
|
|
2417
|
+
else setSeconds((minutes ?? 0) * 60);
|
|
2418
|
+
firedRef.current = false;
|
|
2419
|
+
}, [endTime, minutes, getRemaining]);
|
|
2420
|
+
useEffect4(() => {
|
|
2421
|
+
if (seconds <= 0) return;
|
|
2422
|
+
const id = setInterval(() => {
|
|
2423
|
+
setSeconds((s) => {
|
|
2424
|
+
const next = endTime ? Math.max(0, Math.floor((endTime.getTime() - Date.now()) / 1e3)) : s - 1;
|
|
2425
|
+
if (next <= 0 && !firedRef.current) {
|
|
2426
|
+
firedRef.current = true;
|
|
2427
|
+
onExpire?.();
|
|
2428
|
+
}
|
|
2429
|
+
return Math.max(0, next);
|
|
2430
|
+
});
|
|
2431
|
+
}, 1e3);
|
|
2432
|
+
return () => clearInterval(id);
|
|
2433
|
+
}, [seconds > 0, endTime, onExpire]);
|
|
2434
|
+
const hh = String(Math.floor(seconds / 3600)).padStart(2, "0");
|
|
2435
|
+
const mm = String(Math.floor(seconds % 3600 / 60)).padStart(2, "0");
|
|
2436
|
+
const ss = String(seconds % 60).padStart(2, "0");
|
|
2437
|
+
const display = seconds >= 3600 ? `${hh}:${mm}:${ss}` : `${mm}:${ss}`;
|
|
2438
|
+
return { display, expired: seconds <= 0 };
|
|
2439
|
+
}
|
|
2440
|
+
function TimeBox({ value }) {
|
|
2441
|
+
return /* @__PURE__ */ jsx43(XStack29, { backgroundColor: "rgba(0,0,0,0.15)", paddingHorizontal: "$2", paddingVertical: "$1", borderRadius: "$3", children: /* @__PURE__ */ jsx43(SizableText36, { size: "$6", fontWeight: "800", color: "white", fontFamily: "$mono", children: value }) });
|
|
2442
|
+
}
|
|
2443
|
+
function CountdownBanner({ endTime, minutes, label = "Offer ends in", onExpire, variant = "banner" }) {
|
|
2444
|
+
const { display, expired } = useCountdown2(endTime, minutes, onExpire);
|
|
2445
|
+
if (expired) return null;
|
|
2446
|
+
const parts = display.split(":");
|
|
2447
|
+
if (variant === "badge") {
|
|
2448
|
+
return /* @__PURE__ */ jsxs34(XStack29, { backgroundColor: "$red9", paddingHorizontal: "$2.5", paddingVertical: "$1", borderRadius: "$10", gap: "$1.5", alignItems: "center", children: [
|
|
2449
|
+
/* @__PURE__ */ jsx43(SizableText36, { size: "$1", fontWeight: "600", color: "white", children: label }),
|
|
2450
|
+
/* @__PURE__ */ jsx43(SizableText36, { size: "$2", fontWeight: "800", color: "white", fontFamily: "$mono", children: display })
|
|
2451
|
+
] });
|
|
2452
|
+
}
|
|
2453
|
+
if (variant === "compact") {
|
|
2454
|
+
return /* @__PURE__ */ jsxs34(XStack29, { backgroundColor: "$red3", paddingHorizontal: "$3", paddingVertical: "$2", borderRadius: "$4", gap: "$2", alignItems: "center", alignSelf: "center", children: [
|
|
2455
|
+
/* @__PURE__ */ jsx43(SizableText36, { size: "$3", fontWeight: "600", color: "$red9", children: label }),
|
|
2456
|
+
/* @__PURE__ */ jsx43(SizableText36, { size: "$5", fontWeight: "800", color: "$red9", fontFamily: "$mono", children: display })
|
|
2457
|
+
] });
|
|
2458
|
+
}
|
|
2459
|
+
return /* @__PURE__ */ jsxs34(YStack34, { backgroundColor: "$red9", paddingVertical: "$3", paddingHorizontal: "$4", gap: "$1.5", alignItems: "center", children: [
|
|
2460
|
+
/* @__PURE__ */ jsx43(SizableText36, { size: "$3", fontWeight: "600", color: "white", opacity: 0.9, children: label }),
|
|
2461
|
+
/* @__PURE__ */ jsx43(XStack29, { gap: "$1.5", alignItems: "center", children: parts.map((p, i) => /* @__PURE__ */ jsxs34(XStack29, { gap: "$1.5", alignItems: "center", children: [
|
|
2462
|
+
i > 0 && /* @__PURE__ */ jsx43(SizableText36, { size: "$6", fontWeight: "800", color: "white", children: ":" }),
|
|
2463
|
+
/* @__PURE__ */ jsx43(TimeBox, { value: p })
|
|
2464
|
+
] }, i)) })
|
|
2465
|
+
] });
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
// src/patterns/TestimonialCard.tsx
|
|
2469
|
+
import { Image as Image7, SizableText as SizableText37, XStack as XStack30, YStack as YStack35 } from "tamagui";
|
|
2470
|
+
import { jsx as jsx44, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2471
|
+
function Stars2({ count = 0 }) {
|
|
2472
|
+
if (!count) return null;
|
|
2473
|
+
return /* @__PURE__ */ jsx44(XStack30, { gap: "$0.5", children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx44(SizableText37, { size: "$3", color: i < Math.round(count) ? "$yellow9" : "$color5", children: "\u2605" }, i)) });
|
|
2474
|
+
}
|
|
2475
|
+
function AuthorRow({ author, role, avatar }) {
|
|
2476
|
+
return /* @__PURE__ */ jsxs35(XStack30, { gap: "$2.5", alignItems: "center", children: [
|
|
2477
|
+
avatar && /* @__PURE__ */ jsx44(Image7, { source: { uri: avatar }, width: 36, height: 36, borderRadius: 18, objectFit: "cover" }),
|
|
2478
|
+
/* @__PURE__ */ jsxs35(YStack35, { children: [
|
|
2479
|
+
/* @__PURE__ */ jsx44(SizableText37, { size: "$3", fontWeight: "600", children: author }),
|
|
2480
|
+
role && /* @__PURE__ */ jsx44(SizableText37, { size: "$2", color: "$color9", children: role })
|
|
2481
|
+
] })
|
|
2482
|
+
] });
|
|
2483
|
+
}
|
|
2484
|
+
function TestimonialCard2({ quote, author, role, avatar, rating, variant = "card" }) {
|
|
2485
|
+
if (variant === "minimal") {
|
|
2486
|
+
return /* @__PURE__ */ jsxs35(YStack35, { gap: "$3", paddingVertical: "$2", children: [
|
|
2487
|
+
/* @__PURE__ */ jsx44(Stars2, { count: rating }),
|
|
2488
|
+
/* @__PURE__ */ jsxs35(SizableText37, { size: "$4", color: "$color11", fontStyle: "italic", lineHeight: 24, children: [
|
|
2489
|
+
'"',
|
|
2490
|
+
quote,
|
|
2491
|
+
'"'
|
|
2492
|
+
] }),
|
|
2493
|
+
/* @__PURE__ */ jsx44(AuthorRow, { author, role, avatar })
|
|
2494
|
+
] });
|
|
2495
|
+
}
|
|
2496
|
+
if (variant === "featured") {
|
|
2497
|
+
return /* @__PURE__ */ jsxs35(YStack35, { backgroundColor: "$color3", padding: "$5", borderRadius: "$6", gap: "$4", alignItems: "center", children: [
|
|
2498
|
+
/* @__PURE__ */ jsx44(SizableText37, { size: "$8", color: "$color9", opacity: 0.3, fontWeight: "800", children: '"' }),
|
|
2499
|
+
/* @__PURE__ */ jsx44(Stars2, { count: rating }),
|
|
2500
|
+
/* @__PURE__ */ jsxs35(SizableText37, { size: "$5", color: "$color12", fontStyle: "italic", textAlign: "center", lineHeight: 28, children: [
|
|
2501
|
+
'"',
|
|
2502
|
+
quote,
|
|
2503
|
+
'"'
|
|
2504
|
+
] }),
|
|
2505
|
+
/* @__PURE__ */ jsx44(AuthorRow, { author, role, avatar })
|
|
2506
|
+
] });
|
|
2507
|
+
}
|
|
2508
|
+
return /* @__PURE__ */ jsxs35(
|
|
2509
|
+
YStack35,
|
|
2510
|
+
{
|
|
2511
|
+
backgroundColor: "$color1",
|
|
2512
|
+
padding: "$4",
|
|
2513
|
+
borderRadius: "$5",
|
|
2514
|
+
borderWidth: 1,
|
|
2515
|
+
borderColor: "$color4",
|
|
2516
|
+
gap: "$3",
|
|
2517
|
+
children: [
|
|
2518
|
+
/* @__PURE__ */ jsx44(Stars2, { count: rating }),
|
|
2519
|
+
/* @__PURE__ */ jsxs35(SizableText37, { size: "$4", color: "$color11", fontStyle: "italic", lineHeight: 24, children: [
|
|
2520
|
+
'"',
|
|
2521
|
+
quote,
|
|
2522
|
+
'"'
|
|
2523
|
+
] }),
|
|
2524
|
+
/* @__PURE__ */ jsx44(AuthorRow, { author, role, avatar })
|
|
2525
|
+
]
|
|
2526
|
+
}
|
|
2527
|
+
);
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
// src/patterns/ConfirmDialog.tsx
|
|
2531
|
+
import { AlertDialog as AlertDialog2, Button as Button10, SizableText as SizableText38, XStack as XStack31, YStack as YStack36 } from "tamagui";
|
|
2532
|
+
import { jsx as jsx45, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2533
|
+
function ConfirmDialog({
|
|
2534
|
+
open,
|
|
2535
|
+
onOpenChange,
|
|
2536
|
+
title,
|
|
2537
|
+
description,
|
|
2538
|
+
confirmLabel = "Confirm",
|
|
2539
|
+
cancelLabel = "Cancel",
|
|
2540
|
+
onConfirm,
|
|
2541
|
+
onCancel,
|
|
2542
|
+
destructive = false,
|
|
2543
|
+
icon
|
|
2544
|
+
}) {
|
|
2545
|
+
const handleCancel = () => {
|
|
2546
|
+
onCancel?.();
|
|
2547
|
+
onOpenChange(false);
|
|
2548
|
+
};
|
|
2549
|
+
const handleConfirm = () => {
|
|
2550
|
+
onConfirm?.();
|
|
2551
|
+
onOpenChange(false);
|
|
2552
|
+
};
|
|
2553
|
+
return /* @__PURE__ */ jsx45(AlertDialog2, { open, onOpenChange, children: /* @__PURE__ */ jsxs36(AlertDialog2.Portal, { children: [
|
|
2554
|
+
/* @__PURE__ */ jsx45(
|
|
2555
|
+
AlertDialog2.Overlay,
|
|
2556
|
+
{
|
|
2557
|
+
opacity: 0.5,
|
|
2558
|
+
enterStyle: { opacity: 0 },
|
|
2559
|
+
exitStyle: { opacity: 0 },
|
|
2560
|
+
animation: "quick"
|
|
2561
|
+
},
|
|
2562
|
+
"overlay"
|
|
2563
|
+
),
|
|
2564
|
+
/* @__PURE__ */ jsx45(
|
|
2565
|
+
AlertDialog2.Content,
|
|
2566
|
+
{
|
|
2567
|
+
bordered: true,
|
|
2568
|
+
elevate: true,
|
|
2569
|
+
width: "90%",
|
|
2570
|
+
maxWidth: 400,
|
|
2571
|
+
enterStyle: { y: -20, opacity: 0, scale: 0.9 },
|
|
2572
|
+
exitStyle: { y: 10, opacity: 0, scale: 0.95 },
|
|
2573
|
+
x: 0,
|
|
2574
|
+
y: 0,
|
|
2575
|
+
scale: 1,
|
|
2576
|
+
opacity: 1,
|
|
2577
|
+
animation: "quick",
|
|
2578
|
+
children: /* @__PURE__ */ jsxs36(YStack36, { gap: "$4", padding: "$4", children: [
|
|
2579
|
+
icon && /* @__PURE__ */ jsx45(YStack36, { alignItems: "center", children: icon }),
|
|
2580
|
+
/* @__PURE__ */ jsxs36(YStack36, { gap: "$2", alignItems: icon ? "center" : "flex-start", children: [
|
|
2581
|
+
/* @__PURE__ */ jsx45(AlertDialog2.Title, { size: "$6", fontWeight: "700", children: title }),
|
|
2582
|
+
description && /* @__PURE__ */ jsx45(
|
|
2583
|
+
AlertDialog2.Description,
|
|
2584
|
+
{
|
|
2585
|
+
size: "$3",
|
|
2586
|
+
color: "$color10",
|
|
2587
|
+
textAlign: icon ? "center" : "left",
|
|
2588
|
+
children: description
|
|
2589
|
+
}
|
|
2590
|
+
)
|
|
2591
|
+
] }),
|
|
2592
|
+
/* @__PURE__ */ jsxs36(XStack31, { gap: "$3", justifyContent: "flex-end", children: [
|
|
2593
|
+
/* @__PURE__ */ jsx45(
|
|
2594
|
+
Button10,
|
|
2595
|
+
{
|
|
2596
|
+
flex: 1,
|
|
2597
|
+
size: "$4",
|
|
2598
|
+
borderRadius: "$4",
|
|
2599
|
+
variant: "outlined",
|
|
2600
|
+
borderColor: "$color7",
|
|
2601
|
+
onPress: handleCancel,
|
|
2602
|
+
pressStyle: { opacity: 0.7 },
|
|
2603
|
+
animation: "quick",
|
|
2604
|
+
children: /* @__PURE__ */ jsx45(SizableText38, { fontWeight: "600", children: cancelLabel })
|
|
2605
|
+
}
|
|
2606
|
+
),
|
|
2607
|
+
/* @__PURE__ */ jsx45(
|
|
2608
|
+
Button10,
|
|
2609
|
+
{
|
|
2610
|
+
flex: 1,
|
|
2611
|
+
size: "$4",
|
|
2612
|
+
borderRadius: "$4",
|
|
2613
|
+
backgroundColor: destructive ? "$red9" : "$color9",
|
|
2614
|
+
onPress: handleConfirm,
|
|
2615
|
+
pressStyle: { backgroundColor: destructive ? "$red8" : "$color8", scale: 0.97 },
|
|
2616
|
+
animation: "quick",
|
|
2617
|
+
children: /* @__PURE__ */ jsx45(SizableText38, { fontWeight: "600", color: "white", children: confirmLabel })
|
|
2618
|
+
}
|
|
2619
|
+
)
|
|
2620
|
+
] })
|
|
2621
|
+
] })
|
|
2622
|
+
},
|
|
2623
|
+
"content"
|
|
2624
|
+
)
|
|
2625
|
+
] }) });
|
|
2626
|
+
}
|
|
2627
|
+
|
|
2628
|
+
// src/patterns/Chip.tsx
|
|
2629
|
+
import { useCallback as useCallback3 } from "react";
|
|
2630
|
+
import { SizableText as SizableText39, XStack as XStack32 } from "tamagui";
|
|
2631
|
+
import { jsx as jsx46, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
2632
|
+
var sizes2 = { sm: { h: 28, px: "$2", text: "$2" }, md: { h: 34, px: "$3", text: "$3" }, lg: { h: 42, px: "$4", text: "$4" } };
|
|
2633
|
+
function Chip({ label, selected, onPress, onRemove, variant = "filled", size = "md", icon, color }) {
|
|
2634
|
+
const s = sizes2[size];
|
|
2635
|
+
const filled = variant === "filled";
|
|
2636
|
+
const active = selected ?? false;
|
|
2637
|
+
const bg = active ? color ?? "$color9" : filled ? "$color3" : "transparent";
|
|
2638
|
+
const border = active ? color ?? "$color9" : "$color6";
|
|
2639
|
+
const fg = active ? "$color1" : "$color11";
|
|
2640
|
+
return /* @__PURE__ */ jsxs37(
|
|
2641
|
+
XStack32,
|
|
2642
|
+
{
|
|
2643
|
+
height: s.h,
|
|
2644
|
+
borderRadius: "$10",
|
|
2645
|
+
paddingHorizontal: s.px,
|
|
2646
|
+
backgroundColor: bg,
|
|
2647
|
+
borderWidth: filled ? 0 : 1,
|
|
2648
|
+
borderColor: border,
|
|
2649
|
+
alignItems: "center",
|
|
2650
|
+
gap: "$1.5",
|
|
2651
|
+
pressStyle: { scale: 0.96, opacity: 0.85 },
|
|
2652
|
+
animation: "quick",
|
|
2653
|
+
onPress,
|
|
2654
|
+
cursor: "pointer",
|
|
2655
|
+
children: [
|
|
2656
|
+
active && /* @__PURE__ */ jsx46(SizableText39, { size: s.text, color: fg, children: "\u2713" }),
|
|
2657
|
+
icon && /* @__PURE__ */ jsx46(SizableText39, { color: fg, children: icon }),
|
|
2658
|
+
/* @__PURE__ */ jsx46(SizableText39, { size: s.text, color: fg, fontWeight: "500", children: label }),
|
|
2659
|
+
onRemove && /* @__PURE__ */ jsx46(
|
|
2660
|
+
SizableText39,
|
|
2661
|
+
{
|
|
2662
|
+
size: "$2",
|
|
2663
|
+
color: fg,
|
|
2664
|
+
opacity: 0.7,
|
|
2665
|
+
pressStyle: { opacity: 1 },
|
|
2666
|
+
onPress: (e) => {
|
|
2667
|
+
e.stopPropagation?.();
|
|
2668
|
+
onRemove();
|
|
2669
|
+
},
|
|
2670
|
+
marginLeft: "$1",
|
|
2671
|
+
children: "\u2715"
|
|
2672
|
+
}
|
|
2673
|
+
)
|
|
2674
|
+
]
|
|
2675
|
+
}
|
|
2676
|
+
);
|
|
2677
|
+
}
|
|
2678
|
+
function ChipGroup({ chips, selected = [], onSelectionChange, multiSelect = true, variant, size }) {
|
|
2679
|
+
const toggle = useCallback3((id) => {
|
|
2680
|
+
if (!onSelectionChange) return;
|
|
2681
|
+
const isSelected = selected.includes(id);
|
|
2682
|
+
if (multiSelect) {
|
|
2683
|
+
onSelectionChange(isSelected ? selected.filter((s) => s !== id) : [...selected, id]);
|
|
2684
|
+
} else {
|
|
2685
|
+
onSelectionChange(isSelected ? [] : [id]);
|
|
2686
|
+
}
|
|
2687
|
+
}, [selected, onSelectionChange, multiSelect]);
|
|
2688
|
+
return /* @__PURE__ */ jsx46(XStack32, { flexWrap: "wrap", gap: "$2", children: chips.map((chip) => /* @__PURE__ */ jsx46(
|
|
2689
|
+
Chip,
|
|
2690
|
+
{
|
|
2691
|
+
label: chip.label,
|
|
2692
|
+
icon: chip.icon,
|
|
2693
|
+
selected: selected.includes(chip.id),
|
|
2694
|
+
onPress: () => toggle(chip.id),
|
|
2695
|
+
variant,
|
|
2696
|
+
size
|
|
2697
|
+
},
|
|
2698
|
+
chip.id
|
|
2699
|
+
)) });
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
// src/patterns/OTPInput.tsx
|
|
2703
|
+
import { useCallback as useCallback4, useRef as useRef2, useState as useState11 } from "react";
|
|
2704
|
+
import { Platform } from "react-native";
|
|
2705
|
+
import { Input as Input3, SizableText as SizableText40, XStack as XStack33, YStack as YStack37 } from "tamagui";
|
|
2706
|
+
import { jsx as jsx47, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
2707
|
+
function OTPInput({ length = 6, value = "", onChange, onComplete, error, autoFocus, secureEntry }) {
|
|
2708
|
+
const inputRef = useRef2(null);
|
|
2709
|
+
const [focused, setFocused] = useState11(false);
|
|
2710
|
+
const digits = value.padEnd(length, " ").slice(0, length);
|
|
2711
|
+
const handleChange = useCallback4((text) => {
|
|
2712
|
+
const cleaned = text.replace(/\D/g, "").slice(0, length);
|
|
2713
|
+
onChange?.(cleaned);
|
|
2714
|
+
if (cleaned.length === length) onComplete?.(cleaned);
|
|
2715
|
+
}, [length, onChange, onComplete]);
|
|
2716
|
+
const focusInput = useCallback4(() => {
|
|
2717
|
+
inputRef.current?.focus();
|
|
2718
|
+
}, []);
|
|
2719
|
+
return /* @__PURE__ */ jsxs38(YStack37, { position: "relative", children: [
|
|
2720
|
+
/* @__PURE__ */ jsx47(XStack33, { gap: "$2", justifyContent: "center", children: Array.from({ length }, (_, i) => {
|
|
2721
|
+
const char = digits[i]?.trim();
|
|
2722
|
+
const isCursor = focused && value.length === i;
|
|
2723
|
+
return /* @__PURE__ */ jsxs38(
|
|
2724
|
+
YStack37,
|
|
2725
|
+
{
|
|
2726
|
+
width: 48,
|
|
2727
|
+
height: 56,
|
|
2728
|
+
borderRadius: "$3",
|
|
2729
|
+
borderWidth: 2,
|
|
2730
|
+
borderColor: error ? "$red9" : isCursor ? "$color9" : char ? "$color7" : "$color5",
|
|
2731
|
+
backgroundColor: error ? "$red2" : isCursor ? "$color2" : "$color1",
|
|
2732
|
+
alignItems: "center",
|
|
2733
|
+
justifyContent: "center",
|
|
2734
|
+
animation: "quick",
|
|
2735
|
+
pointerEvents: "none",
|
|
2736
|
+
children: [
|
|
2737
|
+
/* @__PURE__ */ jsx47(SizableText40, { size: "$7", fontWeight: "600", color: "$color12", children: char ? secureEntry ? "\u25CF" : char : "" }),
|
|
2738
|
+
isCursor && /* @__PURE__ */ jsx47(
|
|
2739
|
+
YStack37,
|
|
2740
|
+
{
|
|
2741
|
+
position: "absolute",
|
|
2742
|
+
bottom: 10,
|
|
2743
|
+
width: 20,
|
|
2744
|
+
height: 2,
|
|
2745
|
+
backgroundColor: "$color9",
|
|
2746
|
+
animation: "quick"
|
|
2747
|
+
}
|
|
2748
|
+
)
|
|
2749
|
+
]
|
|
2750
|
+
},
|
|
2751
|
+
i
|
|
2752
|
+
);
|
|
2753
|
+
}) }),
|
|
2754
|
+
Platform.OS === "web" ? /* @__PURE__ */ jsx47(
|
|
2755
|
+
"input",
|
|
2756
|
+
{
|
|
2757
|
+
ref: inputRef,
|
|
2758
|
+
type: "text",
|
|
2759
|
+
inputMode: "numeric",
|
|
2760
|
+
pattern: "[0-9]*",
|
|
2761
|
+
autoComplete: "one-time-code",
|
|
2762
|
+
maxLength: length,
|
|
2763
|
+
value,
|
|
2764
|
+
autoFocus,
|
|
2765
|
+
onChange: (e) => handleChange(e.target.value),
|
|
2766
|
+
onFocus: () => setFocused(true),
|
|
2767
|
+
onBlur: () => setFocused(false),
|
|
2768
|
+
style: {
|
|
2769
|
+
position: "absolute",
|
|
2770
|
+
top: 0,
|
|
2771
|
+
left: 0,
|
|
2772
|
+
right: 0,
|
|
2773
|
+
bottom: 0,
|
|
2774
|
+
width: "100%",
|
|
2775
|
+
height: "100%",
|
|
2776
|
+
opacity: 0,
|
|
2777
|
+
fontSize: 16,
|
|
2778
|
+
caretColor: "transparent",
|
|
2779
|
+
cursor: "pointer"
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
) : /* @__PURE__ */ jsx47(
|
|
2783
|
+
Input3,
|
|
2784
|
+
{
|
|
2785
|
+
ref: inputRef,
|
|
2786
|
+
value,
|
|
2787
|
+
onChangeText: handleChange,
|
|
2788
|
+
keyboardType: "number-pad",
|
|
2789
|
+
maxLength: length,
|
|
2790
|
+
autoFocus,
|
|
2791
|
+
onFocus: () => setFocused(true),
|
|
2792
|
+
onBlur: () => setFocused(false),
|
|
2793
|
+
position: "absolute",
|
|
2794
|
+
top: 0,
|
|
2795
|
+
left: 0,
|
|
2796
|
+
right: 0,
|
|
2797
|
+
bottom: 0,
|
|
2798
|
+
opacity: 0,
|
|
2799
|
+
fontSize: 16
|
|
2800
|
+
}
|
|
2801
|
+
)
|
|
2802
|
+
] });
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
// src/patterns/PasswordInput.tsx
|
|
2806
|
+
import { useState as useState12, useCallback as useCallback5 } from "react";
|
|
2807
|
+
import { Input as Input4, SizableText as SizableText41, XStack as XStack34, YStack as YStack38 } from "tamagui";
|
|
2808
|
+
import { jsx as jsx48, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
2809
|
+
function getStrength(pw) {
|
|
2810
|
+
if (!pw) return { label: "", color: "$color6", width: "0%" };
|
|
2811
|
+
const score = [pw.length >= 8, /[A-Z]/.test(pw), /[0-9]/.test(pw), /[^A-Za-z0-9]/.test(pw)].filter(Boolean).length;
|
|
2812
|
+
if (score <= 1) return { label: "Weak", color: "$red9", width: "33%" };
|
|
2813
|
+
if (score <= 2) return { label: "Medium", color: "$yellow9", width: "66%" };
|
|
2814
|
+
return { label: "Strong", color: "$green9", width: "100%" };
|
|
2815
|
+
}
|
|
2816
|
+
function PasswordInput({ value = "", onChangeText, placeholder = "Password", label, error, size = "$4", strengthIndicator }) {
|
|
2817
|
+
const [visible, setVisible] = useState12(false);
|
|
2818
|
+
const toggle = useCallback5(() => setVisible((v) => !v), []);
|
|
2819
|
+
const strength = getStrength(value);
|
|
2820
|
+
return /* @__PURE__ */ jsxs39(YStack38, { gap: "$1.5", children: [
|
|
2821
|
+
label && /* @__PURE__ */ jsx48(SizableText41, { size: "$3", color: "$color11", fontWeight: "500", children: label }),
|
|
2822
|
+
/* @__PURE__ */ jsxs39(
|
|
2823
|
+
XStack34,
|
|
2824
|
+
{
|
|
2825
|
+
borderWidth: 1,
|
|
2826
|
+
borderColor: error ? "$red9" : "$color6",
|
|
2827
|
+
borderRadius: "$3",
|
|
2828
|
+
backgroundColor: "$color2",
|
|
2829
|
+
alignItems: "center",
|
|
2830
|
+
paddingRight: "$2",
|
|
2831
|
+
focusStyle: { borderColor: "$color9" },
|
|
2832
|
+
children: [
|
|
2833
|
+
/* @__PURE__ */ jsx48(
|
|
2834
|
+
Input4,
|
|
2835
|
+
{
|
|
2836
|
+
flex: 1,
|
|
2837
|
+
size,
|
|
2838
|
+
value,
|
|
2839
|
+
onChangeText,
|
|
2840
|
+
placeholder,
|
|
2841
|
+
placeholderTextColor: "$color8",
|
|
2842
|
+
secureTextEntry: !visible,
|
|
2843
|
+
backgroundColor: "transparent",
|
|
2844
|
+
borderWidth: 0
|
|
2845
|
+
}
|
|
2846
|
+
),
|
|
2847
|
+
/* @__PURE__ */ jsx48(
|
|
2848
|
+
SizableText41,
|
|
2849
|
+
{
|
|
2850
|
+
size: "$4",
|
|
2851
|
+
color: "$color8",
|
|
2852
|
+
paddingHorizontal: "$2",
|
|
2853
|
+
pressStyle: { opacity: 0.6 },
|
|
2854
|
+
onPress: toggle,
|
|
2855
|
+
cursor: "pointer",
|
|
2856
|
+
children: visible ? "\u25C9" : "\u25CE"
|
|
2857
|
+
}
|
|
2858
|
+
)
|
|
2859
|
+
]
|
|
2860
|
+
}
|
|
2861
|
+
),
|
|
2862
|
+
strengthIndicator && value.length > 0 && /* @__PURE__ */ jsxs39(YStack38, { gap: "$1", children: [
|
|
2863
|
+
/* @__PURE__ */ jsx48(YStack38, { height: 3, backgroundColor: "$color4", borderRadius: 2, overflow: "hidden", children: /* @__PURE__ */ jsx48(YStack38, { height: 3, width: strength.width, backgroundColor: strength.color, borderRadius: 2, animation: "quick" }) }),
|
|
2864
|
+
/* @__PURE__ */ jsx48(SizableText41, { size: "$1", color: strength.color, children: strength.label })
|
|
2865
|
+
] }),
|
|
2866
|
+
error && /* @__PURE__ */ jsx48(SizableText41, { size: "$2", color: "$red9", children: error })
|
|
2867
|
+
] });
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
// src/patterns/AvatarGroup.tsx
|
|
2871
|
+
import { Circle as Circle10, Image as Image8, SizableText as SizableText42, XStack as XStack35 } from "tamagui";
|
|
2872
|
+
import { jsx as jsx49, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
2873
|
+
function getInitials(name) {
|
|
2874
|
+
if (!name) return "?";
|
|
2875
|
+
return name.split(" ").map((p) => p[0]).join("").toUpperCase().slice(0, 2);
|
|
2876
|
+
}
|
|
2877
|
+
function AvatarItem({ uri, name, color, size }) {
|
|
2878
|
+
return /* @__PURE__ */ jsx49(
|
|
2879
|
+
Circle10,
|
|
2880
|
+
{
|
|
2881
|
+
size,
|
|
2882
|
+
backgroundColor: color ?? "$color4",
|
|
2883
|
+
borderWidth: 2,
|
|
2884
|
+
borderColor: "$background",
|
|
2885
|
+
overflow: "hidden",
|
|
2886
|
+
alignItems: "center",
|
|
2887
|
+
justifyContent: "center",
|
|
2888
|
+
children: uri ? /* @__PURE__ */ jsx49(Image8, { source: { uri }, width: size, height: size, objectFit: "cover" }) : /* @__PURE__ */ jsx49(SizableText42, { size: "$2", fontWeight: "600", color: color ? "$color1" : "$color11", children: getInitials(name) })
|
|
2889
|
+
}
|
|
2890
|
+
);
|
|
2891
|
+
}
|
|
2892
|
+
function AvatarGroup({ avatars, max = 4, size = 36, overlap = 10 }) {
|
|
2893
|
+
const visible = avatars.slice(0, max);
|
|
2894
|
+
const remaining = avatars.length - max;
|
|
2895
|
+
return /* @__PURE__ */ jsxs40(XStack35, { alignItems: "center", children: [
|
|
2896
|
+
visible.map((avatar, i) => /* @__PURE__ */ jsx49(XStack35, { marginLeft: i === 0 ? 0 : -overlap, zIndex: visible.length - i, children: /* @__PURE__ */ jsx49(AvatarItem, { ...avatar, size }) }, i)),
|
|
2897
|
+
remaining > 0 && /* @__PURE__ */ jsx49(XStack35, { marginLeft: -overlap, zIndex: 0, children: /* @__PURE__ */ jsx49(
|
|
2898
|
+
Circle10,
|
|
2899
|
+
{
|
|
2900
|
+
size,
|
|
2901
|
+
backgroundColor: "$color6",
|
|
2902
|
+
borderWidth: 2,
|
|
2903
|
+
borderColor: "$background",
|
|
2904
|
+
alignItems: "center",
|
|
2905
|
+
justifyContent: "center",
|
|
2906
|
+
children: /* @__PURE__ */ jsxs40(SizableText42, { size: "$2", fontWeight: "600", color: "$color11", children: [
|
|
2907
|
+
"+",
|
|
2908
|
+
remaining
|
|
2909
|
+
] })
|
|
2910
|
+
}
|
|
2911
|
+
) })
|
|
2912
|
+
] });
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
// src/patterns/SwipeCards.tsx
|
|
2916
|
+
import { useState as useState13, useCallback as useCallback6 } from "react";
|
|
2917
|
+
import { Circle as Circle11, SizableText as SizableText43, XStack as XStack36, YStack as YStack39 } from "tamagui";
|
|
2918
|
+
import { jsx as jsx50, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
2919
|
+
var STACK_SIZE = 3;
|
|
2920
|
+
var CARD_OFFSETS = [
|
|
2921
|
+
{ scale: 1, y: 0, opacity: 1 },
|
|
2922
|
+
{ scale: 0.95, y: 8, opacity: 0.9 },
|
|
2923
|
+
{ scale: 0.9, y: 16, opacity: 0.8 }
|
|
2924
|
+
];
|
|
2925
|
+
function SwipeCards({
|
|
2926
|
+
items,
|
|
2927
|
+
renderCard,
|
|
2928
|
+
onSwipeLeft,
|
|
2929
|
+
onSwipeRight,
|
|
2930
|
+
onEmpty,
|
|
2931
|
+
leftLabel = "Nope",
|
|
2932
|
+
rightLabel = "Like",
|
|
2933
|
+
emptyMessage = "No more cards"
|
|
2934
|
+
}) {
|
|
2935
|
+
const [index, setIndex] = useState13(0);
|
|
2936
|
+
const [exitDir, setExitDir] = useState13(null);
|
|
2937
|
+
const remaining = items.slice(index);
|
|
2938
|
+
const isEmpty = remaining.length === 0;
|
|
2939
|
+
const handleSwipe = useCallback6((dir) => {
|
|
2940
|
+
if (isEmpty) return;
|
|
2941
|
+
const current = items[index];
|
|
2942
|
+
setExitDir(dir);
|
|
2943
|
+
const timer = setTimeout(() => {
|
|
2944
|
+
setExitDir(null);
|
|
2945
|
+
setIndex((i) => {
|
|
2946
|
+
const next = i + 1;
|
|
2947
|
+
if (next >= items.length) onEmpty?.();
|
|
2948
|
+
return next;
|
|
2949
|
+
});
|
|
2950
|
+
dir === "left" ? onSwipeLeft?.(current) : onSwipeRight?.(current);
|
|
2951
|
+
}, 250);
|
|
2952
|
+
return () => clearTimeout(timer);
|
|
2953
|
+
}, [isEmpty, index, items, onEmpty, onSwipeLeft, onSwipeRight]);
|
|
2954
|
+
if (isEmpty) {
|
|
2955
|
+
return /* @__PURE__ */ jsx50(YStack39, { flex: 1, alignItems: "center", justifyContent: "center", gap: "$3", padding: "$4", children: /* @__PURE__ */ jsx50(SizableText43, { size: "$5", color: "$color8", children: emptyMessage }) });
|
|
2956
|
+
}
|
|
2957
|
+
return /* @__PURE__ */ jsxs41(YStack39, { flex: 1, gap: "$4", children: [
|
|
2958
|
+
/* @__PURE__ */ jsx50(YStack39, { flex: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsx50(YStack39, { width: "100%", maxWidth: 340, aspectRatio: 3 / 4, position: "relative", children: remaining.slice(0, STACK_SIZE).reverse().map((item, reverseIdx) => {
|
|
2959
|
+
const stackIdx = Math.min(remaining.length, STACK_SIZE) - 1 - reverseIdx;
|
|
2960
|
+
const isTop = stackIdx === 0;
|
|
2961
|
+
const offset = CARD_OFFSETS[stackIdx] ?? CARD_OFFSETS[2];
|
|
2962
|
+
const exitX = exitDir === "left" ? -400 : exitDir === "right" ? 400 : 0;
|
|
2963
|
+
const exitRotate = exitDir === "left" ? "-15deg" : exitDir === "right" ? "15deg" : "0deg";
|
|
2964
|
+
return /* @__PURE__ */ jsxs41(
|
|
2965
|
+
YStack39,
|
|
2966
|
+
{
|
|
2967
|
+
position: "absolute",
|
|
2968
|
+
top: 0,
|
|
2969
|
+
left: 0,
|
|
2970
|
+
right: 0,
|
|
2971
|
+
bottom: 0,
|
|
2972
|
+
animation: "quick",
|
|
2973
|
+
borderRadius: "$5",
|
|
2974
|
+
overflow: "hidden",
|
|
2975
|
+
backgroundColor: "$background",
|
|
2976
|
+
elevation: isTop ? 4 : 1,
|
|
2977
|
+
shadowColor: "$shadowColor",
|
|
2978
|
+
shadowRadius: isTop ? 16 : 4,
|
|
2979
|
+
scale: isTop && exitDir ? 1 : offset.scale,
|
|
2980
|
+
opacity: isTop && exitDir ? 0 : offset.opacity,
|
|
2981
|
+
y: isTop && exitDir ? 0 : offset.y,
|
|
2982
|
+
x: isTop ? exitX : 0,
|
|
2983
|
+
rotate: isTop ? exitRotate : "0deg",
|
|
2984
|
+
children: [
|
|
2985
|
+
renderCard(item),
|
|
2986
|
+
isTop && exitDir === "left" && /* @__PURE__ */ jsx50(
|
|
2987
|
+
YStack39,
|
|
2988
|
+
{
|
|
2989
|
+
position: "absolute",
|
|
2990
|
+
top: "$4",
|
|
2991
|
+
right: "$4",
|
|
2992
|
+
borderWidth: 3,
|
|
2993
|
+
borderColor: "$red10",
|
|
2994
|
+
borderRadius: "$3",
|
|
2995
|
+
padding: "$2",
|
|
2996
|
+
rotate: "15deg",
|
|
2997
|
+
children: /* @__PURE__ */ jsx50(SizableText43, { size: "$7", fontWeight: "800", color: "$red10", children: leftLabel.toUpperCase() })
|
|
2998
|
+
}
|
|
2999
|
+
),
|
|
3000
|
+
isTop && exitDir === "right" && /* @__PURE__ */ jsx50(
|
|
3001
|
+
YStack39,
|
|
3002
|
+
{
|
|
3003
|
+
position: "absolute",
|
|
3004
|
+
top: "$4",
|
|
3005
|
+
left: "$4",
|
|
3006
|
+
borderWidth: 3,
|
|
3007
|
+
borderColor: "$green10",
|
|
3008
|
+
borderRadius: "$3",
|
|
3009
|
+
padding: "$2",
|
|
3010
|
+
rotate: "-15deg",
|
|
3011
|
+
children: /* @__PURE__ */ jsx50(SizableText43, { size: "$7", fontWeight: "800", color: "$green10", children: rightLabel.toUpperCase() })
|
|
3012
|
+
}
|
|
3013
|
+
)
|
|
3014
|
+
]
|
|
3015
|
+
},
|
|
3016
|
+
item.id
|
|
3017
|
+
);
|
|
3018
|
+
}) }) }),
|
|
3019
|
+
/* @__PURE__ */ jsxs41(XStack36, { justifyContent: "center", gap: "$6", paddingBottom: "$4", children: [
|
|
3020
|
+
/* @__PURE__ */ jsx50(
|
|
3021
|
+
Circle11,
|
|
3022
|
+
{
|
|
3023
|
+
size: 60,
|
|
3024
|
+
backgroundColor: "$red3",
|
|
3025
|
+
borderWidth: 2,
|
|
3026
|
+
borderColor: "$red7",
|
|
3027
|
+
pressStyle: { scale: 0.9, backgroundColor: "$red5" },
|
|
3028
|
+
animation: "quick",
|
|
3029
|
+
onPress: () => handleSwipe("left"),
|
|
3030
|
+
alignItems: "center",
|
|
3031
|
+
justifyContent: "center",
|
|
3032
|
+
children: /* @__PURE__ */ jsx50(SizableText43, { size: "$6", color: "$red10", fontWeight: "700", children: "\u2715" })
|
|
3033
|
+
}
|
|
3034
|
+
),
|
|
3035
|
+
/* @__PURE__ */ jsx50(
|
|
3036
|
+
Circle11,
|
|
3037
|
+
{
|
|
3038
|
+
size: 60,
|
|
3039
|
+
backgroundColor: "$green3",
|
|
3040
|
+
borderWidth: 2,
|
|
3041
|
+
borderColor: "$green7",
|
|
3042
|
+
pressStyle: { scale: 0.9, backgroundColor: "$green5" },
|
|
3043
|
+
animation: "quick",
|
|
3044
|
+
onPress: () => handleSwipe("right"),
|
|
3045
|
+
alignItems: "center",
|
|
3046
|
+
justifyContent: "center",
|
|
3047
|
+
children: /* @__PURE__ */ jsx50(SizableText43, { size: "$6", color: "$green10", fontWeight: "700", children: "\u2665" })
|
|
3048
|
+
}
|
|
3049
|
+
)
|
|
3050
|
+
] })
|
|
3051
|
+
] });
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
// src/patterns/GlassCard.tsx
|
|
3055
|
+
import { styled as styled12, YStack as YStack40 } from "tamagui";
|
|
3056
|
+
import { jsx as jsx51 } from "react/jsx-runtime";
|
|
3057
|
+
var BLUR = { light: 8, medium: 16, heavy: 24 };
|
|
3058
|
+
var TINT_BG = {
|
|
3059
|
+
light: "rgba(255,255,255,0.15)",
|
|
3060
|
+
dark: "rgba(0,0,0,0.25)"
|
|
3061
|
+
};
|
|
3062
|
+
var GlassFrame = styled12(YStack40, {
|
|
3063
|
+
borderWidth: 1,
|
|
3064
|
+
borderColor: "rgba(255,255,255,0.2)",
|
|
3065
|
+
overflow: "hidden"
|
|
3066
|
+
});
|
|
3067
|
+
function GlassCard({
|
|
3068
|
+
children,
|
|
3069
|
+
intensity = "medium",
|
|
3070
|
+
tint = "light",
|
|
3071
|
+
borderRadius = "$4",
|
|
3072
|
+
padding = "$4",
|
|
3073
|
+
elevated = false
|
|
3074
|
+
}) {
|
|
3075
|
+
const blur = BLUR[intensity];
|
|
3076
|
+
return /* @__PURE__ */ jsx51(
|
|
3077
|
+
GlassFrame,
|
|
3078
|
+
{
|
|
3079
|
+
borderRadius,
|
|
3080
|
+
padding,
|
|
3081
|
+
backgroundColor: TINT_BG[tint],
|
|
3082
|
+
elevation: elevated ? 4 : 0,
|
|
3083
|
+
shadowColor: elevated ? "$shadowColor" : void 0,
|
|
3084
|
+
shadowRadius: elevated ? 20 : void 0,
|
|
3085
|
+
shadowOpacity: elevated ? 0.3 : void 0,
|
|
3086
|
+
style: { backdropFilter: `blur(${blur}px)`, WebkitBackdropFilter: `blur(${blur}px)` },
|
|
3087
|
+
children
|
|
1636
3088
|
}
|
|
1637
3089
|
);
|
|
1638
3090
|
}
|
|
3091
|
+
|
|
3092
|
+
// src/patterns/DataTable.tsx
|
|
3093
|
+
import { useMemo, useState as useState14 } from "react";
|
|
3094
|
+
import { SizableText as SizableText44, Separator as Separator5, XStack as XStack37, YStack as YStack41, useMedia, styled as styled13, View as View6 } from "tamagui";
|
|
3095
|
+
import { jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
3096
|
+
var TH = styled13(View6, { padding: "$3", justifyContent: "center" });
|
|
3097
|
+
var TD = styled13(View6, { padding: "$3", justifyContent: "center" });
|
|
3098
|
+
function StatusBadge({ status }) {
|
|
3099
|
+
const isActive = status.toLowerCase() === "active";
|
|
3100
|
+
return /* @__PURE__ */ jsxs42(XStack37, { gap: "$2", alignItems: "center", children: [
|
|
3101
|
+
/* @__PURE__ */ jsx52(
|
|
3102
|
+
View6,
|
|
3103
|
+
{
|
|
3104
|
+
width: 8,
|
|
3105
|
+
height: 8,
|
|
3106
|
+
borderRadius: 4,
|
|
3107
|
+
backgroundColor: isActive ? "$green9" : "$orange9"
|
|
3108
|
+
}
|
|
3109
|
+
),
|
|
3110
|
+
/* @__PURE__ */ jsx52(SizableText44, { size: "$3", color: "$color11", children: status })
|
|
3111
|
+
] });
|
|
3112
|
+
}
|
|
3113
|
+
function HeaderCell({ col, sort, onSort }) {
|
|
3114
|
+
const active = sort?.key === col.key;
|
|
3115
|
+
const indicator = active ? sort.dir === "asc" ? " \u25B2" : " \u25BC" : "";
|
|
3116
|
+
return /* @__PURE__ */ jsx52(
|
|
3117
|
+
TH,
|
|
3118
|
+
{
|
|
3119
|
+
width: col.width,
|
|
3120
|
+
flexDirection: "row",
|
|
3121
|
+
alignItems: "center",
|
|
3122
|
+
cursor: col.sortable ? "pointer" : void 0,
|
|
3123
|
+
onPress: col.sortable ? onSort : void 0,
|
|
3124
|
+
pressStyle: col.sortable ? { opacity: 0.7 } : void 0,
|
|
3125
|
+
children: /* @__PURE__ */ jsxs42(
|
|
3126
|
+
SizableText44,
|
|
3127
|
+
{
|
|
3128
|
+
size: "$2",
|
|
3129
|
+
fontWeight: "700",
|
|
3130
|
+
color: active ? "$color12" : "$color9",
|
|
3131
|
+
textTransform: "uppercase",
|
|
3132
|
+
letterSpacing: 0.5,
|
|
3133
|
+
children: [
|
|
3134
|
+
col.header,
|
|
3135
|
+
indicator
|
|
3136
|
+
]
|
|
3137
|
+
}
|
|
3138
|
+
)
|
|
3139
|
+
},
|
|
3140
|
+
col.key
|
|
3141
|
+
);
|
|
3142
|
+
}
|
|
3143
|
+
function TableRow({ row, columns, onPress, odd }) {
|
|
3144
|
+
return /* @__PURE__ */ jsx52(
|
|
3145
|
+
XStack37,
|
|
3146
|
+
{
|
|
3147
|
+
backgroundColor: odd ? "$color2" : "transparent",
|
|
3148
|
+
borderBottomWidth: 0.5,
|
|
3149
|
+
borderColor: "$color4",
|
|
3150
|
+
hoverStyle: { backgroundColor: "$color3" },
|
|
3151
|
+
cursor: onPress ? "pointer" : void 0,
|
|
3152
|
+
onPress: onPress ? () => onPress(row) : void 0,
|
|
3153
|
+
pressStyle: onPress ? { opacity: 0.85 } : void 0,
|
|
3154
|
+
animation: "quick",
|
|
3155
|
+
children: columns.map((col) => /* @__PURE__ */ jsx52(TD, { width: col.width, flex: col.width ? void 0 : 1, children: col.render ? col.render(row[col.key], row) : /* @__PURE__ */ jsx52(SizableText44, { size: "$3", color: "$color11", children: String(row[col.key] ?? "") }) }, col.key))
|
|
3156
|
+
}
|
|
3157
|
+
);
|
|
3158
|
+
}
|
|
3159
|
+
function CardRow({ row, columns, onPress }) {
|
|
3160
|
+
return /* @__PURE__ */ jsx52(
|
|
3161
|
+
YStack41,
|
|
3162
|
+
{
|
|
3163
|
+
backgroundColor: "$color1",
|
|
3164
|
+
borderRadius: "$4",
|
|
3165
|
+
borderWidth: 1,
|
|
3166
|
+
borderColor: "$color4",
|
|
3167
|
+
padding: "$3",
|
|
3168
|
+
gap: "$2",
|
|
3169
|
+
onPress: onPress ? () => onPress(row) : void 0,
|
|
3170
|
+
pressStyle: onPress ? { scale: 0.98, opacity: 0.9 } : void 0,
|
|
3171
|
+
animation: "quick",
|
|
3172
|
+
children: columns.map((col, i) => /* @__PURE__ */ jsxs42(YStack41, { children: [
|
|
3173
|
+
i > 0 && /* @__PURE__ */ jsx52(Separator5, { marginVertical: "$1.5", borderColor: "$color4" }),
|
|
3174
|
+
/* @__PURE__ */ jsxs42(XStack37, { justifyContent: "space-between", alignItems: "center", children: [
|
|
3175
|
+
/* @__PURE__ */ jsx52(SizableText44, { size: "$2", color: "$color9", fontWeight: "600", children: col.header }),
|
|
3176
|
+
col.render ? col.render(row[col.key], row) : /* @__PURE__ */ jsx52(SizableText44, { size: "$3", color: "$color11", children: String(row[col.key] ?? "") })
|
|
3177
|
+
] })
|
|
3178
|
+
] }, col.key))
|
|
3179
|
+
}
|
|
3180
|
+
);
|
|
3181
|
+
}
|
|
3182
|
+
function DataTable({ columns, data, onRowPress, emptyMessage = "No data" }) {
|
|
3183
|
+
const [sort, setSort] = useState14(null);
|
|
3184
|
+
const media = useMedia();
|
|
3185
|
+
const isSmall = media.sm;
|
|
3186
|
+
const sorted = useMemo(() => {
|
|
3187
|
+
if (!sort) return data;
|
|
3188
|
+
return [...data].sort((a, b) => {
|
|
3189
|
+
const av = a[sort.key], bv = b[sort.key];
|
|
3190
|
+
const cmp = typeof av === "number" && typeof bv === "number" ? av - bv : String(av ?? "").localeCompare(String(bv ?? ""));
|
|
3191
|
+
return sort.dir === "asc" ? cmp : -cmp;
|
|
3192
|
+
});
|
|
3193
|
+
}, [data, sort]);
|
|
3194
|
+
const toggleSort = (key) => setSort((s) => s?.key === key ? { key, dir: s.dir === "asc" ? "desc" : "asc" } : { key, dir: "asc" });
|
|
3195
|
+
if (!data.length) {
|
|
3196
|
+
return /* @__PURE__ */ jsx52(YStack41, { padding: "$6", alignItems: "center", children: /* @__PURE__ */ jsx52(SizableText44, { size: "$4", color: "$color9", children: emptyMessage }) });
|
|
3197
|
+
}
|
|
3198
|
+
if (isSmall) {
|
|
3199
|
+
return /* @__PURE__ */ jsx52(YStack41, { gap: "$3", children: sorted.map((row, i) => /* @__PURE__ */ jsx52(CardRow, { row, columns, onPress: onRowPress }, i)) });
|
|
3200
|
+
}
|
|
3201
|
+
return /* @__PURE__ */ jsxs42(YStack41, { borderWidth: 1, borderColor: "$color4", borderRadius: "$4", overflow: "hidden", children: [
|
|
3202
|
+
/* @__PURE__ */ jsx52(XStack37, { backgroundColor: "$color1", borderBottomWidth: 1, borderColor: "$color4", children: columns.map((col) => /* @__PURE__ */ jsx52(HeaderCell, { col, sort, onSort: () => toggleSort(col.key) }, col.key)) }),
|
|
3203
|
+
sorted.map((row, i) => /* @__PURE__ */ jsx52(TableRow, { row, columns, onPress: onRowPress, odd: i % 2 === 1 }, i))
|
|
3204
|
+
] });
|
|
3205
|
+
}
|
|
3206
|
+
|
|
3207
|
+
// src/patterns/DatePicker.tsx
|
|
3208
|
+
import { useCallback as useCallback7, useMemo as useMemo2, useState as useState15 } from "react";
|
|
3209
|
+
import { SizableText as SizableText45, XStack as XStack38, YStack as YStack42 } from "tamagui";
|
|
3210
|
+
import { jsx as jsx53, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3211
|
+
var MONTH_NAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
3212
|
+
var DAY_LABELS_SUN = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
3213
|
+
var DAY_LABELS_MON = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
|
|
3214
|
+
function daysInMonth(year, month) {
|
|
3215
|
+
return new Date(year, month + 1, 0).getDate();
|
|
3216
|
+
}
|
|
3217
|
+
function sameDay(a, b) {
|
|
3218
|
+
return a ? a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate() : false;
|
|
3219
|
+
}
|
|
3220
|
+
function buildGrid(year, month, startDay) {
|
|
3221
|
+
const total = daysInMonth(year, month);
|
|
3222
|
+
const firstWeekday = new Date(year, month, 1).getDay();
|
|
3223
|
+
const offset = (firstWeekday - startDay + 7) % 7;
|
|
3224
|
+
const prevTotal = daysInMonth(year, month - 1);
|
|
3225
|
+
const cells = [];
|
|
3226
|
+
for (let i = offset - 1; i >= 0; i--)
|
|
3227
|
+
cells.push({ day: prevTotal - i, month: month - 1, year: month === 0 ? year - 1 : year, outside: true });
|
|
3228
|
+
for (let d = 1; d <= total; d++)
|
|
3229
|
+
cells.push({ day: d, month, year, outside: false });
|
|
3230
|
+
while (cells.length < 42)
|
|
3231
|
+
cells.push({ day: cells.length - offset - total + 1, month: month + 1, year: month === 11 ? year + 1 : year, outside: true });
|
|
3232
|
+
return cells;
|
|
3233
|
+
}
|
|
3234
|
+
function NavButton({ label, onPress }) {
|
|
3235
|
+
return /* @__PURE__ */ jsx53(
|
|
3236
|
+
XStack38,
|
|
3237
|
+
{
|
|
3238
|
+
width: 36,
|
|
3239
|
+
height: 36,
|
|
3240
|
+
borderRadius: "$10",
|
|
3241
|
+
alignItems: "center",
|
|
3242
|
+
justifyContent: "center",
|
|
3243
|
+
backgroundColor: "$color3",
|
|
3244
|
+
pressStyle: { scale: 0.92, backgroundColor: "$color5" },
|
|
3245
|
+
animation: "quick",
|
|
3246
|
+
onPress,
|
|
3247
|
+
cursor: "pointer",
|
|
3248
|
+
children: /* @__PURE__ */ jsx53(SizableText45, { size: "$5", color: "$color11", fontWeight: "600", children: label })
|
|
3249
|
+
}
|
|
3250
|
+
);
|
|
3251
|
+
}
|
|
3252
|
+
function DatePicker({ value, onDateChange, minDate, maxDate, startDay = 1 }) {
|
|
3253
|
+
const today = useMemo2(() => /* @__PURE__ */ new Date(), []);
|
|
3254
|
+
const [viewMonth, setViewMonth] = useState15(value?.getMonth() ?? today.getMonth());
|
|
3255
|
+
const [viewYear, setViewYear] = useState15(value?.getFullYear() ?? today.getFullYear());
|
|
3256
|
+
const headers = startDay === 1 ? DAY_LABELS_MON : DAY_LABELS_SUN;
|
|
3257
|
+
const grid = useMemo2(() => buildGrid(viewYear, viewMonth, startDay), [viewYear, viewMonth, startDay]);
|
|
3258
|
+
const navigate = useCallback7((dir) => {
|
|
3259
|
+
setViewMonth((m) => {
|
|
3260
|
+
const next = m + dir;
|
|
3261
|
+
if (next < 0) {
|
|
3262
|
+
setViewYear((y) => y - 1);
|
|
3263
|
+
return 11;
|
|
3264
|
+
}
|
|
3265
|
+
if (next > 11) {
|
|
3266
|
+
setViewYear((y) => y + 1);
|
|
3267
|
+
return 0;
|
|
3268
|
+
}
|
|
3269
|
+
return next;
|
|
3270
|
+
});
|
|
3271
|
+
}, []);
|
|
3272
|
+
const isDisabled = useCallback7((d) => {
|
|
3273
|
+
if (minDate && d < new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate())) return true;
|
|
3274
|
+
if (maxDate && d > new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate())) return true;
|
|
3275
|
+
return false;
|
|
3276
|
+
}, [minDate, maxDate]);
|
|
3277
|
+
return /* @__PURE__ */ jsxs43(YStack42, { backgroundColor: "$color2", borderRadius: "$4", padding: "$3", gap: "$2", animation: "quick", children: [
|
|
3278
|
+
/* @__PURE__ */ jsxs43(XStack38, { alignItems: "center", justifyContent: "space-between", children: [
|
|
3279
|
+
/* @__PURE__ */ jsx53(NavButton, { label: "\u2039", onPress: () => navigate(-1) }),
|
|
3280
|
+
/* @__PURE__ */ jsxs43(SizableText45, { size: "$4", fontWeight: "700", color: "$color12", children: [
|
|
3281
|
+
MONTH_NAMES[viewMonth],
|
|
3282
|
+
" ",
|
|
3283
|
+
viewYear
|
|
3284
|
+
] }),
|
|
3285
|
+
/* @__PURE__ */ jsx53(NavButton, { label: "\u203A", onPress: () => navigate(1) })
|
|
3286
|
+
] }),
|
|
3287
|
+
/* @__PURE__ */ jsx53(XStack38, { children: headers.map((h) => /* @__PURE__ */ jsx53(SizableText45, { size: "$2", color: "$color8", fontWeight: "600", textAlign: "center", flex: 1, children: h }, h)) }),
|
|
3288
|
+
Array.from({ length: Math.ceil(grid.length / 7) }, (_, row) => /* @__PURE__ */ jsx53(XStack38, { children: grid.slice(row * 7, row * 7 + 7).map((cell, i) => {
|
|
3289
|
+
const date = new Date(cell.year, cell.month, cell.day);
|
|
3290
|
+
const selected = sameDay(value, date);
|
|
3291
|
+
const isToday = sameDay(today, date);
|
|
3292
|
+
const disabled = cell.outside || isDisabled(date);
|
|
3293
|
+
return /* @__PURE__ */ jsx53(YStack42, { flex: 1, alignItems: "center", paddingVertical: "$0.5", children: /* @__PURE__ */ jsx53(
|
|
3294
|
+
XStack38,
|
|
3295
|
+
{
|
|
3296
|
+
width: 40,
|
|
3297
|
+
height: 40,
|
|
3298
|
+
borderRadius: "$10",
|
|
3299
|
+
alignItems: "center",
|
|
3300
|
+
justifyContent: "center",
|
|
3301
|
+
backgroundColor: selected ? "$color9" : "transparent",
|
|
3302
|
+
borderWidth: isToday && !selected ? 1.5 : 0,
|
|
3303
|
+
borderColor: "$color9",
|
|
3304
|
+
pressStyle: disabled ? void 0 : { scale: 0.9, backgroundColor: selected ? "$color10" : "$color4" },
|
|
3305
|
+
animation: "quick",
|
|
3306
|
+
opacity: disabled ? 0.35 : 1,
|
|
3307
|
+
cursor: disabled ? "default" : "pointer",
|
|
3308
|
+
onPress: disabled ? void 0 : () => onDateChange?.(date),
|
|
3309
|
+
children: /* @__PURE__ */ jsx53(
|
|
3310
|
+
SizableText45,
|
|
3311
|
+
{
|
|
3312
|
+
size: "$3",
|
|
3313
|
+
fontWeight: selected || isToday ? "700" : "400",
|
|
3314
|
+
color: selected ? "white" : cell.outside ? "$color5" : "$color12",
|
|
3315
|
+
children: cell.day
|
|
3316
|
+
}
|
|
3317
|
+
)
|
|
3318
|
+
}
|
|
3319
|
+
) }, `${row}-${i}`);
|
|
3320
|
+
}) }, row))
|
|
3321
|
+
] });
|
|
3322
|
+
}
|
|
3323
|
+
|
|
3324
|
+
// src/patterns/EventCard.tsx
|
|
3325
|
+
import { SizableText as SizableText46, Theme, XStack as XStack39, YStack as YStack43 } from "tamagui";
|
|
3326
|
+
import { jsx as jsx54, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3327
|
+
var THEME_MAP = {
|
|
3328
|
+
purple: "purple",
|
|
3329
|
+
green: "green",
|
|
3330
|
+
blue: "blue",
|
|
3331
|
+
orange: "orange",
|
|
3332
|
+
red: "red",
|
|
3333
|
+
pink: "pink"
|
|
3334
|
+
};
|
|
3335
|
+
function ParticipantDots({ count, max }) {
|
|
3336
|
+
const dots = Math.min(count, 5);
|
|
3337
|
+
return /* @__PURE__ */ jsxs44(XStack39, { alignItems: "center", gap: "$1.5", children: [
|
|
3338
|
+
/* @__PURE__ */ jsx54(XStack39, { children: Array.from({ length: dots }, (_, i) => /* @__PURE__ */ jsx54(
|
|
3339
|
+
YStack43,
|
|
3340
|
+
{
|
|
3341
|
+
width: 22,
|
|
3342
|
+
height: 22,
|
|
3343
|
+
borderRadius: 11,
|
|
3344
|
+
backgroundColor: "$color7",
|
|
3345
|
+
borderWidth: 2,
|
|
3346
|
+
borderColor: "$color4",
|
|
3347
|
+
marginLeft: i > 0 ? -8 : 0,
|
|
3348
|
+
alignItems: "center",
|
|
3349
|
+
justifyContent: "center",
|
|
3350
|
+
children: /* @__PURE__ */ jsx54(SizableText46, { size: "$1", color: "$color1", fontWeight: "700", children: String.fromCharCode(65 + i) })
|
|
3351
|
+
},
|
|
3352
|
+
i
|
|
3353
|
+
)) }),
|
|
3354
|
+
/* @__PURE__ */ jsxs44(SizableText46, { size: "$2", color: "$color11", fontWeight: "500", children: [
|
|
3355
|
+
count,
|
|
3356
|
+
max ? `/${max}` : ""
|
|
3357
|
+
] })
|
|
3358
|
+
] });
|
|
3359
|
+
}
|
|
3360
|
+
function CardInner({ title, subtitle, time, location, label, participants, maxParticipants, onPress, actions }) {
|
|
3361
|
+
return /* @__PURE__ */ jsxs44(
|
|
3362
|
+
YStack43,
|
|
3363
|
+
{
|
|
3364
|
+
backgroundColor: "$color4",
|
|
3365
|
+
borderRadius: "$5",
|
|
3366
|
+
padding: "$4",
|
|
3367
|
+
gap: "$3",
|
|
3368
|
+
borderWidth: 1,
|
|
3369
|
+
borderColor: "$color7",
|
|
3370
|
+
onPress,
|
|
3371
|
+
animation: "quick",
|
|
3372
|
+
pressStyle: onPress ? { scale: 0.97, opacity: 0.9 } : void 0,
|
|
3373
|
+
cursor: onPress ? "pointer" : void 0,
|
|
3374
|
+
children: [
|
|
3375
|
+
/* @__PURE__ */ jsxs44(XStack39, { justifyContent: "space-between", alignItems: "flex-start", children: [
|
|
3376
|
+
/* @__PURE__ */ jsxs44(YStack43, { flex: 1, gap: "$1", children: [
|
|
3377
|
+
/* @__PURE__ */ jsx54(SizableText46, { size: "$6", fontWeight: "700", color: "$color12", children: title }),
|
|
3378
|
+
subtitle && /* @__PURE__ */ jsx54(SizableText46, { size: "$3", color: "$color11", opacity: 0.8, children: subtitle })
|
|
3379
|
+
] }),
|
|
3380
|
+
time && /* @__PURE__ */ jsx54(YStack43, { backgroundColor: "$color6", paddingHorizontal: "$2.5", paddingVertical: "$1.5", borderRadius: "$3", children: /* @__PURE__ */ jsx54(SizableText46, { size: "$2", fontWeight: "600", color: "$color12", children: time }) })
|
|
3381
|
+
] }),
|
|
3382
|
+
/* @__PURE__ */ jsxs44(XStack39, { gap: "$4", alignItems: "center", flexWrap: "wrap", children: [
|
|
3383
|
+
location && /* @__PURE__ */ jsxs44(XStack39, { gap: "$1.5", alignItems: "center", children: [
|
|
3384
|
+
/* @__PURE__ */ jsx54(SizableText46, { size: "$3", children: "\u{1F4CD}" }),
|
|
3385
|
+
/* @__PURE__ */ jsx54(SizableText46, { size: "$3", color: "$color11", children: location })
|
|
3386
|
+
] }),
|
|
3387
|
+
participants !== void 0 && /* @__PURE__ */ jsx54(ParticipantDots, { count: participants, max: maxParticipants })
|
|
3388
|
+
] }),
|
|
3389
|
+
(label || actions) && /* @__PURE__ */ jsxs44(XStack39, { justifyContent: "space-between", alignItems: "center", children: [
|
|
3390
|
+
label ? /* @__PURE__ */ jsx54(XStack39, { backgroundColor: "$color6", paddingHorizontal: "$2.5", paddingVertical: "$1", borderRadius: "$10", children: /* @__PURE__ */ jsx54(SizableText46, { size: "$2", fontWeight: "600", color: "$color11", children: label }) }) : /* @__PURE__ */ jsx54(YStack43, {}),
|
|
3391
|
+
actions
|
|
3392
|
+
] })
|
|
3393
|
+
]
|
|
3394
|
+
}
|
|
3395
|
+
);
|
|
3396
|
+
}
|
|
3397
|
+
function EventCard({ theme = "purple", ...props }) {
|
|
3398
|
+
return /* @__PURE__ */ jsx54(Theme, { name: THEME_MAP[theme], children: /* @__PURE__ */ jsx54(CardInner, { ...props }) });
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3401
|
+
// src/patterns/UserPreferences.tsx
|
|
3402
|
+
import { Separator as Separator6, SizableText as SizableText47, Slider, Switch as Switch2, XStack as XStack40, YStack as YStack44 } from "tamagui";
|
|
3403
|
+
import { jsx as jsx55, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3404
|
+
function ItemLabel({ title, description, color }) {
|
|
3405
|
+
return /* @__PURE__ */ jsxs45(YStack44, { flex: 1, gap: "$1", children: [
|
|
3406
|
+
/* @__PURE__ */ jsx55(SizableText47, { size: "$4", fontWeight: "500", color: color ?? "$color12", children: title }),
|
|
3407
|
+
description && /* @__PURE__ */ jsx55(SizableText47, { size: "$2", color: "$color9", children: description })
|
|
3408
|
+
] });
|
|
3409
|
+
}
|
|
3410
|
+
function ToggleRow({ item }) {
|
|
3411
|
+
return /* @__PURE__ */ jsxs45(XStack40, { alignItems: "center", gap: "$3", paddingVertical: "$3", paddingHorizontal: "$4", children: [
|
|
3412
|
+
/* @__PURE__ */ jsx55(ItemLabel, { title: item.title, description: item.description }),
|
|
3413
|
+
/* @__PURE__ */ jsx55(Switch2, { size: "$3", checked: item.value, onCheckedChange: item.onValueChange, children: /* @__PURE__ */ jsx55(Switch2.Thumb, { animation: "quick" }) })
|
|
3414
|
+
] });
|
|
3415
|
+
}
|
|
3416
|
+
function SelectRow({ item }) {
|
|
3417
|
+
const current = item.options.find((o) => o.value === item.value);
|
|
3418
|
+
return /* @__PURE__ */ jsxs45(
|
|
3419
|
+
XStack40,
|
|
3420
|
+
{
|
|
3421
|
+
alignItems: "center",
|
|
3422
|
+
gap: "$3",
|
|
3423
|
+
paddingVertical: "$3",
|
|
3424
|
+
paddingHorizontal: "$4",
|
|
3425
|
+
pressStyle: { backgroundColor: "$color3" },
|
|
3426
|
+
animation: "quick",
|
|
3427
|
+
cursor: "pointer",
|
|
3428
|
+
onPress: () => {
|
|
3429
|
+
const idx = item.options.findIndex((o) => o.value === item.value);
|
|
3430
|
+
const next = item.options[(idx + 1) % item.options.length];
|
|
3431
|
+
if (next) item.onValueChange(next.value);
|
|
3432
|
+
},
|
|
3433
|
+
children: [
|
|
3434
|
+
/* @__PURE__ */ jsx55(ItemLabel, { title: item.title, description: item.description }),
|
|
3435
|
+
/* @__PURE__ */ jsx55(SizableText47, { size: "$3", color: "$color9", fontWeight: "500", children: current?.label ?? item.value }),
|
|
3436
|
+
/* @__PURE__ */ jsx55(SizableText47, { size: "$4", color: "$color8", children: "\u203A" })
|
|
3437
|
+
]
|
|
3438
|
+
}
|
|
3439
|
+
);
|
|
3440
|
+
}
|
|
3441
|
+
function SliderRow({ item }) {
|
|
3442
|
+
const min = item.min ?? 0;
|
|
3443
|
+
const max = item.max ?? 100;
|
|
3444
|
+
return /* @__PURE__ */ jsxs45(YStack44, { gap: "$2", paddingVertical: "$3", paddingHorizontal: "$4", children: [
|
|
3445
|
+
/* @__PURE__ */ jsxs45(XStack40, { justifyContent: "space-between", alignItems: "center", children: [
|
|
3446
|
+
/* @__PURE__ */ jsx55(ItemLabel, { title: item.title, description: item.description }),
|
|
3447
|
+
/* @__PURE__ */ jsx55(SizableText47, { size: "$3", fontWeight: "600", color: "$color11", children: item.value })
|
|
3448
|
+
] }),
|
|
3449
|
+
/* @__PURE__ */ jsxs45(
|
|
3450
|
+
Slider,
|
|
3451
|
+
{
|
|
3452
|
+
value: [item.value],
|
|
3453
|
+
min,
|
|
3454
|
+
max,
|
|
3455
|
+
step: 1,
|
|
3456
|
+
onValueChange: ([v]) => {
|
|
3457
|
+
if (v !== void 0) item.onValueChange(v);
|
|
3458
|
+
},
|
|
3459
|
+
children: [
|
|
3460
|
+
/* @__PURE__ */ jsx55(Slider.Track, { backgroundColor: "$color4", height: 4, children: /* @__PURE__ */ jsx55(Slider.TrackActive, { backgroundColor: "$color9" }) }),
|
|
3461
|
+
/* @__PURE__ */ jsx55(Slider.Thumb, { index: 0, size: "$1.5", backgroundColor: "$color9", borderWidth: 0, circular: true })
|
|
3462
|
+
]
|
|
3463
|
+
}
|
|
3464
|
+
)
|
|
3465
|
+
] });
|
|
3466
|
+
}
|
|
3467
|
+
function ActionRow({ item }) {
|
|
3468
|
+
return /* @__PURE__ */ jsxs45(
|
|
3469
|
+
XStack40,
|
|
3470
|
+
{
|
|
3471
|
+
alignItems: "center",
|
|
3472
|
+
gap: "$3",
|
|
3473
|
+
paddingVertical: "$3",
|
|
3474
|
+
paddingHorizontal: "$4",
|
|
3475
|
+
pressStyle: { backgroundColor: "$color3" },
|
|
3476
|
+
animation: "quick",
|
|
3477
|
+
cursor: "pointer",
|
|
3478
|
+
onPress: item.onPress,
|
|
3479
|
+
children: [
|
|
3480
|
+
/* @__PURE__ */ jsx55(
|
|
3481
|
+
ItemLabel,
|
|
3482
|
+
{
|
|
3483
|
+
title: item.title,
|
|
3484
|
+
description: item.description,
|
|
3485
|
+
color: item.destructive ? "$red10" : void 0
|
|
3486
|
+
}
|
|
3487
|
+
),
|
|
3488
|
+
/* @__PURE__ */ jsx55(SizableText47, { size: "$4", color: "$color8", children: "\u203A" })
|
|
3489
|
+
]
|
|
3490
|
+
}
|
|
3491
|
+
);
|
|
3492
|
+
}
|
|
3493
|
+
function PreferenceRow({ item }) {
|
|
3494
|
+
switch (item.type) {
|
|
3495
|
+
case "toggle":
|
|
3496
|
+
return /* @__PURE__ */ jsx55(ToggleRow, { item });
|
|
3497
|
+
case "select":
|
|
3498
|
+
return /* @__PURE__ */ jsx55(SelectRow, { item });
|
|
3499
|
+
case "slider":
|
|
3500
|
+
return /* @__PURE__ */ jsx55(SliderRow, { item });
|
|
3501
|
+
case "action":
|
|
3502
|
+
return /* @__PURE__ */ jsx55(ActionRow, { item });
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
function UserPreferences({ sections }) {
|
|
3506
|
+
return /* @__PURE__ */ jsx55(YStack44, { gap: "$5", children: sections.map((section, si) => /* @__PURE__ */ jsxs45(YStack44, { gap: "$2", children: [
|
|
3507
|
+
/* @__PURE__ */ jsxs45(YStack44, { paddingHorizontal: "$1", gap: "$0.5", children: [
|
|
3508
|
+
/* @__PURE__ */ jsx55(SizableText47, { size: "$2", fontWeight: "600", color: "$color9", textTransform: "uppercase", children: section.title }),
|
|
3509
|
+
section.description && /* @__PURE__ */ jsx55(SizableText47, { size: "$2", color: "$color8", children: section.description })
|
|
3510
|
+
] }),
|
|
3511
|
+
/* @__PURE__ */ jsx55(
|
|
3512
|
+
YStack44,
|
|
3513
|
+
{
|
|
3514
|
+
backgroundColor: "$color2",
|
|
3515
|
+
borderRadius: "$4",
|
|
3516
|
+
overflow: "hidden",
|
|
3517
|
+
borderWidth: 1,
|
|
3518
|
+
borderColor: "$color4",
|
|
3519
|
+
children: section.items.map((item, ii) => /* @__PURE__ */ jsxs45(YStack44, { children: [
|
|
3520
|
+
/* @__PURE__ */ jsx55(PreferenceRow, { item }),
|
|
3521
|
+
ii < section.items.length - 1 && /* @__PURE__ */ jsx55(Separator6, { borderColor: "$color4" })
|
|
3522
|
+
] }, item.id))
|
|
3523
|
+
}
|
|
3524
|
+
)
|
|
3525
|
+
] }, si)) });
|
|
3526
|
+
}
|
|
3527
|
+
|
|
3528
|
+
// src/patterns/BlinkSelect.tsx
|
|
3529
|
+
import { Select, Adapt, Sheet as Sheet3, YStack as YStack45, SizableText as SizableText48 } from "tamagui";
|
|
3530
|
+
import { jsx as jsx56, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3531
|
+
function BlinkSelect({
|
|
3532
|
+
items,
|
|
3533
|
+
value,
|
|
3534
|
+
onValueChange,
|
|
3535
|
+
placeholder = "Select...",
|
|
3536
|
+
label,
|
|
3537
|
+
size = "$4",
|
|
3538
|
+
disabled,
|
|
3539
|
+
width = "100%"
|
|
3540
|
+
}) {
|
|
3541
|
+
return /* @__PURE__ */ jsxs46(YStack45, { gap: "$1.5", width, children: [
|
|
3542
|
+
label ? /* @__PURE__ */ jsx56(SizableText48, { size: "$3", fontWeight: "600", children: label }) : null,
|
|
3543
|
+
/* @__PURE__ */ jsxs46(
|
|
3544
|
+
Select,
|
|
3545
|
+
{
|
|
3546
|
+
value,
|
|
3547
|
+
onValueChange,
|
|
3548
|
+
disablePreventBodyScroll: true,
|
|
3549
|
+
...disabled ? { disabled: true } : {},
|
|
3550
|
+
children: [
|
|
3551
|
+
/* @__PURE__ */ jsx56(Select.Trigger, { width: "100%", iconAfter: () => /* @__PURE__ */ jsx56(SizableText48, { children: "\u25BC" }), size, children: /* @__PURE__ */ jsx56(Select.Value, { placeholder }) }),
|
|
3552
|
+
/* @__PURE__ */ jsx56(Adapt, { when: "maxMd", platform: "touch", children: /* @__PURE__ */ jsxs46(Sheet3, { modal: true, dismissOnSnapToBottom: true, snapPointsMode: "fit", children: [
|
|
3553
|
+
/* @__PURE__ */ jsx56(Sheet3.Frame, { padding: "$4", children: /* @__PURE__ */ jsx56(Adapt.Contents, {}) }),
|
|
3554
|
+
/* @__PURE__ */ jsx56(Sheet3.Overlay, {})
|
|
3555
|
+
] }) }),
|
|
3556
|
+
/* @__PURE__ */ jsxs46(Select.Content, { zIndex: 2e5, children: [
|
|
3557
|
+
/* @__PURE__ */ jsx56(Select.ScrollUpButton, { alignItems: "center", justifyContent: "center", height: "$3", children: /* @__PURE__ */ jsx56(SizableText48, { children: "\u25B2" }) }),
|
|
3558
|
+
/* @__PURE__ */ jsx56(Select.Viewport, { minWidth: 200, children: /* @__PURE__ */ jsx56(Select.Group, { children: items.map((item, i) => /* @__PURE__ */ jsxs46(Select.Item, { index: i, value: item.value, children: [
|
|
3559
|
+
/* @__PURE__ */ jsx56(Select.ItemText, { children: item.label }),
|
|
3560
|
+
/* @__PURE__ */ jsx56(Select.ItemIndicator, { marginLeft: "auto", children: /* @__PURE__ */ jsx56(SizableText48, { children: "\u2713" }) })
|
|
3561
|
+
] }, item.value)) }) }),
|
|
3562
|
+
/* @__PURE__ */ jsx56(Select.ScrollDownButton, { alignItems: "center", justifyContent: "center", height: "$3", children: /* @__PURE__ */ jsx56(SizableText48, { children: "\u25BC" }) })
|
|
3563
|
+
] })
|
|
3564
|
+
]
|
|
3565
|
+
}
|
|
3566
|
+
)
|
|
3567
|
+
] });
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
// src/patterns/BlinkDialog.tsx
|
|
3571
|
+
import { Dialog, Adapt as Adapt2, Sheet as Sheet4, Button as Button11, XStack as XStack41 } from "tamagui";
|
|
3572
|
+
import { jsx as jsx57, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
3573
|
+
function BlinkDialog({
|
|
3574
|
+
open,
|
|
3575
|
+
onOpenChange,
|
|
3576
|
+
trigger,
|
|
3577
|
+
title,
|
|
3578
|
+
description,
|
|
3579
|
+
children,
|
|
3580
|
+
confirmLabel = "Confirm",
|
|
3581
|
+
cancelLabel = "Cancel",
|
|
3582
|
+
onConfirm,
|
|
3583
|
+
onCancel,
|
|
3584
|
+
confirmTheme = "active"
|
|
3585
|
+
}) {
|
|
3586
|
+
return /* @__PURE__ */ jsxs47(Dialog, { modal: true, open, onOpenChange, children: [
|
|
3587
|
+
trigger && /* @__PURE__ */ jsx57(Dialog.Trigger, { asChild: true, children: trigger }),
|
|
3588
|
+
/* @__PURE__ */ jsx57(Adapt2, { when: "maxMd", platform: "touch", children: /* @__PURE__ */ jsxs47(Sheet4, { modal: true, dismissOnSnapToBottom: true, snapPointsMode: "fit", children: [
|
|
3589
|
+
/* @__PURE__ */ jsx57(Sheet4.Frame, { padding: "$4", gap: "$4", children: /* @__PURE__ */ jsx57(Adapt2.Contents, {}) }),
|
|
3590
|
+
/* @__PURE__ */ jsx57(Sheet4.Overlay, {})
|
|
3591
|
+
] }) }),
|
|
3592
|
+
/* @__PURE__ */ jsxs47(Dialog.Portal, { children: [
|
|
3593
|
+
/* @__PURE__ */ jsx57(
|
|
3594
|
+
Dialog.Overlay,
|
|
3595
|
+
{
|
|
3596
|
+
animation: "quick",
|
|
3597
|
+
opacity: 0.5,
|
|
3598
|
+
enterStyle: { opacity: 0 },
|
|
3599
|
+
exitStyle: { opacity: 0 }
|
|
3600
|
+
},
|
|
3601
|
+
"overlay"
|
|
3602
|
+
),
|
|
3603
|
+
/* @__PURE__ */ jsxs47(
|
|
3604
|
+
Dialog.Content,
|
|
3605
|
+
{
|
|
3606
|
+
bordered: true,
|
|
3607
|
+
elevate: true,
|
|
3608
|
+
animateOnly: ["transform", "opacity"],
|
|
3609
|
+
animation: ["quick", { opacity: { overshootClamping: true } }],
|
|
3610
|
+
enterStyle: { x: 0, y: -20, opacity: 0, scale: 0.9 },
|
|
3611
|
+
exitStyle: { x: 0, y: 10, opacity: 0, scale: 0.95 },
|
|
3612
|
+
gap: "$4",
|
|
3613
|
+
children: [
|
|
3614
|
+
title && /* @__PURE__ */ jsx57(Dialog.Title, { children: title }),
|
|
3615
|
+
description && /* @__PURE__ */ jsx57(Dialog.Description, { size: "$3", color: "$color10", children: description }),
|
|
3616
|
+
children,
|
|
3617
|
+
(onConfirm || onCancel) && /* @__PURE__ */ jsxs47(XStack41, { justifyContent: "flex-end", gap: "$3", children: [
|
|
3618
|
+
onCancel && /* @__PURE__ */ jsx57(Dialog.Close, { displayWhenAdapted: true, asChild: true, children: /* @__PURE__ */ jsx57(Button11, { variant: "outlined", onPress: onCancel, children: cancelLabel }) }),
|
|
3619
|
+
onConfirm && /* @__PURE__ */ jsx57(Dialog.Close, { displayWhenAdapted: true, asChild: true, children: /* @__PURE__ */ jsx57(Button11, { theme: confirmTheme, onPress: onConfirm, children: confirmLabel }) })
|
|
3620
|
+
] })
|
|
3621
|
+
]
|
|
3622
|
+
},
|
|
3623
|
+
"content"
|
|
3624
|
+
)
|
|
3625
|
+
] })
|
|
3626
|
+
] });
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
// src/patterns/BlinkPopover.tsx
|
|
3630
|
+
import { Popover as Popover2, Adapt as Adapt3, YStack as YStack46 } from "tamagui";
|
|
3631
|
+
import { jsx as jsx58, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
3632
|
+
function BlinkPopover({
|
|
3633
|
+
trigger,
|
|
3634
|
+
children,
|
|
3635
|
+
placement = "bottom",
|
|
3636
|
+
allowFlip = true,
|
|
3637
|
+
size = "$5"
|
|
3638
|
+
}) {
|
|
3639
|
+
return /* @__PURE__ */ jsxs48(Popover2, { size, allowFlip, placement, children: [
|
|
3640
|
+
/* @__PURE__ */ jsx58(Popover2.Trigger, { asChild: true, children: trigger }),
|
|
3641
|
+
/* @__PURE__ */ jsx58(Adapt3, { when: "maxMd", platform: "touch", children: /* @__PURE__ */ jsxs48(Popover2.Sheet, { modal: true, dismissOnSnapToBottom: true, snapPointsMode: "fit", children: [
|
|
3642
|
+
/* @__PURE__ */ jsx58(Popover2.Sheet.Frame, { padding: "$4", children: /* @__PURE__ */ jsx58(Adapt3.Contents, {}) }),
|
|
3643
|
+
/* @__PURE__ */ jsx58(Popover2.Sheet.Overlay, {})
|
|
3644
|
+
] }) }),
|
|
3645
|
+
/* @__PURE__ */ jsxs48(
|
|
3646
|
+
Popover2.Content,
|
|
3647
|
+
{
|
|
3648
|
+
borderWidth: 1,
|
|
3649
|
+
borderColor: "$borderColor",
|
|
3650
|
+
enterStyle: { y: -10, opacity: 0 },
|
|
3651
|
+
exitStyle: { y: -10, opacity: 0 },
|
|
3652
|
+
elevate: true,
|
|
3653
|
+
animation: ["quick", { opacity: { overshootClamping: true } }],
|
|
3654
|
+
children: [
|
|
3655
|
+
/* @__PURE__ */ jsx58(Popover2.Arrow, { borderWidth: 1, borderColor: "$borderColor" }),
|
|
3656
|
+
/* @__PURE__ */ jsx58(YStack46, { gap: "$3", padding: "$3", children })
|
|
3657
|
+
]
|
|
3658
|
+
}
|
|
3659
|
+
)
|
|
3660
|
+
] });
|
|
3661
|
+
}
|
|
3662
|
+
|
|
3663
|
+
// src/index.ts
|
|
3664
|
+
export * from "@tamagui/lucide-icons";
|
|
3665
|
+
|
|
3666
|
+
// src/patterns/ImmersiveMediaScreen.tsx
|
|
3667
|
+
import { Button as Button12, SizableText as SizableText49, XStack as XStack42, YStack as YStack47 } from "tamagui";
|
|
3668
|
+
import { jsx as jsx59, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
3669
|
+
function ImmersiveMediaScreen({
|
|
3670
|
+
variant = "reel",
|
|
3671
|
+
media,
|
|
3672
|
+
title,
|
|
3673
|
+
subtitle,
|
|
3674
|
+
topLeft,
|
|
3675
|
+
topCenter,
|
|
3676
|
+
topRight,
|
|
3677
|
+
actions = [],
|
|
3678
|
+
bottomMeta,
|
|
3679
|
+
inputPlaceholder,
|
|
3680
|
+
onInputPress,
|
|
3681
|
+
sheetContent
|
|
3682
|
+
}) {
|
|
3683
|
+
const showSheet = variant === "sheet";
|
|
3684
|
+
return /* @__PURE__ */ jsxs49(YStack47, { flex: 1, backgroundColor: "$color1", children: [
|
|
3685
|
+
/* @__PURE__ */ jsxs49(YStack47, { flex: 1, position: "relative", children: [
|
|
3686
|
+
media,
|
|
3687
|
+
/* @__PURE__ */ jsxs49(XStack42, { position: "absolute", top: "$5", left: "$4", right: "$4", justifyContent: "space-between", alignItems: "center", children: [
|
|
3688
|
+
/* @__PURE__ */ jsx59(XStack42, { minWidth: 56, children: topLeft }),
|
|
3689
|
+
/* @__PURE__ */ jsx59(YStack47, { alignItems: "center", flex: 1, children: topCenter }),
|
|
3690
|
+
/* @__PURE__ */ jsx59(XStack42, { minWidth: 56, justifyContent: "flex-end", children: topRight })
|
|
3691
|
+
] }),
|
|
3692
|
+
actions.length > 0 ? /* @__PURE__ */ jsx59(YStack47, { position: "absolute", right: "$3", bottom: showSheet ? "$20" : "$10", gap: "$3", alignItems: "center", children: actions.map((action) => /* @__PURE__ */ jsxs49(YStack47, { gap: "$1", alignItems: "center", onPress: action.onPress, children: [
|
|
3693
|
+
/* @__PURE__ */ jsx59(
|
|
3694
|
+
YStack47,
|
|
3695
|
+
{
|
|
3696
|
+
width: 44,
|
|
3697
|
+
height: 44,
|
|
3698
|
+
borderRadius: "$10",
|
|
3699
|
+
backgroundColor: "rgba(0,0,0,0.55)",
|
|
3700
|
+
alignItems: "center",
|
|
3701
|
+
justifyContent: "center",
|
|
3702
|
+
children: action.icon ?? /* @__PURE__ */ jsx59(SizableText49, { size: "$5", color: "white", children: "\u2022" })
|
|
3703
|
+
}
|
|
3704
|
+
),
|
|
3705
|
+
action.value ? /* @__PURE__ */ jsx59(SizableText49, { size: "$2", color: "white", children: action.value }) : null,
|
|
3706
|
+
action.label ? /* @__PURE__ */ jsx59(SizableText49, { size: "$1", color: "rgba(255,255,255,0.8)", children: action.label }) : null
|
|
3707
|
+
] }, action.id)) }) : null,
|
|
3708
|
+
/* @__PURE__ */ jsxs49(YStack47, { position: "absolute", left: "$4", right: "$4", bottom: showSheet ? "$20" : "$6", gap: "$2", children: [
|
|
3709
|
+
title ? /* @__PURE__ */ jsx59(SizableText49, { size: "$6", fontWeight: "800", color: "white", children: title }) : null,
|
|
3710
|
+
subtitle ? /* @__PURE__ */ jsx59(SizableText49, { size: "$3", color: "rgba(255,255,255,0.82)", children: subtitle }) : null,
|
|
3711
|
+
bottomMeta,
|
|
3712
|
+
variant === "story" && inputPlaceholder ? /* @__PURE__ */ jsx59(
|
|
3713
|
+
XStack42,
|
|
3714
|
+
{
|
|
3715
|
+
onPress: onInputPress,
|
|
3716
|
+
alignItems: "center",
|
|
3717
|
+
paddingHorizontal: "$4",
|
|
3718
|
+
paddingVertical: "$3",
|
|
3719
|
+
borderRadius: "$10",
|
|
3720
|
+
backgroundColor: "rgba(255,255,255,0.14)",
|
|
3721
|
+
borderWidth: 1,
|
|
3722
|
+
borderColor: "rgba(255,255,255,0.25)",
|
|
3723
|
+
children: /* @__PURE__ */ jsx59(SizableText49, { size: "$3", color: "rgba(255,255,255,0.82)", children: inputPlaceholder })
|
|
3724
|
+
}
|
|
3725
|
+
) : null
|
|
3726
|
+
] })
|
|
3727
|
+
] }),
|
|
3728
|
+
showSheet ? /* @__PURE__ */ jsxs49(YStack47, { padding: "$4", gap: "$3", backgroundColor: "$background", borderTopLeftRadius: "$8", borderTopRightRadius: "$8", marginTop: -18, children: [
|
|
3729
|
+
/* @__PURE__ */ jsx59(XStack42, { alignSelf: "center", width: 48, height: 5, borderRadius: "$10", backgroundColor: "$color5" }),
|
|
3730
|
+
sheetContent,
|
|
3731
|
+
inputPlaceholder ? /* @__PURE__ */ jsx59(Button12, { size: "$5", backgroundColor: "$color9", color: "$color1", onPress: onInputPress, children: inputPlaceholder }) : null
|
|
3732
|
+
] }) : null
|
|
3733
|
+
] });
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3736
|
+
// src/patterns/FinanceDashboard.tsx
|
|
3737
|
+
import { SizableText as SizableText50, XStack as XStack43, YStack as YStack48 } from "tamagui";
|
|
3738
|
+
import { jsx as jsx60, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
3739
|
+
function FinanceDashboard({
|
|
3740
|
+
title = "Overview",
|
|
3741
|
+
balanceLabel = "Available balance",
|
|
3742
|
+
balance,
|
|
3743
|
+
rangeLabel,
|
|
3744
|
+
metrics = [],
|
|
3745
|
+
quickActions = [],
|
|
3746
|
+
sections = [],
|
|
3747
|
+
chartSlot,
|
|
3748
|
+
topRight
|
|
3749
|
+
}) {
|
|
3750
|
+
return /* @__PURE__ */ jsxs50(YStack48, { flex: 1, backgroundColor: "$background", padding: "$4", gap: "$4", children: [
|
|
3751
|
+
/* @__PURE__ */ jsxs50(XStack43, { justifyContent: "space-between", alignItems: "center", paddingTop: "$4", children: [
|
|
3752
|
+
/* @__PURE__ */ jsxs50(YStack48, { gap: "$1", children: [
|
|
3753
|
+
/* @__PURE__ */ jsx60(SizableText50, { size: "$6", fontWeight: "700", children: title }),
|
|
3754
|
+
rangeLabel ? /* @__PURE__ */ jsx60(SizableText50, { size: "$2", color: "$color9", children: rangeLabel }) : null
|
|
3755
|
+
] }),
|
|
3756
|
+
topRight
|
|
3757
|
+
] }),
|
|
3758
|
+
/* @__PURE__ */ jsxs50(YStack48, { backgroundColor: "$color1", borderRadius: "$7", padding: "$4", gap: "$2", borderWidth: 1, borderColor: "$color4", children: [
|
|
3759
|
+
/* @__PURE__ */ jsx60(SizableText50, { size: "$3", color: "$color10", children: balanceLabel }),
|
|
3760
|
+
/* @__PURE__ */ jsx60(SizableText50, { size: "$11", fontWeight: "800", children: balance }),
|
|
3761
|
+
chartSlot ? /* @__PURE__ */ jsx60(YStack48, { marginTop: "$2", children: chartSlot }) : null
|
|
3762
|
+
] }),
|
|
3763
|
+
metrics.length > 0 ? /* @__PURE__ */ jsx60(XStack43, { gap: "$3", flexWrap: "wrap", children: metrics.map((metric) => /* @__PURE__ */ jsxs50(YStack48, { flex: 1, minWidth: 120, backgroundColor: "$color1", borderRadius: "$6", padding: "$3", gap: "$1", borderWidth: 1, borderColor: "$color4", children: [
|
|
3764
|
+
/* @__PURE__ */ jsx60(SizableText50, { size: "$2", color: "$color10", children: metric.label }),
|
|
3765
|
+
/* @__PURE__ */ jsx60(SizableText50, { size: "$7", fontWeight: "800", children: metric.value }),
|
|
3766
|
+
metric.change ? /* @__PURE__ */ jsx60(SizableText50, { size: "$2", color: "$color9", children: metric.change }) : null
|
|
3767
|
+
] }, metric.label)) }) : null,
|
|
3768
|
+
quickActions.length > 0 ? /* @__PURE__ */ jsx60(XStack43, { gap: "$3", flexWrap: "wrap", children: quickActions.map((action) => /* @__PURE__ */ jsxs50(
|
|
3769
|
+
YStack48,
|
|
3770
|
+
{
|
|
3771
|
+
flex: 1,
|
|
3772
|
+
minWidth: 88,
|
|
3773
|
+
backgroundColor: "$color1",
|
|
3774
|
+
borderRadius: "$6",
|
|
3775
|
+
padding: "$3",
|
|
3776
|
+
gap: "$2",
|
|
3777
|
+
alignItems: "center",
|
|
3778
|
+
justifyContent: "center",
|
|
3779
|
+
borderWidth: 1,
|
|
3780
|
+
borderColor: "$color4",
|
|
3781
|
+
onPress: action.onPress,
|
|
3782
|
+
children: [
|
|
3783
|
+
/* @__PURE__ */ jsx60(YStack48, { width: 36, height: 36, borderRadius: "$10", backgroundColor: "$color3", alignItems: "center", justifyContent: "center", children: action.icon ?? /* @__PURE__ */ jsx60(SizableText50, { size: "$4", children: "\u2022" }) }),
|
|
3784
|
+
/* @__PURE__ */ jsx60(SizableText50, { size: "$2", textAlign: "center", children: action.label })
|
|
3785
|
+
]
|
|
3786
|
+
},
|
|
3787
|
+
action.id
|
|
3788
|
+
)) }) : null,
|
|
3789
|
+
/* @__PURE__ */ jsx60(YStack48, { gap: "$3", children: sections.map((section, index) => /* @__PURE__ */ jsxs50(YStack48, { backgroundColor: "$color1", borderRadius: "$6", borderWidth: 1, borderColor: "$color4", overflow: "hidden", children: [
|
|
3790
|
+
/* @__PURE__ */ jsx60(XStack43, { padding: "$3", justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsx60(SizableText50, { size: "$4", fontWeight: "700", children: section.title }) }),
|
|
3791
|
+
/* @__PURE__ */ jsx60(YStack48, { children: section.rows.map((row, index2) => /* @__PURE__ */ jsxs50(
|
|
3792
|
+
XStack43,
|
|
3793
|
+
{
|
|
3794
|
+
padding: "$3",
|
|
3795
|
+
gap: "$3",
|
|
3796
|
+
alignItems: "center",
|
|
3797
|
+
borderTopWidth: index2 === 0 ? 0 : 1,
|
|
3798
|
+
borderTopColor: "$color4",
|
|
3799
|
+
children: [
|
|
3800
|
+
row.leading ? /* @__PURE__ */ jsx60(YStack48, { width: 32, height: 32, borderRadius: "$8", backgroundColor: "$color3", alignItems: "center", justifyContent: "center", children: row.leading }) : null,
|
|
3801
|
+
/* @__PURE__ */ jsxs50(YStack48, { flex: 1, children: [
|
|
3802
|
+
/* @__PURE__ */ jsx60(SizableText50, { size: "$3", fontWeight: "600", children: row.title }),
|
|
3803
|
+
row.subtitle ? /* @__PURE__ */ jsx60(SizableText50, { size: "$2", color: "$color10", children: row.subtitle }) : null
|
|
3804
|
+
] }),
|
|
3805
|
+
row.value ? /* @__PURE__ */ jsx60(SizableText50, { size: "$3", color: "$color11", children: row.value }) : null
|
|
3806
|
+
]
|
|
3807
|
+
},
|
|
3808
|
+
row.id
|
|
3809
|
+
)) })
|
|
3810
|
+
] }, section.id ?? `${section.title}-${index}`)) })
|
|
3811
|
+
] });
|
|
3812
|
+
}
|
|
1639
3813
|
export {
|
|
1640
3814
|
Accordion,
|
|
1641
3815
|
ActionSheet,
|
|
1642
|
-
Adapt,
|
|
1643
|
-
|
|
3816
|
+
Adapt4 as Adapt,
|
|
3817
|
+
AlertDialog3 as AlertDialog,
|
|
1644
3818
|
Anchor,
|
|
3819
|
+
AnimatePresence,
|
|
1645
3820
|
AppHeader,
|
|
3821
|
+
AppleLogo,
|
|
3822
|
+
Article,
|
|
3823
|
+
Aside,
|
|
1646
3824
|
Avatar2 as Avatar,
|
|
3825
|
+
AvatarGroup,
|
|
3826
|
+
BLINK_DESIGN_THEMES,
|
|
3827
|
+
BLINK_DESIGN_THEME_IDS,
|
|
1647
3828
|
Badge,
|
|
1648
3829
|
BlinkAccordion,
|
|
1649
3830
|
Avatar as BlinkAvatar,
|
|
1650
3831
|
Button as BlinkButton,
|
|
1651
3832
|
Card as BlinkCard,
|
|
3833
|
+
BlinkDialog,
|
|
1652
3834
|
Input as BlinkInput,
|
|
3835
|
+
BlinkPopover,
|
|
3836
|
+
TamaguiProvider2 as BlinkProvider,
|
|
3837
|
+
BlinkSelect,
|
|
1653
3838
|
BlinkTabs,
|
|
1654
3839
|
BlinkText,
|
|
1655
3840
|
BlinkToastProvider,
|
|
1656
3841
|
BlinkToggleGroup,
|
|
1657
3842
|
BlinkTooltip,
|
|
1658
3843
|
BottomSheet,
|
|
1659
|
-
|
|
3844
|
+
Button13 as Button,
|
|
1660
3845
|
Card2 as Card,
|
|
1661
3846
|
Carousel,
|
|
1662
3847
|
ChatBubble,
|
|
1663
3848
|
Checkbox,
|
|
1664
|
-
|
|
3849
|
+
Chip,
|
|
3850
|
+
ChipGroup,
|
|
3851
|
+
Circle12 as Circle,
|
|
3852
|
+
ConfirmDialog,
|
|
1665
3853
|
Container,
|
|
1666
|
-
|
|
3854
|
+
CountdownBanner,
|
|
3855
|
+
DataTable,
|
|
3856
|
+
DatePicker,
|
|
3857
|
+
Dialog2 as Dialog,
|
|
1667
3858
|
DialogProvider,
|
|
1668
3859
|
Divider,
|
|
1669
3860
|
EmptyState,
|
|
3861
|
+
EnsureFlexed,
|
|
3862
|
+
EventCard,
|
|
1670
3863
|
Fieldset,
|
|
3864
|
+
FinanceDashboard,
|
|
1671
3865
|
FloatingActionButton,
|
|
3866
|
+
Footer,
|
|
1672
3867
|
Form,
|
|
1673
3868
|
FormField,
|
|
3869
|
+
Frame,
|
|
3870
|
+
GitHubLogo,
|
|
3871
|
+
GlassCard,
|
|
3872
|
+
GoogleLogo,
|
|
1674
3873
|
Grid,
|
|
3874
|
+
Group,
|
|
1675
3875
|
H12 as H1,
|
|
1676
3876
|
H22 as H2,
|
|
1677
3877
|
H32 as H3,
|
|
1678
3878
|
H42 as H4,
|
|
1679
3879
|
H52 as H5,
|
|
1680
3880
|
H62 as H6,
|
|
3881
|
+
Header,
|
|
3882
|
+
Heading,
|
|
1681
3883
|
ICONS,
|
|
1682
3884
|
Icon,
|
|
1683
3885
|
Image2 as Image,
|
|
1684
|
-
|
|
3886
|
+
ImmersiveMediaScreen,
|
|
3887
|
+
Input5 as Input,
|
|
1685
3888
|
KeyboardStickyFooter,
|
|
1686
3889
|
Label,
|
|
1687
3890
|
ListItem,
|
|
1688
3891
|
LoginScreen,
|
|
3892
|
+
Main,
|
|
1689
3893
|
MediaCard,
|
|
3894
|
+
MicrosoftLogo,
|
|
3895
|
+
Nav,
|
|
1690
3896
|
NotificationBanner,
|
|
3897
|
+
OTPInput,
|
|
1691
3898
|
OnboardingCarousel,
|
|
1692
3899
|
PageContainer,
|
|
1693
3900
|
PageMainContainer,
|
|
1694
3901
|
Paragraph,
|
|
3902
|
+
PasswordInput,
|
|
1695
3903
|
PaywallScreen,
|
|
1696
|
-
|
|
3904
|
+
Popover3 as Popover,
|
|
3905
|
+
Portal,
|
|
3906
|
+
PortalHost,
|
|
3907
|
+
PortalItem,
|
|
1697
3908
|
PortalProvider,
|
|
1698
3909
|
Pressable,
|
|
3910
|
+
PricingTable,
|
|
3911
|
+
ProductCard,
|
|
1699
3912
|
ProfileHeader,
|
|
1700
3913
|
Progress,
|
|
1701
3914
|
ProgressSteps,
|
|
@@ -1703,56 +3916,91 @@ export {
|
|
|
1703
3916
|
RadioGroup,
|
|
1704
3917
|
SafeArea,
|
|
1705
3918
|
ScreenLayout,
|
|
1706
|
-
|
|
3919
|
+
ScrollView6 as ScrollView,
|
|
1707
3920
|
SearchBar,
|
|
1708
3921
|
Section,
|
|
1709
|
-
Select,
|
|
3922
|
+
Select2 as Select,
|
|
1710
3923
|
SepHeading,
|
|
1711
|
-
|
|
3924
|
+
Separator7 as Separator,
|
|
1712
3925
|
SettingsScreen,
|
|
1713
|
-
|
|
1714
|
-
|
|
3926
|
+
Sheet5 as Sheet,
|
|
3927
|
+
SizableStack,
|
|
3928
|
+
SizableText51 as SizableText,
|
|
1715
3929
|
Skeleton,
|
|
1716
|
-
Slider,
|
|
3930
|
+
Slider2 as Slider,
|
|
3931
|
+
Spacer,
|
|
1717
3932
|
Spinner2 as Spinner,
|
|
1718
3933
|
Square,
|
|
3934
|
+
Stack,
|
|
3935
|
+
StatusBadge,
|
|
1719
3936
|
StepPageLayout,
|
|
1720
3937
|
SubHeading,
|
|
3938
|
+
SwipeCards,
|
|
1721
3939
|
SwipeableRow,
|
|
1722
|
-
|
|
3940
|
+
Switch3 as Switch,
|
|
1723
3941
|
TabBar,
|
|
1724
3942
|
Tabs,
|
|
1725
|
-
|
|
3943
|
+
Image9 as TamaguiImage,
|
|
1726
3944
|
ListItem2 as TamaguiListItem,
|
|
1727
3945
|
TamaguiProvider,
|
|
3946
|
+
TestimonialCard2 as TestimonialCard,
|
|
1728
3947
|
Text,
|
|
1729
3948
|
TextArea,
|
|
1730
|
-
Theme,
|
|
1731
|
-
|
|
1732
|
-
ToastProvider,
|
|
1733
|
-
ToastViewport,
|
|
3949
|
+
Theme2 as Theme,
|
|
3950
|
+
ThemeableStack,
|
|
1734
3951
|
ToggleGroup,
|
|
1735
3952
|
Tooltip,
|
|
1736
3953
|
TooltipSimple,
|
|
1737
3954
|
Unspaced,
|
|
1738
|
-
|
|
3955
|
+
UserPreferences,
|
|
3956
|
+
View7 as View,
|
|
1739
3957
|
VisuallyHidden,
|
|
1740
3958
|
XGroup,
|
|
1741
|
-
|
|
3959
|
+
XStack44 as XStack,
|
|
1742
3960
|
YGroup,
|
|
1743
|
-
|
|
3961
|
+
YStack49 as YStack,
|
|
1744
3962
|
ZStack,
|
|
3963
|
+
addTheme,
|
|
1745
3964
|
blinkConfig,
|
|
3965
|
+
composeEventHandlers,
|
|
3966
|
+
composeRefs,
|
|
3967
|
+
createFont,
|
|
3968
|
+
createMedia,
|
|
3969
|
+
createStyledContext,
|
|
3970
|
+
createTamagui2 as createTamagui,
|
|
3971
|
+
createTheme,
|
|
3972
|
+
createTokens,
|
|
3973
|
+
createVariable,
|
|
1746
3974
|
dialogConfirm,
|
|
3975
|
+
getBlinkDesignTheme,
|
|
3976
|
+
getBlinkThemePalettes,
|
|
3977
|
+
getConfig,
|
|
3978
|
+
getToken,
|
|
3979
|
+
getTokenValue,
|
|
3980
|
+
getTokens,
|
|
3981
|
+
isClient,
|
|
3982
|
+
isWeb,
|
|
3983
|
+
replaceTheme,
|
|
1747
3984
|
showError,
|
|
1748
|
-
|
|
3985
|
+
styled14 as styled,
|
|
3986
|
+
defaultConfig2 as tamaguiDefaultConfig,
|
|
1749
3987
|
toast,
|
|
3988
|
+
updateTheme,
|
|
1750
3989
|
useBlinkToast,
|
|
1751
|
-
|
|
3990
|
+
useComposedRefs,
|
|
3991
|
+
useControllableState,
|
|
3992
|
+
useDebounce,
|
|
3993
|
+
useDebounceValue,
|
|
3994
|
+
useDidFinishSSR,
|
|
3995
|
+
useEvent,
|
|
3996
|
+
useForceUpdate,
|
|
3997
|
+
useIsPresent,
|
|
3998
|
+
useIsomorphicLayoutEffect,
|
|
3999
|
+
useMedia2 as useMedia,
|
|
4000
|
+
usePresence,
|
|
1752
4001
|
useTheme,
|
|
1753
4002
|
useThemeName,
|
|
1754
|
-
|
|
1755
|
-
useToastState,
|
|
4003
|
+
useWindowDimensions,
|
|
1756
4004
|
withStaticProperties2 as withStaticProperties
|
|
1757
4005
|
};
|
|
1758
4006
|
//# sourceMappingURL=index.mjs.map
|