astryx-dracula 0.5.0 → 0.6.2

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.
Files changed (129) hide show
  1. package/BRAND.md +3 -3
  2. package/README.md +7 -4
  3. package/USAGE.md +49 -49
  4. package/astryx-dracula.d.ts +2 -2
  5. package/astryx-dracula.js +25 -9
  6. package/astryx-dracula.variants.d.ts +2 -2
  7. package/astryx.integration.mjs +1 -1
  8. package/icons.mjs +21 -17
  9. package/icons.tsx +69 -62
  10. package/package.json +125 -120
  11. package/shared/auth-chrome-config.ts +6 -6
  12. package/shared/auth-chrome.tsx +143 -144
  13. package/shared/auth-copy.ts +14 -14
  14. package/shared/chaptered-doc-config.ts +48 -51
  15. package/shared/chaptered-doc.tsx +267 -289
  16. package/shared/chart-hues.ts +25 -10
  17. package/shared/chart-labels.tsx +31 -30
  18. package/shared/chart-legend.tsx +55 -56
  19. package/shared/chart-panel-style.ts +3 -3
  20. package/shared/data-bar.tsx +97 -102
  21. package/shared/format-money.ts +1 -1
  22. package/shared/gallery-image.ts +6 -6
  23. package/shared/login-demo.ts +1 -1
  24. package/shared/metric-card.tsx +101 -105
  25. package/shared/metric-delta.tsx +28 -27
  26. package/shared/order-desk.tsx +205 -216
  27. package/shared/revenue-chart.tsx +145 -165
  28. package/shared/scene-castle.tsx +206 -291
  29. package/shared/scene-frame.tsx +33 -32
  30. package/shared/scene-hues.ts +17 -17
  31. package/shared/scene-tile.tsx +88 -92
  32. package/shared/settings-data.ts +119 -125
  33. package/shared/settings-rows.tsx +122 -159
  34. package/shared/sparkline.tsx +75 -88
  35. package/shared/sso-icons.tsx +10 -22
  36. package/shared/stars.tsx +16 -25
  37. package/templates/ai-chat-landing.template.mjs +5 -4
  38. package/templates/ai-chat-landing.tsx +473 -460
  39. package/templates/ai-chat.template.mjs +5 -4
  40. package/templates/ai-chat.tsx +543 -612
  41. package/templates/blank.template.mjs +5 -4
  42. package/templates/blank.tsx +18 -14
  43. package/templates/centered-hero.template.mjs +5 -4
  44. package/templates/centered-hero.tsx +55 -68
  45. package/templates/classic-gallery.template.mjs +5 -4
  46. package/templates/classic-gallery.tsx +97 -104
  47. package/templates/contact-form.template.mjs +5 -4
  48. package/templates/contact-form.tsx +247 -282
  49. package/templates/dashboard-portfolio.template.mjs +5 -4
  50. package/templates/dashboard-portfolio.tsx +717 -548
  51. package/templates/dashboard.template.mjs +5 -4
  52. package/templates/dashboard.tsx +596 -567
  53. package/templates/detail-page.template.mjs +5 -4
  54. package/templates/detail-page.tsx +546 -603
  55. package/templates/documentation-design.template.mjs +5 -4
  56. package/templates/documentation-design.tsx +231 -243
  57. package/templates/documentation-technical.template.mjs +5 -4
  58. package/templates/documentation-technical.tsx +236 -239
  59. package/templates/documentation.template.mjs +5 -4
  60. package/templates/documentation.tsx +267 -279
  61. package/templates/editor.template.mjs +5 -4
  62. package/templates/editor.tsx +844 -877
  63. package/templates/file-explorer.template.mjs +5 -4
  64. package/templates/file-explorer.tsx +566 -590
  65. package/templates/form-two-column.template.mjs +5 -4
  66. package/templates/form-two-column.tsx +195 -210
  67. package/templates/gallery-hero.template.mjs +5 -4
  68. package/templates/gallery-hero.tsx +93 -114
  69. package/templates/ide.template.mjs +5 -4
  70. package/templates/ide.tsx +407 -453
  71. package/templates/incident-console.template.mjs +5 -4
  72. package/templates/incident-console.tsx +593 -575
  73. package/templates/kanban-board.template.mjs +5 -4
  74. package/templates/kanban-board.tsx +665 -683
  75. package/templates/library.template.mjs +5 -4
  76. package/templates/library.tsx +409 -430
  77. package/templates/login-card.template.mjs +5 -4
  78. package/templates/login-card.tsx +63 -72
  79. package/templates/login-split.template.mjs +5 -4
  80. package/templates/login-split.tsx +192 -193
  81. package/templates/login-sso.template.mjs +5 -4
  82. package/templates/login-sso.tsx +257 -258
  83. package/templates/login.template.mjs +5 -4
  84. package/templates/login.tsx +53 -49
  85. package/templates/messaging-shell.template.mjs +5 -4
  86. package/templates/messaging-shell.tsx +556 -574
  87. package/templates/mixed-gallery.template.mjs +5 -4
  88. package/templates/mixed-gallery.tsx +60 -58
  89. package/templates/payment-form.template.mjs +5 -4
  90. package/templates/payment-form.tsx +882 -991
  91. package/templates/product-detail.template.mjs +5 -4
  92. package/templates/product-detail.tsx +261 -272
  93. package/templates/product-gallery.template.mjs +5 -4
  94. package/templates/product-gallery.tsx +126 -137
  95. package/templates/product-tour.template.mjs +5 -4
  96. package/templates/product-tour.tsx +741 -773
  97. package/templates/settings-dialog.template.mjs +5 -4
  98. package/templates/settings-dialog.tsx +688 -717
  99. package/templates/settings-sidebar.template.mjs +5 -4
  100. package/templates/settings-sidebar.tsx +762 -807
  101. package/templates/settings.template.mjs +5 -4
  102. package/templates/settings.tsx +289 -304
  103. package/templates/shell-nav.template.mjs +5 -4
  104. package/templates/shell-nav.tsx +212 -219
  105. package/templates/shell-side-nav.template.mjs +5 -4
  106. package/templates/shell-side-nav.tsx +135 -157
  107. package/templates/shell-top-nav.template.mjs +5 -4
  108. package/templates/shell-top-nav.tsx +182 -203
  109. package/templates/side-gallery.template.mjs +5 -4
  110. package/templates/side-gallery.tsx +85 -90
  111. package/templates/table-grouped.template.mjs +5 -4
  112. package/templates/table-grouped.tsx +1000 -1053
  113. package/templates/table-page-chart.template.mjs +5 -4
  114. package/templates/table-page-chart.tsx +400 -398
  115. package/templates/table-page-heatmap-status.template.mjs +5 -4
  116. package/templates/table-page-heatmap-status.tsx +483 -512
  117. package/templates/table-page-shoe-store-heatmap.template.mjs +5 -4
  118. package/templates/table-page-shoe-store-heatmap.tsx +748 -746
  119. package/templates/table-page.template.mjs +5 -4
  120. package/templates/table-page.tsx +396 -405
  121. package/templates/table.template.mjs +5 -4
  122. package/templates/table.tsx +92 -93
  123. package/templates/tech-report.template.mjs +5 -4
  124. package/templates/tech-report.tsx +1316 -1304
  125. package/templates/theme-showcase.template.mjs +5 -4
  126. package/templates/theme-showcase.tsx +871 -951
  127. package/theme.css +35 -77
  128. package/theme.css.d.ts +9 -0
  129. package/tokens.css +373 -380
@@ -1,311 +1,310 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // Ctr > C[p=4 mw=400] > V[g=4] > ((V[g=1 a=center] > Hd"Welcome back to the night"[level=1] + Tx"Whisper your details to enter the night"[t=body]) + (V[g=1] > TI"Work email"[t=email] + Lk"Having trouble signing in?") + B.primary"Continue" + D"Or continue with" + B.secondary"Continue with SSO" + (V[a=center] > Tx"New to the castle?"[t=supporting] + Lk"Request access") + (V[g=2 a=center] > Av + Hd"Sign in with Google Workspace"[level=1] + Tx"You will be redirected back after signing in."[t=body]) + (C[p=0] > S[p=4 muted] > (H[g=2 a=center] > Ic + (V[g=0] > Tx"Google Workspace"[t=label] + Tx"vlad@castle.ro"[t=supporting]))) + (V[g=3] > B.primary"Continue with Google Workspace" + B.ghost"Use a different email") + (V[g=1 a=center] > Hd"Welcome back to the night"[level=1] + Tx"vlad@castle.ro"[t=body]) + (V[g=4] > (V[g=1] > TI"Password"[t=password] + Lk"Forgot password?") + (V[g=3] > B.primary"Enter the night" + B.ghost"Use a different email")) + (V[a=center] > Tx"By clicking continue, you agree to our Terms of service and Privacy policy"[t=supporting]))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // Ctr > C[p=4 mw=400] > V[g=4] > ((V[g=1 a=center] > Hd"Welcome back to the night"[level=1 t=display-2] + Tx"Whisper your details to enter the night"[t=body]) + (V[g=1] > TI"Work email"[t=email] + Lk"Having trouble signing in?") + B.primary"Continue" + D"Or continue with" + B.secondary"Continue with SSO" + (V[a=center] > Tx"New to the castle?"[t=supporting] + Lk"Request access") + (V[g=2 a=center] > Av + Hd"Sign in with Google Workspace"[level=1 t=display-2] + Tx"You will be redirected back after signing in."[t=body]) + (C.muted[p=4] > (H[g=2 a=center] > Ic + (V[g=0] > Tx"Google Workspace"[t=label] + Tx"vlad@castle.ro"[t=supporting]))) + (V[g=3] > B.primary"Continue with Google Workspace" + B.ghost"Use a different email") + (V[g=1 a=center] > Hd"Welcome back to the night"[level=1 t=display-2] + Tx"vlad@castle.ro"[t=body]) + (V[g=4] > (V[g=1] > TI"Password"[t=password] + Lk"Forgot password?") + (V[g=3] > B.primary"Sign in" + B.ghost"Use a different email")) + (V[a=center] > Tx"By clicking continue, you agree to our Terms of service and Privacy policy"[t=supporting]))
4
6
 
5
- // Step-conditional h1: the email and SSO-confirm steps each render their own
6
- // h1 (email entry vs provider confirm); the password fallback reuses the
7
- // family heading, so exactly one h1 shows per step.
8
- import {useState, useTransition} from 'react';
9
- import {authPageStyle as pageStyle, inputAutoComplete} from 'astryx-dracula/shared/auth-chrome-config';
10
- import {demoLogin} from 'astryx-dracula/shared/login-demo';
7
+ import { Avatar } from "@astryxdesign/core/Avatar";
8
+ import { Button } from "@astryxdesign/core/Button";
9
+ import { Card } from "@astryxdesign/core/Card";
10
+ import { Center } from "@astryxdesign/core/Center";
11
+ import { Divider } from "@astryxdesign/core/Divider";
12
+ import { Icon } from "@astryxdesign/core/Icon";
13
+ import { HStack, VStack } from "@astryxdesign/core/Layout";
14
+ import { Link } from "@astryxdesign/core/Link";
15
+ import { Heading, Text } from "@astryxdesign/core/Text";
16
+ import { TextInput } from "@astryxdesign/core/TextInput";
11
17
  import {
12
- AUTH_HEADING,
13
- AUTH_PRIMARY_CTA,
14
- AUTH_SIGNUP_PROMPT,
15
- AUTH_SSO_DIVIDER,
16
- AUTH_FORGOT_PASSWORD,
17
- AUTH_ERROR_MESSAGE,
18
- AUTH_EMAIL_PLACEHOLDER,
19
- AUTH_TERMS_PREFIX,
20
- AUTH_TERMS_SERVICE,
21
- AUTH_TERMS_PRIVACY,
22
- } from 'astryx-dracula/shared/auth-copy';
23
- import {VStack, HStack} from '@astryxdesign/core/Layout';
24
- import {Center} from '@astryxdesign/core/Center';
25
- import {Text, Heading} from '@astryxdesign/core/Text';
26
- import {TextInput} from '@astryxdesign/core/TextInput';
27
- import {Button} from '@astryxdesign/core/Button';
28
- import {Card} from '@astryxdesign/core/Card';
29
- import {Link} from '@astryxdesign/core/Link';
30
- import {Divider} from '@astryxdesign/core/Divider';
31
- import {Icon} from '@astryxdesign/core/Icon';
32
- import {Avatar} from '@astryxdesign/core/Avatar';
33
-
18
+ inputAutoComplete,
19
+ authPageStyle as pageStyle,
20
+ } from "astryx-dracula/shared/auth-chrome-config";
21
+ import {
22
+ AUTH_EMAIL_PLACEHOLDER,
23
+ AUTH_ERROR_MESSAGE,
24
+ AUTH_FORGOT_PASSWORD,
25
+ AUTH_HEADING,
26
+ AUTH_PRIMARY_CTA,
27
+ AUTH_SIGNUP_PROMPT,
28
+ AUTH_SSO_DIVIDER,
29
+ AUTH_TERMS_PREFIX,
30
+ AUTH_TERMS_PRIVACY,
31
+ AUTH_TERMS_SERVICE,
32
+ } from "astryx-dracula/shared/auth-copy";
33
+ import { demoLogin } from "astryx-dracula/shared/login-demo";
34
34
  // ============= ICONS (verified lucide-react exports) =============
35
35
  // ShieldCheck ← ShieldCheckIcon.
36
- import {ShieldCheck} from 'lucide-react';
36
+ import { ShieldCheck } from "lucide-react";
37
+ // Step-conditional h1: the email and SSO-confirm steps each render their own
38
+ // h1 (email entry vs provider confirm); the password fallback reuses the
39
+ // family heading, so exactly one h1 shows per step.
40
+ import { useState, useTransition } from "react";
37
41
 
38
42
  type SSOProvider = {
39
- name: string;
40
- abbr: string;
43
+ name: string;
44
+ abbr: string;
41
45
  };
42
46
  const SSO_PROVIDERS: Record<string, SSOProvider> = {
43
- 'google.com': {name: 'Google Workspace', abbr: 'G'},
44
- 'microsoft.com': {name: 'Microsoft Entra ID', abbr: 'M'},
45
- 'okta.com': {name: 'Okta', abbr: 'O'},
46
- 'meta.com': {name: 'Meta SSO', abbr: 'M'},
47
- 'apple.com': {name: 'Apple Business', abbr: 'A'},
47
+ "google.com": { name: "Google Workspace", abbr: "G" },
48
+ "microsoft.com": { name: "Microsoft Entra ID", abbr: "M" },
49
+ "okta.com": { name: "Okta", abbr: "O" },
50
+ "meta.com": { name: "Meta SSO", abbr: "M" },
51
+ "apple.com": { name: "Apple Business", abbr: "A" },
48
52
  };
49
53
 
50
54
  function getProvider(email: string) {
51
- const domain = email.split('@')[1]?.toLowerCase();
52
- return domain ? (SSO_PROVIDERS[domain] ?? null) : null;
55
+ const domain = email.split("@")[1]?.toLowerCase();
56
+ return domain ? (SSO_PROVIDERS[domain] ?? null) : null;
53
57
  }
54
58
 
55
59
  function isValidEmail(email: string) {
56
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
60
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
57
61
  }
58
62
 
59
63
  // ---------------------------------------------------------------------------
60
64
  // Component
61
65
  // ---------------------------------------------------------------------------
62
66
 
63
- type Step = 'email' | 'sso-confirm' | 'password-fallback';
67
+ type Step = "email" | "sso-confirm" | "password-fallback";
64
68
 
65
69
  export default function LoginSso() {
66
- const [step, setStep] = useState<Step>('email');
67
- const [email, setEmail] = useState('');
68
- const [password, setPassword] = useState('');
69
- const [error, setError] = useState<string | null>(null);
70
- const [isLoading, startTransition] = useTransition();
70
+ const [step, setStep] = useState<Step>("email");
71
+ const [email, setEmail] = useState("");
72
+ const [password, setPassword] = useState("");
73
+ const [error, setError] = useState<string | null>(null);
74
+ const [isLoading, startTransition] = useTransition();
71
75
 
72
- const provider = getProvider(email);
73
- const emailValid = isValidEmail(email);
76
+ const provider = getProvider(email);
77
+ const emailValid = isValidEmail(email);
74
78
 
75
- const handleContinue = () => {
76
- if (!emailValid) {
77
- // The Continue buttons stay enabled and explain themselves. Disabling
78
- // them greyed the buttons out with no stated reason, so a malformed
79
- // address produced silence rather than guidance.
80
- setError('Enter a valid email address to continue.');
81
- return;
82
- }
83
- setError(null);
84
- if (provider) {
85
- setStep('sso-confirm');
86
- } else {
87
- setStep('password-fallback');
88
- }
89
- };
79
+ const handleContinue = () => {
80
+ if (!emailValid) {
81
+ // The Continue buttons stay enabled and explain themselves. Disabling
82
+ // them greyed the buttons out with no stated reason, so a malformed
83
+ // address produced silence rather than guidance.
84
+ setError("Enter a valid email address to continue.");
85
+ return;
86
+ }
87
+ setError(null);
88
+ if (provider) {
89
+ setStep("sso-confirm");
90
+ } else {
91
+ setStep("password-fallback");
92
+ }
93
+ };
90
94
 
91
- const handleBack = () => {
92
- setStep('email');
93
- setError(null);
94
- };
95
+ const handleBack = () => {
96
+ setStep("email");
97
+ setError(null);
98
+ };
95
99
 
96
- const handleSignIn = () => {
97
- if (!password) {
98
- setError(AUTH_ERROR_MESSAGE);
99
- return;
100
- }
101
- setError(null);
102
- startTransition(async () => {
103
- await demoLogin();
104
- setError(AUTH_ERROR_MESSAGE);
105
- });
106
- };
100
+ const handleSignIn = () => {
101
+ if (!password) {
102
+ setError(AUTH_ERROR_MESSAGE);
103
+ return;
104
+ }
105
+ setError(null);
106
+ startTransition(async () => {
107
+ await demoLogin();
108
+ setError(AUTH_ERROR_MESSAGE);
109
+ });
110
+ };
107
111
 
108
- return (
109
- <Center axis="both" style={pageStyle}>
110
- <Card padding={4} width="100%" maxWidth={400}>
111
- <VStack gap={4} hAlign="stretch">
112
- {/* ── Step 1: Email entry, route by domain ──
112
+ return (
113
+ <Center axis="both" style={pageStyle}>
114
+ <Card padding={4} width="100%" maxWidth={400}>
115
+ <VStack gap={4} hAlign="stretch">
116
+ {/* ── Step 1: Email entry, route by domain ──
113
117
  The password is collected on the fallback step below, never
114
118
  here: a recognised domain goes straight to SSO. */}
115
- {step === 'email' && (
116
- <>
117
- <VStack gap={1} hAlign="center">
118
- <Heading level={1} type="display-2">
119
- {AUTH_HEADING}
120
- </Heading>
121
- <Text type="body" color="secondary">
122
- Whisper your details to enter the night
123
- </Text>
124
- </VStack>
119
+ {step === "email" && (
120
+ <>
121
+ <VStack gap={1} hAlign="center">
122
+ <Heading level={1} type="display-2">
123
+ {AUTH_HEADING}
124
+ </Heading>
125
+ <Text type="body" color="secondary">
126
+ Whisper your details to enter the night
127
+ </Text>
128
+ </VStack>
125
129
 
126
- {/* The helper link belongs to the field above it, so the two
130
+ {/* The helper link belongs to the field above it, so the two
127
131
  share a gap={1} group — as the password step below groups
128
132
  its own. As siblings in the outer gap={4} flow it read as
129
133
  one more control in the button column, 16px from each. */}
130
- <VStack gap={1}>
131
- <TextInput
132
- label="Work email"
133
- isLabelHidden
134
- type="email"
135
- {...inputAutoComplete('email')}
136
- placeholder={AUTH_EMAIL_PLACEHOLDER}
137
- value={email}
138
- onChange={(v: string) => {
139
- setEmail(v);
140
- setError(null);
141
- }}
142
- size="lg"
143
- onKeyDown={(e: React.KeyboardEvent) => {
144
- if (e.key === 'Enter') {
145
- handleContinue();
146
- }
147
- }}
148
- status={error ? {type: 'error', message: error} : undefined}
149
- />
134
+ <VStack gap={1}>
135
+ <TextInput
136
+ label="Work email"
137
+ isLabelHidden
138
+ type="email"
139
+ {...inputAutoComplete("email")}
140
+ placeholder={AUTH_EMAIL_PLACEHOLDER}
141
+ value={email}
142
+ onChange={(v: string) => {
143
+ setEmail(v);
144
+ setError(null);
145
+ }}
146
+ size="lg"
147
+ onKeyDown={(e: React.KeyboardEvent) => {
148
+ if (e.key === "Enter") {
149
+ handleContinue();
150
+ }
151
+ }}
152
+ status={error ? { type: "error", message: error } : undefined}
153
+ />
150
154
 
151
- <Link href="#/templates/login-sso" isStandalone>
152
- Having trouble signing in?
153
- </Link>
154
- </VStack>
155
+ <Link href="#/templates/login-sso" isStandalone>
156
+ Having trouble signing in?
157
+ </Link>
158
+ </VStack>
155
159
 
156
- <Button
157
- label="Continue"
158
- variant="primary"
159
- size="lg"
160
- onClick={handleContinue}
161
- />
160
+ <Button label="Continue" variant="primary" size="lg" onClick={handleContinue} />
162
161
 
163
- <Divider label={AUTH_SSO_DIVIDER} />
162
+ <Divider label={AUTH_SSO_DIVIDER} />
164
163
 
165
- <Button
166
- label="Continue with SSO"
167
- variant="secondary"
168
- size="lg"
169
- onClick={handleContinue}
170
- />
164
+ <Button
165
+ label="Continue with SSO"
166
+ variant="secondary"
167
+ size="lg"
168
+ onClick={handleContinue}
169
+ />
171
170
 
172
- {/* Prose link: colour alone is not a cue inside a sentence
171
+ {/* Prose link: colour alone is not a cue inside a sentence
173
172
  (WCAG 1.4.1 / F73), so it asks for the underline the kit
174
173
  only gives on hover. */}
175
- <VStack hAlign="center">
176
- <Text type="supporting" color="secondary">
177
- {AUTH_SIGNUP_PROMPT}{' '}
178
- <Link href="#/templates/login-sso" type="supporting" hasUnderline>
179
- Request access
180
- </Link>
181
- </Text>
182
- </VStack>
183
- </>
184
- )}
174
+ <VStack hAlign="center">
175
+ <Text type="supporting" color="secondary">
176
+ {AUTH_SIGNUP_PROMPT}{" "}
177
+ <Link href="#/templates/login-sso" type="supporting" hasUnderline>
178
+ Request access
179
+ </Link>
180
+ </Text>
181
+ </VStack>
182
+ </>
183
+ )}
185
184
 
186
- {/* ── Step 2a: SSO provider detected ── */}
187
- {step === 'sso-confirm' && provider && (
188
- <>
189
- <VStack gap={2} hAlign="center">
190
- <Avatar name={provider.name} size={48} />
191
- <Heading level={1} type="display-2">
192
- Sign in with {provider.name}
193
- </Heading>
194
- <Text type="body" color="secondary">
195
- You will be redirected back after signing in.
196
- </Text>
197
- </VStack>
185
+ {/* ── Step 2a: SSO provider detected ── */}
186
+ {step === "sso-confirm" && provider && (
187
+ <>
188
+ <VStack gap={2} hAlign="center">
189
+ <Avatar name={provider.name} size={48} />
190
+ <Heading level={1} type="display-2">
191
+ Sign in with {provider.name}
192
+ </Heading>
193
+ <Text type="body" color="secondary">
194
+ You will be redirected back after signing in.
195
+ </Text>
196
+ </VStack>
198
197
 
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>
209
- </Card>
198
+ <Card padding={4} variant="muted">
199
+ <HStack gap={2} vAlign="center">
200
+ <Icon icon={ShieldCheck} color="secondary" />
201
+ <VStack gap={0}>
202
+ <Text type="label">{provider.name}</Text>
203
+ <Text type="supporting" color="secondary">
204
+ {email}
205
+ </Text>
206
+ </VStack>
207
+ </HStack>
208
+ </Card>
210
209
 
211
- <VStack gap={3}>
212
- <Button
213
- label={`Continue with ${provider.name}`}
214
- variant="primary"
215
- size="lg"
216
- isLoading={isLoading}
217
- onClick={() => {
218
- startTransition(async () => {
219
- await demoLogin();
220
- });
221
- }}
222
- />
223
- <Button
224
- label="Use a different email"
225
- variant="ghost"
226
- size="lg"
227
- onClick={handleBack}
228
- />
229
- </VStack>
230
- </>
231
- )}
210
+ <VStack gap={3}>
211
+ <Button
212
+ label={`Continue with ${provider.name}`}
213
+ variant="primary"
214
+ size="lg"
215
+ isLoading={isLoading}
216
+ onClick={() => {
217
+ startTransition(async () => {
218
+ await demoLogin();
219
+ });
220
+ }}
221
+ />
222
+ <Button
223
+ label="Use a different email"
224
+ variant="ghost"
225
+ size="lg"
226
+ onClick={handleBack}
227
+ />
228
+ </VStack>
229
+ </>
230
+ )}
232
231
 
233
- {/* ── Step 2b: No SSO — password fallback ── */}
234
- {step === 'password-fallback' && (
235
- <>
236
- <VStack gap={1} hAlign="center">
237
- <Heading level={1} type="display-2">
238
- {AUTH_HEADING}
239
- </Heading>
240
- <Text type="body" color="secondary">
241
- {email}
242
- </Text>
243
- </VStack>
232
+ {/* ── Step 2b: No SSO — password fallback ── */}
233
+ {step === "password-fallback" && (
234
+ <>
235
+ <VStack gap={1} hAlign="center">
236
+ <Heading level={1} type="display-2">
237
+ {AUTH_HEADING}
238
+ </Heading>
239
+ <Text type="body" color="secondary">
240
+ {email}
241
+ </Text>
242
+ </VStack>
244
243
 
245
- <VStack gap={4}>
246
- <VStack gap={1}>
247
- <TextInput
248
- label="Password"
249
- type="password"
250
- {...inputAutoComplete('current-password')}
251
- value={password}
252
- size="lg"
253
- onChange={(v: string) => {
254
- setPassword(v);
255
- setError(null);
256
- }}
257
- onEnter={handleSignIn}
258
- status={error ? {type: 'error', message: error} : undefined}
259
- />
260
- {error && (
261
- <VStack hAlign="end">
262
- <Link href="#/templates/login-sso" isStandalone>
263
- {AUTH_FORGOT_PASSWORD}
264
- </Link>
265
- </VStack>
266
- )}
267
- </VStack>
244
+ <VStack gap={4}>
245
+ <VStack gap={1}>
246
+ <TextInput
247
+ label="Password"
248
+ type="password"
249
+ {...inputAutoComplete("current-password")}
250
+ value={password}
251
+ size="lg"
252
+ onChange={(v: string) => {
253
+ setPassword(v);
254
+ setError(null);
255
+ }}
256
+ onEnter={handleSignIn}
257
+ status={error ? { type: "error", message: error } : undefined}
258
+ />
259
+ {error && (
260
+ <VStack hAlign="end">
261
+ <Link href="#/templates/login-sso" isStandalone>
262
+ {AUTH_FORGOT_PASSWORD}
263
+ </Link>
264
+ </VStack>
265
+ )}
266
+ </VStack>
268
267
 
269
- {/* gap={3} is the family rhythm for a button pair: the
268
+ {/* gap={3} is the family rhythm for a button pair: the
270
269
  primary/ghost pair in the confirm step above, the social
271
270
  pairs in login-card and login-split. At the outer gap={4}
272
271
  the same two buttons sat 4px further apart in this step
273
272
  than in the step above it. */}
274
- <VStack gap={3}>
275
- <Button
276
- label={AUTH_PRIMARY_CTA}
277
- variant="primary"
278
- size="lg"
279
- isLoading={isLoading}
280
- onClick={handleSignIn}
281
- />
282
- <Button
283
- label="Use a different email"
284
- variant="ghost"
285
- size="lg"
286
- onClick={handleBack}
287
- />
288
- </VStack>
289
- </VStack>
290
- </>
291
- )}
273
+ <VStack gap={3}>
274
+ <Button
275
+ label={AUTH_PRIMARY_CTA}
276
+ variant="primary"
277
+ size="lg"
278
+ isLoading={isLoading}
279
+ onClick={handleSignIn}
280
+ />
281
+ <Button
282
+ label="Use a different email"
283
+ variant="ghost"
284
+ size="lg"
285
+ onClick={handleBack}
286
+ />
287
+ </VStack>
288
+ </VStack>
289
+ </>
290
+ )}
292
291
 
293
- {/* Terms — family line, shown on every step */}
294
- <VStack hAlign="center" width="100%">
295
- <Text type="supporting" color="secondary" justify="center">
296
- {AUTH_TERMS_PREFIX}{' '}
297
- <Link href="#/templates/login-sso" type="supporting" hasUnderline>
298
- {AUTH_TERMS_SERVICE}
299
- </Link>{' '}
300
- and{' '}
301
- <Link href="#/templates/login-sso" type="supporting" hasUnderline>
302
- {AUTH_TERMS_PRIVACY}
303
- </Link>
304
- .
305
- </Text>
306
- </VStack>
307
- </VStack>
308
- </Card>
309
- </Center>
310
- );
292
+ {/* Terms — family line, shown on every step */}
293
+ <VStack hAlign="center" width="100%">
294
+ <Text type="supporting" color="secondary" justify="center">
295
+ {AUTH_TERMS_PREFIX}{" "}
296
+ <Link href="#/templates/login-sso" type="supporting" hasUnderline>
297
+ {AUTH_TERMS_SERVICE}
298
+ </Link>{" "}
299
+ and{" "}
300
+ <Link href="#/templates/login-sso" type="supporting" hasUnderline>
301
+ {AUTH_TERMS_PRIVACY}
302
+ </Link>
303
+ .
304
+ </Text>
305
+ </VStack>
306
+ </VStack>
307
+ </Card>
308
+ </Center>
309
+ );
311
310
  }
@@ -1,6 +1,7 @@
1
1
  export default {
2
- type: 'page',
3
- name: 'Basic Login',
4
- description: 'Auth form with email and password inputs',
5
- category: 'auth',
2
+ type: "page",
3
+ name: "Basic Login",
4
+ description: "Auth form with email and password inputs",
5
+ keywords: ["login", "sign in", "auth", "credentials", "account", "form"],
6
+ category: "auth",
6
7
  };