@godxjp/ui 19.2.0 → 19.4.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/components/data-display/badge.d.ts +26 -2
- package/dist/components/data-display/badge.js +20 -5
- package/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/popover.d.ts +13 -1
- package/dist/components/data-display/popover.js +3 -1
- package/dist/components/data-display/table.d.ts +19 -2
- package/dist/components/data-display/table.js +4 -1
- package/dist/components/data-display/timeline-grid.d.ts +18 -0
- package/dist/components/data-display/timeline-grid.js +222 -0
- package/dist/components/data-entry/cascader.js +4 -6
- package/dist/components/data-entry/checkbox.js +1 -1
- package/dist/components/data-entry/search-select.js +5 -7
- package/dist/components/data-entry/select.js +32 -28
- package/dist/components/data-entry/tree-select.js +4 -6
- package/dist/components/general/inert-background.d.ts +5 -0
- package/dist/components/general/inert-background.js +48 -0
- package/dist/components/layout/auth-shell.d.ts +4 -2
- package/dist/components/layout/auth-shell.js +7 -1
- package/dist/components/layout/centered-shell.d.ts +2 -2
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +2 -1
- package/dist/components/layout/index.d.ts +3 -0
- package/dist/components/layout/index.js +2 -0
- package/dist/components/layout/mobile-shell.d.ts +21 -0
- package/dist/components/layout/mobile-shell.js +43 -0
- package/dist/components/layout/sidebar-link.d.ts +1 -1
- package/dist/components/navigation/context-menu.js +13 -9
- package/dist/components/navigation/dropdown-menu.js +17 -13
- package/dist/inertia/index.d.ts +1 -1
- package/dist/lib/variants.d.ts +3 -3
- package/dist/lib/variants.js +1 -0
- package/dist/props/components/data-display.prop.d.ts +72 -0
- package/dist/props/components/data-entry.prop.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +93 -6
- package/dist/props/registry.d.ts +113 -2
- package/dist/props/registry.js +155 -1
- package/dist/props/vocabulary/data.prop.d.ts +6 -0
- package/dist/props/vocabulary/index.d.ts +3 -3
- package/dist/props/vocabulary/layout.prop.d.ts +17 -2
- package/dist/props/vocabulary/shared.prop.d.ts +7 -0
- package/dist/styles/badge-layout.css +15 -0
- package/dist/styles/control.css +18 -1
- package/dist/styles/data-display-layout.css +167 -0
- package/dist/styles/layout.css +7 -0
- package/dist/styles/shell-layout.css +148 -0
- package/dist/styles/table-layout.css +23 -4
- package/dist/tokens/components/badge.css +8 -0
- package/dist/tokens/components/control.css +1 -0
- package/dist/tokens/components/data-display.css +20 -0
- package/dist/tokens/components/shell.css +22 -0
- package/dist/tokens/components/table.css +2 -0
- package/docs/SPACING.md +19 -6
- package/docs/charts/compact-bar-trend.tsx +5 -6
- package/docs/data-display/avatar.tsx +7 -9
- package/docs/data-display/badge.tsx +37 -1
- package/docs/data-display/card/index.tsx +6 -4
- package/docs/data-display/carousel.tsx +8 -4
- package/docs/data-display/data-table/examples/approval-queue.tsx +1 -1
- package/docs/data-display/data-table/examples/grid-features.tsx +1 -1
- package/docs/data-display/data-table/index.tsx +1 -1
- package/docs/data-display/permission-matrix.tsx +15 -11
- package/docs/data-display/popover.tsx +2 -1
- package/docs/data-display/scroll-area.tsx +108 -76
- package/docs/data-display/table.tsx +2 -2
- package/docs/data-display/timeline-grid.tsx +119 -0
- package/docs/data-entry/branch-scope-picker.tsx +1 -1
- package/docs/data-entry/calendar.tsx +1 -1
- package/docs/data-entry/checkbox.tsx +1 -1
- package/docs/data-entry/country-picker-recipe.tsx +11 -6
- package/docs/data-entry/form-field/index.tsx +33 -29
- package/docs/data-entry/form-root.tsx +1 -1
- package/docs/data-entry/input-otp.tsx +1 -1
- package/docs/data-entry/password-input.tsx +1 -5
- package/docs/data-entry/select.tsx +7 -7
- package/docs/data-entry/textarea.tsx +3 -3
- package/docs/data-entry/toggle-count.tsx +1 -1
- package/docs/feedback/alert.tsx +1 -1
- package/docs/feedback/banner.tsx +1 -1
- package/docs/feedback/sheet.tsx +112 -102
- package/docs/feedback/skeleton.tsx +2 -2
- package/docs/foundation/colors.tsx +8 -6
- package/docs/foundation/email-tokens.tsx +83 -66
- package/docs/foundation/radius-shadow.tsx +13 -11
- package/docs/general/activity.tsx +1 -1
- package/docs/layout/app-shell.tsx +2 -2
- package/docs/layout/aspect-ratio.tsx +30 -14
- package/docs/layout/auth-account-summary.tsx +1 -1
- package/docs/layout/auth-recovery/examples/mobile-390.tsx +1 -1
- package/docs/layout/auth-recovery/examples/password-recovery.tsx +0 -2
- package/docs/layout/auth-shell-context.tsx +1 -1
- package/docs/layout/auth-shell-device.tsx +2 -2
- package/docs/layout/auth-shell-registration.tsx +1 -1
- package/docs/layout/auth-shell.tsx +1 -1
- package/docs/layout/flex.tsx +6 -2
- package/docs/layout/master-detail.tsx +2 -2
- package/docs/layout/mobile-shell.tsx +101 -0
- package/docs/layout/page-container.tsx +15 -7
- package/docs/layout/responsive-grid.tsx +12 -4
- package/docs/layout/separator.tsx +2 -2
- package/docs/layout/service-role-panel.tsx +1 -1
- package/docs/layout/sidebar.tsx +175 -152
- package/docs/layout/split-pane.tsx +45 -28
- package/docs/layout/topbar.tsx +19 -23
- package/docs/navigation/app-setting-picker.tsx +5 -4
- package/docs/navigation/breadcrumb.tsx +12 -5
- package/docs/navigation/context-menu.tsx +10 -4
- package/docs/navigation/filter-bar.tsx +2 -2
- package/docs/navigation/navigation-menu.tsx +89 -96
- package/docs/navigation/pagination.tsx +2 -2
- package/docs/navigation/steps.tsx +13 -11
- package/docs/navigation/tabs.tsx +27 -21
- package/docs/navigation/toolbar.tsx +15 -15
- package/docs/providers/format-date.tsx +2 -2
- package/docs/showcase/acme-portal.tsx +41 -28
- package/docs/showcase/acme-website.tsx +67 -61
- package/docs/showcase/case1-warehouse-dashboard.tsx +46 -31
- package/docs/showcase/case2-employee-me.tsx +33 -36
- package/docs/showcase/case3-approval-workflow.tsx +34 -32
- package/docs/showcase/case4-login.tsx +95 -101
- package/docs/showcase/case5-shift-calendar.tsx +182 -281
- package/docs/showcase/case6-agency-handy.tsx +514 -470
- package/docs/showcase/futurelastic-web.tsx +32 -29
- package/docs/showcase/org-switcher.tsx +20 -13
- package/docs/showcase/permission-matrix.tsx +20 -17
- package/docs/showcase/public-landing.tsx +1 -1
- package/docs/showcase/settings-account-sections.tsx +2 -2
- package/docs/showcase/settings-security-mfa.tsx +3 -3
- package/docs/showcase/table-approval-queue.tsx +1 -1
- package/docs/showcase/table-bulk-actions.tsx +49 -52
- package/docs/showcase/table-conditional-format.tsx +9 -9
- package/docs/showcase/table-crud-list.tsx +4 -4
- package/docs/showcase/table-density.tsx +49 -42
- package/docs/showcase/table-expandable-rows.tsx +112 -100
- package/docs/showcase/table-filter-chips.tsx +78 -71
- package/docs/showcase/table-footer-totals.tsx +30 -23
- package/docs/showcase/table-grouped-subtotals.tsx +31 -25
- package/docs/showcase/table-master-detail.tsx +27 -24
- package/docs/showcase/table-pagination.tsx +34 -27
- package/docs/showcase/table-states.tsx +42 -34
- package/docs/showcase/table-sticky-columns.tsx +11 -7
- package/docs/showcase/table-tree-rows.tsx +22 -15
- package/docs/showcase/table-view-tabs.tsx +12 -14
- package/package.json +7 -7
package/docs/navigation/tabs.tsx
CHANGED
|
@@ -67,7 +67,7 @@ export default function Demo() {
|
|
|
67
67
|
</CardContent>
|
|
68
68
|
</Card>
|
|
69
69
|
|
|
70
|
-
{/* Disabled first item — fallback selection must skip it
|
|
70
|
+
{/* Disabled first item — fallback selection must skip it */}
|
|
71
71
|
<Card>
|
|
72
72
|
<CardHeader>
|
|
73
73
|
<CardTitle level={2}>先頭タブが disabled · フォールバック選択</CardTitle>
|
|
@@ -111,25 +111,31 @@ export default function Demo() {
|
|
|
111
111
|
</CardDescription>
|
|
112
112
|
</CardHeader>
|
|
113
113
|
<CardContent>
|
|
114
|
-
<
|
|
115
|
-
<
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
{
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
114
|
+
<Card className="max-w-80">
|
|
115
|
+
<CardContent>
|
|
116
|
+
<Tabs
|
|
117
|
+
defaultValue="methods"
|
|
118
|
+
variant="line"
|
|
119
|
+
items={[
|
|
120
|
+
{
|
|
121
|
+
value: "methods",
|
|
122
|
+
label: "サインイン方法とパスワード",
|
|
123
|
+
content: <Text>方法</Text>,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
value: "two-factor",
|
|
127
|
+
label: "二要素認証の設定",
|
|
128
|
+
content: <Text>二要素認証</Text>,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
value: "recovery",
|
|
132
|
+
label: "アカウントの復旧方法",
|
|
133
|
+
content: <Text>復旧</Text>,
|
|
134
|
+
},
|
|
135
|
+
]}
|
|
136
|
+
/>
|
|
137
|
+
</CardContent>
|
|
138
|
+
</Card>
|
|
133
139
|
</CardContent>
|
|
134
140
|
</Card>
|
|
135
141
|
|
|
@@ -196,7 +202,7 @@ export default function Demo() {
|
|
|
196
202
|
</CardDescription>
|
|
197
203
|
</CardHeader>
|
|
198
204
|
<CardContent>
|
|
199
|
-
<Tabs defaultValue="overview" orientation="vertical"
|
|
205
|
+
<Tabs defaultValue="overview" orientation="vertical" style={{ gap: "var(--space-6)" }}>
|
|
200
206
|
<TabsList variant="line" className="h-auto w-40 flex-col items-stretch">
|
|
201
207
|
<TabsTrigger value="overview">概要</TabsTrigger>
|
|
202
208
|
<TabsTrigger value="ledger">元帳</TabsTrigger>
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
CardDescription,
|
|
9
9
|
CardHeader,
|
|
10
10
|
CardTitle,
|
|
11
|
+
EmptyState,
|
|
11
12
|
} from "@godxjp/ui/data-display";
|
|
12
13
|
import { Button, Text } from "@godxjp/ui/general";
|
|
13
14
|
import {
|
|
@@ -111,7 +112,7 @@ export default function Demo() {
|
|
|
111
112
|
sticky
|
|
112
113
|
hasActiveFilters={hasMemberFilters}
|
|
113
114
|
onClear={clearMemberFilters}
|
|
114
|
-
className="border-border bg-card border-b
|
|
115
|
+
className="border-border bg-card border-b"
|
|
115
116
|
>
|
|
116
117
|
<SearchInput
|
|
117
118
|
aria-label="メンバーを検索"
|
|
@@ -154,16 +155,13 @@ export default function Demo() {
|
|
|
154
155
|
wrap
|
|
155
156
|
align="center"
|
|
156
157
|
gap="xs"
|
|
157
|
-
className="border-border bg-muted/40 min-h-9 border-b
|
|
158
|
+
className="border-border bg-muted/40 min-h-9 border-b"
|
|
158
159
|
>
|
|
159
|
-
<Flex
|
|
160
|
-
direction="row"
|
|
161
|
-
align="center"
|
|
162
|
-
gap="xs"
|
|
163
|
-
className="text-muted-foreground pe-1"
|
|
164
|
-
>
|
|
160
|
+
<Flex direction="row" align="center" gap="xs">
|
|
165
161
|
<Filter className="size-3.5" aria-hidden="true" />
|
|
166
|
-
<Text size="xs"
|
|
162
|
+
<Text size="xs" tone="muted">
|
|
163
|
+
適用中
|
|
164
|
+
</Text>
|
|
167
165
|
</Flex>
|
|
168
166
|
{!hasMemberFilters && (
|
|
169
167
|
<Text size="xs" tone="muted">
|
|
@@ -171,7 +169,7 @@ export default function Demo() {
|
|
|
171
169
|
</Text>
|
|
172
170
|
)}
|
|
173
171
|
{activeChips.map((chip) => (
|
|
174
|
-
<
|
|
172
|
+
<Flex key={chip.key} align="center" gap="xs">
|
|
175
173
|
<Badge tone={chip.tone} variant="outline">
|
|
176
174
|
{chip.label}
|
|
177
175
|
</Badge>
|
|
@@ -183,7 +181,7 @@ export default function Demo() {
|
|
|
183
181
|
>
|
|
184
182
|
<X aria-hidden="true" />
|
|
185
183
|
</Button>
|
|
186
|
-
</
|
|
184
|
+
</Flex>
|
|
187
185
|
))}
|
|
188
186
|
{hasMemberFilters && (
|
|
189
187
|
<Button
|
|
@@ -205,7 +203,7 @@ export default function Demo() {
|
|
|
205
203
|
direction="row"
|
|
206
204
|
align="center"
|
|
207
205
|
justify="between"
|
|
208
|
-
className="border-border/60 border-b
|
|
206
|
+
className="border-border/60 border-b"
|
|
209
207
|
>
|
|
210
208
|
<Text size="sm">
|
|
211
209
|
{memberQuery.trim() || "田中"} {i + 1} 番
|
|
@@ -269,9 +267,11 @@ export default function Demo() {
|
|
|
269
267
|
</Toolbar>
|
|
270
268
|
|
|
271
269
|
{/* Simulated table body */}
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
|
|
270
|
+
<EmptyState
|
|
271
|
+
variant="section"
|
|
272
|
+
titleAs="p"
|
|
273
|
+
title="DataTable がここに入ります · Toolbar は Card の外側 (上) に置く"
|
|
274
|
+
/>
|
|
275
275
|
</Flex>
|
|
276
276
|
</CardContent>
|
|
277
277
|
</Card>
|
|
@@ -51,10 +51,10 @@ export default function Demo() {
|
|
|
51
51
|
<CardContent>
|
|
52
52
|
<Text as="p" tone="muted">
|
|
53
53
|
このデモは{" "}
|
|
54
|
-
<
|
|
54
|
+
<Text as="code" mono size="xs">
|
|
55
55
|
defaultLocale="ja" defaultTimezone="Asia/Tokyo"
|
|
56
56
|
defaultDateFormat="iso" defaultTimeFormat="24h"
|
|
57
|
-
</
|
|
57
|
+
</Text>{" "}
|
|
58
58
|
の AppProvider でラップされている。
|
|
59
59
|
</Text>
|
|
60
60
|
</CardContent>
|
|
@@ -45,11 +45,12 @@ import {
|
|
|
45
45
|
Avatar,
|
|
46
46
|
AvatarFallback,
|
|
47
47
|
Badge,
|
|
48
|
-
type BadgeProps,
|
|
49
48
|
Card,
|
|
49
|
+
CardAction,
|
|
50
50
|
CardContent,
|
|
51
51
|
CardHeader,
|
|
52
52
|
CardTitle,
|
|
53
|
+
ListRow,
|
|
53
54
|
Progress,
|
|
54
55
|
StatCard,
|
|
55
56
|
Table,
|
|
@@ -58,6 +59,7 @@ import {
|
|
|
58
59
|
TableHead,
|
|
59
60
|
TableHeader,
|
|
60
61
|
TableRow,
|
|
62
|
+
type BadgeProps,
|
|
61
63
|
} from "@godxjp/ui/data-display";
|
|
62
64
|
import { SearchInput } from "@godxjp/ui/data-entry";
|
|
63
65
|
import {
|
|
@@ -341,40 +343,49 @@ export default function AcmePortalShowcase() {
|
|
|
341
343
|
{/* Queue + Journey */}
|
|
342
344
|
<ResponsiveGrid columns={{ sm: 1, md: 1, lg: 2 }}>
|
|
343
345
|
<Card className="self-start">
|
|
344
|
-
<CardHeader
|
|
346
|
+
<CardHeader>
|
|
345
347
|
<CardTitle level={2}>Cần bạn xử lý</CardTitle>
|
|
346
|
-
<
|
|
347
|
-
|
|
348
|
-
|
|
348
|
+
<CardAction>
|
|
349
|
+
<Text size="xs" tone="muted">
|
|
350
|
+
{QUEUE.length} việc
|
|
351
|
+
</Text>
|
|
352
|
+
</CardAction>
|
|
349
353
|
</CardHeader>
|
|
350
354
|
<CardContent flush>
|
|
351
355
|
<ul className="divide-border divide-y">
|
|
352
356
|
{QUEUE.map((q) => (
|
|
353
|
-
<
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
{q.
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
357
|
+
<ListRow
|
|
358
|
+
as="li"
|
|
359
|
+
key={q.title}
|
|
360
|
+
leading={
|
|
361
|
+
<Badge
|
|
362
|
+
tone={q.tone}
|
|
363
|
+
variant="outline"
|
|
364
|
+
icon={q.icon}
|
|
365
|
+
aria-label={q.title}
|
|
366
|
+
/>
|
|
367
|
+
}
|
|
368
|
+
title={q.title}
|
|
369
|
+
description={q.meta}
|
|
370
|
+
trailing={
|
|
371
|
+
<Button variant="outline" size="sm">
|
|
372
|
+
{q.action}
|
|
373
|
+
</Button>
|
|
374
|
+
}
|
|
375
|
+
/>
|
|
367
376
|
))}
|
|
368
377
|
</ul>
|
|
369
378
|
</CardContent>
|
|
370
379
|
</Card>
|
|
371
380
|
|
|
372
381
|
<Card className="self-start">
|
|
373
|
-
<CardHeader
|
|
382
|
+
<CardHeader>
|
|
374
383
|
<CardTitle level={2}>Hành trình đơn TXM-100241</CardTitle>
|
|
375
|
-
<
|
|
376
|
-
<
|
|
377
|
-
|
|
384
|
+
<CardAction>
|
|
385
|
+
<Badge tone="info" variant="outline">
|
|
386
|
+
<Plane aria-hidden="true" /> Đang vận chuyển
|
|
387
|
+
</Badge>
|
|
388
|
+
</CardAction>
|
|
378
389
|
</CardHeader>
|
|
379
390
|
<CardContent>
|
|
380
391
|
<Flex direction="col" gap="md">
|
|
@@ -393,12 +404,14 @@ export default function AcmePortalShowcase() {
|
|
|
393
404
|
|
|
394
405
|
{/* Orders table — the centerpiece */}
|
|
395
406
|
<Card>
|
|
396
|
-
<CardHeader
|
|
407
|
+
<CardHeader>
|
|
397
408
|
<CardTitle level={2}>Đơn mua hộ gần đây</CardTitle>
|
|
398
|
-
<
|
|
399
|
-
<
|
|
400
|
-
|
|
401
|
-
|
|
409
|
+
<CardAction>
|
|
410
|
+
<Button variant="ghost" size="sm">
|
|
411
|
+
<Wallet aria-hidden="true" />
|
|
412
|
+
Xem tất cả
|
|
413
|
+
</Button>
|
|
414
|
+
</CardAction>
|
|
402
415
|
</CardHeader>
|
|
403
416
|
<CardContent flush>
|
|
404
417
|
<Table>
|
|
@@ -121,7 +121,7 @@ function Navbar() {
|
|
|
121
121
|
<span className="tx-brand" data-logotype="">
|
|
122
122
|
TIXI<span className="tx-gold">MAX</span>
|
|
123
123
|
</span>
|
|
124
|
-
<Flex direction="row" gap="xs" align="center"
|
|
124
|
+
<Flex direction="row" gap="xs" align="center">
|
|
125
125
|
{links.map((l, i) => (
|
|
126
126
|
<Button key={l} variant="ghost" size="sm" aria-current={i === 0 ? "page" : undefined}>
|
|
127
127
|
{l}
|
|
@@ -156,7 +156,7 @@ function Hero() {
|
|
|
156
156
|
<section className="tx-navy relative overflow-hidden">
|
|
157
157
|
<div className="tx-glow tx-glow-tr" />
|
|
158
158
|
<div className={`${SHELL} tx-hero-grid relative`}>
|
|
159
|
-
<
|
|
159
|
+
<Flex direction="col" gap="xl">
|
|
160
160
|
<div className="tx-eyebrow">Mua hộ & vận chuyển quốc tế</div>
|
|
161
161
|
<h1 className="tx-display">
|
|
162
162
|
Mua sắm toàn cầu,
|
|
@@ -167,7 +167,7 @@ function Hero() {
|
|
|
167
167
|
Đặt mua, thanh toán và vận chuyển hàng từ Nhật, Hàn, Indonesia và Mỹ về tận nhà. Minh
|
|
168
168
|
bạch chi phí, theo dõi từng bước.
|
|
169
169
|
</p>
|
|
170
|
-
<Flex direction="row" gap="md"
|
|
170
|
+
<Flex direction="row" gap="md">
|
|
171
171
|
<Button size="lg">
|
|
172
172
|
Nhận báo giá miễn phí
|
|
173
173
|
<ArrowRight aria-hidden="true" />
|
|
@@ -177,7 +177,7 @@ function Hero() {
|
|
|
177
177
|
Tra cứu đơn
|
|
178
178
|
</Button>
|
|
179
179
|
</Flex>
|
|
180
|
-
<Flex direction="row" gap="lg"
|
|
180
|
+
<Flex direction="row" gap="lg">
|
|
181
181
|
{stats.map(([n, l]) => (
|
|
182
182
|
<div key={l}>
|
|
183
183
|
<div className="tx-stat">{n}</div>
|
|
@@ -187,34 +187,36 @@ function Hero() {
|
|
|
187
187
|
</div>
|
|
188
188
|
))}
|
|
189
189
|
</Flex>
|
|
190
|
-
</
|
|
190
|
+
</Flex>
|
|
191
191
|
|
|
192
192
|
<Card>
|
|
193
193
|
<CardContent>
|
|
194
|
-
<
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
<
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
194
|
+
<Flex direction="col" gap="md">
|
|
195
|
+
<div className="tx-eyebrow">Ước tính phí vận chuyển</div>
|
|
196
|
+
<Flex direction="col" gap="sm">
|
|
197
|
+
{fields.map(([Icon, label, value]) => (
|
|
198
|
+
<div key={label} className="tx-field">
|
|
199
|
+
<Icon aria-hidden="true" className="tx-gold tx-icon-18" />
|
|
200
|
+
<div className="min-w-0 flex-1">
|
|
201
|
+
<Text as="div" size="2xs" tone="muted">
|
|
202
|
+
{label}
|
|
203
|
+
</Text>
|
|
204
|
+
<Text as="div" weight="bold">
|
|
205
|
+
{value}
|
|
206
|
+
</Text>
|
|
207
|
+
</div>
|
|
208
|
+
<ChevronDown aria-hidden="true" className="tx-icon-18" />
|
|
206
209
|
</div>
|
|
207
|
-
|
|
210
|
+
))}
|
|
211
|
+
<div className="tx-quote-total">
|
|
212
|
+
<Text as="span" weight="bold" className="text-primary-foreground">
|
|
213
|
+
Tạm tính
|
|
214
|
+
</Text>
|
|
215
|
+
<Text as="span" weight="bold" size="2xl" className="text-primary-foreground">
|
|
216
|
+
525.000đ
|
|
217
|
+
</Text>
|
|
208
218
|
</div>
|
|
209
|
-
|
|
210
|
-
<div className="tx-quote-total">
|
|
211
|
-
<Text as="span" weight="bold" className="text-primary-foreground">
|
|
212
|
-
Tạm tính
|
|
213
|
-
</Text>
|
|
214
|
-
<Text as="span" weight="bold" size="2xl" className="text-primary-foreground">
|
|
215
|
-
525.000đ
|
|
216
|
-
</Text>
|
|
217
|
-
</div>
|
|
219
|
+
</Flex>
|
|
218
220
|
</Flex>
|
|
219
221
|
</CardContent>
|
|
220
222
|
</Card>
|
|
@@ -235,7 +237,7 @@ function SectionHead({
|
|
|
235
237
|
center?: boolean;
|
|
236
238
|
}) {
|
|
237
239
|
return (
|
|
238
|
-
<div className={center ? "mx-auto
|
|
240
|
+
<div className={center ? "mx-auto text-center" : undefined}>
|
|
239
241
|
<div className="tx-eyebrow">{eyebrow}</div>
|
|
240
242
|
<h2 className="tx-h2">{title}</h2>
|
|
241
243
|
{sub ? <p className="tx-lead mx-auto">{sub}</p> : null}
|
|
@@ -270,7 +272,7 @@ function Services() {
|
|
|
270
272
|
];
|
|
271
273
|
return (
|
|
272
274
|
<section className="bg-card tx-section">
|
|
273
|
-
<
|
|
275
|
+
<Flex direction="col" gap="xl" className={SHELL}>
|
|
274
276
|
<SectionHead
|
|
275
277
|
center
|
|
276
278
|
eyebrow="Dịch vụ"
|
|
@@ -281,18 +283,20 @@ function Services() {
|
|
|
281
283
|
{items.map(([icon, t, d]) => (
|
|
282
284
|
<Card key={t}>
|
|
283
285
|
<CardContent>
|
|
284
|
-
<
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
286
|
+
<Flex direction="col" gap="md">
|
|
287
|
+
<Medallion icon={icon} />
|
|
288
|
+
<Text as="div" weight="bold" size="lg">
|
|
289
|
+
{t}
|
|
290
|
+
</Text>
|
|
291
|
+
<Text as="p" size="sm" tone="muted">
|
|
292
|
+
{d}
|
|
293
|
+
</Text>
|
|
294
|
+
</Flex>
|
|
291
295
|
</CardContent>
|
|
292
296
|
</Card>
|
|
293
297
|
))}
|
|
294
298
|
</ResponsiveGrid>
|
|
295
|
-
</
|
|
299
|
+
</Flex>
|
|
296
300
|
</section>
|
|
297
301
|
);
|
|
298
302
|
}
|
|
@@ -306,12 +310,12 @@ function Steps() {
|
|
|
306
310
|
];
|
|
307
311
|
return (
|
|
308
312
|
<section className="bg-background tx-section">
|
|
309
|
-
<
|
|
313
|
+
<Flex direction="col" gap="xl" className={SHELL}>
|
|
310
314
|
<SectionHead eyebrow="Quy trình" title="Mua hàng quốc tế trong 4 bước" />
|
|
311
315
|
<ResponsiveGrid columns={{ sm: 1, md: 2, lg: 4 }}>
|
|
312
316
|
{steps.map(([Icon, t, d], i) => (
|
|
313
|
-
<
|
|
314
|
-
<Flex direction="row" gap="sm" align="center"
|
|
317
|
+
<Flex direction="col" gap="md" key={t}>
|
|
318
|
+
<Flex direction="row" gap="sm" align="center">
|
|
315
319
|
<Avatar>
|
|
316
320
|
<AvatarFallback className="bg-secondary text-primary font-bold">
|
|
317
321
|
{i + 1}
|
|
@@ -322,13 +326,13 @@ function Steps() {
|
|
|
322
326
|
<Text as="div" weight="bold" size="lg">
|
|
323
327
|
{t}
|
|
324
328
|
</Text>
|
|
325
|
-
<Text as="p" size="sm" tone="muted"
|
|
329
|
+
<Text as="p" size="sm" tone="muted">
|
|
326
330
|
{d}
|
|
327
331
|
</Text>
|
|
328
|
-
</
|
|
332
|
+
</Flex>
|
|
329
333
|
))}
|
|
330
334
|
</ResponsiveGrid>
|
|
331
|
-
</
|
|
335
|
+
</Flex>
|
|
332
336
|
</section>
|
|
333
337
|
);
|
|
334
338
|
}
|
|
@@ -342,7 +346,7 @@ function Routes() {
|
|
|
342
346
|
];
|
|
343
347
|
return (
|
|
344
348
|
<section className="bg-card tx-section">
|
|
345
|
-
<
|
|
349
|
+
<Flex direction="col" gap="xl" className={SHELL}>
|
|
346
350
|
<SectionHead eyebrow="Tuyến vận chuyển" title="Giá cước rõ ràng theo từng tuyến" />
|
|
347
351
|
<ResponsiveGrid columns={{ sm: 1, md: 2, lg: 4 }}>
|
|
348
352
|
{routes.map(([c, code, mode, price]) => (
|
|
@@ -351,20 +355,22 @@ function Routes() {
|
|
|
351
355
|
<span className="tx-route-code">{code}</span>
|
|
352
356
|
</CardCover>
|
|
353
357
|
<CardContent>
|
|
354
|
-
<
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
358
|
+
<Flex direction="col" gap="md">
|
|
359
|
+
<Text as="div" weight="bold" size="lg">
|
|
360
|
+
{c}
|
|
361
|
+
</Text>
|
|
362
|
+
<Text as="div" size="xs" tone="muted">
|
|
363
|
+
{mode}
|
|
364
|
+
</Text>
|
|
365
|
+
<Text as="div" weight="bold" size="2xl">
|
|
366
|
+
{price}
|
|
367
|
+
</Text>
|
|
368
|
+
</Flex>
|
|
363
369
|
</CardContent>
|
|
364
370
|
</Card>
|
|
365
371
|
))}
|
|
366
372
|
</ResponsiveGrid>
|
|
367
|
-
</
|
|
373
|
+
</Flex>
|
|
368
374
|
</section>
|
|
369
375
|
);
|
|
370
376
|
}
|
|
@@ -376,7 +382,7 @@ function CtaBanner() {
|
|
|
376
382
|
<div className={`${SHELL} relative text-center`}>
|
|
377
383
|
<h2 className="tx-h2">Sẵn sàng cho đơn hàng đầu tiên?</h2>
|
|
378
384
|
<p className="tx-lead mx-auto">Tạo tài khoản miễn phí và nhận báo giá trong 5 phút.</p>
|
|
379
|
-
<Flex direction="row" gap="md"
|
|
385
|
+
<Flex direction="row" gap="md" justify="center">
|
|
380
386
|
<Button size="lg">
|
|
381
387
|
<UserPlus aria-hidden="true" />
|
|
382
388
|
Đăng ký ngay
|
|
@@ -399,18 +405,18 @@ function Footer() {
|
|
|
399
405
|
return (
|
|
400
406
|
<footer className="tx-navy tx-navy-deep">
|
|
401
407
|
<div className={`${SHELL} tx-footer-grid`} style={{ paddingBlock: "3.5rem 2rem" }}>
|
|
402
|
-
<
|
|
408
|
+
<Flex direction="col" gap="md">
|
|
403
409
|
<span className="tx-brand">
|
|
404
410
|
TIXI<span className="tx-gold">MAX</span>
|
|
405
411
|
</span>
|
|
406
|
-
<Text as="p" size="sm" tone="muted"
|
|
412
|
+
<Text as="p" size="sm" tone="muted">
|
|
407
413
|
Dịch vụ mua hộ & vận chuyển quốc tế uy tín, minh bạch về tận nhà bạn.
|
|
408
414
|
</Text>
|
|
409
|
-
</
|
|
415
|
+
</Flex>
|
|
410
416
|
{cols.map(([h, items]) => (
|
|
411
|
-
<
|
|
417
|
+
<Flex direction="col" gap="md" key={h}>
|
|
412
418
|
<div className="tx-eyebrow">{h}</div>
|
|
413
|
-
<Flex direction="col" gap="xs"
|
|
419
|
+
<Flex direction="col" gap="xs">
|
|
414
420
|
{items.map((i) => (
|
|
415
421
|
<Button
|
|
416
422
|
key={i}
|
|
@@ -422,7 +428,7 @@ function Footer() {
|
|
|
422
428
|
</Button>
|
|
423
429
|
))}
|
|
424
430
|
</Flex>
|
|
425
|
-
</
|
|
431
|
+
</Flex>
|
|
426
432
|
))}
|
|
427
433
|
</div>
|
|
428
434
|
<div className={`${SHELL} tx-footer-bottom`}>
|