@hanzo/ui 4.6.0 → 4.8.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.
- package/assets/general.tsx +1 -1
- package/assets/hanzo-logo.tsx +3 -1
- package/assets/index.ts +119 -5
- package/blocks/auth/index.ts +6 -0
- package/blocks/auth/login-2fa.tsx +165 -0
- package/blocks/auth/login-basic.tsx +94 -0
- package/blocks/auth/login-social.tsx +148 -0
- package/blocks/auth/magic-link.tsx +129 -0
- package/blocks/auth/password-reset.tsx +97 -0
- package/blocks/auth/signup.tsx +157 -0
- package/blocks/data-display/activity-feed.tsx +242 -0
- package/blocks/data-display/data-table.tsx +235 -0
- package/blocks/data-display/stats-grid.tsx +194 -0
- package/blocks/ecommerce/checkout.tsx +242 -0
- package/blocks/ecommerce/index.ts +7 -0
- package/blocks/ecommerce/product-detail.tsx +257 -0
- package/blocks/ecommerce/product-grid.tsx +148 -0
- package/blocks/ecommerce/shopping-cart.tsx +181 -0
- package/blocks/marketing/cta-section.tsx +207 -0
- package/blocks/marketing/faq.tsx +159 -0
- package/blocks/marketing/features-grid.tsx +156 -0
- package/blocks/marketing/hero-section.tsx +192 -0
- package/blocks/marketing/index.ts +6 -0
- package/blocks/marketing/pricing-table.tsx +121 -0
- package/blocks/marketing/testimonials.tsx +196 -0
- package/components/index.ts +4 -51
- package/dist/index.js +9351 -0
- package/dist/index.mjs +9340 -0
- package/dist/lib/utils.js +47 -0
- package/dist/lib/utils.mjs +28 -0
- package/dist/src/utils.js +47 -0
- package/dist/src/utils.mjs +28 -0
- package/dist/tailwind/index.js +2050 -0
- package/dist/tailwind/index.mjs +2019 -0
- package/dist/types/index.js +79 -0
- package/dist/types/index.mjs +56 -0
- package/dist/util/format-text.js +51 -0
- package/dist/util/format-text.mjs +32 -0
- package/dist/util/index.js +384 -0
- package/dist/util/index.mjs +363 -0
- package/frameworks/core/index.ts +6 -0
- package/frameworks/core/utils/index.ts +64 -0
- package/frameworks/react/components/button.tsx +26 -0
- package/frameworks/react/components/index.ts +5 -0
- package/frameworks/react/hooks/index.ts +5 -0
- package/frameworks/react/index.ts +9 -0
- package/frameworks/react/package.json +8 -0
- package/frameworks/react/utils/index.ts +2 -0
- package/frameworks/react-native/index.ts +9 -0
- package/frameworks/react-native/package.json +8 -0
- package/frameworks/registry.json +371 -0
- package/frameworks/setup.sh +69 -0
- package/frameworks/svelte/index.ts +9 -0
- package/frameworks/svelte/package.json +8 -0
- package/frameworks/tracker.json +1854 -0
- package/frameworks/vue/index.ts +9 -0
- package/frameworks/vue/package.json +8 -0
- package/package.json +192 -28
- package/primitives/accordion.tsx +1 -1
- package/primitives/alert-dialog.tsx +1 -1
- package/primitives/alert.tsx +1 -1
- package/primitives/avatar.tsx +1 -1
- package/primitives/badge.tsx +2 -1
- package/primitives/breadcrumb.tsx +1 -1
- package/primitives/button.tsx +37 -47
- package/primitives/card.tsx +1 -1
- package/primitives/carousel.tsx +3 -2
- package/primitives/chat/chat-input-area.tsx +5 -4
- package/primitives/chat/chat-input.tsx +2 -2
- package/primitives/chat/files-preview.tsx +5 -4
- package/primitives/chat/message-list.tsx +2 -1
- package/primitives/chat/sqlite-preview.tsx +8 -8
- package/primitives/checkbox.tsx +2 -1
- package/primitives/command.tsx +3 -1
- package/primitives/context-menu.tsx +1 -1
- package/primitives/dialog.tsx +6 -1
- package/primitives/drawer.tsx +4 -1
- package/primitives/dropdown-menu.tsx +1 -1
- package/primitives/file-uploader.tsx +4 -2
- package/primitives/form.tsx +1 -1
- package/primitives/hover-card.tsx +1 -1
- package/primitives/icons/github.tsx +2 -2
- package/primitives/icons/youtube-logo.tsx +1 -1
- package/primitives/index-common.ts +7 -6
- package/primitives/input-otp.tsx +1 -1
- package/primitives/input.tsx +2 -1
- package/primitives/label.tsx +2 -1
- package/primitives/markdown-preview.tsx +3 -0
- package/primitives/mermaid.tsx +13 -18
- package/primitives/next/image.tsx +2 -1
- package/primitives/next/inline-icon.tsx +14 -14
- package/primitives/next/media-stack.tsx +2 -19
- package/primitives/pagination.tsx +1 -1
- package/primitives/popover.tsx +4 -2
- package/primitives/progress.tsx +2 -1
- package/primitives/prompt-textarea.tsx +1 -1
- package/primitives/radio-group.tsx +1 -1
- package/primitives/scroll-area.tsx +1 -1
- package/primitives/search-input.tsx +1 -1
- package/primitives/select.tsx +1 -1
- package/primitives/separator.tsx +2 -1
- package/primitives/sheet.tsx +1 -1
- package/primitives/skeleton.tsx +1 -0
- package/primitives/slider.tsx +2 -1
- package/primitives/stepper.tsx +1 -1
- package/primitives/switch.tsx +2 -1
- package/primitives/table.tsx +1 -1
- package/primitives/tabs.tsx +1 -1
- package/primitives/textarea.tsx +2 -1
- package/primitives/textfield.tsx +1 -0
- package/primitives/toggle-group.tsx +1 -1
- package/primitives/toggle.tsx +1 -1
- package/primitives/tooltip.tsx +1 -1
- package/src/hooks/use-copy-clipboard.ts +1 -1
- package/src/index-lean.ts +87 -0
- package/src/index.ts +54 -0
- package/src/registry/api.ts +1 -1
- package/src/utils.ts +19 -1
- package/tailwind/tailwind.config.hanzo-preset.js +7 -7
- package/tailwind/typo-plugin/index.js +1 -1
- package/types/animation-def.ts +1 -1
- package/types/index.ts +2 -1
- package/util/blob.ts +9 -4
- package/util/date.ts +2 -1
- package/util/format-text.ts +2 -1
- package/util/index.ts +103 -0
- package/util/spread-to-transform.ts +9 -8
- package/MCP-INSTRUCTIONS.md +0 -73
- package/README-MCP.md +0 -175
- package/dist/button.d.ts +0 -1
- package/dist/button.js +0 -1
- package/dist/hooks/index.d.ts +0 -7
- package/dist/hooks/index.js +0 -7
- package/dist/hooks/use-click-away.d.ts +0 -2
- package/dist/hooks/use-click-away.js +0 -23
- package/dist/hooks/use-combined-refs.d.ts +0 -3
- package/dist/hooks/use-combined-refs.js +0 -18
- package/dist/hooks/use-copy-clipboard.d.ts +0 -9
- package/dist/hooks/use-copy-clipboard.js +0 -21
- package/dist/hooks/use-debounce.d.ts +0 -1
- package/dist/hooks/use-debounce.js +0 -13
- package/dist/hooks/use-fill-ids.d.ts +0 -8
- package/dist/hooks/use-fill-ids.js +0 -20
- package/dist/hooks/use-map.d.ts +0 -1
- package/dist/hooks/use-map.js +0 -20
- package/dist/hooks/use-measure.d.ts +0 -8
- package/dist/hooks/use-measure.js +0 -25
- package/dist/hooks/use-reverse-video-playback.d.ts +0 -1
- package/dist/hooks/use-reverse-video-playback.js +0 -41
- package/dist/hooks/use-scroll-restoration.d.ts +0 -8
- package/dist/hooks/use-scroll-restoration.js +0 -36
- package/dist/mcp/enhanced-server.d.ts +0 -29
- package/dist/mcp/enhanced-server.js +0 -1128
- package/dist/mcp/index.d.ts +0 -28
- package/dist/mcp/index.js +0 -436
- package/dist/registry/api.d.ts +0 -37
- package/dist/registry/api.js +0 -129
- package/dist/registry/index.d.ts +0 -353
- package/dist/registry/index.js +0 -45
- package/dist/utils.d.ts +0 -1
- package/dist/utils.js +0 -1
- package/environment.d.ts +0 -6
- package/public/r/accordion.json +0 -11
- package/public/r/alert.json +0 -11
- package/public/r/avatar.json +0 -11
- package/public/r/badge.json +0 -11
- package/public/r/button.json +0 -11
- package/public/r/card.json +0 -11
- package/public/r/checkbox.json +0 -11
- package/public/r/default.json +0 -6
- package/public/r/dialog.json +0 -11
- package/public/r/input.json +0 -11
- package/public/r/label.json +0 -11
- package/public/r/new-york.json +0 -6
- package/public/r/popover.json +0 -11
- package/public/r/select.json +0 -11
- package/public/r/table.json +0 -11
- package/public/r/tabs.json +0 -11
- package/public/r/toast.json +0 -11
- package/registry.json +0 -184
- package/test/test-registry.js +0 -73
- package/test-imports.mjs +0 -19
- package/tsconfig.json +0 -22
- package/utils.ts +0 -9
package/assets/general.tsx
CHANGED
|
@@ -167,7 +167,7 @@ export const ChatBubbleIcon = ({ className }: { className?: string }) => (
|
|
|
167
167
|
</svg>
|
|
168
168
|
);
|
|
169
169
|
|
|
170
|
-
export const
|
|
170
|
+
export const AttachmentIcon = ({ className }: { className?: string }) => (
|
|
171
171
|
<svg
|
|
172
172
|
className={cn('shrink-0', className)}
|
|
173
173
|
fill="none"
|
package/assets/hanzo-logo.tsx
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export type HanzoLogoProps = React.SVGProps<SVGSVGElement>;
|
|
4
|
+
|
|
5
|
+
export const HanzoLogo = ({ className, ...props }: HanzoLogoProps) => (
|
|
4
6
|
<svg viewBox="0 0 67 67" xmlns="http://www.w3.org/2000/svg" className={className} {...props}>
|
|
5
7
|
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="currentColor"/>
|
|
6
8
|
<path d="M0 44.6369L22.21 46.8285V44.6369H0Z" fill="currentColor" opacity="0.85"/>
|
package/assets/index.ts
CHANGED
|
@@ -1,8 +1,122 @@
|
|
|
1
1
|
// Export all asset components and icons
|
|
2
|
-
export
|
|
3
|
-
|
|
2
|
+
// Note: Some files have overlapping exports, so we export them selectively
|
|
3
|
+
|
|
4
|
+
// File-related icons
|
|
4
5
|
export * from './file';
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
// File type icons (specific exports from file-type-icon to avoid conflicts with general)
|
|
8
|
+
export {
|
|
9
|
+
FileTypeIcon,
|
|
10
|
+
DirectoryTypeIcon,
|
|
11
|
+
type FileTypeIconProps
|
|
12
|
+
} from './file-type-icon';
|
|
13
|
+
|
|
14
|
+
// General icons (excluding duplicates: DirectoryTypeIcon, FileTypeIcon, HanzoIcon)
|
|
15
|
+
export {
|
|
16
|
+
HanzoLogoIcon,
|
|
17
|
+
HanzoLogoSoloIcon,
|
|
18
|
+
HanzoCombinationMarkIcon,
|
|
19
|
+
SendIcon,
|
|
20
|
+
ExportIcon,
|
|
21
|
+
QrIcon,
|
|
22
|
+
JobBubbleIcon,
|
|
23
|
+
ChatBubbleIcon,
|
|
24
|
+
AttachmentIcon,
|
|
25
|
+
DisconnectIcon,
|
|
26
|
+
AgentIcon,
|
|
27
|
+
AddAgentIcon,
|
|
28
|
+
InboxIcon,
|
|
29
|
+
ArchiveIcon,
|
|
30
|
+
ArchivedIcon,
|
|
31
|
+
ActiveIcon,
|
|
32
|
+
FilesIcon,
|
|
33
|
+
SharedFolderIcon,
|
|
34
|
+
AddNewFolderIcon,
|
|
35
|
+
UploadVectorResourceIcon,
|
|
36
|
+
GenerateDocIcon,
|
|
37
|
+
GenerateFromWebIcon,
|
|
38
|
+
CreateAIIcon,
|
|
39
|
+
FileEmptyStateIcon,
|
|
40
|
+
AiTasksIcon,
|
|
41
|
+
AISearchContentIcon,
|
|
42
|
+
BrowseSubscriptionIcon,
|
|
43
|
+
MySubscriptionsIcon,
|
|
44
|
+
PromptLibraryIcon,
|
|
45
|
+
NotificationIcon,
|
|
46
|
+
SheetFileIcon,
|
|
47
|
+
FormulaIcon,
|
|
48
|
+
SheetIcon,
|
|
49
|
+
ShortcutsIcon,
|
|
50
|
+
NetworkAgentIcon,
|
|
51
|
+
MCPIcon,
|
|
52
|
+
ToolsIcon,
|
|
53
|
+
ToolsDisabledIcon,
|
|
54
|
+
StoreIcon,
|
|
55
|
+
ScheduledTasksIcon,
|
|
56
|
+
AddCryptoWalletIcon,
|
|
57
|
+
CryptoWalletIcon,
|
|
58
|
+
ReactJsIcon,
|
|
59
|
+
AIAgentIcon,
|
|
60
|
+
AisIcon,
|
|
61
|
+
ToolAssetsIcon,
|
|
62
|
+
ScheduledTasksComingSoonIcon,
|
|
63
|
+
EmbeddingsGeneratedIcon,
|
|
64
|
+
UnknownLanguageIcon,
|
|
65
|
+
PythonIcon,
|
|
66
|
+
TypeScriptIcon,
|
|
67
|
+
MetadataIcon,
|
|
68
|
+
SaveIcon,
|
|
69
|
+
CloudModelIcon,
|
|
70
|
+
LocalModelIcon,
|
|
71
|
+
ArrowRightIcon,
|
|
72
|
+
ImportIcon,
|
|
73
|
+
WebSearchIcon,
|
|
74
|
+
WebSearchDisabledIcon,
|
|
75
|
+
ChatSettingsIcon,
|
|
76
|
+
PlusIcon,
|
|
77
|
+
ReasoningIcon,
|
|
78
|
+
HomeIcon,
|
|
79
|
+
TracingIcon,
|
|
80
|
+
DownloadIcon,
|
|
81
|
+
CategoryIcon,
|
|
82
|
+
PartyIcon,
|
|
83
|
+
// Exclude DirectoryTypeIcon and FileTypeIcon as they're exported above
|
|
84
|
+
// Exclude HanzoIcon as it's exported below from hanzo-logo
|
|
85
|
+
} from './general';
|
|
86
|
+
|
|
87
|
+
// Crypto icons
|
|
6
88
|
export * from './crypto';
|
|
7
|
-
|
|
8
|
-
|
|
89
|
+
|
|
90
|
+
// AI-related icons are already exported from general above
|
|
91
|
+
// Removed duplicate exports to avoid conflicts
|
|
92
|
+
|
|
93
|
+
// LLM provider icons (specific exports to avoid HanzoIcon conflict)
|
|
94
|
+
export {
|
|
95
|
+
MistralIcon,
|
|
96
|
+
GoogleIcon,
|
|
97
|
+
MetaIcon,
|
|
98
|
+
MicrosoftIcon,
|
|
99
|
+
OpenBMBIcon,
|
|
100
|
+
AnthropicIcon,
|
|
101
|
+
AzureIcon,
|
|
102
|
+
DeepSeekIcon,
|
|
103
|
+
GroqIcon,
|
|
104
|
+
LmStudioIcon,
|
|
105
|
+
OllamaIcon,
|
|
106
|
+
OpenAIIcon,
|
|
107
|
+
OpenRouterIcon,
|
|
108
|
+
PerplexityIcon,
|
|
109
|
+
QwenIcon,
|
|
110
|
+
ExoIcon,
|
|
111
|
+
GeminiIcon,
|
|
112
|
+
GrokIcon,
|
|
113
|
+
AyaCohereIcon,
|
|
114
|
+
// Exclude HanzoIcon as it's exported below from hanzo-logo
|
|
115
|
+
} from './llm-provider';
|
|
116
|
+
|
|
117
|
+
// Hanzo logo (primary export for HanzoIcon)
|
|
118
|
+
export {
|
|
119
|
+
HanzoLogo,
|
|
120
|
+
HanzoIcon, // Use this as the canonical HanzoIcon export
|
|
121
|
+
type HanzoLogoProps
|
|
122
|
+
} from './hanzo-logo';
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { cn } from '@hanzo/ui/util'
|
|
5
|
+
import { Button } from '@hanzo/ui/primitives'
|
|
6
|
+
import {
|
|
7
|
+
Card,
|
|
8
|
+
CardContent,
|
|
9
|
+
CardDescription,
|
|
10
|
+
CardHeader,
|
|
11
|
+
CardTitle,
|
|
12
|
+
} from '@hanzo/ui/primitives'
|
|
13
|
+
import { Input } from '@hanzo/ui/primitives'
|
|
14
|
+
import { Label } from '@hanzo/ui/primitives'
|
|
15
|
+
import {
|
|
16
|
+
InputOTP,
|
|
17
|
+
InputOTPGroup,
|
|
18
|
+
InputOTPSeparator,
|
|
19
|
+
InputOTPSlot,
|
|
20
|
+
} from '@hanzo/ui/primitives'
|
|
21
|
+
|
|
22
|
+
interface Login2FAProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
23
|
+
onSubmit?: (email: string, password: string, code?: string) => void
|
|
24
|
+
onResendCode?: () => void
|
|
25
|
+
onForgotPassword?: () => void
|
|
26
|
+
onSignUp?: () => void
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function Login2FA({
|
|
30
|
+
className,
|
|
31
|
+
onSubmit,
|
|
32
|
+
onResendCode,
|
|
33
|
+
onForgotPassword,
|
|
34
|
+
onSignUp,
|
|
35
|
+
...props
|
|
36
|
+
}: Login2FAProps) {
|
|
37
|
+
const [step, setStep] = useState<'credentials' | '2fa'>('credentials')
|
|
38
|
+
const [credentials, setCredentials] = useState({ email: '', password: '' })
|
|
39
|
+
const [otpValue, setOtpValue] = useState('')
|
|
40
|
+
|
|
41
|
+
const handleCredentialsSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
42
|
+
e.preventDefault()
|
|
43
|
+
const formData = new FormData(e.currentTarget)
|
|
44
|
+
const email = formData.get('email') as string
|
|
45
|
+
const password = formData.get('password') as string
|
|
46
|
+
setCredentials({ email, password })
|
|
47
|
+
setStep('2fa')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const handleOTPSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
51
|
+
e.preventDefault()
|
|
52
|
+
onSubmit?.(credentials.email, credentials.password, otpValue)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className={cn('flex flex-col gap-6', className)} {...props}>
|
|
57
|
+
<Card>
|
|
58
|
+
<CardHeader>
|
|
59
|
+
<CardTitle className="text-2xl">
|
|
60
|
+
{step === 'credentials' ? 'Login' : 'Two-factor authentication'}
|
|
61
|
+
</CardTitle>
|
|
62
|
+
<CardDescription>
|
|
63
|
+
{step === 'credentials'
|
|
64
|
+
? 'Enter your email and password to login'
|
|
65
|
+
: 'Enter the 6-digit code from your authenticator app'}
|
|
66
|
+
</CardDescription>
|
|
67
|
+
</CardHeader>
|
|
68
|
+
<CardContent>
|
|
69
|
+
{step === 'credentials' ? (
|
|
70
|
+
<form onSubmit={handleCredentialsSubmit}>
|
|
71
|
+
<div className="flex flex-col gap-6">
|
|
72
|
+
<div className="grid gap-2">
|
|
73
|
+
<Label htmlFor="email">Email</Label>
|
|
74
|
+
<Input
|
|
75
|
+
id="email"
|
|
76
|
+
name="email"
|
|
77
|
+
type="email"
|
|
78
|
+
placeholder="m@example.com"
|
|
79
|
+
required
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
<div className="grid gap-2">
|
|
83
|
+
<div className="flex items-center">
|
|
84
|
+
<Label htmlFor="password">Password</Label>
|
|
85
|
+
{onForgotPassword && (
|
|
86
|
+
<button
|
|
87
|
+
type="button"
|
|
88
|
+
onClick={onForgotPassword}
|
|
89
|
+
className="ml-auto inline-block text-sm underline-offset-4 hover:underline"
|
|
90
|
+
>
|
|
91
|
+
Forgot your password?
|
|
92
|
+
</button>
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
95
|
+
<Input id="password" name="password" type="password" required />
|
|
96
|
+
</div>
|
|
97
|
+
<Button type="submit" className="w-full">
|
|
98
|
+
Continue
|
|
99
|
+
</Button>
|
|
100
|
+
</div>
|
|
101
|
+
{onSignUp && (
|
|
102
|
+
<div className="mt-4 text-center text-sm">
|
|
103
|
+
Don't have an account?{' '}
|
|
104
|
+
<button
|
|
105
|
+
type="button"
|
|
106
|
+
onClick={onSignUp}
|
|
107
|
+
className="underline underline-offset-4"
|
|
108
|
+
>
|
|
109
|
+
Sign up
|
|
110
|
+
</button>
|
|
111
|
+
</div>
|
|
112
|
+
)}
|
|
113
|
+
</form>
|
|
114
|
+
) : (
|
|
115
|
+
<form onSubmit={handleOTPSubmit}>
|
|
116
|
+
<div className="flex flex-col gap-6">
|
|
117
|
+
<div className="flex justify-center">
|
|
118
|
+
<InputOTP
|
|
119
|
+
maxLength={6}
|
|
120
|
+
value={otpValue}
|
|
121
|
+
onChange={(value) => setOtpValue(value)}
|
|
122
|
+
>
|
|
123
|
+
<InputOTPGroup>
|
|
124
|
+
<InputOTPSlot index={0} />
|
|
125
|
+
<InputOTPSlot index={1} />
|
|
126
|
+
<InputOTPSlot index={2} />
|
|
127
|
+
</InputOTPGroup>
|
|
128
|
+
<InputOTPSeparator />
|
|
129
|
+
<InputOTPGroup>
|
|
130
|
+
<InputOTPSlot index={3} />
|
|
131
|
+
<InputOTPSlot index={4} />
|
|
132
|
+
<InputOTPSlot index={5} />
|
|
133
|
+
</InputOTPGroup>
|
|
134
|
+
</InputOTP>
|
|
135
|
+
</div>
|
|
136
|
+
<Button type="submit" className="w-full" disabled={otpValue.length !== 6}>
|
|
137
|
+
Verify
|
|
138
|
+
</Button>
|
|
139
|
+
<div className="flex flex-col gap-2">
|
|
140
|
+
<Button
|
|
141
|
+
type="button"
|
|
142
|
+
variant="outline"
|
|
143
|
+
className="w-full"
|
|
144
|
+
onClick={() => setStep('credentials')}
|
|
145
|
+
>
|
|
146
|
+
Back to login
|
|
147
|
+
</Button>
|
|
148
|
+
{onResendCode && (
|
|
149
|
+
<button
|
|
150
|
+
type="button"
|
|
151
|
+
onClick={onResendCode}
|
|
152
|
+
className="text-center text-sm underline underline-offset-4"
|
|
153
|
+
>
|
|
154
|
+
Didn't receive a code? Resend
|
|
155
|
+
</button>
|
|
156
|
+
)}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
</form>
|
|
160
|
+
)}
|
|
161
|
+
</CardContent>
|
|
162
|
+
</Card>
|
|
163
|
+
</div>
|
|
164
|
+
)
|
|
165
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@hanzo/ui/util'
|
|
4
|
+
import { Button } from '@hanzo/ui/primitives'
|
|
5
|
+
import {
|
|
6
|
+
Card,
|
|
7
|
+
CardContent,
|
|
8
|
+
CardDescription,
|
|
9
|
+
CardHeader,
|
|
10
|
+
CardTitle,
|
|
11
|
+
} from '@hanzo/ui/primitives'
|
|
12
|
+
import { Input } from '@hanzo/ui/primitives'
|
|
13
|
+
import { Label } from '@hanzo/ui/primitives'
|
|
14
|
+
|
|
15
|
+
interface LoginBasicProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
16
|
+
onSubmit?: (email: string, password: string) => void
|
|
17
|
+
onForgotPassword?: () => void
|
|
18
|
+
onSignUp?: () => void
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function LoginBasic({
|
|
22
|
+
className,
|
|
23
|
+
onSubmit,
|
|
24
|
+
onForgotPassword,
|
|
25
|
+
onSignUp,
|
|
26
|
+
...props
|
|
27
|
+
}: LoginBasicProps) {
|
|
28
|
+
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
29
|
+
e.preventDefault()
|
|
30
|
+
const formData = new FormData(e.currentTarget)
|
|
31
|
+
const email = formData.get('email') as string
|
|
32
|
+
const password = formData.get('password') as string
|
|
33
|
+
onSubmit?.(email, password)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div className={cn('flex flex-col gap-6', className)} {...props}>
|
|
38
|
+
<Card>
|
|
39
|
+
<CardHeader>
|
|
40
|
+
<CardTitle className="text-2xl">Login</CardTitle>
|
|
41
|
+
<CardDescription>
|
|
42
|
+
Enter your email below to login to your account
|
|
43
|
+
</CardDescription>
|
|
44
|
+
</CardHeader>
|
|
45
|
+
<CardContent>
|
|
46
|
+
<form onSubmit={handleSubmit}>
|
|
47
|
+
<div className="flex flex-col gap-6">
|
|
48
|
+
<div className="grid gap-2">
|
|
49
|
+
<Label htmlFor="email">Email</Label>
|
|
50
|
+
<Input
|
|
51
|
+
id="email"
|
|
52
|
+
name="email"
|
|
53
|
+
type="email"
|
|
54
|
+
placeholder="m@example.com"
|
|
55
|
+
required
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
<div className="grid gap-2">
|
|
59
|
+
<div className="flex items-center">
|
|
60
|
+
<Label htmlFor="password">Password</Label>
|
|
61
|
+
{onForgotPassword && (
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
onClick={onForgotPassword}
|
|
65
|
+
className="ml-auto inline-block text-sm underline-offset-4 hover:underline"
|
|
66
|
+
>
|
|
67
|
+
Forgot your password?
|
|
68
|
+
</button>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
<Input id="password" name="password" type="password" required />
|
|
72
|
+
</div>
|
|
73
|
+
<Button type="submit" className="w-full">
|
|
74
|
+
Login
|
|
75
|
+
</Button>
|
|
76
|
+
</div>
|
|
77
|
+
{onSignUp && (
|
|
78
|
+
<div className="mt-4 text-center text-sm">
|
|
79
|
+
Don't have an account?{' '}
|
|
80
|
+
<button
|
|
81
|
+
type="button"
|
|
82
|
+
onClick={onSignUp}
|
|
83
|
+
className="underline underline-offset-4"
|
|
84
|
+
>
|
|
85
|
+
Sign up
|
|
86
|
+
</button>
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
</form>
|
|
90
|
+
</CardContent>
|
|
91
|
+
</Card>
|
|
92
|
+
</div>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@hanzo/ui/util'
|
|
4
|
+
import { Button } from '@hanzo/ui/primitives'
|
|
5
|
+
import {
|
|
6
|
+
Card,
|
|
7
|
+
CardContent,
|
|
8
|
+
CardDescription,
|
|
9
|
+
CardHeader,
|
|
10
|
+
CardTitle,
|
|
11
|
+
} from '@hanzo/ui/primitives'
|
|
12
|
+
import { Input } from '@hanzo/ui/primitives'
|
|
13
|
+
import { Label } from '@hanzo/ui/primitives'
|
|
14
|
+
import { Icons } from '@hanzo/ui/primitives'
|
|
15
|
+
|
|
16
|
+
interface LoginSocialProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
17
|
+
onSubmit?: (email: string, password: string) => void
|
|
18
|
+
onGoogleLogin?: () => void
|
|
19
|
+
onGitHubLogin?: () => void
|
|
20
|
+
onTwitterLogin?: () => void
|
|
21
|
+
onForgotPassword?: () => void
|
|
22
|
+
onSignUp?: () => void
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function LoginSocial({
|
|
26
|
+
className,
|
|
27
|
+
onSubmit,
|
|
28
|
+
onGoogleLogin,
|
|
29
|
+
onGitHubLogin,
|
|
30
|
+
onTwitterLogin,
|
|
31
|
+
onForgotPassword,
|
|
32
|
+
onSignUp,
|
|
33
|
+
...props
|
|
34
|
+
}: LoginSocialProps) {
|
|
35
|
+
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
36
|
+
e.preventDefault()
|
|
37
|
+
const formData = new FormData(e.currentTarget)
|
|
38
|
+
const email = formData.get('email') as string
|
|
39
|
+
const password = formData.get('password') as string
|
|
40
|
+
onSubmit?.(email, password)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className={cn('flex flex-col gap-6', className)} {...props}>
|
|
45
|
+
<Card>
|
|
46
|
+
<CardHeader>
|
|
47
|
+
<CardTitle className="text-2xl">Login</CardTitle>
|
|
48
|
+
<CardDescription>
|
|
49
|
+
Enter your email below to login to your account
|
|
50
|
+
</CardDescription>
|
|
51
|
+
</CardHeader>
|
|
52
|
+
<CardContent>
|
|
53
|
+
<form onSubmit={handleSubmit}>
|
|
54
|
+
<div className="flex flex-col gap-6">
|
|
55
|
+
<div className="grid gap-2">
|
|
56
|
+
<Label htmlFor="email">Email</Label>
|
|
57
|
+
<Input
|
|
58
|
+
id="email"
|
|
59
|
+
name="email"
|
|
60
|
+
type="email"
|
|
61
|
+
placeholder="m@example.com"
|
|
62
|
+
required
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
<div className="grid gap-2">
|
|
66
|
+
<div className="flex items-center">
|
|
67
|
+
<Label htmlFor="password">Password</Label>
|
|
68
|
+
{onForgotPassword && (
|
|
69
|
+
<button
|
|
70
|
+
type="button"
|
|
71
|
+
onClick={onForgotPassword}
|
|
72
|
+
className="ml-auto inline-block text-sm underline-offset-4 hover:underline"
|
|
73
|
+
>
|
|
74
|
+
Forgot your password?
|
|
75
|
+
</button>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
<Input id="password" name="password" type="password" required />
|
|
79
|
+
</div>
|
|
80
|
+
<Button type="submit" className="w-full">
|
|
81
|
+
Login
|
|
82
|
+
</Button>
|
|
83
|
+
|
|
84
|
+
<div className="relative">
|
|
85
|
+
<div className="absolute inset-0 flex items-center">
|
|
86
|
+
<span className="w-full border-t" />
|
|
87
|
+
</div>
|
|
88
|
+
<div className="relative flex justify-center text-xs uppercase">
|
|
89
|
+
<span className="bg-background px-2 text-muted-foreground">
|
|
90
|
+
Or continue with
|
|
91
|
+
</span>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div className="grid gap-2">
|
|
96
|
+
{onGoogleLogin && (
|
|
97
|
+
<Button
|
|
98
|
+
type="button"
|
|
99
|
+
variant="outline"
|
|
100
|
+
className="w-full"
|
|
101
|
+
onClick={onGoogleLogin}
|
|
102
|
+
>
|
|
103
|
+
<Icons.google className="mr-2 h-4 w-4" />
|
|
104
|
+
Google
|
|
105
|
+
</Button>
|
|
106
|
+
)}
|
|
107
|
+
{onGitHubLogin && (
|
|
108
|
+
<Button
|
|
109
|
+
type="button"
|
|
110
|
+
variant="outline"
|
|
111
|
+
className="w-full"
|
|
112
|
+
onClick={onGitHubLogin}
|
|
113
|
+
>
|
|
114
|
+
<Icons.gitHub className="mr-2 h-4 w-4" />
|
|
115
|
+
GitHub
|
|
116
|
+
</Button>
|
|
117
|
+
)}
|
|
118
|
+
{onTwitterLogin && (
|
|
119
|
+
<Button
|
|
120
|
+
type="button"
|
|
121
|
+
variant="outline"
|
|
122
|
+
className="w-full"
|
|
123
|
+
onClick={onTwitterLogin}
|
|
124
|
+
>
|
|
125
|
+
<Icons.twitter className="mr-2 h-4 w-4" />
|
|
126
|
+
Twitter
|
|
127
|
+
</Button>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
{onSignUp && (
|
|
132
|
+
<div className="mt-4 text-center text-sm">
|
|
133
|
+
Don't have an account?{' '}
|
|
134
|
+
<button
|
|
135
|
+
type="button"
|
|
136
|
+
onClick={onSignUp}
|
|
137
|
+
className="underline underline-offset-4"
|
|
138
|
+
>
|
|
139
|
+
Sign up
|
|
140
|
+
</button>
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
</form>
|
|
144
|
+
</CardContent>
|
|
145
|
+
</Card>
|
|
146
|
+
</div>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { cn } from '@hanzo/ui/util'
|
|
5
|
+
import { Button } from '@hanzo/ui/primitives'
|
|
6
|
+
import {
|
|
7
|
+
Card,
|
|
8
|
+
CardContent,
|
|
9
|
+
CardDescription,
|
|
10
|
+
CardHeader,
|
|
11
|
+
CardTitle,
|
|
12
|
+
} from '@hanzo/ui/primitives'
|
|
13
|
+
import { Input } from '@hanzo/ui/primitives'
|
|
14
|
+
import { Label } from '@hanzo/ui/primitives'
|
|
15
|
+
import { Icons } from '@hanzo/ui/primitives'
|
|
16
|
+
|
|
17
|
+
interface MagicLinkProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
18
|
+
onSubmit?: (email: string) => void
|
|
19
|
+
onSignUp?: () => void
|
|
20
|
+
onUsePassword?: () => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function MagicLink({
|
|
24
|
+
className,
|
|
25
|
+
onSubmit,
|
|
26
|
+
onSignUp,
|
|
27
|
+
onUsePassword,
|
|
28
|
+
...props
|
|
29
|
+
}: MagicLinkProps) {
|
|
30
|
+
const [sent, setSent] = useState(false)
|
|
31
|
+
const [email, setEmail] = useState('')
|
|
32
|
+
|
|
33
|
+
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
34
|
+
e.preventDefault()
|
|
35
|
+
const formData = new FormData(e.currentTarget)
|
|
36
|
+
const emailValue = formData.get('email') as string
|
|
37
|
+
setEmail(emailValue)
|
|
38
|
+
setSent(true)
|
|
39
|
+
onSubmit?.(emailValue)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className={cn('flex flex-col gap-6', className)} {...props}>
|
|
44
|
+
<Card>
|
|
45
|
+
<CardHeader>
|
|
46
|
+
<CardTitle className="text-2xl">
|
|
47
|
+
{sent ? 'Check your email' : 'Sign in with email'}
|
|
48
|
+
</CardTitle>
|
|
49
|
+
<CardDescription>
|
|
50
|
+
{sent
|
|
51
|
+
? `We've sent a magic link to ${email}`
|
|
52
|
+
: 'We'll send you a magic link to sign in instantly'}
|
|
53
|
+
</CardDescription>
|
|
54
|
+
</CardHeader>
|
|
55
|
+
<CardContent>
|
|
56
|
+
{sent ? (
|
|
57
|
+
<div className="flex flex-col gap-6">
|
|
58
|
+
<div className="flex justify-center">
|
|
59
|
+
<div className="rounded-full bg-primary/10 p-6">
|
|
60
|
+
<Icons.mail className="h-8 w-8 text-primary" />
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
<div className="text-center text-sm text-muted-foreground">
|
|
64
|
+
Click the link in your email to sign in. The link will expire in 10 minutes.
|
|
65
|
+
</div>
|
|
66
|
+
<div className="flex flex-col gap-2">
|
|
67
|
+
<Button
|
|
68
|
+
type="button"
|
|
69
|
+
variant="outline"
|
|
70
|
+
className="w-full"
|
|
71
|
+
onClick={() => setSent(false)}
|
|
72
|
+
>
|
|
73
|
+
Try a different email
|
|
74
|
+
</Button>
|
|
75
|
+
<button
|
|
76
|
+
type="button"
|
|
77
|
+
onClick={() => onSubmit?.(email)}
|
|
78
|
+
className="text-center text-sm underline underline-offset-4"
|
|
79
|
+
>
|
|
80
|
+
Didn't receive the email? Resend
|
|
81
|
+
</button>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
) : (
|
|
85
|
+
<form onSubmit={handleSubmit}>
|
|
86
|
+
<div className="flex flex-col gap-6">
|
|
87
|
+
<div className="grid gap-2">
|
|
88
|
+
<Label htmlFor="email">Email</Label>
|
|
89
|
+
<Input
|
|
90
|
+
id="email"
|
|
91
|
+
name="email"
|
|
92
|
+
type="email"
|
|
93
|
+
placeholder="m@example.com"
|
|
94
|
+
required
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
<Button type="submit" className="w-full">
|
|
98
|
+
Send magic link
|
|
99
|
+
</Button>
|
|
100
|
+
{onUsePassword && (
|
|
101
|
+
<Button
|
|
102
|
+
type="button"
|
|
103
|
+
variant="outline"
|
|
104
|
+
className="w-full"
|
|
105
|
+
onClick={onUsePassword}
|
|
106
|
+
>
|
|
107
|
+
Use password instead
|
|
108
|
+
</Button>
|
|
109
|
+
)}
|
|
110
|
+
</div>
|
|
111
|
+
{onSignUp && (
|
|
112
|
+
<div className="mt-4 text-center text-sm">
|
|
113
|
+
Don't have an account?{' '}
|
|
114
|
+
<button
|
|
115
|
+
type="button"
|
|
116
|
+
onClick={onSignUp}
|
|
117
|
+
className="underline underline-offset-4"
|
|
118
|
+
>
|
|
119
|
+
Sign up
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
)}
|
|
123
|
+
</form>
|
|
124
|
+
)}
|
|
125
|
+
</CardContent>
|
|
126
|
+
</Card>
|
|
127
|
+
</div>
|
|
128
|
+
)
|
|
129
|
+
}
|