import { useState } from 'react' import { IconChevronRight, IconEggCracked, IconLoader2, IconPlus } from '@tabler/icons-react' import { Link, useLocation } from 'wouter' import { useDiscoveredWorkspaces, useWorkspacePreview, useWorkspaces, useWorkspaceSetupInfo } from './api' import { CreateWorkspaceDialog } from './workspace-setup/CreateWorkspaceDialog' import { ImportWorkspaceDialog } from './workspace-setup/ImportWorkspaceDialog' import { DemoDialog } from './workspace-setup/DemoDialog' import { useWorkspaceImport } from './workspace-setup/useWorkspaceImport' import { HomeLogo } from './HomeLogo' import { useAppConfig } from '@/client/api/app-config' import { Button } from '@/client/components/ui/button' import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/client/components/ui/collapsible' import { cn } from '@/client/lib/cn' import { getWorkspaceThemeStyle, usePreloadWorkspaceFonts } from '@/client/runtime/workspace-theme' import { useUiStore } from '@/client/store/ui' import { WorkspaceAgentIcons, workspaceDisplayName, workspaceProviderIcon } from '@/client/features/home/workspace-presentation' import type { DiscoveredWorkspace, WorkspaceEntry } from '@/lib/types' import { WorkspacePreview } from './WorkspacePreview' export function HomePage() { usePreloadWorkspaceFonts() const [, navigate] = useLocation() const workspacesQuery = useWorkspaces() const discoveredQuery = useDiscoveredWorkspaces() const setupInfo = useWorkspaceSetupInfo() const importFlow = useWorkspaceImport({ onSuccess: entry => navigate(`/workspace/${entry.id}`) }) const appConfig = useAppConfig() const [promoDialogOpen, setPromoDialogOpen] = useState(false) const discoveredWorkspacesOpen = useUiStore(state => state.discoveredWorkspacesOpen) const setDiscoveredWorkspacesOpen = useUiStore(state => state.setDiscoveredWorkspacesOpen) if (workspacesQuery.isPending || discoveredQuery.isPending) { return (
) } if (workspacesQuery.isError || discoveredQuery.isError) { return (

Could not load spaces.

) } const workspaces = workspacesQuery.data const discovered = discoveredQuery.data const count = workspaces.length function handleAdd(suggestion: DiscoveredWorkspace) { // Cloud demo: adding workspaces is off — offer the promo dialog instead. if (appConfig.cloudDemo) { setPromoDialogOpen(true) return } importFlow.startImport(suggestion) } return (
{count > 0 ? (

My workspaces

New } />
{workspaces.map(workspace => ( ))}
) : (

Let’s start with creating your first workspace

Workspace is a place for all the chats, widgets, and views that share the same context. Create a new one or import an existing folder you’ve worked in before.

Create workspace} />
)} {discovered.length > 0 && (
Import from this computer
    {discovered.map(item => ( ))}
)} {importFlow.choice && ( )}
) } type WorkspaceCardProps = { workspace: WorkspaceEntry } function WorkspaceCard({ workspace }: WorkspaceCardProps) { const name = workspaceDisplayName(workspace) const previewQuery = useWorkspacePreview(workspace.id) const theme = previewQuery.data?.theme const updatedAt = previewQuery.data?.updatedAt ?? new Date(workspace.addedAt).getTime() return (
{name}
{formatUpdatedAt(updatedAt)}
) } type SuggestedRowProps = { suggestion: DiscoveredWorkspace onAdd: (suggestion: DiscoveredWorkspace) => void } function SuggestedRow({ suggestion, onAdd }: SuggestedRowProps) { const { path, types } = suggestion const name = workspaceDisplayName(suggestion) return (
  • {name} {suggestion.displayPath ?? path}
  • ) } function formatUpdatedAt(timestamp: number): string { const ms = Date.now() - timestamp const mins = Math.floor(ms / 60000) if (mins < 1) return 'Updated just now' if (mins < 60) return `Updated ${mins} min${mins === 1 ? '' : 's'} ago` const hours = Math.floor(mins / 60) if (hours < 24) return `Updated ${hours} hour${hours === 1 ? '' : 's'} ago` const days = Math.floor(hours / 24) if (days < 30) return `Updated ${days} day${days === 1 ? '' : 's'} ago` return `Updated ${new Date(timestamp).toLocaleDateString()}` }