@nexub/patterns 2.1.0 → 2.2.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/chunk-27N33TGN.js +61 -0
- package/dist/chunk-33Z2ZPO7.js +71 -0
- package/dist/chunk-64PSI75E.js +83 -0
- package/dist/chunk-7QCJC2DV.js +113 -0
- package/dist/chunk-CJBHDX2U.js +42 -0
- package/dist/chunk-CWFZA7ZQ.js +1 -0
- package/dist/chunk-CZR6NZDH.js +134 -0
- package/dist/chunk-M3OHX4F4.js +42 -0
- package/dist/chunk-OC4XY3US.js +87 -0
- package/dist/chunk-RFCPEZGF.js +1 -0
- package/dist/chunk-UNQD426H.js +101 -0
- package/dist/components/ActivityPage/index.js +11 -0
- package/dist/components/ChatPage/index.js +9 -0
- package/dist/components/CheckoutPage/index.js +9 -0
- package/dist/components/DashboardPage/index.js +10 -0
- package/dist/components/PageFrame/index.js +14 -0
- package/dist/components/PaywallPage/index.js +8 -0
- package/dist/components/SettingsPage/index.js +8 -0
- package/dist/components/SignInPage/index.js +9 -0
- package/dist/components/TransactionDetailPage/index.js +9 -0
- package/dist/index.d.ts +330 -1
- package/dist/index.js +61 -15
- package/package.json +7 -7
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
PageFrame,
|
|
4
|
+
usePageMessages
|
|
5
|
+
} from "./chunk-7QCJC2DV.js";
|
|
6
|
+
|
|
7
|
+
// src/components/SettingsPage/SettingsPage.tsx
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { cn } from "@nexub/react";
|
|
10
|
+
import { ChevronRight } from "@nexub/icons";
|
|
11
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
function Row({ item }) {
|
|
13
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14
|
+
item.leading && /* @__PURE__ */ jsx("span", { className: "flex shrink-0 text-[var(--color-on-surface-variant)]", children: item.leading }),
|
|
15
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col text-start", children: [
|
|
16
|
+
/* @__PURE__ */ jsx(
|
|
17
|
+
"span",
|
|
18
|
+
{
|
|
19
|
+
className: cn(
|
|
20
|
+
"text-body-md font-medium",
|
|
21
|
+
item.destructive ? "text-[var(--color-error)]" : "text-[var(--color-on-surface)]"
|
|
22
|
+
),
|
|
23
|
+
children: item.title
|
|
24
|
+
}
|
|
25
|
+
),
|
|
26
|
+
item.subtitle && /* @__PURE__ */ jsx("span", { className: "text-body-sm text-[var(--color-on-surface-muted)]", children: item.subtitle })
|
|
27
|
+
] }),
|
|
28
|
+
item.value != null && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-body-md text-[var(--color-on-surface-muted)]", children: item.value }),
|
|
29
|
+
(item.href || item.onSelect) && !item.destructive && /* @__PURE__ */ jsx(ChevronRight, { size: "sm", "aria-hidden": "true", className: "shrink-0 text-[var(--color-on-surface-muted)] rtl:-scale-x-100" })
|
|
30
|
+
] });
|
|
31
|
+
const row = "flex min-h-[56px] w-full items-center gap-3 px-4 py-3";
|
|
32
|
+
if (item.href)
|
|
33
|
+
return /* @__PURE__ */ jsx("a", { href: item.href, onClick: item.onSelect && ((e) => {
|
|
34
|
+
e.preventDefault();
|
|
35
|
+
item.onSelect?.();
|
|
36
|
+
}), className: cn(row, "nx-state-layer"), children: content });
|
|
37
|
+
if (item.onSelect)
|
|
38
|
+
return /* @__PURE__ */ jsx("button", { type: "button", onClick: item.onSelect, className: cn(row, "nx-state-layer"), children: content });
|
|
39
|
+
return /* @__PURE__ */ jsxs("div", { className: row, children: [
|
|
40
|
+
content,
|
|
41
|
+
item.control && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: item.control })
|
|
42
|
+
] });
|
|
43
|
+
}
|
|
44
|
+
var SettingsPage = React.forwardRef(function SettingsPage2({ groups, header, title, messages, ...props }, ref) {
|
|
45
|
+
const m = usePageMessages(messages);
|
|
46
|
+
return /* @__PURE__ */ jsxs(PageFrame, { ref, title: title ?? m.settings, ...props, children: [
|
|
47
|
+
header,
|
|
48
|
+
groups.map((g, i) => {
|
|
49
|
+
const id = `settings-group-${i}`;
|
|
50
|
+
return /* @__PURE__ */ jsxs("section", { "aria-labelledby": g.header ? id : void 0, className: "flex flex-col gap-2", children: [
|
|
51
|
+
g.header && /* @__PURE__ */ jsx("h2", { id, className: "px-4 text-label-lg text-[var(--color-on-surface-variant)]", children: g.header }),
|
|
52
|
+
/* @__PURE__ */ jsx("ul", { className: "overflow-hidden rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)]", children: g.items.map((it) => /* @__PURE__ */ jsx("li", { className: "border-t border-[var(--color-outline-variant)] first:border-t-0", children: /* @__PURE__ */ jsx(Row, { item: it }) }, it.title)) }),
|
|
53
|
+
g.footer && /* @__PURE__ */ jsx("p", { className: "px-4 text-body-sm text-[var(--color-on-surface-muted)]", children: g.footer })
|
|
54
|
+
] }, g.header ?? i);
|
|
55
|
+
})
|
|
56
|
+
] });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export {
|
|
60
|
+
SettingsPage
|
|
61
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
StatCard
|
|
4
|
+
} from "./chunk-INKX2GYA.js";
|
|
5
|
+
import {
|
|
6
|
+
TransactionRow
|
|
7
|
+
} from "./chunk-OC4XY3US.js";
|
|
8
|
+
import {
|
|
9
|
+
PageFrame,
|
|
10
|
+
usePageMessages,
|
|
11
|
+
useTemplateLocale
|
|
12
|
+
} from "./chunk-7QCJC2DV.js";
|
|
13
|
+
|
|
14
|
+
// src/components/DashboardPage/DashboardPage.tsx
|
|
15
|
+
import * as React from "react";
|
|
16
|
+
import { Amount, Button, Card } from "@nexub/react";
|
|
17
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
+
function Panel({ title, action, children }) {
|
|
19
|
+
const id = React.useId();
|
|
20
|
+
return /* @__PURE__ */ jsxs("section", { "aria-labelledby": id, className: "flex flex-col gap-3", children: [
|
|
21
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
22
|
+
/* @__PURE__ */ jsx("h2", { id, className: "text-title-md text-[var(--color-on-surface)]", children: title }),
|
|
23
|
+
action
|
|
24
|
+
] }),
|
|
25
|
+
children
|
|
26
|
+
] });
|
|
27
|
+
}
|
|
28
|
+
var DashboardPage = React.forwardRef(function DashboardPage2({
|
|
29
|
+
title,
|
|
30
|
+
balance,
|
|
31
|
+
quickActions = [],
|
|
32
|
+
stats = [],
|
|
33
|
+
recent = [],
|
|
34
|
+
onSelectTransaction,
|
|
35
|
+
onSeeAllActivity,
|
|
36
|
+
insights = [],
|
|
37
|
+
messages,
|
|
38
|
+
...props
|
|
39
|
+
}, ref) {
|
|
40
|
+
const m = usePageMessages(messages);
|
|
41
|
+
const locale = useTemplateLocale();
|
|
42
|
+
return /* @__PURE__ */ jsx(PageFrame, { ref, width: "lg", title, ...props, children: /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-3", children: [
|
|
43
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-6 lg:col-span-2", children: [
|
|
44
|
+
/* @__PURE__ */ jsxs(Card, { className: "flex flex-col gap-5 p-6", children: [
|
|
45
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
46
|
+
/* @__PURE__ */ jsx("p", { className: "text-label-lg text-[var(--color-on-surface-variant)]", children: balance.label ?? m.totalBalance }),
|
|
47
|
+
/* @__PURE__ */ jsx(Amount, { value: balance.value, currency: balance.currency, locale, size: "display" })
|
|
48
|
+
] }),
|
|
49
|
+
quickActions.length > 0 && /* @__PURE__ */ jsx("ul", { "aria-label": m.quickActions, className: "grid grid-cols-2 gap-2 sm:grid-cols-4", children: quickActions.map((a) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Button, { variant: "secondary", fullWidth: true, onClick: a.onSelect, leadingIcon: a.icon, children: a.label }) }, a.id)) })
|
|
50
|
+
] }),
|
|
51
|
+
stats.length > 0 && /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-3", children: stats.map((s) => /* @__PURE__ */ jsx(StatCard, { ...s }, s.label)) }),
|
|
52
|
+
recent.length > 0 && /* @__PURE__ */ jsx(
|
|
53
|
+
Panel,
|
|
54
|
+
{
|
|
55
|
+
title: m.recentActivity,
|
|
56
|
+
action: onSeeAllActivity && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onSeeAllActivity, children: m.seeAll }),
|
|
57
|
+
children: /* @__PURE__ */ jsx("ul", { className: "overflow-hidden rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)]", children: recent.map((t) => /* @__PURE__ */ jsx(TransactionRow, { t, onSelect: onSelectTransaction, m, locale }, t.id)) })
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
] }),
|
|
61
|
+
insights.length > 0 && /* @__PURE__ */ jsx(Panel, { title: m.insights, children: /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-3", children: insights.map((i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Card, { className: "flex flex-col gap-2 p-4", children: [
|
|
62
|
+
/* @__PURE__ */ jsx("h3", { className: "text-title-sm text-[var(--color-on-surface)]", children: i.title }),
|
|
63
|
+
/* @__PURE__ */ jsx("p", { className: "text-body-sm text-[var(--color-on-surface-muted)]", children: i.body }),
|
|
64
|
+
i.action && /* @__PURE__ */ jsx(Button, { variant: "link", size: "sm", className: "self-start px-0", onClick: i.action.onSelect, children: i.action.label })
|
|
65
|
+
] }) }, i.id)) }) })
|
|
66
|
+
] }) });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
DashboardPage
|
|
71
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
Conversation
|
|
4
|
+
} from "./chunk-WRP73TXG.js";
|
|
5
|
+
import {
|
|
6
|
+
usePageMessages
|
|
7
|
+
} from "./chunk-7QCJC2DV.js";
|
|
8
|
+
|
|
9
|
+
// src/components/ChatPage/ChatPage.tsx
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
import { MessageBubble, PromptInput, ThinkingIndicator, cn } from "@nexub/react";
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
var ChatPage = React.forwardRef(function ChatPage2({
|
|
14
|
+
messages: list,
|
|
15
|
+
onSend,
|
|
16
|
+
onStop,
|
|
17
|
+
thinking,
|
|
18
|
+
placeholder,
|
|
19
|
+
empty,
|
|
20
|
+
assistantAvatar,
|
|
21
|
+
title,
|
|
22
|
+
showTitle = false,
|
|
23
|
+
as: Tag = "main",
|
|
24
|
+
strings,
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
}, ref) {
|
|
28
|
+
const m = usePageMessages(strings);
|
|
29
|
+
const [draft, setDraft] = React.useState("");
|
|
30
|
+
const streaming = list.at(-1)?.streaming ?? false;
|
|
31
|
+
const headingId = React.useId();
|
|
32
|
+
return /* @__PURE__ */ jsxs(
|
|
33
|
+
Tag,
|
|
34
|
+
{
|
|
35
|
+
ref,
|
|
36
|
+
"aria-labelledby": headingId,
|
|
37
|
+
className: cn("flex h-full min-h-0 w-full flex-col", className),
|
|
38
|
+
...props,
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx("h1", { id: headingId, className: showTitle ? "px-4 pt-4 text-title-lg text-[var(--color-on-surface)]" : "sr-only", children: title ?? m.chat }),
|
|
41
|
+
/* @__PURE__ */ jsx(
|
|
42
|
+
Conversation,
|
|
43
|
+
{
|
|
44
|
+
className: "min-h-0 flex-1",
|
|
45
|
+
composer: /* @__PURE__ */ jsx(
|
|
46
|
+
PromptInput,
|
|
47
|
+
{
|
|
48
|
+
value: draft,
|
|
49
|
+
onValueChange: setDraft,
|
|
50
|
+
placeholder,
|
|
51
|
+
status: streaming ? "streaming" : thinking ? "submitting" : "idle",
|
|
52
|
+
onStop,
|
|
53
|
+
onSubmit: (text) => {
|
|
54
|
+
const t = text.trim();
|
|
55
|
+
if (!t) return;
|
|
56
|
+
onSend(t);
|
|
57
|
+
setDraft("");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
children: list.length === 0 && !thinking ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center py-16 text-center text-body-md text-[var(--color-on-surface-muted)]", children: empty ?? m.chatEmpty }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
62
|
+
list.map((msg) => /* @__PURE__ */ jsx(
|
|
63
|
+
MessageBubble,
|
|
64
|
+
{
|
|
65
|
+
from: msg.role,
|
|
66
|
+
avatar: msg.role === "assistant" ? assistantAvatar : void 0,
|
|
67
|
+
"aria-busy": msg.streaming || void 0,
|
|
68
|
+
children: msg.text
|
|
69
|
+
},
|
|
70
|
+
msg.id
|
|
71
|
+
)),
|
|
72
|
+
thinking && /* @__PURE__ */ jsx(ThinkingIndicator, {})
|
|
73
|
+
] })
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
ChatPage
|
|
83
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// src/components/PageFrame/PageFrame.tsx
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { Badge, cn, useLocale, useNexubMessages } from "@nexub/react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
var defaultPageTemplateMessages = {
|
|
8
|
+
activity: "Activity",
|
|
9
|
+
noActivityTitle: "No activity yet",
|
|
10
|
+
noActivityDescription: "Your payments and transfers will show up here.",
|
|
11
|
+
loadMore: "Load more",
|
|
12
|
+
refresh: "Refresh",
|
|
13
|
+
pending: "Pending",
|
|
14
|
+
failed: "Failed",
|
|
15
|
+
completed: "Completed",
|
|
16
|
+
date: "Date",
|
|
17
|
+
details: "Details",
|
|
18
|
+
back: "Back",
|
|
19
|
+
settings: "Settings",
|
|
20
|
+
signIn: "Sign in",
|
|
21
|
+
email: "Email",
|
|
22
|
+
password: "Password",
|
|
23
|
+
forgotPassword: "Forgot password?",
|
|
24
|
+
createAccount: "Create an account",
|
|
25
|
+
howMuch: "How much?",
|
|
26
|
+
amountToSend: "Amount to send",
|
|
27
|
+
balance: (b) => `Balance ${b}`,
|
|
28
|
+
overBalance: (b) => `More than your balance (${b})`,
|
|
29
|
+
fee: "Fee",
|
|
30
|
+
rate: "Rate",
|
|
31
|
+
recipientGets: "Recipient gets",
|
|
32
|
+
arrives: "Arrives",
|
|
33
|
+
continue: "Continue",
|
|
34
|
+
checkDetails: "Check the details",
|
|
35
|
+
edit: "Edit",
|
|
36
|
+
done: "Done",
|
|
37
|
+
stepOf: (s, t) => `Step ${s} of ${t}`,
|
|
38
|
+
sent: "Sent",
|
|
39
|
+
chat: "Chat",
|
|
40
|
+
chatEmpty: "Ask anything to get started.",
|
|
41
|
+
restorePurchases: "Restore purchases",
|
|
42
|
+
choosePlan: "Choose a plan",
|
|
43
|
+
totalBalance: "Total balance",
|
|
44
|
+
quickActions: "Quick actions",
|
|
45
|
+
recentActivity: "Recent activity",
|
|
46
|
+
seeAll: "See all",
|
|
47
|
+
insights: "Insights"
|
|
48
|
+
};
|
|
49
|
+
function usePageMessages(overrides) {
|
|
50
|
+
const provided = useNexubMessages();
|
|
51
|
+
const out = { ...defaultPageTemplateMessages };
|
|
52
|
+
for (const key of Object.keys(out)) {
|
|
53
|
+
const v = overrides?.[key] ?? provided[key];
|
|
54
|
+
if (v !== void 0 && typeof v === typeof out[key]) out[key] = v;
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
function formatMoney(value, currency, locale, opts) {
|
|
59
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency, ...opts }).format(value);
|
|
60
|
+
}
|
|
61
|
+
function groupByDay(transactions, locale) {
|
|
62
|
+
const day = new Intl.DateTimeFormat(locale, { dateStyle: "medium" });
|
|
63
|
+
const map = /* @__PURE__ */ new Map();
|
|
64
|
+
for (const t of [...transactions].sort((a, b) => +b.date - +a.date)) {
|
|
65
|
+
const key = day.format(t.date);
|
|
66
|
+
map.set(key, [...map.get(key) ?? [], t]);
|
|
67
|
+
}
|
|
68
|
+
return [...map].map(([title, data]) => ({ title, data }));
|
|
69
|
+
}
|
|
70
|
+
function useTemplateLocale() {
|
|
71
|
+
return useLocale().locale;
|
|
72
|
+
}
|
|
73
|
+
function StatusBadge({ status, m, dot }) {
|
|
74
|
+
if (!status) return null;
|
|
75
|
+
return /* @__PURE__ */ jsxs(Badge, { tone: status === "failed" ? "danger" : "warning", size: "sm", children: [
|
|
76
|
+
dot && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "me-1 inline-block h-1.5 w-1.5 rounded-full bg-current" }),
|
|
77
|
+
status === "failed" ? m.failed : m.pending
|
|
78
|
+
] });
|
|
79
|
+
}
|
|
80
|
+
var widths = { sm: "max-w-[480px]", md: "max-w-3xl", lg: "max-w-6xl" };
|
|
81
|
+
var PageFrame = React.forwardRef(function PageFrame2({ as: Tag = "main", title, description, actions, eyebrow, width = "md", className, children, ...props }, ref) {
|
|
82
|
+
const headingId = React.useId();
|
|
83
|
+
return /* @__PURE__ */ jsxs(
|
|
84
|
+
Tag,
|
|
85
|
+
{
|
|
86
|
+
ref,
|
|
87
|
+
"aria-labelledby": title ? headingId : void 0,
|
|
88
|
+
className: cn("mx-auto flex w-full flex-col gap-6 px-4 py-6 sm:px-6 lg:py-10", widths[width], className),
|
|
89
|
+
...props,
|
|
90
|
+
children: [
|
|
91
|
+
(title || actions || eyebrow) && /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-2", children: [
|
|
92
|
+
eyebrow,
|
|
93
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
94
|
+
title && /* @__PURE__ */ jsx("h1", { id: headingId, className: "text-headline-sm text-[var(--color-on-surface)]", children: title }),
|
|
95
|
+
actions && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: actions })
|
|
96
|
+
] }),
|
|
97
|
+
description && /* @__PURE__ */ jsx("p", { className: "text-body-md text-[var(--color-on-surface-muted)]", children: description })
|
|
98
|
+
] }),
|
|
99
|
+
children
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
defaultPageTemplateMessages,
|
|
107
|
+
usePageMessages,
|
|
108
|
+
formatMoney,
|
|
109
|
+
groupByDay,
|
|
110
|
+
useTemplateLocale,
|
|
111
|
+
StatusBadge,
|
|
112
|
+
PageFrame
|
|
113
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
InfoList
|
|
4
|
+
} from "./chunk-WPNT5JOU.js";
|
|
5
|
+
import {
|
|
6
|
+
PageFrame,
|
|
7
|
+
usePageMessages,
|
|
8
|
+
useTemplateLocale
|
|
9
|
+
} from "./chunk-7QCJC2DV.js";
|
|
10
|
+
|
|
11
|
+
// src/components/TransactionDetailPage/TransactionDetailPage.tsx
|
|
12
|
+
import * as React from "react";
|
|
13
|
+
import { Amount, Avatar, Badge, Button } from "@nexub/react";
|
|
14
|
+
import { ArrowLeft } from "@nexub/icons";
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
var TransactionDetailPage = React.forwardRef(
|
|
17
|
+
function TransactionDetailPage2({ transaction: t, rows = [], footer, onBack, messages, ...props }, ref) {
|
|
18
|
+
const m = usePageMessages(messages);
|
|
19
|
+
const locale = useTemplateLocale();
|
|
20
|
+
const headingId = React.useId();
|
|
21
|
+
const when = new Intl.DateTimeFormat(locale, { dateStyle: "full", timeStyle: "short" }).format(t.date);
|
|
22
|
+
return /* @__PURE__ */ jsxs(PageFrame, { ref, width: "sm", "aria-labelledby": headingId, ...props, children: [
|
|
23
|
+
onBack && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "self-start", onClick: onBack, leadingIcon: /* @__PURE__ */ jsx(ArrowLeft, { size: "sm", className: "rtl:-scale-x-100", "aria-hidden": "true" }), children: m.back }),
|
|
24
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-4 text-center", children: [
|
|
25
|
+
/* @__PURE__ */ jsx(Avatar, { name: t.title, src: t.image, size: "xl" }),
|
|
26
|
+
/* @__PURE__ */ jsx("h1", { id: headingId, className: "text-title-lg text-[var(--color-on-surface)]", children: t.title }),
|
|
27
|
+
/* @__PURE__ */ jsx(Amount, { value: t.amount, currency: t.currency, locale, size: "display", tone: "auto", signDisplay: "exceptZero" }),
|
|
28
|
+
/* @__PURE__ */ jsx(Badge, { tone: t.status === "failed" ? "danger" : t.status === "pending" ? "warning" : "success", children: t.status === "failed" ? m.failed : t.status === "pending" ? m.pending : m.completed })
|
|
29
|
+
] }),
|
|
30
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)] px-4", children: /* @__PURE__ */ jsxs(InfoList.Root, { children: [
|
|
31
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.date, value: when }),
|
|
32
|
+
t.subtitle && /* @__PURE__ */ jsx(InfoList.Item, { label: m.details, value: t.subtitle }),
|
|
33
|
+
rows.map((r) => /* @__PURE__ */ jsx(InfoList.Item, { label: r.label, value: r.value }, r.label))
|
|
34
|
+
] }) }),
|
|
35
|
+
footer && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 sm:flex-row sm:justify-center", children: footer })
|
|
36
|
+
] });
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
TransactionDetailPage
|
|
42
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use client';
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
InfoList
|
|
4
|
+
} from "./chunk-WPNT5JOU.js";
|
|
5
|
+
import {
|
|
6
|
+
PageFrame,
|
|
7
|
+
formatMoney,
|
|
8
|
+
usePageMessages,
|
|
9
|
+
useTemplateLocale
|
|
10
|
+
} from "./chunk-7QCJC2DV.js";
|
|
11
|
+
|
|
12
|
+
// src/components/CheckoutPage/CheckoutPage.tsx
|
|
13
|
+
import * as React from "react";
|
|
14
|
+
import { Alert, Amount, Button, FormField, MoneyInput, Progress } from "@nexub/react";
|
|
15
|
+
import { CheckCircle2, ShieldCheck } from "@nexub/icons";
|
|
16
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
17
|
+
var CheckoutPage = React.forwardRef(function CheckoutPage2({
|
|
18
|
+
from,
|
|
19
|
+
to,
|
|
20
|
+
balance,
|
|
21
|
+
quote,
|
|
22
|
+
reviewRows,
|
|
23
|
+
confirmLabel,
|
|
24
|
+
confirmHint,
|
|
25
|
+
onConfirm,
|
|
26
|
+
resultTitle,
|
|
27
|
+
resultDescription,
|
|
28
|
+
onDone,
|
|
29
|
+
messages,
|
|
30
|
+
...props
|
|
31
|
+
}, ref) {
|
|
32
|
+
const m = usePageMessages(messages);
|
|
33
|
+
const locale = useTemplateLocale();
|
|
34
|
+
const [step, setStep] = React.useState("amount");
|
|
35
|
+
const [amount, setAmount] = React.useState(null);
|
|
36
|
+
const [busy, setBusy] = React.useState(false);
|
|
37
|
+
const [error, setError] = React.useState();
|
|
38
|
+
const headingRef = React.useRef(null);
|
|
39
|
+
const fmt = (n, c) => formatMoney(n, c, locale);
|
|
40
|
+
const over = amount != null && amount > balance;
|
|
41
|
+
const q = amount && !over ? quote(amount) : void 0;
|
|
42
|
+
const index = step === "amount" ? 1 : step === "review" ? 2 : 3;
|
|
43
|
+
const first = React.useRef(true);
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
if (first.current) {
|
|
46
|
+
first.current = false;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
headingRef.current?.focus();
|
|
50
|
+
}, [step]);
|
|
51
|
+
const rows = amount && q ? reviewRows?.(amount, q) ?? [
|
|
52
|
+
{ label: m.amountToSend, value: fmt(amount, from) },
|
|
53
|
+
{ label: m.fee, value: fmt(q.fee, from) },
|
|
54
|
+
{ label: m.rate, value: `1 ${from} = ${q.rate} ${to}` },
|
|
55
|
+
{ label: m.recipientGets, value: fmt((amount - q.fee) * q.rate, to) },
|
|
56
|
+
{ label: m.arrives, value: q.arrives }
|
|
57
|
+
] : [];
|
|
58
|
+
const confirm = async () => {
|
|
59
|
+
if (!amount) return;
|
|
60
|
+
setBusy(true);
|
|
61
|
+
setError(void 0);
|
|
62
|
+
try {
|
|
63
|
+
await onConfirm(amount);
|
|
64
|
+
setStep("done");
|
|
65
|
+
} catch (e) {
|
|
66
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
67
|
+
} finally {
|
|
68
|
+
setBusy(false);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const title = step === "amount" ? m.howMuch : step === "review" ? m.checkDetails : resultTitle ?? m.sent;
|
|
72
|
+
return /* @__PURE__ */ jsxs(PageFrame, { ref, width: "sm", ...props, children: [
|
|
73
|
+
step !== "done" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
74
|
+
/* @__PURE__ */ jsx(Progress, { value: index, max: 3, "aria-label": m.stepOf(index, 3) }),
|
|
75
|
+
/* @__PURE__ */ jsx("p", { className: "text-label-md text-[var(--color-on-surface-variant)]", children: m.stepOf(index, 3) })
|
|
76
|
+
] }),
|
|
77
|
+
step === "done" ? /* @__PURE__ */ jsxs("div", { role: "status", className: "flex flex-col items-center gap-4 py-8 text-center", children: [
|
|
78
|
+
/* @__PURE__ */ jsx("span", { className: "grid h-20 w-20 place-items-center rounded-full bg-[var(--color-success-container)] text-[var(--color-success)]", children: /* @__PURE__ */ jsx(CheckCircle2, { size: 40, "aria-hidden": "true" }) }),
|
|
79
|
+
/* @__PURE__ */ jsx("h1", { ref: headingRef, tabIndex: -1, className: "text-headline-sm text-[var(--color-on-surface)] outline-none", children: title }),
|
|
80
|
+
amount != null && /* @__PURE__ */ jsx(Amount, { value: amount, currency: from, locale, size: "display" }),
|
|
81
|
+
resultDescription && /* @__PURE__ */ jsx("p", { className: "text-body-md text-[var(--color-on-surface-muted)]", children: resultDescription }),
|
|
82
|
+
/* @__PURE__ */ jsx(Button, { size: "lg", fullWidth: true, onClick: onDone, children: m.done })
|
|
83
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
84
|
+
/* @__PURE__ */ jsx("h1", { ref: headingRef, tabIndex: -1, className: "text-headline-sm text-[var(--color-on-surface)] outline-none", children: title }),
|
|
85
|
+
step === "amount" && /* @__PURE__ */ jsxs(
|
|
86
|
+
"form",
|
|
87
|
+
{
|
|
88
|
+
className: "flex flex-col gap-6",
|
|
89
|
+
onSubmit: (e) => {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
if (amount && !over) setStep("review");
|
|
92
|
+
},
|
|
93
|
+
children: [
|
|
94
|
+
/* @__PURE__ */ jsxs(FormField.Root, { invalid: over, children: [
|
|
95
|
+
/* @__PURE__ */ jsx(FormField.Label, { children: m.amountToSend }),
|
|
96
|
+
/* @__PURE__ */ jsx(FormField.Control, { children: /* @__PURE__ */ jsx(MoneyInput, { currency: from, locale, value: amount, onValueChange: setAmount }) }),
|
|
97
|
+
over ? /* @__PURE__ */ jsx(FormField.Error, { children: m.overBalance(fmt(balance, from)) }) : /* @__PURE__ */ jsx(FormField.Description, { children: m.balance(fmt(balance, from)) })
|
|
98
|
+
] }),
|
|
99
|
+
q && amount && /* @__PURE__ */ jsx("div", { "aria-live": "polite", className: "rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)] px-4", children: /* @__PURE__ */ jsxs(InfoList.Root, { children: [
|
|
100
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.fee, value: fmt(q.fee, from) }),
|
|
101
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.rate, value: `1 ${from} = ${q.rate} ${to}` }),
|
|
102
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.recipientGets, value: fmt((amount - q.fee) * q.rate, to) }),
|
|
103
|
+
/* @__PURE__ */ jsx(InfoList.Item, { label: m.arrives, value: q.arrives })
|
|
104
|
+
] }) }),
|
|
105
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", size: "lg", fullWidth: true, disabled: !amount || over, children: m.continue })
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
step === "review" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
110
|
+
error && /* @__PURE__ */ jsx(Alert, { tone: "danger", role: "alert", children: error }),
|
|
111
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)] px-4", children: /* @__PURE__ */ jsx(InfoList.Root, { children: rows.map((r) => /* @__PURE__ */ jsx(InfoList.Item, { label: r.label, value: r.value }, r.label)) }) }),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
113
|
+
/* @__PURE__ */ jsx(
|
|
114
|
+
Button,
|
|
115
|
+
{
|
|
116
|
+
size: "lg",
|
|
117
|
+
fullWidth: true,
|
|
118
|
+
loading: busy,
|
|
119
|
+
leadingIcon: confirmHint ? /* @__PURE__ */ jsx(ShieldCheck, { size: "sm", "aria-hidden": "true" }) : void 0,
|
|
120
|
+
onClick: confirm,
|
|
121
|
+
children: confirmLabel
|
|
122
|
+
}
|
|
123
|
+
),
|
|
124
|
+
confirmHint && /* @__PURE__ */ jsx("p", { className: "text-center text-body-sm text-[var(--color-on-surface-muted)]", children: confirmHint }),
|
|
125
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "lg", fullWidth: true, disabled: busy, onClick: () => setStep("amount"), children: m.edit })
|
|
126
|
+
] })
|
|
127
|
+
] })
|
|
128
|
+
] })
|
|
129
|
+
] });
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
CheckoutPage
|
|
134
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
PageFrame,
|
|
4
|
+
usePageMessages
|
|
5
|
+
} from "./chunk-7QCJC2DV.js";
|
|
6
|
+
|
|
7
|
+
// src/components/PaywallPage/PaywallPage.tsx
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { Badge, Button, RadioCard, RadioCardGroup } from "@nexub/react";
|
|
10
|
+
import { Check } from "@nexub/icons";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
var PaywallPage = React.forwardRef(function PaywallPage2({ title, description, plans, defaultPlan, onSubscribe, onRestore, terms, loading, messages, ...props }, ref) {
|
|
13
|
+
const m = usePageMessages(messages);
|
|
14
|
+
const [plan, setPlan] = React.useState(defaultPlan ?? plans[0]?.id);
|
|
15
|
+
return /* @__PURE__ */ jsxs(PageFrame, { ref, width: "sm", title, description, ...props, children: [
|
|
16
|
+
/* @__PURE__ */ jsx(RadioCardGroup, { value: plan, onValueChange: setPlan, "aria-label": m.choosePlan, columns: 1, children: plans.map((p) => /* @__PURE__ */ jsx(
|
|
17
|
+
RadioCard,
|
|
18
|
+
{
|
|
19
|
+
value: p.id,
|
|
20
|
+
title: /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-center gap-2", children: [
|
|
21
|
+
p.name,
|
|
22
|
+
p.badge && /* @__PURE__ */ jsx(Badge, { tone: "info", size: "sm", children: p.badge })
|
|
23
|
+
] }),
|
|
24
|
+
description: p.price,
|
|
25
|
+
children: /* @__PURE__ */ jsx("ul", { className: "mt-2 flex flex-col gap-1.5", children: p.features.map((f) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2 text-body-sm text-[var(--color-on-surface-variant)]", children: [
|
|
26
|
+
/* @__PURE__ */ jsx(Check, { size: "sm", "aria-hidden": "true", className: "mt-0.5 shrink-0 text-[var(--color-success)]" }),
|
|
27
|
+
f
|
|
28
|
+
] }, f)) })
|
|
29
|
+
},
|
|
30
|
+
p.id
|
|
31
|
+
)) }),
|
|
32
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
33
|
+
/* @__PURE__ */ jsx(Button, { size: "lg", fullWidth: true, loading, disabled: !plan, onClick: () => plan && onSubscribe(plan), children: m.continue }),
|
|
34
|
+
onRestore && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "lg", fullWidth: true, onClick: onRestore, children: m.restorePurchases }),
|
|
35
|
+
terms && /* @__PURE__ */ jsx("p", { className: "text-center text-label-sm text-[var(--color-on-surface-muted)]", children: terms })
|
|
36
|
+
] })
|
|
37
|
+
] });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
PaywallPage
|
|
42
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
PageFrame,
|
|
4
|
+
StatusBadge,
|
|
5
|
+
groupByDay,
|
|
6
|
+
usePageMessages,
|
|
7
|
+
useTemplateLocale
|
|
8
|
+
} from "./chunk-7QCJC2DV.js";
|
|
9
|
+
|
|
10
|
+
// src/components/ActivityPage/ActivityPage.tsx
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import { Amount, Avatar, Button, EmptyState, cn } from "@nexub/react";
|
|
13
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
function TransactionRow({
|
|
15
|
+
t,
|
|
16
|
+
onSelect,
|
|
17
|
+
actions,
|
|
18
|
+
m,
|
|
19
|
+
locale
|
|
20
|
+
}) {
|
|
21
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22
|
+
/* @__PURE__ */ jsx(Avatar, { name: t.title, src: t.image }),
|
|
23
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col text-start", children: [
|
|
24
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-body-md font-medium text-[var(--color-on-surface)]", children: t.title }),
|
|
25
|
+
t.subtitle && /* @__PURE__ */ jsx("span", { className: "truncate text-body-sm text-[var(--color-on-surface-muted)]", children: t.subtitle })
|
|
26
|
+
] }),
|
|
27
|
+
/* @__PURE__ */ jsxs("span", { className: "flex shrink-0 flex-col items-end gap-1", children: [
|
|
28
|
+
/* @__PURE__ */ jsx(Amount, { value: t.amount, currency: t.currency, locale, tone: "auto", signDisplay: "exceptZero" }),
|
|
29
|
+
/* @__PURE__ */ jsx(StatusBadge, { status: t.status, m })
|
|
30
|
+
] })
|
|
31
|
+
] });
|
|
32
|
+
const row = "flex w-full items-center gap-3 px-4 py-3";
|
|
33
|
+
return /* @__PURE__ */ jsxs("li", { className: "flex items-center border-t border-[var(--color-outline-variant)] first:border-t-0", children: [
|
|
34
|
+
onSelect ? /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onSelect(t), className: cn(row, "nx-state-layer min-h-[56px]"), children: body }) : /* @__PURE__ */ jsx("div", { className: row, children: body }),
|
|
35
|
+
actions && /* @__PURE__ */ jsx("div", { className: "shrink-0 pe-2", children: actions })
|
|
36
|
+
] });
|
|
37
|
+
}
|
|
38
|
+
var ActivityPage = React.forwardRef(function ActivityPage2({
|
|
39
|
+
transactions,
|
|
40
|
+
onSelect,
|
|
41
|
+
onRefresh,
|
|
42
|
+
refreshing,
|
|
43
|
+
onLoadMore,
|
|
44
|
+
hasMore,
|
|
45
|
+
loadingMore,
|
|
46
|
+
rowActions,
|
|
47
|
+
toolbar,
|
|
48
|
+
empty,
|
|
49
|
+
title,
|
|
50
|
+
actions,
|
|
51
|
+
messages,
|
|
52
|
+
...props
|
|
53
|
+
}, ref) {
|
|
54
|
+
const m = usePageMessages(messages);
|
|
55
|
+
const locale = useTemplateLocale();
|
|
56
|
+
const sections = React.useMemo(() => groupByDay(transactions, locale), [transactions, locale]);
|
|
57
|
+
return /* @__PURE__ */ jsxs(
|
|
58
|
+
PageFrame,
|
|
59
|
+
{
|
|
60
|
+
ref,
|
|
61
|
+
title: title ?? m.activity,
|
|
62
|
+
actions: (actions || onRefresh) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
63
|
+
actions,
|
|
64
|
+
onRefresh && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onRefresh, loading: refreshing, children: m.refresh })
|
|
65
|
+
] }),
|
|
66
|
+
...props,
|
|
67
|
+
children: [
|
|
68
|
+
toolbar,
|
|
69
|
+
sections.length === 0 ? empty ?? /* @__PURE__ */ jsxs(EmptyState.Root, { children: [
|
|
70
|
+
/* @__PURE__ */ jsx(EmptyState.Title, { children: m.noActivityTitle }),
|
|
71
|
+
/* @__PURE__ */ jsx(EmptyState.Description, { children: m.noActivityDescription })
|
|
72
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", "aria-busy": refreshing || void 0, children: [
|
|
73
|
+
sections.map((s) => /* @__PURE__ */ jsxs("section", { "aria-label": s.title, className: "flex flex-col gap-2", children: [
|
|
74
|
+
/* @__PURE__ */ jsx("h2", { className: "px-1 text-title-sm text-[var(--color-on-surface-variant)]", children: s.title }),
|
|
75
|
+
/* @__PURE__ */ jsx("ul", { className: "overflow-hidden rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface-elevated)]", children: s.data.map((t) => /* @__PURE__ */ jsx(TransactionRow, { t, onSelect, actions: rowActions?.(t), m, locale }, t.id)) })
|
|
76
|
+
] }, s.title)),
|
|
77
|
+
onLoadMore && hasMore && /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "self-center", onClick: onLoadMore, loading: loadingMore, children: m.loadMore })
|
|
78
|
+
] })
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
TransactionRow,
|
|
86
|
+
ActivityPage
|
|
87
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use client';
|