feat(appliance): initial release of MERICA standalone appliance v1.0.0
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Layers, ShieldCheck, UserCheck, Eye, Lock, ArrowRight, CheckCircle } from 'lucide-react';
|
||||
|
||||
export default function LoginModal({ isOpen, onLogin }) {
|
||||
const [email, setEmail] = useState('admin@dlh.go.id');
|
||||
const [password, setPassword] = useState('admin123');
|
||||
const [selectedRole, setSelectedRole] = useState('admin');
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
const handleQuickFill = (role) => {
|
||||
setSelectedRole(role);
|
||||
if (role === 'admin') {
|
||||
setEmail('admin@dlh.go.id');
|
||||
setPassword('admin123');
|
||||
} else {
|
||||
setEmail('viewer@dlh.go.id');
|
||||
setPassword('viewer123');
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
onLogin({
|
||||
email,
|
||||
role: selectedRole,
|
||||
name: selectedRole === 'admin' ? 'Administrator (DLH Lead)' : 'Guest Inspector (Viewer)',
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
background: 'rgba(8, 9, 13, 0.85)',
|
||||
backdropFilter: 'blur(12px)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
zIndex: 1000,
|
||||
padding: '20px',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
maxWidth: '480px',
|
||||
background: 'var(--color-surface, #0E1016)',
|
||||
border: '1px solid var(--color-border-strong, rgba(255,255,255,0.14))',
|
||||
borderRadius: 'var(--radius-2xl, 24px)',
|
||||
boxShadow: '0 25px 70px rgba(0,0,0,0.5)',
|
||||
padding: '32px',
|
||||
color: 'var(--color-text-primary, #F5F7FA)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '24px',
|
||||
}}
|
||||
>
|
||||
{/* BRAND HEADER */}
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<div
|
||||
style={{
|
||||
width: '52px',
|
||||
height: '52px',
|
||||
borderRadius: '16px',
|
||||
background: 'linear-gradient(135deg, #8B7CFF 0%, #6377FF 100%)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
margin: '0 auto 14px auto',
|
||||
boxShadow: '0 8px 24px rgba(139, 124, 255, 0.35)',
|
||||
}}
|
||||
>
|
||||
<Layers size={28} color="#ffffff" />
|
||||
</div>
|
||||
<h2 style={{ fontSize: '20px', fontWeight: '700', margin: '0 0 6px 0', letterSpacing: '-0.3px' }}>
|
||||
DLH Low-Code Studio Access
|
||||
</h2>
|
||||
<p style={{ fontSize: '13px', color: 'var(--color-text-muted, #707686)', margin: 0 }}>
|
||||
Select user role or quick-autofill credentials to sign in
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* QUICK AUTOFILL ROLE SELECTOR BUTTONS */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px' }}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleQuickFill('admin')}
|
||||
style={{
|
||||
padding: '12px',
|
||||
borderRadius: '12px',
|
||||
border: selectedRole === 'admin' ? '2px solid #8B7CFF' : '1px solid var(--color-border-subtle, rgba(255,255,255,0.06))',
|
||||
background: selectedRole === 'admin' ? 'rgba(139, 124, 255, 0.12)' : 'var(--color-surface-raised, #12141B)',
|
||||
color: selectedRole === 'admin' ? '#ffffff' : 'var(--color-text-muted, #707686)',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
transition: 'all 0.2s ease',
|
||||
}}
|
||||
>
|
||||
<UserCheck size={20} color={selectedRole === 'admin' ? '#8B7CFF' : '#707686'} />
|
||||
<span style={{ fontSize: '12px', fontWeight: '700' }}>👑 Admin Role</span>
|
||||
<span style={{ fontSize: '10px', opacity: 0.8 }}>Full Edit & Deploy</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleQuickFill('viewer')}
|
||||
style={{
|
||||
padding: '12px',
|
||||
borderRadius: '12px',
|
||||
border: selectedRole === 'viewer' ? '2px solid #38bdf8' : '1px solid var(--color-border-subtle, rgba(255,255,255,0.06))',
|
||||
background: selectedRole === 'viewer' ? 'rgba(56, 189, 248, 0.12)' : 'var(--color-surface-raised, #12141B)',
|
||||
color: selectedRole === 'viewer' ? '#ffffff' : 'var(--color-text-muted, #707686)',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
transition: 'all 0.2s ease',
|
||||
}}
|
||||
>
|
||||
<Eye size={20} color={selectedRole === 'viewer' ? '#38bdf8' : '#707686'} />
|
||||
<span style={{ fontSize: '12px', fontWeight: '700' }}>👁️ Viewer Role</span>
|
||||
<span style={{ fontSize: '10px', opacity: 0.8 }}>Read-Only Canvas</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* LOGIN FORM */}
|
||||
<form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '14px' }}>
|
||||
<div>
|
||||
<label style={{ fontSize: '12px', fontWeight: '600', color: 'var(--color-text-secondary, #A5AAB8)', display: 'block', marginBottom: '6px' }}>
|
||||
User Email Address
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '10px 14px',
|
||||
borderRadius: '8px',
|
||||
background: 'var(--color-surface-raised, #12141B)',
|
||||
border: '1px solid var(--color-border-default, rgba(255,255,255,0.09))',
|
||||
color: 'var(--color-text-primary, #F5F7FA)',
|
||||
fontSize: '13px',
|
||||
outline: 'none',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={{ fontSize: '12px', fontWeight: '600', color: 'var(--color-text-secondary, #A5AAB8)', display: 'block', marginBottom: '6px' }}>
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '10px 14px',
|
||||
borderRadius: '8px',
|
||||
background: 'var(--color-surface-raised, #12141B)',
|
||||
border: '1px solid var(--color-border-default, rgba(255,255,255,0.09))',
|
||||
color: 'var(--color-text-primary, #F5F7FA)',
|
||||
fontSize: '13px',
|
||||
outline: 'none',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '12px',
|
||||
borderRadius: '10px',
|
||||
background: selectedRole === 'admin'
|
||||
? 'linear-gradient(135deg, #8B7CFF 0%, #6377FF 100%)'
|
||||
: 'linear-gradient(135deg, #0EA5E9 0%, #0284C7 100%)',
|
||||
color: '#ffffff',
|
||||
border: 'none',
|
||||
fontSize: '14px',
|
||||
fontWeight: '700',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '8px',
|
||||
marginTop: '6px',
|
||||
boxShadow: '0 4px 16px rgba(139, 124, 255, 0.3)',
|
||||
}}
|
||||
>
|
||||
Enter Studio Workspace as {selectedRole.toUpperCase()} <ArrowRight size={16} />
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user