mirror of
https://gitlab.com/soapbox-pub/mkstack.git
synced 2025-08-27 13:09:22 +00:00
review updates
This commit is contained in:
parent
c7cfc0fe99
commit
3f25629923
@ -2,7 +2,7 @@
|
|||||||
// It is important that all functionality in this file is preserved, and should only be modified if explicitly requested.
|
// It is important that all functionality in this file is preserved, and should only be modified if explicitly requested.
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { User } from 'lucide-react';
|
import { User, UserPlus } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button.tsx';
|
import { Button } from '@/components/ui/button.tsx';
|
||||||
import LoginDialog from './LoginDialog';
|
import LoginDialog from './LoginDialog';
|
||||||
import SignupDialog from './SignupDialog';
|
import SignupDialog from './SignupDialog';
|
||||||
@ -29,13 +29,22 @@ export function LoginArea({ className }: LoginAreaProps) {
|
|||||||
{currentUser ? (
|
{currentUser ? (
|
||||||
<AccountSwitcher onAddAccountClick={() => setLoginDialogOpen(true)} />
|
<AccountSwitcher onAddAccountClick={() => setLoginDialogOpen(true)} />
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<div className="flex gap-3 justify-center">
|
||||||
onClick={() => setLoginDialogOpen(true)}
|
<Button
|
||||||
className='flex items-center gap-2 px-4 py-2 rounded-full bg-primary text-primary-foreground w-full font-medium transition-all hover:bg-primary/90 animate-scale-in'
|
onClick={() => setLoginDialogOpen(true)}
|
||||||
>
|
className='flex items-center gap-2 px-4 py-2 rounded-full bg-primary text-primary-foreground w-full font-medium transition-all hover:bg-primary/90 animate-scale-in'
|
||||||
<User className='w-4 h-4' />
|
>
|
||||||
<span className='truncate'>Log in</span>
|
<User className='w-4 h-4' />
|
||||||
</Button>
|
<span className='truncate'>Log in</span>
|
||||||
|
</Button><Button
|
||||||
|
onClick={() => setSignupDialogOpen(true)}
|
||||||
|
variant="outline"
|
||||||
|
className="flex items-center gap-2 px-4 py-2 rounded-full font-medium transition-all"
|
||||||
|
>
|
||||||
|
<UserPlus className="w-4 h-4" />
|
||||||
|
<span>Sign Up</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<LoginDialog
|
<LoginDialog
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
// It is important that all functionality in this file is preserved, and should only be modified if explicitly requested.
|
// It is important that all functionality in this file is preserved, and should only be modified if explicitly requested.
|
||||||
|
|
||||||
import React, { useRef, useState, useEffect } from 'react';
|
import React, { useRef, useState, useEffect } from 'react';
|
||||||
import { Shield, Upload, AlertTriangle, Sparkles, UserPlus, KeyRound, Lock } from 'lucide-react';
|
import { Shield, Upload, AlertTriangle, UserPlus, KeyRound, Sparkles, Cloud } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
|
import { Dialog, DialogContent, DialogHeader, DialogDescription } from "@/components/ui/dialog";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||||
import { useLoginActions } from '@/hooks/useLoginActions';
|
import { useLoginActions } from '@/hooks/useLoginActions';
|
||||||
@ -182,12 +182,10 @@ const LoginDialog: React.FC<LoginDialogProps> = ({ isOpen, onClose, onLogin, onS
|
|||||||
return (
|
return (
|
||||||
<Dialog open={isOpen} onOpenChange={onClose}>
|
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className={cn("max-w-[95vw] sm:max-w-md max-h-[90vh] max-h-[90dvh] p-0 overflow-hidden rounded-2xl")}
|
className={cn("max-w-[95vw] sm:max-w-md max-h-[90vh] max-h-[90dvh] p-0 overflow-hidden rounded-2xl overflow-y-scroll")}
|
||||||
>
|
>
|
||||||
<DialogHeader className={cn('px-6 pt-6 pb-1 relative')}>
|
<DialogHeader className={cn('px-6 pt-6 pb-1 relative')}>
|
||||||
<DialogTitle className={cn('font-semibold text-center')}>
|
|
||||||
Welcome!
|
|
||||||
</DialogTitle>
|
|
||||||
<DialogDescription className="text-center">
|
<DialogDescription className="text-center">
|
||||||
Sign up or log in to continue
|
Sign up or log in to continue
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
@ -197,22 +195,20 @@ const LoginDialog: React.FC<LoginDialogProps> = ({ isOpen, onClose, onLogin, onS
|
|||||||
<div className='relative p-4 rounded-2xl bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-blue-950/50 dark:to-indigo-950/50 border border-blue-200 dark:border-blue-800 overflow-hidden'>
|
<div className='relative p-4 rounded-2xl bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-blue-950/50 dark:to-indigo-950/50 border border-blue-200 dark:border-blue-800 overflow-hidden'>
|
||||||
<div className='relative z-10 text-center space-y-3'>
|
<div className='relative z-10 text-center space-y-3'>
|
||||||
<div className='flex justify-center items-center gap-2 mb-2'>
|
<div className='flex justify-center items-center gap-2 mb-2'>
|
||||||
<UserPlus className='w-5 h-5 text-blue-600' />
|
<Sparkles className='w-5 h-5 text-purple-600' />
|
||||||
<span className='font-semibold text-blue-800 dark:text-blue-200'>
|
<span className='font-semibold text-purple-800 dark:text-purple-200'>
|
||||||
New to Nostr?
|
New to Nostr?
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<p className='text-sm text-purple-700/80 dark:text-purple-300/80'>
|
||||||
<p className='text-sm text-blue-700 dark:text-blue-300 mb-3'>
|
Create a new account to get started. It's free and open.
|
||||||
Create a new account to join the network.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSignupClick}
|
onClick={handleSignupClick}
|
||||||
className='w-full rounded-full py-3 text-base font-semibold bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 transform transition-all duration-200 hover:scale-105 shadow-lg border-0'
|
className='w-full rounded-full py-3 text-base font-semibold bg-gradient-to-r from-purple-600 to-yellow-600 hover:from-purple-700 hover:to-yellow-700 transform transition-all duration-200 hover:scale-105 shadow-lg border-0'
|
||||||
>
|
>
|
||||||
<Sparkles className='w-4 h-4 mr-2' />
|
<UserPlus className='w-4 h-4 mr-2' />
|
||||||
<span>Create Account</span>
|
<span>Sign Up</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -241,7 +237,7 @@ const LoginDialog: React.FC<LoginDialogProps> = ({ isOpen, onClose, onLogin, onS
|
|||||||
<span>Key</span>
|
<span>Key</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger value="bunker" className="flex items-center gap-2">
|
<TabsTrigger value="bunker" className="flex items-center gap-2">
|
||||||
<Lock className="w-4 h-4" />
|
<Cloud className="w-4 h-4" />
|
||||||
<span>Bunker</span>
|
<span>Bunker</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
@ -276,7 +272,6 @@ const LoginDialog: React.FC<LoginDialogProps> = ({ isOpen, onClose, onLogin, onS
|
|||||||
Secret Key (nsec)
|
Secret Key (nsec)
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
type='password'
|
|
||||||
id='nsec'
|
id='nsec'
|
||||||
type="password"
|
type="password"
|
||||||
value={nsec}
|
value={nsec}
|
||||||
|
@ -99,7 +99,7 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
|
|||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: 'Secret Key Saved!',
|
title: 'Secret Key Saved!',
|
||||||
description: 'Your key has been safely stored. Keep it safe!',
|
description: 'Your key has been safely stored.',
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
toast({
|
toast({
|
||||||
@ -264,7 +264,7 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
|
|||||||
if (step === 'download') return (
|
if (step === 'download') return (
|
||||||
<span className="flex items-center justify-center gap-2">
|
<span className="flex items-center justify-center gap-2">
|
||||||
<Lock className="w-5 h-5 text-primary" />
|
<Lock className="w-5 h-5 text-primary" />
|
||||||
Secure Your Secret Key
|
Secret Key
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
if (step === 'profile') return (
|
if (step === 'profile') return (
|
||||||
@ -284,7 +284,7 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
|
|||||||
const getDescription = () => {
|
const getDescription = () => {
|
||||||
if (step === 'welcome') return 'Ready to join the Nostr network?';
|
if (step === 'welcome') return 'Ready to join the Nostr network?';
|
||||||
if (step === 'generate') return 'Creating your secret key to access Nostr.';
|
if (step === 'generate') return 'Creating your secret key to access Nostr.';
|
||||||
if (step === 'download') return 'This key is your password - keep it safe!';
|
|
||||||
if (step === 'profile') return 'Tell others about yourself.';
|
if (step === 'profile') return 'Tell others about yourself.';
|
||||||
return 'Your account is ready!';
|
return 'Your account is ready!';
|
||||||
};
|
};
|
||||||
@ -320,11 +320,11 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
|
|||||||
<DialogTitle className={cn('font-semibold text-center text-lg')}>
|
<DialogTitle className={cn('font-semibold text-center text-lg')}>
|
||||||
{getTitle()}
|
{getTitle()}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription className={cn('text-muted-foreground text-center')}>
|
<DialogDescription className={cn(`text-muted-foreground text-center ${step === 'download' && 'hidden'}`)}>
|
||||||
{getDescription()}
|
{getDescription()}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className='px-6 pt-2 pb-4 space-y-4 overflow-y-auto flex-1'>
|
<div className='px-6 pt-2 pb-4 space-y-4 overflow-y-scroll flex-1'>
|
||||||
{/* Welcome Step - New engaging introduction */}
|
{/* Welcome Step - New engaging introduction */}
|
||||||
{step === 'welcome' && (
|
{step === 'welcome' && (
|
||||||
<div className='text-center space-y-4'>
|
<div className='text-center space-y-4'>
|
||||||
@ -430,9 +430,7 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
|
|||||||
<p className='text-sm text-muted-foreground px-5'>
|
<p className='text-sm text-muted-foreground px-5'>
|
||||||
This key will be your password to access applications within the Nostr network.
|
This key will be your password to access applications within the Nostr network.
|
||||||
</p>
|
</p>
|
||||||
<p className='text-sm text-muted-foreground px-5'>
|
|
||||||
It's completely unique and secure:<br></br>keep it secret, keep it safe!
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -499,106 +497,95 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Key vault */}
|
{/* Key vault */}
|
||||||
<div className='relative p-3 bg-gradient-to-br from-slate-100 to-slate-200 dark:from-slate-800 dark:to-slate-900 rounded-xl border-2 border-dashed border-blue-400 dark:border-blue-600 shadow-inner'>
|
|
||||||
<div className='flex items-center gap-2 mb-2'>
|
|
||||||
<Lock className='w-4 h-4 text-blue-600' />
|
|
||||||
<span className='text-sm font-medium text-blue-800 dark:text-blue-200'>
|
|
||||||
Your Secret Key
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className='p-2 bg-background/90 rounded-lg border border-blue-300 dark:border-blue-700'>
|
|
||||||
<code className='text-xs break-all font-mono text-blue-900 dark:text-blue-100'>{nsec}</code>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Security options */}
|
{/* Security options */}
|
||||||
<div className='space-y-3'>
|
<div className='space-y-3'>
|
||||||
<div className='text-center'>
|
|
||||||
<p className='text-sm font-medium text-muted-foreground mb-2'>
|
|
||||||
Choose how to secure your key:
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='grid grid-cols-1 gap-2'>
|
<div className='grid grid-cols-1 gap-2'>
|
||||||
{/* Copy Option */}
|
|
||||||
<Card className={`cursor-pointer transition-all duration-200 ${
|
|
||||||
keySecured === 'copied'
|
|
||||||
? 'ring-2 ring-green-500 bg-green-50 dark:bg-green-950/20'
|
|
||||||
: 'hover:bg-muted/50 dark:bg-muted'
|
|
||||||
}`}>
|
|
||||||
<CardContent className='p-3'>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
className='w-full h-auto p-0 justify-start'
|
|
||||||
onClick={copyKey}
|
|
||||||
>
|
|
||||||
<div className='flex items-center gap-3 w-full'>
|
|
||||||
<div className={`p-1.5 rounded-lg ${
|
|
||||||
keySecured === 'copied'
|
|
||||||
? 'bg-green-100 dark:bg-green-900'
|
|
||||||
: 'bg-muted'
|
|
||||||
}`}>
|
|
||||||
{keySecured === 'copied' ? (
|
|
||||||
<CheckCircle className='w-4 h-4 text-green-600' />
|
|
||||||
) : (
|
|
||||||
<Copy className='w-4 h-4 text-muted-foreground' />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className='flex-1 text-left'>
|
|
||||||
<div className='font-medium text-sm'>
|
|
||||||
Copy to Clipboard
|
|
||||||
</div>
|
|
||||||
<div className='text-xs text-muted-foreground'>
|
|
||||||
Save to password manager
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{keySecured === 'copied' && (
|
|
||||||
<div className='text-xs font-medium text-green-600'>
|
|
||||||
✓ Copied
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Download Option */}
|
{/* Download Option */}
|
||||||
<Card className={`cursor-pointer transition-all duration-200 ${
|
<Card className={`cursor-pointer transition-all duration-200 ${
|
||||||
keySecured === 'downloaded'
|
keySecured === 'downloaded'
|
||||||
? 'ring-2 ring-green-500 bg-green-50 dark:bg-green-950/20'
|
? 'ring-2 ring-green-500 bg-green-50 dark:bg-green-950/20'
|
||||||
: 'hover:bg-muted/50 dark:bg-muted'
|
: 'hover:bg-primary/5 hover:border-primary/20'
|
||||||
}`}>
|
}`}>
|
||||||
<CardContent className='p-3'>
|
<CardContent className='p-3'>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className='w-full h-auto p-0 justify-start'
|
className='w-full h-auto p-0 justify-start hover:bg-transparent'
|
||||||
onClick={downloadKey}
|
onClick={downloadKey}
|
||||||
>
|
>
|
||||||
<div className='flex items-center gap-3 w-full'>
|
<div className='flex items-center gap-3 w-full'>
|
||||||
<div className={`p-1.5 rounded-lg ${
|
<div className={`p-1.5 rounded-lg ${
|
||||||
keySecured === 'downloaded'
|
keySecured === 'downloaded'
|
||||||
? 'bg-green-100 dark:bg-green-900'
|
? 'bg-green-100 dark:bg-green-900'
|
||||||
: 'bg-muted'
|
: 'bg-primary/10'
|
||||||
}`}>
|
}`}>
|
||||||
{keySecured === 'downloaded' ? (
|
{keySecured === 'downloaded' ? (
|
||||||
<CheckCircle className='w-4 h-4 text-green-600' />
|
<CheckCircle className='w-4 h-4 text-green-600' />
|
||||||
) : (
|
) : (
|
||||||
<Download className='w-4 h-4 text-muted-foreground' />
|
<Download className='w-4 h-4 text-primary' />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex-1 text-left'>
|
<div className='flex-1 text-left'>
|
||||||
<div className='font-medium text-sm'>
|
<div className='font-medium text-sm'>
|
||||||
Download as File
|
Download as File
|
||||||
</div>
|
</div>
|
||||||
<div className='text-xs text-muted-foreground'>
|
<div className='text-xs text-muted-foreground'>
|
||||||
Save as secret-key.txt file
|
Save as secret-key.txt file
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{keySecured === 'downloaded' && (
|
{keySecured === 'downloaded' && (
|
||||||
<div className='text-xs font-medium text-green-600'>
|
<div className='text-xs font-medium text-green-600'>
|
||||||
✓ Downloaded
|
✓ Downloaded
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Copy Option */}
|
||||||
|
<Card className={`cursor-pointer transition-all duration-200 ${
|
||||||
|
keySecured === 'copied'
|
||||||
|
? 'ring-2 ring-green-500 bg-green-50 dark:bg-green-950/20'
|
||||||
|
: 'hover:bg-primary/5 hover:border-primary/20'
|
||||||
|
}`}>
|
||||||
|
<CardContent className='p-3'>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className='w-full h-auto p-0 justify-start hover:bg-transparent'
|
||||||
|
onClick={copyKey}
|
||||||
|
>
|
||||||
|
<div className='flex items-center gap-3 w-full'>
|
||||||
|
<div className={`p-1.5 rounded-lg ${
|
||||||
|
keySecured === 'copied'
|
||||||
|
? 'bg-green-100 dark:bg-green-900'
|
||||||
|
: 'bg-primary/10'
|
||||||
|
}`}>
|
||||||
|
{keySecured === 'copied' ? (
|
||||||
|
<CheckCircle className='w-4 h-4 text-green-600' />
|
||||||
|
) : (
|
||||||
|
<Copy className='w-4 h-4 text-primary' />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='flex-1 text-left'>
|
||||||
|
<div className='font-medium text-sm'>
|
||||||
|
Copy to Clipboard
|
||||||
|
</div>
|
||||||
|
<div className='text-xs text-muted-foreground'>
|
||||||
|
Save to password manager
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div className='text-[.7rem] text-muted-foreground'>
|
||||||
|
{nsec.slice(0,16)}...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{keySecured === 'copied' && (
|
||||||
|
<div className='text-xs font-medium text-green-600'>
|
||||||
|
✓ Copied
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@ -609,8 +596,8 @@ const SignupDialog: React.FC<SignupDialogProps> = ({ isOpen, onClose, onComplete
|
|||||||
<Button
|
<Button
|
||||||
className={`w-full rounded-full py-4 text-base font-semibold transform transition-all duration-200 shadow-lg ${
|
className={`w-full rounded-full py-4 text-base font-semibold transform transition-all duration-200 shadow-lg ${
|
||||||
keySecured !== 'none'
|
keySecured !== 'none'
|
||||||
? 'bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 hover:scale-105'
|
? 'bg-gradient-to-r from-purple-600 to-yellow-600 hover:from-purple-700 hover:to-yellow-700 hover:scale-105'
|
||||||
: 'bg-muted text-muted-foreground cursor-not-allowed'
|
: 'bg-gradient-to-r from-purple-600/60 to-yellow-600/60 text-foreground cursor-not-allowed'
|
||||||
}`}
|
}`}
|
||||||
onClick={finishKeySetup}
|
onClick={finishKeySetup}
|
||||||
disabled={keySecured === 'none'}
|
disabled={keySecured === 'none'}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user