Skip to content
Clone
eeff292
87 lines 4.0 KB
import { KernelMark } from '@app/components/brand'
import { useT } from '@app/i18n'
import { getRegion, toggleTheme, useTheme } from '@app/lib'
import { IconMoon as Moon, IconSun as Sun } from '@tabler/icons-react'
import { type ReactNode, useEffect } from 'react'
import { Link } from 'react-router-dom'
export interface AuthShellProps {
/** Breadcrumb current segment, e.g. "SIGN IN". */
current: string
/** Mono caption above the status row, unique per screen. */
hint: string
children: ReactNode
}
const mark = 'pointer-events-none absolute size-[18px] border-border'
const markTL = 'left-4 top-4 sm:left-6 sm:top-6 lg:left-9 lg:top-9'
const markTR = 'right-4 top-4 sm:right-6 sm:top-6 lg:right-9 lg:top-9'
const markBL = 'bottom-4 left-4 sm:bottom-6 sm:left-6 lg:bottom-9 lg:left-9'
const markBR = 'bottom-4 right-4 sm:bottom-6 sm:right-6 lg:bottom-9 lg:right-9'
const crumbSep = 'font-mono text-[10px] text-border'
/** Full-viewport chrome shared by all auth screens. */
export function AuthShell({ current, hint, children }: AuthShellProps) {
const { t } = useT()
const theme = useTheme()
const region = getRegion()
// Each auth screen is a full document: keep the tab title in step with the
// active step and the interface language (current is already localized).
useEffect(() => {
document.title = `${current} · ${t('common.app.name')}`
}, [current, t])
return (
<main className="relative flex min-h-screen items-center justify-center overflow-hidden bg-background px-4 py-10 sm:px-8 lg:p-6">
<div
aria-hidden
className="pointer-events-none absolute left-1/2 top-1/2 h-[400px] w-[340px] -translate-x-1/2 -translate-y-1/2 bg-[radial-gradient(closest-side,rgba(255,132,0,0.15),rgba(255,132,0,0))] sm:h-[480px] sm:w-[620px] lg:h-[600px] lg:w-[900px]"
/>
<div
aria-hidden
className="pointer-events-none absolute inset-0 bg-gradient-to-b from-transparent via-transparent via-55% to-black/[0.04] dark:to-white/[0.05]"
/>
<div aria-hidden className={`${mark} ${markTL} border-l border-t`} />
<div aria-hidden className={`${mark} ${markTR} border-r border-t`} />
<div aria-hidden className={`${mark} ${markBL} border-b border-l`} />
<div aria-hidden className={`${mark} ${markBR} border-b border-r`} />
<nav
aria-label={t('auth.shell.breadcrumb')}
className="absolute left-8 top-9 hidden items-center gap-2 font-mono text-[10px] tracking-[1.2px] sm:flex lg:left-[70px]"
>
<KernelMark size={14} radius={4} />
<Link to="/" className="font-bold text-foreground">
GitDataAI
</Link>
<span className={crumbSep}>/</span>
<span className="text-muted-foreground">AUTH</span>
<span className={crumbSep}>/</span>
<span className="font-bold text-warning-foreground">{current}</span>
</nav>
<button
type="button"
onClick={toggleTheme}
aria-label={theme === 'dark' ? t('auth.shell.switchToLight') : t('auth.shell.switchToDark')}
className="absolute right-[40px] top-[16px] z-20 flex size-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring sm:right-[52px] sm:top-[20px] lg:right-[60px] lg:top-[30px]"
>
{theme === 'dark' ? <Sun size={15} aria-hidden /> : <Moon size={15} aria-hidden />}
</button>
<div className="relative z-10 flex w-full justify-center">{children}</div>
<div className="pointer-events-none absolute inset-x-0 bottom-[39px] flex flex-col items-center gap-[10px] px-4">
<p className="text-center font-mono text-[10px] leading-relaxed tracking-[1.2px] text-muted-foreground">
{hint}
</p>
<p className="flex items-center gap-2.5 font-mono text-[11px] tracking-[0.5px] text-muted-foreground">
<span>{t('auth.shell.region', { region }).toUpperCase()}</span>
<span className="text-border">·</span>
<span>© 2026 GitDataAI</span>
</p>
</div>
</main>
)
}