astryx-dracula 0.4.0 → 0.5.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/package.json +6 -2
- package/shared/auth-chrome.tsx +156 -6
- package/shared/chaptered-doc.tsx +3 -4
- package/shared/chart-hues.ts +0 -5
- package/shared/chart-legend.tsx +2 -3
- package/shared/data-bar.tsx +5 -5
- package/shared/format-money.ts +3 -0
- package/shared/metric-card.tsx +127 -0
- package/shared/scene-hues.ts +0 -8
- package/shared/scene-tile.tsx +3 -11
- package/shared/settings-data.ts +28 -0
- package/shared/settings-rows.tsx +1 -6
- package/shared/stars.tsx +28 -0
- package/templates/ai-chat-landing.tsx +88 -58
- package/templates/ai-chat.tsx +65 -78
- package/templates/centered-hero.tsx +2 -2
- package/templates/dashboard-portfolio.tsx +77 -155
- package/templates/dashboard.tsx +17 -134
- package/templates/detail-page.tsx +14 -18
- package/templates/documentation-design.tsx +66 -519
- package/templates/documentation-technical.tsx +2 -22
- package/templates/editor.tsx +168 -185
- package/templates/file-explorer.tsx +10 -24
- package/templates/ide.tsx +12 -18
- package/templates/incident-console.tsx +48 -46
- package/templates/kanban-board.tsx +36 -85
- package/templates/library.tsx +42 -66
- package/templates/login-card.tsx +33 -126
- package/templates/login-split.tsx +91 -123
- package/templates/login-sso.tsx +12 -33
- package/templates/login.tsx +21 -121
- package/templates/messaging-shell.tsx +162 -168
- package/templates/payment-form.tsx +24 -26
- package/templates/product-detail.tsx +7 -40
- package/templates/product-tour.tsx +38 -60
- package/templates/settings-dialog.tsx +10 -32
- package/templates/settings-sidebar.tsx +44 -77
- package/templates/settings.tsx +208 -121
- package/templates/shell-nav.tsx +20 -75
- package/templates/shell-side-nav.tsx +16 -90
- package/templates/shell-top-nav.tsx +20 -53
- package/templates/side-gallery.tsx +19 -19
- package/templates/table-grouped.tsx +17 -164
- package/templates/table-page-chart.tsx +12 -11
- package/templates/table-page-heatmap-status.tsx +0 -17
- package/templates/table-page-shoe-store-heatmap.tsx +12 -12
- package/templates/table-page.tsx +4 -31
- package/templates/table.tsx +7 -10
- package/templates/tech-report.tsx +58 -72
- package/templates/theme-showcase.tsx +124 -415
package/templates/login-card.tsx
CHANGED
|
@@ -6,31 +6,16 @@ import {useState, useTransition} from 'react';
|
|
|
6
6
|
import {demoLogin} from 'astryx-dracula/shared/login-demo';
|
|
7
7
|
import {AppleIcon, GoogleIcon} from 'astryx-dracula/shared/sso-icons';
|
|
8
8
|
import {
|
|
9
|
-
AUTH_HEADING,
|
|
10
|
-
AUTH_SUBTITLE,
|
|
11
|
-
AUTH_PRIMARY_CTA,
|
|
12
|
-
AUTH_SIGNUP_PROMPT,
|
|
13
|
-
AUTH_SIGNUP_LINK,
|
|
14
9
|
AUTH_SSO_DIVIDER,
|
|
15
|
-
AUTH_FORGOT_PASSWORD,
|
|
16
10
|
AUTH_ERROR_MESSAGE,
|
|
17
|
-
AUTH_EMAIL_PLACEHOLDER,
|
|
18
|
-
AUTH_PASSWORD_PLACEHOLDER,
|
|
19
|
-
AUTH_TERMS_PREFIX,
|
|
20
|
-
AUTH_TERMS_SERVICE,
|
|
21
|
-
AUTH_TERMS_PRIVACY,
|
|
22
11
|
} from 'astryx-dracula/shared/auth-copy';
|
|
23
12
|
import {VStack} from '@astryxdesign/core/Layout';
|
|
24
13
|
import {Center} from '@astryxdesign/core/Center';
|
|
25
|
-
import {Text, Heading} from '@astryxdesign/core/Text';
|
|
26
|
-
import {TextInput} from '@astryxdesign/core/TextInput';
|
|
27
14
|
import {Button} from '@astryxdesign/core/Button';
|
|
28
|
-
import {Card} from '@astryxdesign/core/Card';
|
|
29
|
-
import {Link} from '@astryxdesign/core/Link';
|
|
30
15
|
import {Divider} from '@astryxdesign/core/Divider';
|
|
31
16
|
|
|
32
|
-
import {authPageStyle as pageStyle, authContentStyle as contentStyle
|
|
33
|
-
import {LoginBrand} from 'astryx-dracula/shared/auth-chrome';
|
|
17
|
+
import {authPageStyle as pageStyle, authContentStyle as contentStyle} from 'astryx-dracula/shared/auth-chrome-config';
|
|
18
|
+
import {LoginBrand, AuthCard, AuthLoginFields} from 'astryx-dracula/shared/auth-chrome';
|
|
34
19
|
|
|
35
20
|
export default function LoginCard() {
|
|
36
21
|
const [email, setEmail] = useState('');
|
|
@@ -55,121 +40,43 @@ export default function LoginCard() {
|
|
|
55
40
|
<VStack gap={4} hAlign="center" style={contentStyle}>
|
|
56
41
|
<LoginBrand />
|
|
57
42
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
43
|
+
<AuthCard selfHash="#/templates/login-card">
|
|
44
|
+
<AuthLoginFields
|
|
45
|
+
email={email}
|
|
46
|
+
password={password}
|
|
47
|
+
error={error}
|
|
48
|
+
selfHash="#/templates/login-card"
|
|
49
|
+
isLoading={isLoading}
|
|
50
|
+
onEmailChange={(v: string) => {
|
|
51
|
+
setEmail(v);
|
|
52
|
+
setError(null);
|
|
53
|
+
}}
|
|
54
|
+
onPasswordChange={(v: string) => {
|
|
55
|
+
setPassword(v);
|
|
56
|
+
setError(null);
|
|
57
|
+
}}
|
|
58
|
+
onSubmit={handleLogin}
|
|
59
|
+
/>
|
|
70
60
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
<TextInput
|
|
74
|
-
label="Email"
|
|
75
|
-
isLabelHidden
|
|
76
|
-
type="email"
|
|
77
|
-
{...inputAutoComplete('email')}
|
|
78
|
-
placeholder={AUTH_EMAIL_PLACEHOLDER}
|
|
79
|
-
value={email}
|
|
80
|
-
onChange={(v: string) => {
|
|
81
|
-
setEmail(v);
|
|
82
|
-
setError(null);
|
|
83
|
-
}}
|
|
84
|
-
size="lg"
|
|
85
|
-
onEnter={handleLogin}
|
|
86
|
-
status={error ? {type: 'error', message: error} : undefined}
|
|
87
|
-
/>
|
|
88
|
-
<VStack gap={1}>
|
|
89
|
-
<TextInput
|
|
90
|
-
label="Password"
|
|
91
|
-
isLabelHidden
|
|
92
|
-
placeholder={AUTH_PASSWORD_PLACEHOLDER}
|
|
93
|
-
type="password"
|
|
94
|
-
{...inputAutoComplete('current-password')}
|
|
95
|
-
value={password}
|
|
96
|
-
onChange={(v: string) => {
|
|
97
|
-
setPassword(v);
|
|
98
|
-
setError(null);
|
|
99
|
-
}}
|
|
100
|
-
size="lg"
|
|
101
|
-
onEnter={handleLogin}
|
|
102
|
-
status={error ? {type: 'error', message: error} : undefined}
|
|
103
|
-
/>
|
|
104
|
-
{error && (
|
|
105
|
-
<VStack hAlign="end">
|
|
106
|
-
<Link
|
|
107
|
-
href="#/templates/login-card"
|
|
108
|
-
color="secondary"
|
|
109
|
-
isStandalone>
|
|
110
|
-
{AUTH_FORGOT_PASSWORD}
|
|
111
|
-
</Link>
|
|
112
|
-
</VStack>
|
|
113
|
-
)}
|
|
114
|
-
</VStack>
|
|
115
|
-
</VStack>
|
|
61
|
+
{/* Divider */}
|
|
62
|
+
<Divider label={AUTH_SSO_DIVIDER} />
|
|
116
63
|
|
|
117
|
-
|
|
64
|
+
{/* Social buttons */}
|
|
65
|
+
<VStack gap={3} hAlign="stretch">
|
|
118
66
|
<Button
|
|
119
|
-
label=
|
|
120
|
-
variant="
|
|
67
|
+
label="Login with Apple"
|
|
68
|
+
variant="secondary"
|
|
69
|
+
icon={<AppleIcon />}
|
|
70
|
+
size="lg"
|
|
71
|
+
/>
|
|
72
|
+
<Button
|
|
73
|
+
label="Login with Google"
|
|
74
|
+
variant="secondary"
|
|
75
|
+
icon={<GoogleIcon />}
|
|
121
76
|
size="lg"
|
|
122
|
-
isLoading={isLoading}
|
|
123
|
-
onClick={handleLogin}
|
|
124
77
|
/>
|
|
125
|
-
|
|
126
|
-
{/* Divider */}
|
|
127
|
-
<Divider label={AUTH_SSO_DIVIDER} />
|
|
128
|
-
|
|
129
|
-
{/* Social buttons */}
|
|
130
|
-
<VStack gap={3} hAlign="stretch">
|
|
131
|
-
<Button
|
|
132
|
-
label="Login with Apple"
|
|
133
|
-
variant="secondary"
|
|
134
|
-
icon={<AppleIcon />}
|
|
135
|
-
size="lg"
|
|
136
|
-
/>
|
|
137
|
-
<Button
|
|
138
|
-
label="Login with Google"
|
|
139
|
-
variant="secondary"
|
|
140
|
-
icon={<GoogleIcon />}
|
|
141
|
-
size="lg"
|
|
142
|
-
/>
|
|
143
|
-
</VStack>
|
|
144
|
-
|
|
145
|
-
{/* Prose links. A link inside a sentence needs a persistent
|
|
146
|
-
underline — colour alone is not a cue (WCAG 1.4.1 / F73),
|
|
147
|
-
and the kit underlines on hover only. */}
|
|
148
|
-
<VStack hAlign="center">
|
|
149
|
-
<Text type="supporting" color="secondary">
|
|
150
|
-
{AUTH_SIGNUP_PROMPT}{' '}
|
|
151
|
-
<Link href="#/templates/login-card" type="supporting" hasUnderline>
|
|
152
|
-
{AUTH_SIGNUP_LINK}
|
|
153
|
-
</Link>
|
|
154
|
-
</Text>
|
|
155
|
-
</VStack>
|
|
156
78
|
</VStack>
|
|
157
|
-
</
|
|
158
|
-
|
|
159
|
-
{/* Terms */}
|
|
160
|
-
<VStack hAlign="center" width="100%">
|
|
161
|
-
<Text type="supporting" color="secondary" justify="center">
|
|
162
|
-
{AUTH_TERMS_PREFIX}{' '}
|
|
163
|
-
<Link href="#/templates/login-card" type="supporting" hasUnderline>
|
|
164
|
-
{AUTH_TERMS_SERVICE}
|
|
165
|
-
</Link>{' '}
|
|
166
|
-
and{' '}
|
|
167
|
-
<Link href="#/templates/login-card" type="supporting" hasUnderline>
|
|
168
|
-
{AUTH_TERMS_PRIVACY}
|
|
169
|
-
</Link>
|
|
170
|
-
.
|
|
171
|
-
</Text>
|
|
172
|
-
</VStack>
|
|
79
|
+
</AuthCard>
|
|
173
80
|
</VStack>
|
|
174
81
|
</Center>
|
|
175
82
|
);
|
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
3
3
|
// Ctr > V[g=4] > (Ctr.horizontal > C[p=0] > G[c={min:240} g=8 a=stretch] > (S[p=0] > V[g=4] > (H[g=2 a=center] > Ic + Tx"Castle Dracula"[t=body]) + (V[g=4] > (V[g=1] > Hd"Welcome back to the night"[level=1] + Tx"Sign in to your crypt"[t=body]) + (V[g=2] > TI"Email"[t=email] + (V[g=1] > TI"Password"[t=password] + Lk"Forgot password?")) + B.primary"Enter the night" + D"Or continue with" + (G[c={min:200} g=3] > B.secondary"Login with Apple" + B.secondary"Login with Google")) + (V[a=center] > Tx"New to the castle?"[t=supporting] + Lk"Sign up")) + (C[p=0] > AR)) + (V[a=center] > Tx"By clicking continue, you agree to our Terms of service and Privacy policy"[t=supporting])
|
|
4
4
|
|
|
5
|
-
import {useState, useTransition
|
|
6
|
-
import {inputAutoComplete} from 'astryx-dracula/shared/auth-chrome-config';
|
|
5
|
+
import {useState, useTransition} from 'react';
|
|
6
|
+
import {authPageStyle, inputAutoComplete} from 'astryx-dracula/shared/auth-chrome-config';
|
|
7
7
|
import {demoLogin} from 'astryx-dracula/shared/login-demo';
|
|
8
8
|
import {AppleIcon, GoogleIcon} from 'astryx-dracula/shared/sso-icons';
|
|
9
9
|
import {
|
|
10
10
|
AUTH_HEADING,
|
|
11
11
|
AUTH_SUBTITLE,
|
|
12
12
|
AUTH_PRIMARY_CTA,
|
|
13
|
-
AUTH_SIGNUP_PROMPT,
|
|
14
|
-
AUTH_SIGNUP_LINK,
|
|
15
13
|
AUTH_SSO_DIVIDER,
|
|
16
14
|
AUTH_FORGOT_PASSWORD,
|
|
17
15
|
AUTH_ERROR_MESSAGE,
|
|
18
16
|
AUTH_EMAIL_PLACEHOLDER,
|
|
19
17
|
AUTH_PASSWORD_PLACEHOLDER,
|
|
20
18
|
AUTH_BRAND_NAME,
|
|
19
|
+
AUTH_SIGNUP_PROMPT,
|
|
20
|
+
AUTH_SIGNUP_LINK,
|
|
21
21
|
AUTH_TERMS_PREFIX,
|
|
22
22
|
AUTH_TERMS_SERVICE,
|
|
23
23
|
AUTH_TERMS_PRIVACY,
|
|
@@ -30,40 +30,23 @@ import {Card} from '@astryxdesign/core/Card';
|
|
|
30
30
|
import {Section} from '@astryxdesign/core/Section';
|
|
31
31
|
import {Text, Heading} from '@astryxdesign/core/Text';
|
|
32
32
|
import {Icon} from '@astryxdesign/core/Icon';
|
|
33
|
-
import {EmptyState} from '@astryxdesign/core/EmptyState';
|
|
34
33
|
import {TextInput} from '@astryxdesign/core/TextInput';
|
|
35
34
|
import {Button} from '@astryxdesign/core/Button';
|
|
36
35
|
import {Link} from '@astryxdesign/core/Link';
|
|
37
36
|
import {Divider} from '@astryxdesign/core/Divider';
|
|
38
37
|
|
|
39
38
|
// ============= ICONS (verified lucide-react exports) =============
|
|
40
|
-
// Moon is the castle brand mark (see login, login-card)
|
|
41
|
-
|
|
42
|
-
import {Moon, CircleCheck} from 'lucide-react';
|
|
39
|
+
// Moon is the castle brand mark (see login, login-card).
|
|
40
|
+
import {Moon} from 'lucide-react';
|
|
43
41
|
|
|
44
42
|
// Cover art lives in shared/scene-castle (`rooftops` variant:
|
|
45
43
|
// crescent-overlay moon over a rooftop skyline). The transparent Card clips
|
|
46
44
|
// it to rounded corners (overflow:clip + radius), so the art needs no radius.
|
|
47
|
-
|
|
48
|
-
// grid inset and page padding must fit the narrowest phone or the column is
|
|
49
|
-
// clipped. 320 − 2×24 (page) − 2×16 (stacked inset) = 240.
|
|
50
|
-
const COLUMN_MIN_WIDTH = 240;
|
|
51
|
-
// repeat:'fit' (auto-fit) collapses the two columns to one — expanding to fill —
|
|
52
|
-
// below 2×MIN + 32(gap) = 512px. The container query reorders the image and
|
|
53
|
-
// tightens the inset at that same point, keyed to the card width (not the
|
|
54
|
-
// window) so it never desyncs.
|
|
55
|
-
// minHeight:100% fills the host so the centered card never leaves an unpainted
|
|
56
|
-
// band; padding keeps it off the surface edges.
|
|
57
|
-
const pageStyle: CSSProperties = {
|
|
58
|
-
minHeight: '100%',
|
|
59
|
-
backgroundColor: 'var(--color-background-body)',
|
|
60
|
-
padding: 'var(--spacing-6)',
|
|
61
|
-
};
|
|
62
|
-
const cardWrap: CSSProperties = {
|
|
45
|
+
const cardWrap = {
|
|
63
46
|
width: '100%',
|
|
64
47
|
maxWidth: 1000,
|
|
65
48
|
marginInline: 'auto',
|
|
66
|
-
};
|
|
49
|
+
} as const;
|
|
67
50
|
|
|
68
51
|
// The container query lives in a plain <style> tag so it needs NO CSS compiler.
|
|
69
52
|
// - Pad the grid, not the Card: the form's Section escapes Card's
|
|
@@ -72,6 +55,9 @@ const cardWrap: CSSProperties = {
|
|
|
72
55
|
// - repeat:'fit' (auto-fit) collapses the two columns to one below 511px; the
|
|
73
56
|
// query reorders the image (order:-1) and tightens the inset at that point,
|
|
74
57
|
// keyed to the card width (not the window) so it never desyncs.
|
|
58
|
+
// Grid emits minmax(240, 1fr) where 240 is a hard floor, so MIN plus the grid
|
|
59
|
+
// inset and page padding must fit the narrowest phone: 320 − 2×24 (page) −
|
|
60
|
+
// 2×16 (stacked inset) = 240.
|
|
75
61
|
const LOGIN_SPLIT_CSS = `
|
|
76
62
|
.login-split-grid {
|
|
77
63
|
container-type: inline-size;
|
|
@@ -97,7 +83,6 @@ export default function LoginSplit() {
|
|
|
97
83
|
const [password, setPassword] = useState('');
|
|
98
84
|
const [error, setError] = useState<string | null>(null);
|
|
99
85
|
const [isLoading, startTransition] = useTransition();
|
|
100
|
-
const [isSuccess, setIsSuccess] = useState(false);
|
|
101
86
|
|
|
102
87
|
const handleLogin = () => {
|
|
103
88
|
if (!email || !password) {
|
|
@@ -107,18 +92,17 @@ export default function LoginSplit() {
|
|
|
107
92
|
setError(null);
|
|
108
93
|
startTransition(async () => {
|
|
109
94
|
await demoLogin();
|
|
110
|
-
setIsSuccess(true);
|
|
111
95
|
});
|
|
112
96
|
};
|
|
113
97
|
|
|
114
98
|
return (
|
|
115
|
-
<Center axis="both" style={
|
|
99
|
+
<Center axis="both" style={authPageStyle}>
|
|
116
100
|
<style>{LOGIN_SPLIT_CSS}</style>
|
|
117
101
|
<VStack gap={4} width="100%">
|
|
118
102
|
<Center axis="horizontal" style={cardWrap}>
|
|
119
103
|
<Card padding={0} width="100%">
|
|
120
104
|
<Grid
|
|
121
|
-
columns={{minWidth:
|
|
105
|
+
columns={{minWidth: 240, repeat: 'fit'}}
|
|
122
106
|
gap={8}
|
|
123
107
|
align="stretch"
|
|
124
108
|
className="login-split-grid">
|
|
@@ -134,105 +118,91 @@ export default function LoginSplit() {
|
|
|
134
118
|
|
|
135
119
|
<StackItem size="fill">
|
|
136
120
|
<Center axis="vertical" height="100%">
|
|
137
|
-
{
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
/>
|
|
147
|
-
}
|
|
148
|
-
/>
|
|
149
|
-
) : (
|
|
150
|
-
<VStack gap={4} hAlign="stretch" width="100%">
|
|
151
|
-
<VStack gap={1}>
|
|
152
|
-
<Heading level={1} type="display-2">
|
|
153
|
-
{AUTH_HEADING}
|
|
154
|
-
</Heading>
|
|
155
|
-
<Text type="body" color="secondary">
|
|
156
|
-
{AUTH_SUBTITLE}
|
|
157
|
-
</Text>
|
|
158
|
-
</VStack>
|
|
121
|
+
<VStack gap={4} hAlign="stretch" width="100%">
|
|
122
|
+
<VStack gap={1}>
|
|
123
|
+
<Heading level={1} type="display-2">
|
|
124
|
+
{AUTH_HEADING}
|
|
125
|
+
</Heading>
|
|
126
|
+
<Text type="body" color="secondary">
|
|
127
|
+
{AUTH_SUBTITLE}
|
|
128
|
+
</Text>
|
|
129
|
+
</VStack>
|
|
159
130
|
|
|
160
|
-
|
|
131
|
+
<VStack gap={2}>
|
|
132
|
+
<TextInput
|
|
133
|
+
label="Email"
|
|
134
|
+
isLabelHidden
|
|
135
|
+
type="email"
|
|
136
|
+
{...inputAutoComplete('email')}
|
|
137
|
+
placeholder={AUTH_EMAIL_PLACEHOLDER}
|
|
138
|
+
value={email}
|
|
139
|
+
onChange={(v: string) => {
|
|
140
|
+
setEmail(v);
|
|
141
|
+
setError(null);
|
|
142
|
+
}}
|
|
143
|
+
size="lg"
|
|
144
|
+
onEnter={handleLogin}
|
|
145
|
+
status={error ? {type: 'error', message: error} : undefined}
|
|
146
|
+
/>
|
|
147
|
+
<VStack gap={1}>
|
|
161
148
|
<TextInput
|
|
162
|
-
label="
|
|
149
|
+
label="Password"
|
|
163
150
|
isLabelHidden
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
value={
|
|
151
|
+
placeholder={AUTH_PASSWORD_PLACEHOLDER}
|
|
152
|
+
type="password"
|
|
153
|
+
{...inputAutoComplete('current-password')}
|
|
154
|
+
value={password}
|
|
168
155
|
onChange={(v: string) => {
|
|
169
|
-
|
|
156
|
+
setPassword(v);
|
|
170
157
|
setError(null);
|
|
171
158
|
}}
|
|
172
159
|
size="lg"
|
|
173
160
|
onEnter={handleLogin}
|
|
174
161
|
status={error ? {type: 'error', message: error} : undefined}
|
|
175
162
|
/>
|
|
176
|
-
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
setPassword(v);
|
|
186
|
-
setError(null);
|
|
187
|
-
}}
|
|
188
|
-
size="lg"
|
|
189
|
-
onEnter={handleLogin}
|
|
190
|
-
status={error ? {type: 'error', message: error} : undefined}
|
|
191
|
-
/>
|
|
192
|
-
{error && (
|
|
193
|
-
<VStack hAlign="end">
|
|
194
|
-
<Link
|
|
195
|
-
href="#/templates/login-split"
|
|
196
|
-
isStandalone>
|
|
197
|
-
{AUTH_FORGOT_PASSWORD}
|
|
198
|
-
</Link>
|
|
199
|
-
</VStack>
|
|
200
|
-
)}
|
|
201
|
-
</VStack>
|
|
163
|
+
{error && (
|
|
164
|
+
<VStack hAlign="end">
|
|
165
|
+
<Link
|
|
166
|
+
href="#/templates/login-split"
|
|
167
|
+
isStandalone>
|
|
168
|
+
{AUTH_FORGOT_PASSWORD}
|
|
169
|
+
</Link>
|
|
170
|
+
</VStack>
|
|
171
|
+
)}
|
|
202
172
|
</VStack>
|
|
173
|
+
</VStack>
|
|
203
174
|
|
|
175
|
+
<Button
|
|
176
|
+
label={AUTH_PRIMARY_CTA}
|
|
177
|
+
variant="primary"
|
|
178
|
+
size="lg"
|
|
179
|
+
isLoading={isLoading}
|
|
180
|
+
onClick={handleLogin}
|
|
181
|
+
/>
|
|
182
|
+
|
|
183
|
+
<Divider label={AUTH_SSO_DIVIDER} />
|
|
184
|
+
|
|
185
|
+
{/* minWidth (not a fixed 2-up) so the pair stacks inside
|
|
186
|
+
the narrow single-column container instead of
|
|
187
|
+
giving each button ~114px for an icon + label. */}
|
|
188
|
+
<Grid
|
|
189
|
+
columns={{minWidth: 200, repeat: 'fit'}}
|
|
190
|
+
gap={3}
|
|
191
|
+
justify="stretch">
|
|
204
192
|
<Button
|
|
205
|
-
label=
|
|
206
|
-
variant="
|
|
193
|
+
label="Login with Apple"
|
|
194
|
+
variant="secondary"
|
|
195
|
+
icon={<AppleIcon />}
|
|
207
196
|
size="lg"
|
|
208
|
-
isLoading={isLoading}
|
|
209
|
-
onClick={handleLogin}
|
|
210
197
|
/>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
gap={3}
|
|
220
|
-
justify="stretch">
|
|
221
|
-
<Button
|
|
222
|
-
label="Login with Apple"
|
|
223
|
-
variant="secondary"
|
|
224
|
-
icon={<AppleIcon />}
|
|
225
|
-
size="lg"
|
|
226
|
-
/>
|
|
227
|
-
<Button
|
|
228
|
-
label="Login with Google"
|
|
229
|
-
variant="secondary"
|
|
230
|
-
icon={<GoogleIcon />}
|
|
231
|
-
size="lg"
|
|
232
|
-
/>
|
|
233
|
-
</Grid>
|
|
234
|
-
</VStack>
|
|
235
|
-
)}
|
|
198
|
+
<Button
|
|
199
|
+
label="Login with Google"
|
|
200
|
+
variant="secondary"
|
|
201
|
+
icon={<GoogleIcon />}
|
|
202
|
+
size="lg"
|
|
203
|
+
/>
|
|
204
|
+
</Grid>
|
|
205
|
+
</VStack>
|
|
236
206
|
</Center>
|
|
237
207
|
</StackItem>
|
|
238
208
|
|
|
@@ -241,16 +211,14 @@ export default function LoginSplit() {
|
|
|
241
211
|
only gives on hover. The VStack centres the line, as the
|
|
242
212
|
other three login templates do — it was sitting flush
|
|
243
213
|
left under a left-aligned form. */}
|
|
244
|
-
|
|
245
|
-
<
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
</VStack>
|
|
253
|
-
)}
|
|
214
|
+
<VStack hAlign="center">
|
|
215
|
+
<Text type="supporting" color="secondary">
|
|
216
|
+
{AUTH_SIGNUP_PROMPT}{' '}
|
|
217
|
+
<Link href="#/templates/login-split" type="supporting" hasUnderline>
|
|
218
|
+
{AUTH_SIGNUP_LINK}
|
|
219
|
+
</Link>
|
|
220
|
+
</Text>
|
|
221
|
+
</VStack>
|
|
254
222
|
</VStack>
|
|
255
223
|
</Section>
|
|
256
224
|
|
package/templates/login-sso.tsx
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// Step-conditional h1: the email and SSO-confirm steps each render their own
|
|
6
6
|
// h1 (email entry vs provider confirm); the password fallback reuses the
|
|
7
7
|
// family heading, so exactly one h1 shows per step.
|
|
8
|
-
import {useState, useTransition
|
|
8
|
+
import {useState, useTransition} from 'react';
|
|
9
|
+
import {authPageStyle as pageStyle, inputAutoComplete} from 'astryx-dracula/shared/auth-chrome-config';
|
|
9
10
|
import {demoLogin} from 'astryx-dracula/shared/login-demo';
|
|
10
11
|
import {
|
|
11
12
|
AUTH_HEADING,
|
|
@@ -25,7 +26,6 @@ import {Text, Heading} from '@astryxdesign/core/Text';
|
|
|
25
26
|
import {TextInput} from '@astryxdesign/core/TextInput';
|
|
26
27
|
import {Button} from '@astryxdesign/core/Button';
|
|
27
28
|
import {Card} from '@astryxdesign/core/Card';
|
|
28
|
-
import {Section} from '@astryxdesign/core/Section';
|
|
29
29
|
import {Link} from '@astryxdesign/core/Link';
|
|
30
30
|
import {Divider} from '@astryxdesign/core/Divider';
|
|
31
31
|
import {Icon} from '@astryxdesign/core/Icon';
|
|
@@ -34,18 +34,6 @@ import {Avatar} from '@astryxdesign/core/Avatar';
|
|
|
34
34
|
// ============= ICONS (verified lucide-react exports) =============
|
|
35
35
|
// ShieldCheck ← ShieldCheckIcon.
|
|
36
36
|
import {ShieldCheck} from 'lucide-react';
|
|
37
|
-
import {inputAutoComplete} from 'astryx-dracula/shared/auth-chrome-config';
|
|
38
|
-
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
// Styles
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
|
|
43
|
-
// Standalone auth page paints its own body background (no host shell).
|
|
44
|
-
const pageStyle: CSSProperties = {
|
|
45
|
-
minHeight: '100%',
|
|
46
|
-
backgroundColor: 'var(--color-background-body)',
|
|
47
|
-
padding: 'var(--spacing-6)',
|
|
48
|
-
};
|
|
49
37
|
|
|
50
38
|
type SSOProvider = {
|
|
51
39
|
name: string;
|
|
@@ -208,25 +196,16 @@ export default function LoginSso() {
|
|
|
208
196
|
</Text>
|
|
209
197
|
</VStack>
|
|
210
198
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
<Icon icon={ShieldCheck} color="secondary" />
|
|
222
|
-
<VStack gap={0}>
|
|
223
|
-
<Text type="label">{provider.name}</Text>
|
|
224
|
-
<Text type="supporting" color="secondary">
|
|
225
|
-
{email}
|
|
226
|
-
</Text>
|
|
227
|
-
</VStack>
|
|
228
|
-
</HStack>
|
|
229
|
-
</Section>
|
|
199
|
+
<Card padding={4} variant="muted">
|
|
200
|
+
<HStack gap={2} vAlign="center">
|
|
201
|
+
<Icon icon={ShieldCheck} color="secondary" />
|
|
202
|
+
<VStack gap={0}>
|
|
203
|
+
<Text type="label">{provider.name}</Text>
|
|
204
|
+
<Text type="supporting" color="secondary">
|
|
205
|
+
{email}
|
|
206
|
+
</Text>
|
|
207
|
+
</VStack>
|
|
208
|
+
</HStack>
|
|
230
209
|
</Card>
|
|
231
210
|
|
|
232
211
|
<VStack gap={3}>
|