import { useState } from 'react' import { FolderOpen, Plus, AlertTriangle, Loader2, Rocket } from 'lucide-react' interface WelcomeScreenProps { mode: 'welcome' | 'vault-missing' missingPath?: string defaultVaultPath: string onCreateVault: () => void onRetryCreateVault: () => void onCreateNewVault: () => void onOpenFolder: () => void creatingAction: 'template' | 'empty' | null error: string | null canRetryTemplate: boolean } const CONTAINER_STYLE: React.CSSProperties = { width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--sidebar)', } const CARD_STYLE: React.CSSProperties = { width: 520, background: 'var(--background)', borderRadius: 12, border: '1px solid var(--border)', padding: 48, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 24, } const ICON_WRAP_STYLE: React.CSSProperties = { width: 64, height: 64, borderRadius: 16, display: 'flex', alignItems: 'center', justifyContent: 'center', } const TITLE_STYLE: React.CSSProperties = { fontSize: 28, fontWeight: 700, letterSpacing: -0.5, color: 'var(--foreground)', textAlign: 'center', margin: 0, } const SUBTITLE_STYLE: React.CSSProperties = { fontSize: 14, lineHeight: 1.6, color: 'var(--muted-foreground)', textAlign: 'center', margin: 0, } const DIVIDER_STYLE: React.CSSProperties = { width: '100%', height: 1, background: 'var(--border)', } const OPTION_BTN_STYLE: React.CSSProperties = { width: '100%', borderRadius: 8, border: '1px solid var(--border)', background: 'var(--background)', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 14, padding: '14px 16px', textAlign: 'left', transition: 'background 0.15s', } const OPTION_ICON_STYLE: React.CSSProperties = { width: 36, height: 36, borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, } const OPTION_LABEL_STYLE: React.CSSProperties = { fontSize: 14, fontWeight: 600, color: 'var(--foreground)', margin: 0, } const OPTION_DESC_STYLE: React.CSSProperties = { fontSize: 12, color: 'var(--muted-foreground)', margin: 0, marginTop: 2, } const ERROR_STYLE: React.CSSProperties = { fontSize: 13, color: 'var(--destructive, #e03e3e)', textAlign: 'center', margin: 0, } const STATUS_STYLE: React.CSSProperties = { fontSize: 13, color: 'var(--muted-foreground)', textAlign: 'center', margin: 0, } const ERROR_BLOCK_STYLE: React.CSSProperties = { width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10, } const RETRY_BUTTON_STYLE: React.CSSProperties = { borderRadius: 8, border: '1px solid var(--border)', background: 'var(--background)', color: 'var(--foreground)', cursor: 'pointer', padding: '8px 12px', fontSize: 13, fontWeight: 600, } interface OptionButtonProps { icon: React.ReactNode iconBg: string label: string description: string loadingLabel?: string loadingDescription?: string onClick: () => void disabled: boolean loading?: boolean testId: string } function OptionButton({ icon, iconBg, label, description, loadingLabel, loadingDescription, onClick, disabled, loading, testId, }: OptionButtonProps) { const [hover, setHover] = useState(false) return ( ) } export function WelcomeScreen({ mode, defaultVaultPath, onCreateVault, onRetryCreateVault, onCreateNewVault, onOpenFolder, creatingAction, error, canRetryTemplate, }: WelcomeScreenProps) { const isWelcome = mode === 'welcome' const busy = creatingAction !== null return (
{isWelcome ? : }

{isWelcome ? 'Welcome to Laputa' : 'Vault not found'}

{isWelcome ? 'Wiki-linked knowledge management for deep thinkers.\nChoose how to get started.' : 'The vault folder could not be found on disk.\nIt may have been moved or deleted.' }

} iconBg="var(--accent-blue-light, #EBF4FF)" label="Create a new vault" description="Start fresh in a folder you choose" loadingLabel="Creating vault…" loadingDescription="Preparing an empty vault in the selected folder" onClick={onCreateNewVault} disabled={busy} loading={creatingAction === 'empty'} testId="welcome-create-new" /> } iconBg="var(--accent-green-light, #E8F5E9)" label={isWelcome ? 'Open existing vault' : 'Choose a different folder'} description="Point to a folder you already have" onClick={onOpenFolder} disabled={busy} testId="welcome-open-folder" /> } iconBg="var(--accent-purple-light, #F3E8FF)" label="Get started with a template" description={`Download the starter vault from GitHub \u2014 suggested path: ${defaultVaultPath}`} loadingLabel="Downloading template…" loadingDescription="Cloning the Getting Started vault from GitHub" onClick={onCreateVault} disabled={busy} loading={creatingAction === 'template'} testId="welcome-create-vault" />
{creatingAction === 'template' && (

Downloading the Getting Started vault from GitHub…

)} {error && (

{error}

{canRetryTemplate && ( )}
)}
) }