Files
vibn-frontend/design-templates/VIBN (2)/auth-shared.jsx

124 lines
4.7 KiB
JavaScript

// Shared auth-page primitives. Both Sign In and Sign Up use these.
function Logo({ size = 26 }) {
return (
<a href="index.html" className="logo">
<span className="logo-mark" style={{ width: size, height: size }}>
<svg viewBox="0 0 36 32" width="74%" height="74%" fill="currentColor" stroke="currentColor" strokeWidth="1.2" strokeLinejoin="round" aria-hidden="true">
<path d="M4 5 L10 5 L12 18 L14 5 L20 5 L12 27 Z" />
<rect x="22.5" y="23" width="9.5" height="3.8" rx="0.7" className="logo-caret" />
</svg>
</span>
<span>vibn</span>
</a>
);
}
function TopBar({ rightLink }) {
return (
<header className="topbar">
<Logo />
{rightLink && (
<a href={rightLink.href} className="topbar-back">
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M13 8H3M7 4 3 8l4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
{rightLink.label}
</a>
)}
</header>
);
}
function Glows() {
return (
<>
<div className="auth-glow" style={{
width: 700, height: 700,
top: -150, left: "50%", transform: "translateX(-50%)",
background: "radial-gradient(circle at center, oklch(0.74 0.175 35 / 0.22) 0%, transparent 62%)",
}} />
<div className="auth-glow" style={{
width: 500, height: 500,
bottom: -100, left: 0,
background: "radial-gradient(circle at center, oklch(0.45 0.10 35 / 0.20) 0%, transparent 62%)",
}} />
<div className="auth-glow" style={{
width: 450, height: 450,
top: "50%", right: -150,
background: "radial-gradient(circle at center, oklch(0.45 0.10 35 / 0.15) 0%, transparent 62%)",
}} />
</>
);
}
function Arrow({ size = 14 }) {
return (
<svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
);
}
// Google "G" mark — inline SVG so we don't need to bundle an asset.
function GoogleIcon({ size = 16 }) {
return (
<svg width={size} height={size} viewBox="0 0 18 18" aria-hidden="true">
<path fill="#EA4335" d="M9 3.6c1.3 0 2.5.5 3.4 1.3l2.5-2.5C13.4 1 11.3.1 9 .1 5.5.1 2.4 2.1.9 5.1l2.9 2.3C4.5 5.2 6.6 3.6 9 3.6Z"/>
<path fill="#34A853" d="M17.6 9.2c0-.6-.1-1.2-.2-1.8H9v3.4h4.9c-.2 1.1-.9 2-1.9 2.6l2.9 2.3c1.7-1.6 2.7-3.9 2.7-6.5Z"/>
<path fill="#FBBC05" d="M3.8 10.7c-.2-.6-.3-1.1-.3-1.7s.1-1.2.3-1.7L.9 5C.3 6.2 0 7.5 0 9s.3 2.8.9 4l2.9-2.3Z"/>
<path fill="#4285F4" d="M9 17.9c2.4 0 4.4-.8 5.9-2.2l-2.9-2.3c-.8.5-1.8.9-3 .9-2.3 0-4.3-1.6-5-3.7L1.1 12.9C2.6 15.9 5.6 17.9 9 17.9Z"/>
</svg>
);
}
// Apple mark (filled apple silhouette)
function AppleIcon({ size = 16 }) {
return (
<svg width={size} height={size} viewBox="0 0 18 18" fill="currentColor" aria-hidden="true">
<path d="M14.7 13.1c-.4 1-1 1.9-1.7 2.5-.5.5-1.1.7-1.7.7-.6 0-1-.2-1.7-.5-.7-.3-1.3-.5-1.8-.5s-1.2.2-1.9.5c-.7.3-1.2.4-1.6.5-.6 0-1.2-.2-1.7-.7C2 14.8 1.4 13.6.9 12c-.5-1.7-.7-3.3-.6-4.7.1-1.6.7-2.9 1.7-3.9C2.8 2.7 3.8 2.2 5 2.2c.4 0 .9.1 1.5.4s1 .4 1.2.4c.2 0 .7-.1 1.4-.4.7-.3 1.3-.4 1.7-.4 1 .1 1.9.5 2.6 1.3-.9.6-1.4 1.5-1.4 2.6 0 .9.3 1.6 1 2.2.3.3.6.5 1 .6-.1.2-.2.5-.3.7Zm-3-12c0 .8-.3 1.6-.9 2.4-.7.9-1.6 1.5-2.6 1.4 0-.1 0-.2 0-.3 0-.8.3-1.6.9-2.3.3-.4.7-.7 1.1-.9.4-.2.9-.4 1.4-.4 0 .1 0 .1.1.1Z"/>
</svg>
);
}
function MailIcon({ size = 18 }) {
return (
<svg width={size} height={size} viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden="true">
<rect x="2.5" y="4.5" width="15" height="11" rx="1.5"/>
<path d="M3.5 6 10 11l6.5-5"/>
</svg>
);
}
function TrustStrip({ items }) {
return (
<div className="auth-trust">
{items.map((item, i) => (
<React.Fragment key={i}>
{i > 0 && <span className="sep">·</span>}
<span>{item}</span>
</React.Fragment>
))}
</div>
);
}
// useResendTimer — manages a countdown for the "Resend in 30s" CTA after the
// magic-link confirmation state. Returns [remaining, restart].
function useResendTimer(initialSeconds = 30) {
const [left, setLeft] = React.useState(initialSeconds);
React.useEffect(() => {
if (left <= 0) return undefined;
const t = setTimeout(() => setLeft(left - 1), 1000);
return () => clearTimeout(t);
}, [left]);
const restart = () => setLeft(initialSeconds);
return [left, restart];
}
Object.assign(window, {
Logo, TopBar, Glows, Arrow,
GoogleIcon, AppleIcon, MailIcon,
TrustStrip, useResendTimer,
});