@flopay/ui 0.6.1 → 0.7.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.
@@ -0,0 +1,411 @@
1
+ // src/email/index.tsx
2
+ import {
3
+ Body,
4
+ Button,
5
+ Container,
6
+ Head,
7
+ Heading,
8
+ Hr,
9
+ Html,
10
+ Img,
11
+ Link,
12
+ Preview,
13
+ Section,
14
+ Text
15
+ } from "@react-email/components";
16
+ import { toPlainText } from "@react-email/render";
17
+ import { renderToStaticMarkup } from "react-dom/server";
18
+
19
+ // src/email/theme.ts
20
+ var emailTheme = {
21
+ colors: {
22
+ background: "#f7f7f8",
23
+ surface: "#ffffff",
24
+ muted: "#f0f0f2",
25
+ border: "#e5e5e8",
26
+ text: "#0a0a0b",
27
+ textSecondary: "#52525b",
28
+ brand: "#1785e0",
29
+ brandLight: "#4ba6ec",
30
+ accessibleLink: "#0969b3",
31
+ darkBackground: "#0a0a0b",
32
+ darkSurface: "#141416",
33
+ darkMuted: "#1c1c1f",
34
+ darkBorder: "#27272a",
35
+ darkText: "#fafafa",
36
+ darkTextSecondary: "#a1a1aa"
37
+ },
38
+ radius: "8px",
39
+ font: "Inter, -apple-system, BlinkMacSystemFont, Roboto, Arial, sans-serif",
40
+ fontMono: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
41
+ width: "600px"
42
+ };
43
+
44
+ // src/email/index.tsx
45
+ import { jsx, jsxs } from "react/jsx-runtime";
46
+ var FLOPAY_EMAIL_LOGO_URL = "https://flopay.com/logo.png";
47
+ var DEFAULT_TRANSACTIONAL_FOOTER = {
48
+ companyName: "FloPay LLC",
49
+ supportLabel: "hello@flopay.com",
50
+ supportUrl: "mailto:hello@flopay.com",
51
+ privacyUrl: "https://flopay.com/legal/privacy",
52
+ termsUrl: "https://flopay.com/legal/terms",
53
+ notice: "This is a service message about your FloPay account.",
54
+ address: ""
55
+ };
56
+ var FOOTER_TEXT_STYLE = {
57
+ color: emailTheme.colors.textSecondary,
58
+ fontSize: "13px",
59
+ lineHeight: "20px",
60
+ margin: "0 0 12px"
61
+ };
62
+ function Detail({ detail }) {
63
+ if (detail.kind === "keyValue") {
64
+ return /* @__PURE__ */ jsx(
65
+ "table",
66
+ {
67
+ cellPadding: "0",
68
+ cellSpacing: "0",
69
+ className: "email-detail",
70
+ "data-key-value": "true",
71
+ style: {
72
+ backgroundColor: emailTheme.colors.background,
73
+ border: `1px solid ${emailTheme.colors.border}`,
74
+ borderRadius: emailTheme.radius,
75
+ margin: "24px 0",
76
+ width: "100%"
77
+ },
78
+ children: /* @__PURE__ */ jsx("tbody", { children: detail.rows.map((row, index) => /* @__PURE__ */ jsxs("tr", { "data-key-value-row": "true", children: [
79
+ /* @__PURE__ */ jsxs(
80
+ "th",
81
+ {
82
+ className: "email-muted",
83
+ scope: "row",
84
+ style: {
85
+ borderBottom: index < detail.rows.length - 1 ? `1px solid ${emailTheme.colors.border}` : void 0,
86
+ color: emailTheme.colors.textSecondary,
87
+ fontSize: "14px",
88
+ fontWeight: 600,
89
+ padding: "12px 16px",
90
+ verticalAlign: "top",
91
+ width: "36%"
92
+ },
93
+ children: [
94
+ row.label,
95
+ ":"
96
+ ]
97
+ }
98
+ ),
99
+ /* @__PURE__ */ jsxs(
100
+ "td",
101
+ {
102
+ className: "email-text",
103
+ style: {
104
+ borderBottom: index < detail.rows.length - 1 ? `1px solid ${emailTheme.colors.border}` : void 0,
105
+ color: emailTheme.colors.text,
106
+ fontSize: "14px",
107
+ padding: "12px 16px",
108
+ verticalAlign: "top",
109
+ wordBreak: "break-word"
110
+ },
111
+ children: [
112
+ " ",
113
+ row.value
114
+ ]
115
+ }
116
+ )
117
+ ] }, `${index}-${row.label}`)) })
118
+ }
119
+ );
120
+ }
121
+ return /* @__PURE__ */ jsxs(
122
+ Section,
123
+ {
124
+ className: "email-detail",
125
+ style: {
126
+ backgroundColor: emailTheme.colors.muted,
127
+ border: `1px solid ${emailTheme.colors.border}`,
128
+ borderRadius: emailTheme.radius,
129
+ margin: "24px 0",
130
+ padding: "20px"
131
+ },
132
+ children: [
133
+ detail.caption ? /* @__PURE__ */ jsx(
134
+ Text,
135
+ {
136
+ className: "email-muted",
137
+ style: {
138
+ color: emailTheme.colors.textSecondary,
139
+ fontSize: "13px",
140
+ fontWeight: 600,
141
+ lineHeight: "20px",
142
+ margin: "0 0 8px"
143
+ },
144
+ children: detail.caption
145
+ }
146
+ ) : null,
147
+ /* @__PURE__ */ jsx(
148
+ Text,
149
+ {
150
+ className: "email-text",
151
+ style: {
152
+ color: emailTheme.colors.text,
153
+ fontFamily: emailTheme.fontMono,
154
+ fontSize: "24px",
155
+ fontWeight: 700,
156
+ letterSpacing: "0.12em",
157
+ lineHeight: "32px",
158
+ margin: 0,
159
+ overflowWrap: "anywhere"
160
+ },
161
+ children: detail.value
162
+ }
163
+ )
164
+ ]
165
+ }
166
+ );
167
+ }
168
+ function EmailFooter({ overrides }) {
169
+ const footer = { ...DEFAULT_TRANSACTIONAL_FOOTER, ...overrides };
170
+ return /* @__PURE__ */ jsxs(Section, { style: { marginTop: "32px" }, children: [
171
+ /* @__PURE__ */ jsx(
172
+ Hr,
173
+ {
174
+ className: "email-divider",
175
+ style: { borderColor: emailTheme.colors.border, margin: "0 0 24px" }
176
+ }
177
+ ),
178
+ /* @__PURE__ */ jsx(Text, { className: "email-muted", style: FOOTER_TEXT_STYLE, children: footer.notice }),
179
+ /* @__PURE__ */ jsxs(Text, { className: "email-muted", style: FOOTER_TEXT_STYLE, children: [
180
+ "Need help?",
181
+ " ",
182
+ /* @__PURE__ */ jsx(
183
+ Link,
184
+ {
185
+ className: "email-link",
186
+ href: footer.supportUrl,
187
+ style: { color: emailTheme.colors.accessibleLink, textDecoration: "underline" },
188
+ children: footer.supportLabel
189
+ }
190
+ )
191
+ ] }),
192
+ footer.address ? /* @__PURE__ */ jsx(Text, { className: "email-muted", style: FOOTER_TEXT_STYLE, children: footer.address }) : null,
193
+ /* @__PURE__ */ jsxs(Text, { className: "email-muted", style: { ...FOOTER_TEXT_STYLE, margin: 0 }, children: [
194
+ "\xA9 ",
195
+ (/* @__PURE__ */ new Date()).getFullYear(),
196
+ " ",
197
+ footer.companyName,
198
+ ".",
199
+ " ",
200
+ /* @__PURE__ */ jsx(
201
+ Link,
202
+ {
203
+ className: "email-link",
204
+ href: footer.privacyUrl,
205
+ style: { color: emailTheme.colors.accessibleLink, textDecoration: "underline" },
206
+ children: "Privacy"
207
+ }
208
+ ),
209
+ " ",
210
+ "\xB7",
211
+ " ",
212
+ /* @__PURE__ */ jsx(
213
+ Link,
214
+ {
215
+ className: "email-link",
216
+ href: footer.termsUrl,
217
+ style: { color: emailTheme.colors.accessibleLink, textDecoration: "underline" },
218
+ children: "Terms"
219
+ }
220
+ )
221
+ ] })
222
+ ] });
223
+ }
224
+ function Brand({ logoUrl }) {
225
+ return /* @__PURE__ */ jsx("table", { cellPadding: "0", cellSpacing: "0", role: "presentation", style: { marginBottom: "32px" }, children: /* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsxs("tr", { children: [
226
+ /* @__PURE__ */ jsx("td", { style: { verticalAlign: "middle", width: "40px" }, children: /* @__PURE__ */ jsx(
227
+ Img,
228
+ {
229
+ alt: "",
230
+ height: "40",
231
+ src: logoUrl,
232
+ style: { borderRadius: emailTheme.radius },
233
+ width: "40"
234
+ }
235
+ ) }),
236
+ /* @__PURE__ */ jsx("td", { style: { paddingLeft: "12px", verticalAlign: "middle" }, children: /* @__PURE__ */ jsx(
237
+ Text,
238
+ {
239
+ className: "email-text",
240
+ style: {
241
+ color: emailTheme.colors.text,
242
+ fontSize: "18px",
243
+ fontWeight: 700,
244
+ lineHeight: "24px",
245
+ margin: 0
246
+ },
247
+ children: "FloPay"
248
+ }
249
+ ) })
250
+ ] }) }) });
251
+ }
252
+ function TransactionalEmail({
253
+ preheader,
254
+ heading,
255
+ body,
256
+ action,
257
+ detail,
258
+ logoUrl = FLOPAY_EMAIL_LOGO_URL,
259
+ footer
260
+ }) {
261
+ return /* @__PURE__ */ jsxs(Html, { lang: "en", children: [
262
+ /* @__PURE__ */ jsxs(Head, { children: [
263
+ /* @__PURE__ */ jsx("meta", { content: "width=device-width, initial-scale=1.0", name: "viewport" }),
264
+ /* @__PURE__ */ jsx("style", { children: `
265
+ :root {
266
+ color-scheme: light dark;
267
+ supported-color-schemes: light dark;
268
+ }
269
+
270
+ @media only screen and (max-width: 620px) {
271
+ .email-shell { padding: 0 !important; }
272
+ .email-card { border-left: 0 !important; border-radius: 0 !important; border-right: 0 !important; margin: 0 !important; width: 100% !important; }
273
+ .email-content { padding: 24px !important; }
274
+ }
275
+
276
+ @media (prefers-color-scheme: dark) {
277
+ .email-body { background-color: ${emailTheme.colors.darkBackground} !important; }
278
+ .email-shell { background-color: ${emailTheme.colors.darkBackground} !important; }
279
+ .email-card { background-color: ${emailTheme.colors.darkSurface} !important; border-color: ${emailTheme.colors.darkBorder} !important; }
280
+ .email-text { color: ${emailTheme.colors.darkText} !important; }
281
+ .email-muted { color: ${emailTheme.colors.darkTextSecondary} !important; }
282
+ .email-detail { background-color: ${emailTheme.colors.darkMuted} !important; border-color: ${emailTheme.colors.darkBorder} !important; }
283
+ .email-link { color: ${emailTheme.colors.brandLight} !important; }
284
+ .email-action { background-color: ${emailTheme.colors.darkText} !important; color: ${emailTheme.colors.darkBackground} !important; }
285
+ .email-divider { border-color: ${emailTheme.colors.darkBorder} !important; }
286
+ }
287
+ ` })
288
+ ] }),
289
+ /* @__PURE__ */ jsx(Preview, { children: preheader }),
290
+ /* @__PURE__ */ jsx(
291
+ Body,
292
+ {
293
+ className: "email-body",
294
+ style: {
295
+ backgroundColor: emailTheme.colors.background,
296
+ margin: 0,
297
+ padding: 0
298
+ },
299
+ children: /* @__PURE__ */ jsx(
300
+ Section,
301
+ {
302
+ className: "email-shell",
303
+ style: {
304
+ backgroundColor: emailTheme.colors.background,
305
+ color: emailTheme.colors.text,
306
+ fontFamily: emailTheme.font,
307
+ padding: "32px 12px",
308
+ width: "100%"
309
+ },
310
+ children: /* @__PURE__ */ jsx(
311
+ Container,
312
+ {
313
+ className: "email-card",
314
+ style: {
315
+ backgroundColor: emailTheme.colors.surface,
316
+ border: `1px solid ${emailTheme.colors.border}`,
317
+ borderRadius: emailTheme.radius,
318
+ borderTop: `4px solid ${emailTheme.colors.brand}`,
319
+ margin: "0 auto",
320
+ maxWidth: emailTheme.width,
321
+ overflow: "hidden",
322
+ width: "100%"
323
+ },
324
+ children: /* @__PURE__ */ jsxs(Section, { className: "email-content", style: { padding: "40px" }, children: [
325
+ /* @__PURE__ */ jsx(Brand, { logoUrl }),
326
+ /* @__PURE__ */ jsx(
327
+ Heading,
328
+ {
329
+ as: "h1",
330
+ className: "email-text",
331
+ style: {
332
+ color: emailTheme.colors.text,
333
+ fontSize: "28px",
334
+ fontWeight: 700,
335
+ letterSpacing: "-0.02em",
336
+ lineHeight: "36px",
337
+ margin: "0 0 16px"
338
+ },
339
+ children: heading
340
+ }
341
+ ),
342
+ body.map((paragraph, index) => /* @__PURE__ */ jsx(
343
+ Text,
344
+ {
345
+ className: "email-text",
346
+ style: {
347
+ color: emailTheme.colors.text,
348
+ fontSize: "16px",
349
+ lineHeight: "25px",
350
+ margin: "0 0 16px"
351
+ },
352
+ children: paragraph
353
+ },
354
+ `${index}-${paragraph}`
355
+ )),
356
+ detail ? /* @__PURE__ */ jsx(Detail, { detail }) : null,
357
+ action ? /* @__PURE__ */ jsx(
358
+ Button,
359
+ {
360
+ className: "email-action",
361
+ href: action.href,
362
+ style: {
363
+ backgroundColor: emailTheme.colors.text,
364
+ borderRadius: emailTheme.radius,
365
+ color: emailTheme.colors.surface,
366
+ fontSize: "16px",
367
+ fontWeight: 700,
368
+ lineHeight: "20px",
369
+ marginTop: "8px",
370
+ padding: "14px 24px",
371
+ textDecoration: "none"
372
+ },
373
+ children: action.label
374
+ }
375
+ ) : null,
376
+ /* @__PURE__ */ jsx(EmailFooter, { overrides: footer })
377
+ ] })
378
+ }
379
+ )
380
+ }
381
+ )
382
+ }
383
+ )
384
+ ] });
385
+ }
386
+ function renderTransactionalEmail(props) {
387
+ const markup = renderToStaticMarkup(/* @__PURE__ */ jsx(TransactionalEmail, { ...props }));
388
+ const html = `<!doctype html>${markup.replace(
389
+ /<link\b(?=[^>]*\brel="preload")(?=[^>]*\bas="image")[^>]*\/?>/gi,
390
+ ""
391
+ )}`;
392
+ return {
393
+ html,
394
+ text: toPlainText(html, {
395
+ selectors: [
396
+ { selector: "h1", options: { uppercase: false } },
397
+ {
398
+ selector: 'tr[data-key-value-row="true"]',
399
+ format: "block",
400
+ options: { leadingLineBreaks: 1, trailingLineBreaks: 1 }
401
+ }
402
+ ]
403
+ })
404
+ };
405
+ }
406
+ export {
407
+ FLOPAY_EMAIL_LOGO_URL,
408
+ TransactionalEmail,
409
+ renderTransactionalEmail
410
+ };
411
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/email/index.tsx","../../src/email/theme.ts"],"sourcesContent":["import {\n Body,\n Button,\n Container,\n Head,\n Heading,\n Hr,\n Html,\n Img,\n Link,\n Preview,\n Section,\n Text,\n} from '@react-email/components';\nimport { toPlainText } from '@react-email/render';\nimport { renderToStaticMarkup } from 'react-dom/server';\nimport { emailTheme } from './theme';\n\nexport const FLOPAY_EMAIL_LOGO_URL = 'https://flopay.com/logo.png';\n\nexport interface TransactionalEmailAction {\n label: string;\n href: string;\n}\n\nexport interface TransactionalCodeDetail {\n kind: 'code';\n value: string;\n caption?: string;\n}\n\nexport interface TransactionalKeyValueDetail {\n kind: 'keyValue';\n rows: { label: string; value: string }[];\n}\n\nexport type TransactionalEmailDetail = TransactionalCodeDetail | TransactionalKeyValueDetail;\n\nexport interface TransactionalFooter {\n companyName: string;\n supportLabel: string;\n supportUrl: string;\n privacyUrl: string;\n termsUrl: string;\n notice: string;\n address: string;\n}\n\nexport interface TransactionalEmailProps {\n preheader: string;\n heading: string;\n body: string[];\n action?: TransactionalEmailAction;\n detail?: TransactionalEmailDetail;\n logoUrl?: string;\n footer?: Partial<TransactionalFooter>;\n}\n\nexport interface RenderedTransactionalEmail {\n html: string;\n text: string;\n}\n\nconst DEFAULT_TRANSACTIONAL_FOOTER: TransactionalFooter = {\n companyName: 'FloPay LLC',\n supportLabel: 'hello@flopay.com',\n supportUrl: 'mailto:hello@flopay.com',\n privacyUrl: 'https://flopay.com/legal/privacy',\n termsUrl: 'https://flopay.com/legal/terms',\n notice: 'This is a service message about your FloPay account.',\n address: '',\n};\n\nconst FOOTER_TEXT_STYLE = {\n color: emailTheme.colors.textSecondary,\n fontSize: '13px',\n lineHeight: '20px',\n margin: '0 0 12px',\n} as const;\n\nfunction Detail({ detail }: { detail: TransactionalEmailDetail }) {\n if (detail.kind === 'keyValue') {\n return (\n <table\n cellPadding=\"0\"\n cellSpacing=\"0\"\n className=\"email-detail\"\n data-key-value=\"true\"\n style={{\n backgroundColor: emailTheme.colors.background,\n border: `1px solid ${emailTheme.colors.border}`,\n borderRadius: emailTheme.radius,\n margin: '24px 0',\n width: '100%',\n }}\n >\n <tbody>\n {detail.rows.map((row, index) => (\n <tr data-key-value-row=\"true\" key={`${index}-${row.label}`}>\n <th\n className=\"email-muted\"\n scope=\"row\"\n style={{\n borderBottom:\n index < detail.rows.length - 1\n ? `1px solid ${emailTheme.colors.border}`\n : undefined,\n color: emailTheme.colors.textSecondary,\n fontSize: '14px',\n fontWeight: 600,\n padding: '12px 16px',\n verticalAlign: 'top',\n width: '36%',\n }}\n >\n {row.label}:\n </th>\n <td\n className=\"email-text\"\n style={{\n borderBottom:\n index < detail.rows.length - 1\n ? `1px solid ${emailTheme.colors.border}`\n : undefined,\n color: emailTheme.colors.text,\n fontSize: '14px',\n padding: '12px 16px',\n verticalAlign: 'top',\n wordBreak: 'break-word',\n }}\n >\n {' '}\n {row.value}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n }\n\n return (\n <Section\n className=\"email-detail\"\n style={{\n backgroundColor: emailTheme.colors.muted,\n border: `1px solid ${emailTheme.colors.border}`,\n borderRadius: emailTheme.radius,\n margin: '24px 0',\n padding: '20px',\n }}\n >\n {detail.caption ? (\n <Text\n className=\"email-muted\"\n style={{\n color: emailTheme.colors.textSecondary,\n fontSize: '13px',\n fontWeight: 600,\n lineHeight: '20px',\n margin: '0 0 8px',\n }}\n >\n {detail.caption}\n </Text>\n ) : null}\n <Text\n className=\"email-text\"\n style={{\n color: emailTheme.colors.text,\n fontFamily: emailTheme.fontMono,\n fontSize: '24px',\n fontWeight: 700,\n letterSpacing: '0.12em',\n lineHeight: '32px',\n margin: 0,\n overflowWrap: 'anywhere',\n }}\n >\n {detail.value}\n </Text>\n </Section>\n );\n}\n\nfunction EmailFooter({ overrides }: { overrides?: Partial<TransactionalFooter> }) {\n const footer = { ...DEFAULT_TRANSACTIONAL_FOOTER, ...overrides };\n\n return (\n <Section style={{ marginTop: '32px' }}>\n <Hr\n className=\"email-divider\"\n style={{ borderColor: emailTheme.colors.border, margin: '0 0 24px' }}\n />\n <Text className=\"email-muted\" style={FOOTER_TEXT_STYLE}>\n {footer.notice}\n </Text>\n <Text className=\"email-muted\" style={FOOTER_TEXT_STYLE}>\n Need help?{' '}\n <Link\n className=\"email-link\"\n href={footer.supportUrl}\n style={{ color: emailTheme.colors.accessibleLink, textDecoration: 'underline' }}\n >\n {footer.supportLabel}\n </Link>\n </Text>\n {footer.address ? (\n <Text className=\"email-muted\" style={FOOTER_TEXT_STYLE}>\n {footer.address}\n </Text>\n ) : null}\n <Text className=\"email-muted\" style={{ ...FOOTER_TEXT_STYLE, margin: 0 }}>\n © {new Date().getFullYear()} {footer.companyName}.{' '}\n <Link\n className=\"email-link\"\n href={footer.privacyUrl}\n style={{ color: emailTheme.colors.accessibleLink, textDecoration: 'underline' }}\n >\n Privacy\n </Link>{' '}\n ·{' '}\n <Link\n className=\"email-link\"\n href={footer.termsUrl}\n style={{ color: emailTheme.colors.accessibleLink, textDecoration: 'underline' }}\n >\n Terms\n </Link>\n </Text>\n </Section>\n );\n}\n\nfunction Brand({ logoUrl }: { logoUrl: string }) {\n return (\n <table cellPadding=\"0\" cellSpacing=\"0\" role=\"presentation\" style={{ marginBottom: '32px' }}>\n <tbody>\n <tr>\n <td style={{ verticalAlign: 'middle', width: '40px' }}>\n <Img\n alt=\"\"\n height=\"40\"\n src={logoUrl}\n style={{ borderRadius: emailTheme.radius }}\n width=\"40\"\n />\n </td>\n <td style={{ paddingLeft: '12px', verticalAlign: 'middle' }}>\n <Text\n className=\"email-text\"\n style={{\n color: emailTheme.colors.text,\n fontSize: '18px',\n fontWeight: 700,\n lineHeight: '24px',\n margin: 0,\n }}\n >\n FloPay\n </Text>\n </td>\n </tr>\n </tbody>\n </table>\n );\n}\n\nexport function TransactionalEmail({\n preheader,\n heading,\n body,\n action,\n detail,\n logoUrl = FLOPAY_EMAIL_LOGO_URL,\n footer,\n}: TransactionalEmailProps) {\n return (\n <Html lang=\"en\">\n <Head>\n <meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\" />\n <style>{`\n :root {\n color-scheme: light dark;\n supported-color-schemes: light dark;\n }\n\n @media only screen and (max-width: 620px) {\n .email-shell { padding: 0 !important; }\n .email-card { border-left: 0 !important; border-radius: 0 !important; border-right: 0 !important; margin: 0 !important; width: 100% !important; }\n .email-content { padding: 24px !important; }\n }\n\n @media (prefers-color-scheme: dark) {\n .email-body { background-color: ${emailTheme.colors.darkBackground} !important; }\n .email-shell { background-color: ${emailTheme.colors.darkBackground} !important; }\n .email-card { background-color: ${emailTheme.colors.darkSurface} !important; border-color: ${emailTheme.colors.darkBorder} !important; }\n .email-text { color: ${emailTheme.colors.darkText} !important; }\n .email-muted { color: ${emailTheme.colors.darkTextSecondary} !important; }\n .email-detail { background-color: ${emailTheme.colors.darkMuted} !important; border-color: ${emailTheme.colors.darkBorder} !important; }\n .email-link { color: ${emailTheme.colors.brandLight} !important; }\n .email-action { background-color: ${emailTheme.colors.darkText} !important; color: ${emailTheme.colors.darkBackground} !important; }\n .email-divider { border-color: ${emailTheme.colors.darkBorder} !important; }\n }\n `}</style>\n </Head>\n <Preview>{preheader}</Preview>\n <Body\n className=\"email-body\"\n style={{\n backgroundColor: emailTheme.colors.background,\n margin: 0,\n padding: 0,\n }}\n >\n <Section\n className=\"email-shell\"\n style={{\n backgroundColor: emailTheme.colors.background,\n color: emailTheme.colors.text,\n fontFamily: emailTheme.font,\n padding: '32px 12px',\n width: '100%',\n }}\n >\n <Container\n className=\"email-card\"\n style={{\n backgroundColor: emailTheme.colors.surface,\n border: `1px solid ${emailTheme.colors.border}`,\n borderRadius: emailTheme.radius,\n borderTop: `4px solid ${emailTheme.colors.brand}`,\n margin: '0 auto',\n maxWidth: emailTheme.width,\n overflow: 'hidden',\n width: '100%',\n }}\n >\n <Section className=\"email-content\" style={{ padding: '40px' }}>\n <Brand logoUrl={logoUrl} />\n <Heading\n as=\"h1\"\n className=\"email-text\"\n style={{\n color: emailTheme.colors.text,\n fontSize: '28px',\n fontWeight: 700,\n letterSpacing: '-0.02em',\n lineHeight: '36px',\n margin: '0 0 16px',\n }}\n >\n {heading}\n </Heading>\n {body.map((paragraph, index) => (\n <Text\n className=\"email-text\"\n key={`${index}-${paragraph}`}\n style={{\n color: emailTheme.colors.text,\n fontSize: '16px',\n lineHeight: '25px',\n margin: '0 0 16px',\n }}\n >\n {paragraph}\n </Text>\n ))}\n {detail ? <Detail detail={detail} /> : null}\n {action ? (\n <Button\n className=\"email-action\"\n href={action.href}\n style={{\n backgroundColor: emailTheme.colors.text,\n borderRadius: emailTheme.radius,\n color: emailTheme.colors.surface,\n fontSize: '16px',\n fontWeight: 700,\n lineHeight: '20px',\n marginTop: '8px',\n padding: '14px 24px',\n textDecoration: 'none',\n }}\n >\n {action.label}\n </Button>\n ) : null}\n <EmailFooter overrides={footer} />\n </Section>\n </Container>\n </Section>\n </Body>\n </Html>\n );\n}\n\nexport function renderTransactionalEmail(\n props: TransactionalEmailProps,\n): RenderedTransactionalEmail {\n const markup = renderToStaticMarkup(<TransactionalEmail {...props} />);\n const html = `<!doctype html>${markup.replace(\n /<link\\b(?=[^>]*\\brel=\"preload\")(?=[^>]*\\bas=\"image\")[^>]*\\/?>/gi,\n '',\n )}`;\n\n return {\n html,\n text: toPlainText(html, {\n selectors: [\n { selector: 'h1', options: { uppercase: false } },\n {\n selector: 'tr[data-key-value-row=\"true\"]',\n format: 'block',\n options: { leadingLineBreaks: 1, trailingLineBreaks: 1 },\n },\n ],\n }),\n };\n}\n","/**\n * Email clients cannot resolve the package's CSS custom properties. Keep this\n * literal palette aligned with styles/tokens.css and cover changes in the\n * rendered-output snapshot.\n */\nexport const emailTheme = {\n colors: {\n background: '#f7f7f8',\n surface: '#ffffff',\n muted: '#f0f0f2',\n border: '#e5e5e8',\n text: '#0a0a0b',\n textSecondary: '#52525b',\n brand: '#1785e0',\n brandLight: '#4ba6ec',\n accessibleLink: '#0969b3',\n darkBackground: '#0a0a0b',\n darkSurface: '#141416',\n darkMuted: '#1c1c1f',\n darkBorder: '#27272a',\n darkText: '#fafafa',\n darkTextSecondary: '#a1a1aa',\n },\n radius: '8px',\n font: 'Inter, -apple-system, BlinkMacSystemFont, Roboto, Arial, sans-serif',\n fontMono: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',\n width: '600px',\n} as const;\n"],"mappings":"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","names":[]}
@@ -94,7 +94,7 @@ function Footer({ brand, columns = [], legal = [], copyright, className }) {
94
94
  var import_jsx_runtime3 = require("react/jsx-runtime");
95
95
  var TAGLINE = "Payment Orchestration That Keeps Revenue Flowing";
96
96
  var COMPANY = "FloPay LLC";
97
- var DOCS_URL = "https://docs.flopay.com/docs";
97
+ var DOCS_PATH = "/docs";
98
98
  var API_URL = "https://api.flopay.com/docs";
99
99
  var DEMO_URL = "https://demo.flopay.com";
100
100
  function normalizeBase(baseUrl) {
@@ -125,7 +125,7 @@ function flopayFooterContent({
125
125
  {
126
126
  title: "Development",
127
127
  links: [
128
- { href: DOCS_URL, label: "Documentation" },
128
+ { href: route(DOCS_PATH), label: "Documentation" },
129
129
  { href: pending, label: "MCP Server" },
130
130
  { href: API_URL, label: "API Reference" },
131
131
  { href: demoUrl, label: "Demo Playground" }
@@ -137,6 +137,7 @@ function flopayFooterContent({
137
137
  { href: route("/mission"), label: "Mission" },
138
138
  { href: route("/values"), label: "Values" },
139
139
  { href: route("/pricing"), label: "Pricing" },
140
+ { href: route("/partners"), label: "Partners" },
140
141
  { href: route("/blog"), label: "Blog" },
141
142
  { href: contactUrl ?? route("/contact"), label: "Contact" }
142
143
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/marketing/index.ts","../../src/marketing/footer.tsx","../../src/cn.ts","../../src/marketing/link.tsx","../../src/marketing/flopay-footer.tsx","../../src/marketing/nav.tsx"],"sourcesContent":["export type {\n FlopayFooterContent,\n FlopayFooterOptions,\n FlopayFooterProps,\n} from './flopay-footer';\nexport { FlopayFooter, flopayFooterContent } from './flopay-footer';\nexport type { FooterBrand, FooterColumn, FooterLink, FooterProps } from './footer';\nexport { Footer } from './footer';\nexport type { MarketingLinkProps } from './link';\nexport { MarketingLink } from './link';\nexport type { NavLink, NavLogo, NavProps } from './nav';\nexport { Nav } from './nav';\n","import Image, { type ImageProps } from 'next/image';\nimport type { ReactNode } from 'react';\nimport { cn } from '../cn';\nimport { MarketingLink } from './link';\n\nexport interface FooterLink {\n href: string;\n label: ReactNode;\n external?: boolean;\n}\n\nexport interface FooterColumn {\n title: ReactNode;\n links: FooterLink[];\n}\n\nexport interface FooterBrand {\n /** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */\n src: ImageProps['src'];\n alt?: string;\n label?: ReactNode;\n href?: string;\n size?: number;\n mark?: boolean;\n tagline?: ReactNode;\n}\n\nexport interface FooterProps {\n brand: FooterBrand;\n columns?: FooterColumn[];\n legal?: FooterLink[];\n copyright?: ReactNode;\n className?: string;\n}\n\n/** Shared site footer for marketing surfaces (landing, demo). */\nexport function Footer({ brand, columns = [], legal = [], copyright, className }: FooterProps) {\n const size = brand.size ?? 20;\n const image = <Image src={brand.src} alt={brand.alt ?? ''} width={size} height={size} />;\n\n return (\n <footer className={cn('footer', className)}>\n <div className=\"footer-inner\">\n <div className=\"footer-brand\">\n <MarketingLink href={brand.href ?? '/'} className=\"nav-logo\">\n {brand.mark ? (\n <span className=\"nav-logo-mark\" style={{ width: size, height: size }}>\n {image}\n </span>\n ) : (\n image\n )}\n {brand.label}\n </MarketingLink>\n {brand.tagline ? <p>{brand.tagline}</p> : null}\n </div>\n {columns.map((column, index) => (\n <div className=\"footer-column\" key={index}>\n <h4>{column.title}</h4>\n <ul>\n {/* Keyed by index: placeholder links legitimately share an href. */}\n {column.links.map((link, linkIndex) => (\n <li key={linkIndex}>\n <MarketingLink href={link.href} external={link.external}>\n {link.label}\n </MarketingLink>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n <div className=\"footer-bottom\">\n {copyright ? <p>{copyright}</p> : <span />}\n {legal.length > 0 ? (\n <div className=\"footer-legal\">\n {legal.map((link) => (\n <MarketingLink key={link.href} href={link.href} external={link.external}>\n {link.label}\n </MarketingLink>\n ))}\n </div>\n ) : null}\n </div>\n </footer>\n );\n}\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names, resolving conflicting Tailwind utilities (last wins).\n * Mirrors the helper used across the FloPay frontends so consumers can extend\n * any primitive's classes safely.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import Link from 'next/link';\nimport type { ReactNode } from 'react';\n\nexport interface MarketingLinkProps {\n href: string;\n /** Force new-tab rendering. Defaults to true for absolute http(s) URLs. */\n external?: boolean;\n className?: string;\n children: ReactNode;\n}\n\n/**\n * Picks the right element for a marketing link:\n * - internal route (\"/...\", \"#...\") → next/link\n * - protocol link (mailto:/tel:) → plain anchor\n * - absolute URL (or `external`) → new-tab anchor\n */\nexport function MarketingLink({ href, external, className, children }: MarketingLinkProps) {\n const isAbsolute = /^https?:\\/\\//.test(href) || href.startsWith('//');\n const isProtocol = !isAbsolute && /^[a-z][a-z0-9+.-]*:/i.test(href);\n const openExternally = external ?? isAbsolute;\n\n if (openExternally) {\n return (\n <a href={href} className={className} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n );\n }\n if (isProtocol) {\n return (\n <a href={href} className={className}>\n {children}\n </a>\n );\n }\n return (\n <Link href={href} className={className}>\n {children}\n </Link>\n );\n}\n","import type { ImageProps } from 'next/image';\nimport type { FooterBrand, FooterColumn, FooterLink } from './footer';\nimport { Footer } from './footer';\n\nexport interface FlopayFooterOptions {\n /**\n * Origin for marketing-site routes, e.g. `https://flopay.com`. Leave unset on\n * the marketing site itself so its own routes stay relative.\n */\n baseUrl?: string;\n /** Where \"Demo Playground\" points. Defaults to the hosted playground. */\n demoUrl?: string;\n /** Where \"Contact\" points. Defaults to `<baseUrl>/contact`. */\n contactUrl?: string;\n}\n\nexport interface FlopayFooterContent {\n tagline: string;\n columns: FooterColumn[];\n legal: FooterLink[];\n copyright: string;\n}\n\nconst TAGLINE = 'Payment Orchestration That Keeps Revenue Flowing';\nconst COMPANY = 'FloPay LLC';\nconst DOCS_URL = 'https://docs.flopay.com/docs';\nconst API_URL = 'https://api.flopay.com/docs';\nconst DEMO_URL = 'https://demo.flopay.com';\n\n/**\n * Trim trailing slashes so `${base}${path}` can't double up: a caller passing\n * `https://flopay.com/` should still get `https://flopay.com/vault`, and the\n * placeholder href shouldn't keep a dangling slash either.\n */\nfunction normalizeBase(baseUrl: string) {\n return baseUrl.replace(/\\/+$/, '');\n}\n\n/**\n * The FloPay footer sitemap — one source of truth so every portal shows the\n * same columns, labels and order.\n *\n * Products without a page yet point at the marketing home page (`#` when the\n * caller *is* the marketing site, where that would be a self-link).\n */\nexport function flopayFooterContent({\n baseUrl = '',\n demoUrl = DEMO_URL,\n contactUrl,\n}: FlopayFooterOptions = {}): FlopayFooterContent {\n const base = normalizeBase(baseUrl);\n const route = (path: string) => `${base}${path}`;\n const pending = base || '#';\n\n return {\n tagline: TAGLINE,\n columns: [\n {\n title: 'Product',\n links: [\n { href: route('/vault'), label: 'Card Vault' },\n { href: route('/chargeback-prevention'), label: 'Chargeback Prevention' },\n { href: pending, label: 'Agent-Assisted Commerce' },\n { href: pending, label: 'The Agent Vault' },\n { href: pending, label: 'Agentic Discovery Network' },\n { href: pending, label: 'Smart Agentic Orchestration' },\n ],\n },\n {\n title: 'Development',\n links: [\n { href: DOCS_URL, label: 'Documentation' },\n { href: pending, label: 'MCP Server' },\n { href: API_URL, label: 'API Reference' },\n { href: demoUrl, label: 'Demo Playground' },\n ],\n },\n {\n title: 'Company',\n links: [\n { href: route('/mission'), label: 'Mission' },\n { href: route('/values'), label: 'Values' },\n { href: route('/pricing'), label: 'Pricing' },\n { href: route('/blog'), label: 'Blog' },\n { href: contactUrl ?? route('/contact'), label: 'Contact' },\n ],\n },\n ],\n legal: [\n { href: route('/legal/privacy'), label: 'Privacy' },\n { href: route('/legal/terms'), label: 'Terms' },\n { href: route('/legal/cookies'), label: 'Cookies' },\n ],\n copyright: `© ${new Date().getFullYear()} ${COMPANY}. All rights reserved.`,\n };\n}\n\nexport interface FlopayFooterProps extends FlopayFooterOptions {\n /** The shared logo: `import logo from '@flopay/ui/logo.png'`. */\n logo: ImageProps['src'];\n /** Override parts of the default brand block (label, tagline, size, …). */\n brand?: Partial<Omit<FooterBrand, 'src'>>;\n className?: string;\n}\n\n/**\n * The FloPay footer, content included — drop it into any portal and the\n * sitemap, tagline and copyright come from this package.\n *\n * ```tsx\n * import logo from '@flopay/ui/logo.png';\n * <FlopayFooter logo={logo} /> // on flopay.com\n * <FlopayFooter logo={logo} baseUrl=\"https://flopay.com\" /> // anywhere else\n * ```\n */\nexport function FlopayFooter({ logo, brand, className, ...options }: FlopayFooterProps) {\n const { tagline, columns, legal, copyright } = flopayFooterContent(options);\n\n return (\n <Footer\n className={className}\n brand={{\n src: logo,\n alt: 'FloPay',\n label: 'FloPay',\n href: normalizeBase(options.baseUrl ?? '') || '/',\n size: 20,\n mark: true,\n tagline,\n ...brand,\n }}\n columns={columns}\n legal={legal}\n copyright={copyright}\n />\n );\n}\n","import Image, { type ImageProps } from 'next/image';\nimport type { ReactNode } from 'react';\nimport { cn } from '../cn';\nimport { MarketingLink } from './link';\n\nexport interface NavLink {\n href: string;\n label: ReactNode;\n external?: boolean;\n /** Render as the prominent call-to-action button. */\n cta?: boolean;\n}\n\nexport interface NavLogo {\n /** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */\n src: ImageProps['src'];\n alt?: string;\n label?: ReactNode;\n href?: string;\n /** Logo image edge size in px (default 28). */\n size?: number;\n /** Wrap the image in the rounded brand mark. */\n mark?: boolean;\n}\n\nexport interface NavProps {\n logo: NavLogo;\n links?: NavLink[];\n /** Extra item appended to the link list (e.g. an interactive control). */\n children?: ReactNode;\n className?: string;\n}\n\n/** Shared fixed top navigation for marketing surfaces (landing, demo). */\nexport function Nav({ logo, links = [], children, className }: NavProps) {\n const size = logo.size ?? 28;\n const image = <Image src={logo.src} alt={logo.alt ?? ''} width={size} height={size} priority />;\n\n return (\n <nav className={cn('nav', className)}>\n <div className=\"nav-inner\">\n <MarketingLink href={logo.href ?? '/'} className=\"nav-logo\">\n {logo.mark ? (\n <span className=\"nav-logo-mark\" style={{ width: size, height: size }}>\n {image}\n </span>\n ) : (\n image\n )}\n {logo.label}\n </MarketingLink>\n <ul className=\"nav-links\">\n {/* Keyed by index: placeholder links legitimately share an href.\n `nav-link-item` is what the narrow-viewport rule hides, so the\n call to action survives on mobile while the rest collapse. */}\n {links.map((link, index) => (\n <li key={index} className={link.cta ? undefined : 'nav-link-item'}>\n <MarketingLink\n href={link.href}\n external={link.external}\n className={link.cta ? 'nav-cta' : undefined}\n >\n {link.label}\n </MarketingLink>\n </li>\n ))}\n {children ? <li>{children}</li> : null}\n </ul>\n </div>\n </nav>\n );\n}\n"],"mappings":"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","names":["Link","import_jsx_runtime","Image","import_jsx_runtime","import_image","import_jsx_runtime","Image"]}
1
+ {"version":3,"sources":["../../src/marketing/index.ts","../../src/marketing/footer.tsx","../../src/cn.ts","../../src/marketing/link.tsx","../../src/marketing/flopay-footer.tsx","../../src/marketing/nav.tsx"],"sourcesContent":["export type {\n FlopayFooterContent,\n FlopayFooterOptions,\n FlopayFooterProps,\n} from './flopay-footer';\nexport { FlopayFooter, flopayFooterContent } from './flopay-footer';\nexport type { FooterBrand, FooterColumn, FooterLink, FooterProps } from './footer';\nexport { Footer } from './footer';\nexport type { MarketingLinkProps } from './link';\nexport { MarketingLink } from './link';\nexport type { NavLink, NavLogo, NavProps } from './nav';\nexport { Nav } from './nav';\n","import Image, { type ImageProps } from 'next/image';\nimport type { ReactNode } from 'react';\nimport { cn } from '../cn';\nimport { MarketingLink } from './link';\n\nexport interface FooterLink {\n href: string;\n label: ReactNode;\n external?: boolean;\n}\n\nexport interface FooterColumn {\n title: ReactNode;\n links: FooterLink[];\n}\n\nexport interface FooterBrand {\n /** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */\n src: ImageProps['src'];\n alt?: string;\n label?: ReactNode;\n href?: string;\n size?: number;\n mark?: boolean;\n tagline?: ReactNode;\n}\n\nexport interface FooterProps {\n brand: FooterBrand;\n columns?: FooterColumn[];\n legal?: FooterLink[];\n copyright?: ReactNode;\n className?: string;\n}\n\n/** Shared site footer for marketing surfaces (landing, demo). */\nexport function Footer({ brand, columns = [], legal = [], copyright, className }: FooterProps) {\n const size = brand.size ?? 20;\n const image = <Image src={brand.src} alt={brand.alt ?? ''} width={size} height={size} />;\n\n return (\n <footer className={cn('footer', className)}>\n <div className=\"footer-inner\">\n <div className=\"footer-brand\">\n <MarketingLink href={brand.href ?? '/'} className=\"nav-logo\">\n {brand.mark ? (\n <span className=\"nav-logo-mark\" style={{ width: size, height: size }}>\n {image}\n </span>\n ) : (\n image\n )}\n {brand.label}\n </MarketingLink>\n {brand.tagline ? <p>{brand.tagline}</p> : null}\n </div>\n {columns.map((column, index) => (\n <div className=\"footer-column\" key={index}>\n <h4>{column.title}</h4>\n <ul>\n {/* Keyed by index: placeholder links legitimately share an href. */}\n {column.links.map((link, linkIndex) => (\n <li key={linkIndex}>\n <MarketingLink href={link.href} external={link.external}>\n {link.label}\n </MarketingLink>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n <div className=\"footer-bottom\">\n {copyright ? <p>{copyright}</p> : <span />}\n {legal.length > 0 ? (\n <div className=\"footer-legal\">\n {legal.map((link) => (\n <MarketingLink key={link.href} href={link.href} external={link.external}>\n {link.label}\n </MarketingLink>\n ))}\n </div>\n ) : null}\n </div>\n </footer>\n );\n}\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names, resolving conflicting Tailwind utilities (last wins).\n * Mirrors the helper used across the FloPay frontends so consumers can extend\n * any primitive's classes safely.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import Link from 'next/link';\nimport type { ReactNode } from 'react';\n\nexport interface MarketingLinkProps {\n href: string;\n /** Force new-tab rendering. Defaults to true for absolute http(s) URLs. */\n external?: boolean;\n className?: string;\n children: ReactNode;\n}\n\n/**\n * Picks the right element for a marketing link:\n * - internal route (\"/...\", \"#...\") → next/link\n * - protocol link (mailto:/tel:) → plain anchor\n * - absolute URL (or `external`) → new-tab anchor\n */\nexport function MarketingLink({ href, external, className, children }: MarketingLinkProps) {\n const isAbsolute = /^https?:\\/\\//.test(href) || href.startsWith('//');\n const isProtocol = !isAbsolute && /^[a-z][a-z0-9+.-]*:/i.test(href);\n const openExternally = external ?? isAbsolute;\n\n if (openExternally) {\n return (\n <a href={href} className={className} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n );\n }\n if (isProtocol) {\n return (\n <a href={href} className={className}>\n {children}\n </a>\n );\n }\n return (\n <Link href={href} className={className}>\n {children}\n </Link>\n );\n}\n","import type { ImageProps } from 'next/image';\nimport type { FooterBrand, FooterColumn, FooterLink } from './footer';\nimport { Footer } from './footer';\n\nexport interface FlopayFooterOptions {\n /**\n * Origin for marketing-site routes, e.g. `https://flopay.com`. Leave unset on\n * the marketing site itself so its own routes stay relative.\n */\n baseUrl?: string;\n /** Where \"Demo Playground\" points. Defaults to the hosted playground. */\n demoUrl?: string;\n /** Where \"Contact\" points. Defaults to `<baseUrl>/contact`. */\n contactUrl?: string;\n}\n\nexport interface FlopayFooterContent {\n tagline: string;\n columns: FooterColumn[];\n legal: FooterLink[];\n copyright: string;\n}\n\nconst TAGLINE = 'Payment Orchestration That Keeps Revenue Flowing';\nconst COMPANY = 'FloPay LLC';\n/**\n * Developer documentation lives on the marketing site at `/docs` (the old\n * `docs.flopay.com` host is being retired and will 301 there), so it is a\n * `route()` like every other marketing page. The REST API reference is a\n * separate host and stays absolute.\n */\nconst DOCS_PATH = '/docs';\nconst API_URL = 'https://api.flopay.com/docs';\nconst DEMO_URL = 'https://demo.flopay.com';\n\n/**\n * Trim trailing slashes so `${base}${path}` can't double up: a caller passing\n * `https://flopay.com/` should still get `https://flopay.com/vault`, and the\n * placeholder href shouldn't keep a dangling slash either.\n */\nfunction normalizeBase(baseUrl: string) {\n return baseUrl.replace(/\\/+$/, '');\n}\n\n/**\n * The FloPay footer sitemap — one source of truth so every portal shows the\n * same columns, labels and order.\n *\n * Products without a page yet point at the marketing home page (`#` when the\n * caller *is* the marketing site, where that would be a self-link).\n */\nexport function flopayFooterContent({\n baseUrl = '',\n demoUrl = DEMO_URL,\n contactUrl,\n}: FlopayFooterOptions = {}): FlopayFooterContent {\n const base = normalizeBase(baseUrl);\n const route = (path: string) => `${base}${path}`;\n const pending = base || '#';\n\n return {\n tagline: TAGLINE,\n columns: [\n {\n title: 'Product',\n links: [\n { href: route('/vault'), label: 'Card Vault' },\n { href: route('/chargeback-prevention'), label: 'Chargeback Prevention' },\n { href: pending, label: 'Agent-Assisted Commerce' },\n { href: pending, label: 'The Agent Vault' },\n { href: pending, label: 'Agentic Discovery Network' },\n { href: pending, label: 'Smart Agentic Orchestration' },\n ],\n },\n {\n title: 'Development',\n links: [\n { href: route(DOCS_PATH), label: 'Documentation' },\n { href: pending, label: 'MCP Server' },\n { href: API_URL, label: 'API Reference' },\n { href: demoUrl, label: 'Demo Playground' },\n ],\n },\n {\n title: 'Company',\n links: [\n { href: route('/mission'), label: 'Mission' },\n { href: route('/values'), label: 'Values' },\n { href: route('/pricing'), label: 'Pricing' },\n { href: route('/partners'), label: 'Partners' },\n { href: route('/blog'), label: 'Blog' },\n { href: contactUrl ?? route('/contact'), label: 'Contact' },\n ],\n },\n ],\n legal: [\n { href: route('/legal/privacy'), label: 'Privacy' },\n { href: route('/legal/terms'), label: 'Terms' },\n { href: route('/legal/cookies'), label: 'Cookies' },\n ],\n copyright: `© ${new Date().getFullYear()} ${COMPANY}. All rights reserved.`,\n };\n}\n\nexport interface FlopayFooterProps extends FlopayFooterOptions {\n /** The shared logo: `import logo from '@flopay/ui/logo.png'`. */\n logo: ImageProps['src'];\n /** Override parts of the default brand block (label, tagline, size, …). */\n brand?: Partial<Omit<FooterBrand, 'src'>>;\n className?: string;\n}\n\n/**\n * The FloPay footer, content included — drop it into any portal and the\n * sitemap, tagline and copyright come from this package.\n *\n * ```tsx\n * import logo from '@flopay/ui/logo.png';\n * <FlopayFooter logo={logo} /> // on flopay.com\n * <FlopayFooter logo={logo} baseUrl=\"https://flopay.com\" /> // anywhere else\n * ```\n */\nexport function FlopayFooter({ logo, brand, className, ...options }: FlopayFooterProps) {\n const { tagline, columns, legal, copyright } = flopayFooterContent(options);\n\n return (\n <Footer\n className={className}\n brand={{\n src: logo,\n alt: 'FloPay',\n label: 'FloPay',\n href: normalizeBase(options.baseUrl ?? '') || '/',\n size: 20,\n mark: true,\n tagline,\n ...brand,\n }}\n columns={columns}\n legal={legal}\n copyright={copyright}\n />\n );\n}\n","import Image, { type ImageProps } from 'next/image';\nimport type { ReactNode } from 'react';\nimport { cn } from '../cn';\nimport { MarketingLink } from './link';\n\nexport interface NavLink {\n href: string;\n label: ReactNode;\n external?: boolean;\n /** Render as the prominent call-to-action button. */\n cta?: boolean;\n}\n\nexport interface NavLogo {\n /** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */\n src: ImageProps['src'];\n alt?: string;\n label?: ReactNode;\n href?: string;\n /** Logo image edge size in px (default 28). */\n size?: number;\n /** Wrap the image in the rounded brand mark. */\n mark?: boolean;\n}\n\nexport interface NavProps {\n logo: NavLogo;\n links?: NavLink[];\n /** Extra item appended to the link list (e.g. an interactive control). */\n children?: ReactNode;\n className?: string;\n}\n\n/** Shared fixed top navigation for marketing surfaces (landing, demo). */\nexport function Nav({ logo, links = [], children, className }: NavProps) {\n const size = logo.size ?? 28;\n const image = <Image src={logo.src} alt={logo.alt ?? ''} width={size} height={size} priority />;\n\n return (\n <nav className={cn('nav', className)}>\n <div className=\"nav-inner\">\n <MarketingLink href={logo.href ?? '/'} className=\"nav-logo\">\n {logo.mark ? (\n <span className=\"nav-logo-mark\" style={{ width: size, height: size }}>\n {image}\n </span>\n ) : (\n image\n )}\n {logo.label}\n </MarketingLink>\n <ul className=\"nav-links\">\n {/* Keyed by index: placeholder links legitimately share an href.\n `nav-link-item` is what the narrow-viewport rule hides, so the\n call to action survives on mobile while the rest collapse. */}\n {links.map((link, index) => (\n <li key={index} className={link.cta ? undefined : 'nav-link-item'}>\n <MarketingLink\n href={link.href}\n external={link.external}\n className={link.cta ? 'nav-cta' : undefined}\n >\n {link.label}\n </MarketingLink>\n </li>\n ))}\n {children ? <li>{children}</li> : null}\n </ul>\n </div>\n </nav>\n );\n}\n"],"mappings":"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","names":["Link","import_jsx_runtime","Image","import_jsx_runtime","import_image","import_jsx_runtime","Image"]}
@@ -51,7 +51,7 @@ function Footer({ brand, columns = [], legal = [], copyright, className }) {
51
51
  import { jsx as jsx3 } from "react/jsx-runtime";
52
52
  var TAGLINE = "Payment Orchestration That Keeps Revenue Flowing";
53
53
  var COMPANY = "FloPay LLC";
54
- var DOCS_URL = "https://docs.flopay.com/docs";
54
+ var DOCS_PATH = "/docs";
55
55
  var API_URL = "https://api.flopay.com/docs";
56
56
  var DEMO_URL = "https://demo.flopay.com";
57
57
  function normalizeBase(baseUrl) {
@@ -82,7 +82,7 @@ function flopayFooterContent({
82
82
  {
83
83
  title: "Development",
84
84
  links: [
85
- { href: DOCS_URL, label: "Documentation" },
85
+ { href: route(DOCS_PATH), label: "Documentation" },
86
86
  { href: pending, label: "MCP Server" },
87
87
  { href: API_URL, label: "API Reference" },
88
88
  { href: demoUrl, label: "Demo Playground" }
@@ -94,6 +94,7 @@ function flopayFooterContent({
94
94
  { href: route("/mission"), label: "Mission" },
95
95
  { href: route("/values"), label: "Values" },
96
96
  { href: route("/pricing"), label: "Pricing" },
97
+ { href: route("/partners"), label: "Partners" },
97
98
  { href: route("/blog"), label: "Blog" },
98
99
  { href: contactUrl ?? route("/contact"), label: "Contact" }
99
100
  ]