astryx-dracula 0.2.1 → 0.3.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/BRAND.md +30 -18
- package/README.md +17 -12
- package/USAGE.md +29 -10
- package/astryx-dracula.js +19 -13
- package/astryx-dracula.variants.d.ts +15 -0
- package/package.json +59 -17
- package/shared/auth-chrome-config.ts +18 -0
- package/shared/auth-chrome.tsx +25 -0
- package/shared/auth-copy.ts +22 -0
- package/shared/chaptered-doc-config.ts +92 -0
- package/shared/chaptered-doc.tsx +332 -0
- package/shared/chart-hues.ts +27 -0
- package/shared/chart-labels.tsx +44 -0
- package/shared/chart-legend.tsx +100 -0
- package/shared/chart-panel-style.ts +13 -0
- package/shared/data-bar.tsx +160 -0
- package/shared/gallery-image.ts +20 -0
- package/shared/login-demo.ts +7 -0
- package/shared/metric-delta.tsx +36 -0
- package/shared/order-desk.tsx +273 -0
- package/shared/revenue-chart.tsx +174 -0
- package/shared/scene-castle.tsx +322 -0
- package/shared/scene-frame.tsx +88 -0
- package/shared/scene-hues.ts +49 -0
- package/shared/scene-tile.tsx +128 -0
- package/shared/settings-data.ts +125 -0
- package/shared/settings-rows.tsx +179 -0
- package/shared/sparkline.tsx +94 -0
- package/shared/sso-icons.tsx +30 -0
- package/templates/ai-chat-landing.tsx +66 -33
- package/templates/ai-chat.tsx +36 -19
- package/templates/blank.tsx +4 -3
- package/templates/centered-hero.tsx +14 -125
- package/templates/classic-gallery.tsx +20 -66
- package/templates/contact-form.tsx +59 -39
- package/templates/dashboard-portfolio.tsx +143 -226
- package/templates/dashboard.tsx +122 -122
- package/templates/detail-page.tsx +95 -91
- package/templates/documentation-design.template.mjs +1 -1
- package/templates/documentation-design.tsx +83 -96
- package/templates/documentation-technical.template.mjs +1 -1
- package/templates/documentation-technical.tsx +29 -19
- package/templates/documentation.template.mjs +1 -1
- package/templates/documentation.tsx +52 -74
- package/templates/editor.tsx +112 -84
- package/templates/file-explorer.tsx +131 -84
- package/templates/form-two-column.tsx +61 -125
- package/templates/gallery-hero.tsx +15 -171
- package/templates/ide.tsx +22 -20
- package/templates/incident-console.tsx +104 -70
- package/templates/kanban-board.tsx +99 -42
- package/templates/library.template.mjs +2 -2
- package/templates/library.tsx +37 -42
- package/templates/login-card.tsx +58 -87
- package/templates/login-split.tsx +88 -126
- package/templates/login-sso.tsx +105 -64
- package/templates/login.tsx +107 -53
- package/templates/messaging-shell.tsx +171 -144
- package/templates/mixed-gallery.tsx +29 -130
- package/templates/payment-form.tsx +368 -290
- package/templates/product-detail.tsx +39 -58
- package/templates/product-gallery.tsx +30 -41
- package/templates/product-tour.template.mjs +6 -0
- package/templates/product-tour.tsx +916 -0
- package/templates/settings-dialog.tsx +135 -282
- package/templates/settings-sidebar.tsx +178 -268
- package/templates/settings.tsx +41 -14
- package/templates/shell-nav.tsx +31 -24
- package/templates/shell-side-nav.tsx +29 -20
- package/templates/shell-top-nav.tsx +80 -44
- package/templates/side-gallery.tsx +38 -94
- package/templates/table-grouped.tsx +62 -34
- package/templates/table-page-chart.tsx +23 -302
- package/templates/table-page-heatmap-status.tsx +156 -92
- package/templates/table-page-shoe-store-heatmap.tsx +18 -293
- package/templates/table-page.tsx +23 -7
- package/templates/table.tsx +23 -8
- package/templates/tech-report.template.mjs +6 -0
- package/templates/tech-report.tsx +1486 -0
- package/templates/theme-showcase.template.mjs +1 -1
- package/templates/theme-showcase.tsx +299 -237
- package/theme.css +76 -14
- package/tokens.css +425 -30
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
3
|
-
// L > (LP > V[g=4] >
|
|
3
|
+
// L > (LP[p=0] > V[g=4] > Tx"Account settings"[t=label] + (UL > LI*8) + D + LI"Professional hosting tools") + (LC[p=6] > V[g=0] > (Tbar > B.ghost + Hd"Personal info"[level=1]) + Hd"Personal info"[level=1] + (V[g=0] > (H[j=between a=start] > (V[g=0] > Tx"Legal name"[weight=semibold] + Tx"Vlad Dracul"[t=supporting]) + Lk"Edit")*7) + (C.muted > V[g=4] > (H[g=3 a=start] > Ic + (V[g=1] > Tx"Why is info hidden?"[weight=semibold] + Tx[t=supporting]))*3))
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Settings Panels — account sections with a nav panel and divided rows. Frame: Layout nav panel (fill) | content column of section views. One (Frame/responsive/container: see XLE header above.)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {Fragment, useState, type CSSProperties} from 'react';
|
|
6
10
|
import {useMediaQuery} from '@astryxdesign/core/hooks';
|
|
7
11
|
import {
|
|
8
12
|
VStack,
|
|
@@ -23,18 +27,12 @@ import {Card} from '@astryxdesign/core/Card';
|
|
|
23
27
|
import {Switch} from '@astryxdesign/core/Switch';
|
|
24
28
|
import {Divider} from '@astryxdesign/core/Divider';
|
|
25
29
|
import {TabList, Tab} from '@astryxdesign/core/TabList';
|
|
26
|
-
import {
|
|
30
|
+
import {StatusDot} from '@astryxdesign/core/StatusDot';
|
|
27
31
|
import {Icon} from '@astryxdesign/core/Icon';
|
|
28
32
|
import {Center} from '@astryxdesign/core/Center';
|
|
29
33
|
import {
|
|
30
|
-
User,
|
|
31
34
|
Lock,
|
|
32
35
|
ShieldCheck,
|
|
33
|
-
Bell,
|
|
34
|
-
FileText,
|
|
35
|
-
CreditCard,
|
|
36
|
-
Globe,
|
|
37
|
-
Briefcase,
|
|
38
36
|
Wrench,
|
|
39
37
|
Monitor,
|
|
40
38
|
SquarePen,
|
|
@@ -42,6 +40,9 @@ import {
|
|
|
42
40
|
ArrowLeft,
|
|
43
41
|
ChevronRight,
|
|
44
42
|
} from 'lucide-react';
|
|
43
|
+
import {NAV_ITEMS, LOGIN_ROWS, SOCIAL_ROWS, DEVICE_ROWS, INFO_TILES, iconBox, actionNoWrap, sideNavHeading} from 'astryx-dracula/shared/settings-data';
|
|
44
|
+
import {InfoRowItem, ExpandableRow} from 'astryx-dracula/shared/settings-rows';
|
|
45
|
+
import type {InfoRow} from 'astryx-dracula/shared/settings-data';
|
|
45
46
|
|
|
46
47
|
// Anchor the page to the viewport height so the sidebar + content fill the
|
|
47
48
|
// screen. Layout height="fill" is min-height:100% which collapses when the
|
|
@@ -49,11 +50,6 @@ import {
|
|
|
49
50
|
const fillViewport: CSSProperties = {
|
|
50
51
|
minHeight: '100dvh',
|
|
51
52
|
};
|
|
52
|
-
const iconBox: CSSProperties = {
|
|
53
|
-
borderRadius: 'var(--radius-container)',
|
|
54
|
-
backgroundColor: 'var(--color-background-surface)',
|
|
55
|
-
flexShrink: 0,
|
|
56
|
-
};
|
|
57
53
|
const rowPadding: CSSProperties = {
|
|
58
54
|
paddingBlock: 'var(--spacing-4)',
|
|
59
55
|
};
|
|
@@ -61,25 +57,15 @@ const sideNavPadding: CSSProperties = {
|
|
|
61
57
|
paddingBlock: 'var(--spacing-4)',
|
|
62
58
|
paddingInline: 'var(--spacing-3)',
|
|
63
59
|
};
|
|
64
|
-
const sideNavHeading: CSSProperties = {
|
|
65
|
-
marginInline: 'var(--spacing-4)',
|
|
66
|
-
};
|
|
67
60
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
{label: 'Privacy', icon: ShieldCheck},
|
|
72
|
-
{label: 'Notifications', icon: Bell},
|
|
73
|
-
{label: 'Taxes', icon: FileText},
|
|
74
|
-
{label: 'Payments', icon: CreditCard},
|
|
75
|
-
{label: 'Languages & currency', icon: Globe},
|
|
76
|
-
{label: 'Travel for work', icon: Briefcase},
|
|
77
|
-
];
|
|
61
|
+
// Same-route hash: demo links stay focusable anchors without escaping the
|
|
62
|
+
// template through the hash router (bare "#" would drop back to the home page).
|
|
63
|
+
const SELF_HASH = '#/templates/settings-sidebar';
|
|
78
64
|
|
|
79
65
|
// Section title shown beside the mobile back button (matches each section's
|
|
80
66
|
// in-content heading, which is hidden on mobile to avoid a duplicate).
|
|
81
67
|
const SECTION_TITLES: Record<string, string> = {
|
|
82
|
-
'Personal information': 'Personal
|
|
68
|
+
'Personal information': 'Personal information',
|
|
83
69
|
'Login & security': 'Login & security',
|
|
84
70
|
Privacy: 'Privacy',
|
|
85
71
|
Notifications: 'Notifications',
|
|
@@ -90,124 +76,16 @@ const SECTION_TITLES: Record<string, string> = {
|
|
|
90
76
|
'Professional hosting tools': 'Hosting tools',
|
|
91
77
|
};
|
|
92
78
|
|
|
93
|
-
interface InfoRow {
|
|
94
|
-
label: string;
|
|
95
|
-
value: string;
|
|
96
|
-
action: string;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const LOGIN_ROWS: InfoRow[] = [
|
|
100
|
-
{label: 'Password', value: 'Not created', action: 'Create'},
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
const SOCIAL_ROWS: InfoRow[] = [
|
|
104
|
-
{label: 'Google', value: 'Connected', action: 'Disconnect'},
|
|
105
|
-
];
|
|
106
|
-
|
|
107
79
|
const TAX_ROWS: InfoRow[] = [
|
|
108
|
-
{label: '
|
|
109
|
-
{label: '
|
|
80
|
+
{label: 'Tax scrolls', value: 'Not provided', action: 'Add'},
|
|
81
|
+
{label: 'Past scrolls', value: 'No scrolls yet', action: 'View'},
|
|
110
82
|
];
|
|
111
83
|
|
|
112
84
|
const PAYOUT_ROWS: InfoRow[] = [
|
|
113
|
-
{label: 'Payout
|
|
114
|
-
{label: 'Past
|
|
115
|
-
];
|
|
116
|
-
|
|
117
|
-
const DEVICE_ROWS: {
|
|
118
|
-
label: string;
|
|
119
|
-
badge?: string;
|
|
120
|
-
location: string;
|
|
121
|
-
action?: string;
|
|
122
|
-
}[] = [
|
|
123
|
-
{
|
|
124
|
-
label: 'OS X 10.15.7 · Chrome',
|
|
125
|
-
badge: 'CURRENT SESSION',
|
|
126
|
-
location: 'Brașov, Transylvania · March 30, 2026 at 19:31',
|
|
127
|
-
},
|
|
128
|
-
{label: 'Session', location: 'August 9, 2023 at 04:19', action: 'Log out'},
|
|
129
|
-
{
|
|
130
|
-
label: 'OS X 10.15.7 · unknown',
|
|
131
|
-
location: 'Whitby, England · April 14, 2023 at 17:47',
|
|
132
|
-
action: 'Log out',
|
|
133
|
-
},
|
|
85
|
+
{label: 'Payout crypt', value: 'Not set up', action: 'Add'},
|
|
86
|
+
{label: 'Past payouts', value: 'No tributes yet', action: 'View'},
|
|
134
87
|
];
|
|
135
88
|
|
|
136
|
-
function InfoRowItem({label, value, action}: InfoRow) {
|
|
137
|
-
return (
|
|
138
|
-
<>
|
|
139
|
-
<HStack hAlign="between" vAlign="start" style={rowPadding}>
|
|
140
|
-
<VStack gap={0}>
|
|
141
|
-
<Text type="body" weight="semibold" display="block">
|
|
142
|
-
{label}
|
|
143
|
-
</Text>
|
|
144
|
-
<Text type="supporting" color="secondary" display="block">
|
|
145
|
-
{value}
|
|
146
|
-
</Text>
|
|
147
|
-
</VStack>
|
|
148
|
-
{action && <Link href="#/templates/settings-sidebar">{action}</Link>}
|
|
149
|
-
</HStack>
|
|
150
|
-
<Divider />
|
|
151
|
-
</>
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
interface ExpandableRowProps {
|
|
156
|
-
label: string;
|
|
157
|
-
value: string;
|
|
158
|
-
children: React.ReactNode;
|
|
159
|
-
isExpanded: boolean;
|
|
160
|
-
onEdit: () => void;
|
|
161
|
-
onCancel: () => void;
|
|
162
|
-
onSave: () => void;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function ExpandableRow({
|
|
166
|
-
label,
|
|
167
|
-
value,
|
|
168
|
-
children,
|
|
169
|
-
isExpanded,
|
|
170
|
-
onEdit,
|
|
171
|
-
onCancel,
|
|
172
|
-
onSave,
|
|
173
|
-
}: ExpandableRowProps) {
|
|
174
|
-
return (
|
|
175
|
-
<>
|
|
176
|
-
{isExpanded ? (
|
|
177
|
-
<VStack gap={4} style={rowPadding}>
|
|
178
|
-
<Text type="body" weight="semibold" display="block">
|
|
179
|
-
{label}
|
|
180
|
-
</Text>
|
|
181
|
-
{children}
|
|
182
|
-
<HStack gap={2}>
|
|
183
|
-
<Button label="Save" variant="primary" onClick={onSave} />
|
|
184
|
-
<Button label="Cancel" variant="ghost" onClick={onCancel} />
|
|
185
|
-
</HStack>
|
|
186
|
-
</VStack>
|
|
187
|
-
) : (
|
|
188
|
-
<HStack hAlign="between" vAlign="start" style={rowPadding}>
|
|
189
|
-
<VStack gap={0}>
|
|
190
|
-
<Text type="body" weight="semibold" display="block">
|
|
191
|
-
{label}
|
|
192
|
-
</Text>
|
|
193
|
-
<Text type="supporting" color="secondary" display="block">
|
|
194
|
-
{value}
|
|
195
|
-
</Text>
|
|
196
|
-
</VStack>
|
|
197
|
-
<Link
|
|
198
|
-
href="#/templates/settings-sidebar"
|
|
199
|
-
onClick={(e: React.MouseEvent) => {
|
|
200
|
-
e.preventDefault();
|
|
201
|
-
onEdit();
|
|
202
|
-
}}>
|
|
203
|
-
Edit
|
|
204
|
-
</Link>
|
|
205
|
-
</HStack>
|
|
206
|
-
)}
|
|
207
|
-
<Divider />
|
|
208
|
-
</>
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
89
|
|
|
212
90
|
const LANGUAGES = [
|
|
213
91
|
{label: 'English (Canada)', value: 'en-CA'},
|
|
@@ -274,9 +152,9 @@ export default function SettingsSidebar() {
|
|
|
274
152
|
|
|
275
153
|
const navList = (
|
|
276
154
|
<VStack gap={4} style={sideNavPadding}>
|
|
277
|
-
<
|
|
155
|
+
<Text type="label" style={sideNavHeading}>
|
|
278
156
|
Account settings
|
|
279
|
-
</
|
|
157
|
+
</Text>
|
|
280
158
|
<List density="spacious">
|
|
281
159
|
{NAV_ITEMS.map(item => (
|
|
282
160
|
<ListItem
|
|
@@ -298,7 +176,6 @@ export default function SettingsSidebar() {
|
|
|
298
176
|
<ListItem
|
|
299
177
|
label="Professional hosting tools"
|
|
300
178
|
startContent={<Icon icon={Wrench} />}
|
|
301
|
-
onClick={() => {}}
|
|
302
179
|
/>
|
|
303
180
|
</List>
|
|
304
181
|
</VStack>
|
|
@@ -310,7 +187,14 @@ export default function SettingsSidebar() {
|
|
|
310
187
|
<Layout
|
|
311
188
|
height="fill"
|
|
312
189
|
style={fillViewport}
|
|
313
|
-
|
|
190
|
+
// padding={0}, not padding={2}. This wraps the SAME navList element
|
|
191
|
+
// the desktop LayoutPanel renders with padding={0}, and sideNavPadding
|
|
192
|
+
// already supplies the list's 12px inline inset. The extra 8px here is
|
|
193
|
+
// what made the same nav list measure 20px on mobile against 12px on
|
|
194
|
+
// desktop -- and against 24px further down, so the two mobile states
|
|
195
|
+
// disagreed with each other too. The container owns no gutter; the
|
|
196
|
+
// list owns its own.
|
|
197
|
+
content={<LayoutContent padding={0}>{navList}</LayoutContent>}
|
|
314
198
|
/>
|
|
315
199
|
);
|
|
316
200
|
}
|
|
@@ -328,7 +212,7 @@ export default function SettingsSidebar() {
|
|
|
328
212
|
)
|
|
329
213
|
}
|
|
330
214
|
content={
|
|
331
|
-
<LayoutContent padding={
|
|
215
|
+
<LayoutContent padding={6}>
|
|
332
216
|
<VStack gap={0}>
|
|
333
217
|
{/* Mobile detail view: a back button sits beside the section title
|
|
334
218
|
(the per-section headings below are hidden on mobile). Toolbar's
|
|
@@ -336,7 +220,7 @@ export default function SettingsSidebar() {
|
|
|
336
220
|
flush with the content edge. */}
|
|
337
221
|
{isNarrow && (
|
|
338
222
|
<Toolbar
|
|
339
|
-
label={`Back to Account settings
|
|
223
|
+
label={`Back to Account settings: ${SECTION_TITLES[activeNav]}`}
|
|
340
224
|
gap={2}
|
|
341
225
|
startContent={
|
|
342
226
|
<>
|
|
@@ -348,14 +232,14 @@ export default function SettingsSidebar() {
|
|
|
348
232
|
icon={<Icon icon={ArrowLeft} size="sm" />}
|
|
349
233
|
onClick={() => setMobileView('nav')}
|
|
350
234
|
/>
|
|
351
|
-
<Heading level={
|
|
235
|
+
<Heading level={1}>{SECTION_TITLES[activeNav]}</Heading>
|
|
352
236
|
</>
|
|
353
237
|
}
|
|
354
238
|
/>
|
|
355
239
|
)}
|
|
356
240
|
{activeNav === 'Login & security' && (
|
|
357
241
|
<VStack gap={6}>
|
|
358
|
-
{!isNarrow && <Heading level={
|
|
242
|
+
{!isNarrow && <Heading level={1}>Login & security</Heading>}
|
|
359
243
|
|
|
360
244
|
<TabList value={activeTab} onChange={setActiveTab} hasDivider>
|
|
361
245
|
<Tab value="login" label="Login" />
|
|
@@ -365,38 +249,60 @@ export default function SettingsSidebar() {
|
|
|
365
249
|
{activeTab === 'login' && (
|
|
366
250
|
<VStack gap={8}>
|
|
367
251
|
<VStack gap={0}>
|
|
368
|
-
<Heading level={
|
|
252
|
+
<Heading level={2}>Login</Heading>
|
|
369
253
|
<Divider />
|
|
370
254
|
{LOGIN_ROWS.map(row => (
|
|
371
|
-
<InfoRowItem
|
|
255
|
+
<InfoRowItem
|
|
256
|
+
key={row.label}
|
|
257
|
+
{...row}
|
|
258
|
+
href={SELF_HASH}
|
|
259
|
+
style={rowPadding}
|
|
260
|
+
/>
|
|
372
261
|
))}
|
|
373
262
|
</VStack>
|
|
374
263
|
|
|
375
264
|
<VStack gap={0}>
|
|
376
|
-
<Heading level={
|
|
265
|
+
<Heading level={2}>Social accounts</Heading>
|
|
377
266
|
<Divider />
|
|
378
267
|
{SOCIAL_ROWS.map(row => (
|
|
379
|
-
<InfoRowItem
|
|
268
|
+
<InfoRowItem
|
|
269
|
+
key={row.label}
|
|
270
|
+
{...row}
|
|
271
|
+
href={SELF_HASH}
|
|
272
|
+
style={rowPadding}
|
|
273
|
+
/>
|
|
380
274
|
))}
|
|
381
275
|
</VStack>
|
|
382
276
|
|
|
383
277
|
<VStack gap={0}>
|
|
384
|
-
<Heading level={
|
|
278
|
+
<Heading level={2}>Device history</Heading>
|
|
385
279
|
<Divider />
|
|
386
|
-
{DEVICE_ROWS.map((device
|
|
280
|
+
{DEVICE_ROWS.map((device) => (
|
|
387
281
|
<HStack
|
|
388
|
-
key={
|
|
282
|
+
key={device.location}
|
|
389
283
|
gap={3}
|
|
390
284
|
vAlign="start"
|
|
391
285
|
style={rowPadding}>
|
|
392
286
|
<Icon icon={Monitor} />
|
|
393
287
|
<StackItem size="fill">
|
|
394
288
|
<VStack gap={0}>
|
|
395
|
-
|
|
289
|
+
{/* wrap: the label plus the session status
|
|
290
|
+
exceed the content width on a phone. */}
|
|
291
|
+
<HStack gap={2} vAlign="center" wrap="wrap">
|
|
396
292
|
<Text type="body" weight="semibold">
|
|
397
293
|
{device.label}
|
|
398
294
|
</Text>
|
|
399
|
-
{device.
|
|
295
|
+
{device.isCurrent && (
|
|
296
|
+
<HStack gap={1} vAlign="center">
|
|
297
|
+
<StatusDot
|
|
298
|
+
variant="success"
|
|
299
|
+
label="Current session"
|
|
300
|
+
/>
|
|
301
|
+
<Text type="supporting" color="secondary">
|
|
302
|
+
Current session
|
|
303
|
+
</Text>
|
|
304
|
+
</HStack>
|
|
305
|
+
)}
|
|
400
306
|
</HStack>
|
|
401
307
|
<Text
|
|
402
308
|
type="supporting"
|
|
@@ -408,7 +314,9 @@ export default function SettingsSidebar() {
|
|
|
408
314
|
</VStack>
|
|
409
315
|
</StackItem>
|
|
410
316
|
{device.action && (
|
|
411
|
-
<Link href=
|
|
317
|
+
<Link href={SELF_HASH} style={actionNoWrap}>
|
|
318
|
+
{device.action}
|
|
319
|
+
</Link>
|
|
412
320
|
)}
|
|
413
321
|
</HStack>
|
|
414
322
|
))}
|
|
@@ -416,7 +324,7 @@ export default function SettingsSidebar() {
|
|
|
416
324
|
</VStack>
|
|
417
325
|
|
|
418
326
|
<VStack gap={0}>
|
|
419
|
-
<Heading level={
|
|
327
|
+
<Heading level={2}>Account</Heading>
|
|
420
328
|
<Divider />
|
|
421
329
|
<HStack
|
|
422
330
|
hAlign="between"
|
|
@@ -433,7 +341,9 @@ export default function SettingsSidebar() {
|
|
|
433
341
|
This action cannot be undone
|
|
434
342
|
</Text>
|
|
435
343
|
</VStack>
|
|
436
|
-
<Link href=
|
|
344
|
+
<Link href={SELF_HASH} style={actionNoWrap}>
|
|
345
|
+
Deactivate
|
|
346
|
+
</Link>
|
|
437
347
|
</HStack>
|
|
438
348
|
<Divider />
|
|
439
349
|
</VStack>
|
|
@@ -443,12 +353,12 @@ export default function SettingsSidebar() {
|
|
|
443
353
|
{activeTab === 'shared' && (
|
|
444
354
|
<VStack gap={8}>
|
|
445
355
|
<VStack gap={2}>
|
|
446
|
-
<Heading level={
|
|
356
|
+
<Heading level={2}>Shared access</Heading>
|
|
447
357
|
<Divider />
|
|
448
358
|
<Text type="body" color="secondary">
|
|
449
359
|
Review each request carefully before approving access.
|
|
450
|
-
We'll email your
|
|
451
|
-
code that lets them
|
|
360
|
+
We'll email your kin or coven-mate a 4-digit
|
|
361
|
+
code that lets them enter your crypt from their
|
|
452
362
|
trusted device.
|
|
453
363
|
</Text>
|
|
454
364
|
</VStack>
|
|
@@ -459,7 +369,7 @@ export default function SettingsSidebar() {
|
|
|
459
369
|
<Icon icon={Lock} />
|
|
460
370
|
</Center>
|
|
461
371
|
<VStack gap={1}>
|
|
462
|
-
<Text type="body"
|
|
372
|
+
<Text type="body">
|
|
463
373
|
Adding devices from people you trust
|
|
464
374
|
</Text>
|
|
465
375
|
<Text type="body" color="secondary">
|
|
@@ -479,7 +389,7 @@ export default function SettingsSidebar() {
|
|
|
479
389
|
{activeNav === 'Languages & currency' && (
|
|
480
390
|
<VStack gap={6}>
|
|
481
391
|
{!isNarrow && (
|
|
482
|
-
<Heading level={
|
|
392
|
+
<Heading level={1}>Languages & currency</Heading>
|
|
483
393
|
)}
|
|
484
394
|
<VStack gap={0}>
|
|
485
395
|
<ExpandableRow
|
|
@@ -491,7 +401,9 @@ export default function SettingsSidebar() {
|
|
|
491
401
|
isExpanded={expandedRow === 'language'}
|
|
492
402
|
onEdit={() => setExpandedRow('language')}
|
|
493
403
|
onCancel={() => setExpandedRow(null)}
|
|
494
|
-
onSave={() => setExpandedRow(null)}
|
|
404
|
+
onSave={() => setExpandedRow(null)}
|
|
405
|
+
href={SELF_HASH}
|
|
406
|
+
style={rowPadding}>
|
|
495
407
|
<Selector
|
|
496
408
|
label="Language"
|
|
497
409
|
isLabelHidden
|
|
@@ -510,7 +422,9 @@ export default function SettingsSidebar() {
|
|
|
510
422
|
isExpanded={expandedRow === 'currency'}
|
|
511
423
|
onEdit={() => setExpandedRow('currency')}
|
|
512
424
|
onCancel={() => setExpandedRow(null)}
|
|
513
|
-
onSave={() => setExpandedRow(null)}
|
|
425
|
+
onSave={() => setExpandedRow(null)}
|
|
426
|
+
href={SELF_HASH}
|
|
427
|
+
style={rowPadding}>
|
|
514
428
|
<Selector
|
|
515
429
|
label="Currency"
|
|
516
430
|
isLabelHidden
|
|
@@ -529,7 +443,9 @@ export default function SettingsSidebar() {
|
|
|
529
443
|
isExpanded={expandedRow === 'timezone'}
|
|
530
444
|
onEdit={() => setExpandedRow('timezone')}
|
|
531
445
|
onCancel={() => setExpandedRow(null)}
|
|
532
|
-
onSave={() => setExpandedRow(null)}
|
|
446
|
+
onSave={() => setExpandedRow(null)}
|
|
447
|
+
href={SELF_HASH}
|
|
448
|
+
style={rowPadding}>
|
|
533
449
|
<Selector
|
|
534
450
|
label="Time zone"
|
|
535
451
|
isLabelHidden
|
|
@@ -545,7 +461,9 @@ export default function SettingsSidebar() {
|
|
|
545
461
|
|
|
546
462
|
{activeNav === 'Personal information' && (
|
|
547
463
|
<VStack gap={6}>
|
|
548
|
-
{!isNarrow &&
|
|
464
|
+
{!isNarrow && (
|
|
465
|
+
<Heading level={1}>Personal information</Heading>
|
|
466
|
+
)}
|
|
549
467
|
<VStack gap={0}>
|
|
550
468
|
<ExpandableRow
|
|
551
469
|
label="Legal name"
|
|
@@ -553,7 +471,9 @@ export default function SettingsSidebar() {
|
|
|
553
471
|
isExpanded={expandedRow === 'legalName'}
|
|
554
472
|
onEdit={() => setExpandedRow('legalName')}
|
|
555
473
|
onCancel={() => setExpandedRow(null)}
|
|
556
|
-
onSave={() => setExpandedRow(null)}
|
|
474
|
+
onSave={() => setExpandedRow(null)}
|
|
475
|
+
href={SELF_HASH}
|
|
476
|
+
style={rowPadding}>
|
|
557
477
|
<TextInput
|
|
558
478
|
label="Legal name"
|
|
559
479
|
isLabelHidden
|
|
@@ -567,7 +487,9 @@ export default function SettingsSidebar() {
|
|
|
567
487
|
isExpanded={expandedRow === 'preferredName'}
|
|
568
488
|
onEdit={() => setExpandedRow('preferredName')}
|
|
569
489
|
onCancel={() => setExpandedRow(null)}
|
|
570
|
-
onSave={() => setExpandedRow(null)}
|
|
490
|
+
onSave={() => setExpandedRow(null)}
|
|
491
|
+
href={SELF_HASH}
|
|
492
|
+
style={rowPadding}>
|
|
571
493
|
<TextInput
|
|
572
494
|
label="Preferred first name"
|
|
573
495
|
isLabelHidden
|
|
@@ -581,7 +503,9 @@ export default function SettingsSidebar() {
|
|
|
581
503
|
isExpanded={expandedRow === 'email'}
|
|
582
504
|
onEdit={() => setExpandedRow('email')}
|
|
583
505
|
onCancel={() => setExpandedRow(null)}
|
|
584
|
-
onSave={() => setExpandedRow(null)}
|
|
506
|
+
onSave={() => setExpandedRow(null)}
|
|
507
|
+
href={SELF_HASH}
|
|
508
|
+
style={rowPadding}>
|
|
585
509
|
<TextInput
|
|
586
510
|
label="Email address"
|
|
587
511
|
isLabelHidden
|
|
@@ -595,7 +519,9 @@ export default function SettingsSidebar() {
|
|
|
595
519
|
isExpanded={expandedRow === 'phone'}
|
|
596
520
|
onEdit={() => setExpandedRow('phone')}
|
|
597
521
|
onCancel={() => setExpandedRow(null)}
|
|
598
|
-
onSave={() => setExpandedRow(null)}
|
|
522
|
+
onSave={() => setExpandedRow(null)}
|
|
523
|
+
href={SELF_HASH}
|
|
524
|
+
style={rowPadding}>
|
|
599
525
|
<TextInput
|
|
600
526
|
label="Phone number"
|
|
601
527
|
isLabelHidden
|
|
@@ -607,6 +533,8 @@ export default function SettingsSidebar() {
|
|
|
607
533
|
label="Identity verification"
|
|
608
534
|
value="Verified"
|
|
609
535
|
action=""
|
|
536
|
+
href={SELF_HASH}
|
|
537
|
+
style={rowPadding}
|
|
610
538
|
/>
|
|
611
539
|
<ExpandableRow
|
|
612
540
|
label="Residential address"
|
|
@@ -614,7 +542,9 @@ export default function SettingsSidebar() {
|
|
|
614
542
|
isExpanded={expandedRow === 'address'}
|
|
615
543
|
onEdit={() => setExpandedRow('address')}
|
|
616
544
|
onCancel={() => setExpandedRow(null)}
|
|
617
|
-
onSave={() => setExpandedRow(null)}
|
|
545
|
+
onSave={() => setExpandedRow(null)}
|
|
546
|
+
href={SELF_HASH}
|
|
547
|
+
style={rowPadding}>
|
|
618
548
|
<TextInput
|
|
619
549
|
label="Residential address"
|
|
620
550
|
isLabelHidden
|
|
@@ -628,7 +558,9 @@ export default function SettingsSidebar() {
|
|
|
628
558
|
isExpanded={expandedRow === 'mailingAddress'}
|
|
629
559
|
onEdit={() => setExpandedRow('mailingAddress')}
|
|
630
560
|
onCancel={() => setExpandedRow(null)}
|
|
631
|
-
onSave={() => setExpandedRow(null)}
|
|
561
|
+
onSave={() => setExpandedRow(null)}
|
|
562
|
+
href={SELF_HASH}
|
|
563
|
+
style={rowPadding}>
|
|
632
564
|
<TextInput
|
|
633
565
|
label="Mailing address"
|
|
634
566
|
isLabelHidden
|
|
@@ -642,7 +574,9 @@ export default function SettingsSidebar() {
|
|
|
642
574
|
isExpanded={expandedRow === 'emergencyContact'}
|
|
643
575
|
onEdit={() => setExpandedRow('emergencyContact')}
|
|
644
576
|
onCancel={() => setExpandedRow(null)}
|
|
645
|
-
onSave={() => setExpandedRow(null)}
|
|
577
|
+
onSave={() => setExpandedRow(null)}
|
|
578
|
+
href={SELF_HASH}
|
|
579
|
+
style={rowPadding}>
|
|
646
580
|
<TextInput
|
|
647
581
|
label="Emergency contact"
|
|
648
582
|
isLabelHidden
|
|
@@ -654,61 +588,27 @@ export default function SettingsSidebar() {
|
|
|
654
588
|
|
|
655
589
|
<Card padding={4}>
|
|
656
590
|
<VStack gap={4}>
|
|
657
|
-
|
|
658
|
-
<
|
|
659
|
-
<
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
</Center>
|
|
679
|
-
<VStack gap={0}>
|
|
680
|
-
<Text type="body" weight="semibold" display="block">
|
|
681
|
-
Which details can be edited?
|
|
682
|
-
</Text>
|
|
683
|
-
<Text
|
|
684
|
-
type="supporting"
|
|
685
|
-
color="secondary"
|
|
686
|
-
display="block">
|
|
687
|
-
Contact info and personal details can be edited. If
|
|
688
|
-
this info was used to verify your identity,
|
|
689
|
-
you'll need to get verified again the next time
|
|
690
|
-
you book—or to continue hosting.
|
|
691
|
-
</Text>
|
|
692
|
-
</VStack>
|
|
693
|
-
</HStack>
|
|
694
|
-
<Divider />
|
|
695
|
-
<HStack gap={3} vAlign="start">
|
|
696
|
-
<Center width={48} height={48} style={iconBox}>
|
|
697
|
-
<Icon icon={Share2} />
|
|
698
|
-
</Center>
|
|
699
|
-
<VStack gap={0}>
|
|
700
|
-
<Text type="body" weight="semibold" display="block">
|
|
701
|
-
What info is shared with others?
|
|
702
|
-
</Text>
|
|
703
|
-
<Text
|
|
704
|
-
type="supporting"
|
|
705
|
-
color="secondary"
|
|
706
|
-
display="block">
|
|
707
|
-
We only release contact information after a
|
|
708
|
-
reservation is confirmed.
|
|
709
|
-
</Text>
|
|
710
|
-
</VStack>
|
|
711
|
-
</HStack>
|
|
591
|
+
{INFO_TILES.map((tile, i) => (
|
|
592
|
+
<Fragment key={tile.title}>
|
|
593
|
+
{i > 0 && <Divider />}
|
|
594
|
+
<HStack gap={3} vAlign="start">
|
|
595
|
+
<Center width={48} height={48} style={iconBox}>
|
|
596
|
+
<Icon icon={tile.icon} />
|
|
597
|
+
</Center>
|
|
598
|
+
<VStack gap={0}>
|
|
599
|
+
<Text type="body" weight="semibold" display="block">
|
|
600
|
+
{tile.title}
|
|
601
|
+
</Text>
|
|
602
|
+
<Text
|
|
603
|
+
type="body"
|
|
604
|
+
color="secondary"
|
|
605
|
+
display="block">
|
|
606
|
+
{tile.body}
|
|
607
|
+
</Text>
|
|
608
|
+
</VStack>
|
|
609
|
+
</HStack>
|
|
610
|
+
</Fragment>
|
|
611
|
+
))}
|
|
712
612
|
</VStack>
|
|
713
613
|
</Card>
|
|
714
614
|
</VStack>
|
|
@@ -716,11 +616,11 @@ export default function SettingsSidebar() {
|
|
|
716
616
|
|
|
717
617
|
{activeNav === 'Privacy' && (
|
|
718
618
|
<VStack gap={6}>
|
|
719
|
-
{!isNarrow && <Heading level={
|
|
619
|
+
{!isNarrow && <Heading level={1}>Privacy</Heading>}
|
|
720
620
|
|
|
721
621
|
<VStack gap={8}>
|
|
722
622
|
<VStack gap={0}>
|
|
723
|
-
<Heading level={
|
|
623
|
+
<Heading level={2}>Messages</Heading>
|
|
724
624
|
<VStack style={rowPadding}>
|
|
725
625
|
<Switch
|
|
726
626
|
label="Show people when I've read their messages."
|
|
@@ -734,17 +634,17 @@ export default function SettingsSidebar() {
|
|
|
734
634
|
<Text type="body" weight="semibold">
|
|
735
635
|
Blocked people
|
|
736
636
|
</Text>
|
|
737
|
-
<Link href=
|
|
637
|
+
<Link href={SELF_HASH}>View</Link>
|
|
738
638
|
</HStack>
|
|
739
639
|
<Divider />
|
|
740
640
|
</VStack>
|
|
741
641
|
|
|
742
642
|
<VStack gap={0}>
|
|
743
|
-
<Heading level={
|
|
643
|
+
<Heading level={2}>Listings</Heading>
|
|
744
644
|
<VStack style={rowPadding}>
|
|
745
645
|
<Switch
|
|
746
|
-
label="
|
|
747
|
-
description="Turning this on means
|
|
646
|
+
label="List my wares in the scrying mirrors"
|
|
647
|
+
description="Turning this on means scrying engines, like Google, will show your wares to seekers."
|
|
748
648
|
value={searchEngines}
|
|
749
649
|
onChange={setSearchEngines}
|
|
750
650
|
labelPosition="start"
|
|
@@ -755,16 +655,16 @@ export default function SettingsSidebar() {
|
|
|
755
655
|
</VStack>
|
|
756
656
|
|
|
757
657
|
<VStack gap={4}>
|
|
758
|
-
<Heading level={
|
|
658
|
+
<Heading level={2}>Reviews</Heading>
|
|
759
659
|
<Text type="body" color="secondary">
|
|
760
660
|
Choose what's shared when you write a review.{' '}
|
|
761
|
-
<Link href=
|
|
661
|
+
<Link href={SELF_HASH} type="body">
|
|
762
662
|
Learn more
|
|
763
663
|
</Link>
|
|
764
664
|
</Text>
|
|
765
665
|
<VStack gap={4}>
|
|
766
666
|
<Switch
|
|
767
|
-
label="Show my home
|
|
667
|
+
label="Show my home haunt and country"
|
|
768
668
|
description="Ex: City and country"
|
|
769
669
|
value={showCity}
|
|
770
670
|
onChange={setShowCity}
|
|
@@ -772,8 +672,8 @@ export default function SettingsSidebar() {
|
|
|
772
672
|
labelSpacing="spread"
|
|
773
673
|
/>
|
|
774
674
|
<Switch
|
|
775
|
-
label="Show my
|
|
776
|
-
description="Ex:
|
|
675
|
+
label="Show my journey type"
|
|
676
|
+
description="Ex: Rested with kin or familiars"
|
|
777
677
|
value={showTripType}
|
|
778
678
|
onChange={setShowTripType}
|
|
779
679
|
labelPosition="start"
|
|
@@ -788,8 +688,8 @@ export default function SettingsSidebar() {
|
|
|
788
688
|
labelSpacing="spread"
|
|
789
689
|
/>
|
|
790
690
|
<Switch
|
|
791
|
-
label="Show my booked
|
|
792
|
-
description="Ex:
|
|
691
|
+
label="Show my booked revels"
|
|
692
|
+
description="Ex: Midnight feasts and tasting rituals"
|
|
793
693
|
value={showServices}
|
|
794
694
|
onChange={setShowServices}
|
|
795
695
|
labelPosition="start"
|
|
@@ -800,11 +700,11 @@ export default function SettingsSidebar() {
|
|
|
800
700
|
</VStack>
|
|
801
701
|
|
|
802
702
|
<VStack gap={4}>
|
|
803
|
-
<Heading level={
|
|
703
|
+
<Heading level={2}>Data privacy</Heading>
|
|
804
704
|
<Card>
|
|
805
705
|
<HStack hAlign="between" vAlign="center">
|
|
806
706
|
<Text type="body">Request my personal data</Text>
|
|
807
|
-
<Link href=
|
|
707
|
+
<Link href={SELF_HASH}>Request</Link>
|
|
808
708
|
</HStack>
|
|
809
709
|
</Card>
|
|
810
710
|
<Switch
|
|
@@ -818,7 +718,7 @@ export default function SettingsSidebar() {
|
|
|
818
718
|
<Card>
|
|
819
719
|
<HStack hAlign="between" vAlign="center">
|
|
820
720
|
<Text type="body">Delete my account</Text>
|
|
821
|
-
<Link href=
|
|
721
|
+
<Link href={SELF_HASH}>Delete</Link>
|
|
822
722
|
</HStack>
|
|
823
723
|
</Card>
|
|
824
724
|
<Card variant="muted">
|
|
@@ -827,13 +727,13 @@ export default function SettingsSidebar() {
|
|
|
827
727
|
<Icon icon={ShieldCheck} />
|
|
828
728
|
</Center>
|
|
829
729
|
<VStack gap={1}>
|
|
830
|
-
<Text type="body"
|
|
730
|
+
<Text type="body">
|
|
831
731
|
Committed to privacy
|
|
832
732
|
</Text>
|
|
833
|
-
<Text type="
|
|
733
|
+
<Text type="body" color="secondary">
|
|
834
734
|
We're committed to keeping your data protected.
|
|
835
735
|
See details in our{' '}
|
|
836
|
-
<Link href=
|
|
736
|
+
<Link href={SELF_HASH} type="supporting">
|
|
837
737
|
Privacy Policy
|
|
838
738
|
</Link>
|
|
839
739
|
.
|
|
@@ -848,13 +748,13 @@ export default function SettingsSidebar() {
|
|
|
848
748
|
|
|
849
749
|
{activeNav === 'Notifications' && (
|
|
850
750
|
<VStack gap={6}>
|
|
851
|
-
{!isNarrow && <Heading level={
|
|
751
|
+
{!isNarrow && <Heading level={1}>Notifications</Heading>}
|
|
852
752
|
<VStack gap={0}>
|
|
853
|
-
<Heading level={
|
|
753
|
+
<Heading level={2}>Messages</Heading>
|
|
854
754
|
<VStack style={rowPadding}>
|
|
855
755
|
<Switch
|
|
856
756
|
label="Email notifications"
|
|
857
|
-
description="
|
|
757
|
+
description="Coven updates, journey reminders, and crypt activity."
|
|
858
758
|
value={emailNotif}
|
|
859
759
|
onChange={setEmailNotif}
|
|
860
760
|
labelPosition="start"
|
|
@@ -865,7 +765,7 @@ export default function SettingsSidebar() {
|
|
|
865
765
|
<VStack style={rowPadding}>
|
|
866
766
|
<Switch
|
|
867
767
|
label="Push notifications"
|
|
868
|
-
description="
|
|
768
|
+
description="Swift ravens for messages and booking requests."
|
|
869
769
|
value={pushNotif}
|
|
870
770
|
onChange={setPushNotif}
|
|
871
771
|
labelPosition="start"
|
|
@@ -879,12 +779,17 @@ export default function SettingsSidebar() {
|
|
|
879
779
|
|
|
880
780
|
{activeNav === 'Taxes' && (
|
|
881
781
|
<VStack gap={6}>
|
|
882
|
-
{!isNarrow && <Heading level={
|
|
782
|
+
{!isNarrow && <Heading level={1}>Taxes</Heading>}
|
|
883
783
|
<VStack gap={0}>
|
|
884
|
-
<Heading level={
|
|
784
|
+
<Heading level={2}>Tax scrolls</Heading>
|
|
885
785
|
<Divider />
|
|
886
786
|
{TAX_ROWS.map(row => (
|
|
887
|
-
<InfoRowItem
|
|
787
|
+
<InfoRowItem
|
|
788
|
+
key={row.label}
|
|
789
|
+
{...row}
|
|
790
|
+
href={SELF_HASH}
|
|
791
|
+
style={rowPadding}
|
|
792
|
+
/>
|
|
888
793
|
))}
|
|
889
794
|
</VStack>
|
|
890
795
|
</VStack>
|
|
@@ -892,12 +797,17 @@ export default function SettingsSidebar() {
|
|
|
892
797
|
|
|
893
798
|
{activeNav === 'Payments' && (
|
|
894
799
|
<VStack gap={6}>
|
|
895
|
-
{!isNarrow && <Heading level={
|
|
800
|
+
{!isNarrow && <Heading level={1}>Payments</Heading>}
|
|
896
801
|
<VStack gap={0}>
|
|
897
|
-
<Heading level={
|
|
802
|
+
<Heading level={2}>Payout crypt</Heading>
|
|
898
803
|
<Divider />
|
|
899
804
|
{PAYOUT_ROWS.map(row => (
|
|
900
|
-
<InfoRowItem
|
|
805
|
+
<InfoRowItem
|
|
806
|
+
key={row.label}
|
|
807
|
+
{...row}
|
|
808
|
+
href={SELF_HASH}
|
|
809
|
+
style={rowPadding}
|
|
810
|
+
/>
|
|
901
811
|
))}
|
|
902
812
|
</VStack>
|
|
903
813
|
</VStack>
|
|
@@ -905,13 +815,13 @@ export default function SettingsSidebar() {
|
|
|
905
815
|
|
|
906
816
|
{activeNav === 'Travel for work' && (
|
|
907
817
|
<VStack gap={6}>
|
|
908
|
-
{!isNarrow && <Heading level={
|
|
818
|
+
{!isNarrow && <Heading level={1}>Travel for work</Heading>}
|
|
909
819
|
<VStack gap={0}>
|
|
910
|
-
<Heading level={
|
|
820
|
+
<Heading level={2}>Work haunts</Heading>
|
|
911
821
|
<VStack style={rowPadding}>
|
|
912
822
|
<Switch
|
|
913
|
-
label="Show
|
|
914
|
-
description="Add a
|
|
823
|
+
label="Show night-errand options at checkout"
|
|
824
|
+
description="Add a coven address to expense night errands and unlock travel-ready wares."
|
|
915
825
|
value={workTrips}
|
|
916
826
|
onChange={setWorkTrips}
|
|
917
827
|
labelPosition="start"
|
|
@@ -926,7 +836,7 @@ export default function SettingsSidebar() {
|
|
|
926
836
|
{activeNav === 'Professional hosting tools' && (
|
|
927
837
|
<VStack gap={6}>
|
|
928
838
|
{!isNarrow && (
|
|
929
|
-
<Heading level={
|
|
839
|
+
<Heading level={1}>Professional hosting tools</Heading>
|
|
930
840
|
)}
|
|
931
841
|
<Card variant="muted">
|
|
932
842
|
<HStack gap={4} vAlign="start">
|
|
@@ -934,10 +844,10 @@ export default function SettingsSidebar() {
|
|
|
934
844
|
<Icon icon={Wrench} />
|
|
935
845
|
</Center>
|
|
936
846
|
<VStack gap={1}>
|
|
937
|
-
<Text type="body"
|
|
938
|
-
|
|
847
|
+
<Text type="body">
|
|
848
|
+
Hosting grimoire
|
|
939
849
|
</Text>
|
|
940
|
-
<Text type="
|
|
850
|
+
<Text type="body" color="secondary">
|
|
941
851
|
Manage multiple listings, route tasks to co-hosts, and
|
|
942
852
|
review consolidated payouts from one place.
|
|
943
853
|
</Text>
|