From a91f40010031bcc6a29c180d2801afa63ebfe339 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Feb 2026 14:41:18 +0000 Subject: [PATCH 1/3] Add dashboard landing page with clickable logo navigation The Toes logo now links to a system-wide dashboard view that shows app and tool counts. This is the default view when first opening the web app. https://claude.ai/code/session_013L9HKHxMEoub76B1zuKive --- src/client/components/Dashboard.tsx | 7 ++- src/client/components/DashboardLanding.tsx | 40 +++++++++++++ src/client/components/Sidebar.tsx | 13 ++++- src/client/index.tsx | 6 +- src/client/styles/index.ts | 9 +++ src/client/styles/layout.ts | 67 ++++++++++++++++++++++ 6 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 src/client/components/DashboardLanding.tsx diff --git a/src/client/components/Dashboard.tsx b/src/client/components/Dashboard.tsx index 4c436be..427179e 100644 --- a/src/client/components/Dashboard.tsx +++ b/src/client/components/Dashboard.tsx @@ -1,8 +1,9 @@ import { Styles } from '@because/forge' -import { Modal } from './modal' import { apps, isNarrow, selectedApp } from '../state' -import { EmptyState, Layout } from '../styles' +import { Layout } from '../styles' import { AppDetail } from './AppDetail' +import { DashboardLanding } from './DashboardLanding' +import { Modal } from './modal' import { Sidebar } from './Sidebar' export function Dashboard({ render }: { render: () => void }) { @@ -15,7 +16,7 @@ export function Dashboard({ render }: { render: () => void }) { {selected ? ( ) : ( - Select an app to view details + )} diff --git a/src/client/components/DashboardLanding.tsx b/src/client/components/DashboardLanding.tsx new file mode 100644 index 0000000..183d3d2 --- /dev/null +++ b/src/client/components/DashboardLanding.tsx @@ -0,0 +1,40 @@ +import { apps } from '../state' +import { + DashboardContainer, + DashboardHeader, + DashboardSubtitle, + DashboardTitle, + StatCard, + StatLabel, + StatValue, + StatsGrid, +} from '../styles' + +export function DashboardLanding() { + const regularApps = apps.filter(app => !app.tool) + const toolApps = apps.filter(app => app.tool) + const runningApps = apps.filter(app => app.state === 'running') + + return ( + + + 🐾 Toes + Your personal web appliance + + + + {regularApps.length} + Apps + + + {toolApps.length} + Tools + + + {runningApps.length} + Running + + + + ) +} diff --git a/src/client/components/Sidebar.tsx b/src/client/components/Sidebar.tsx index c3987e7..ba586cc 100644 --- a/src/client/components/Sidebar.tsx +++ b/src/client/components/Sidebar.tsx @@ -1,5 +1,6 @@ import { openNewAppModal } from '../modals' import { + setSelectedApp, setSidebarCollapsed, sidebarCollapsed, } from '../state' @@ -7,6 +8,7 @@ import { HamburgerButton, HamburgerLine, Logo, + LogoLink, NewAppButton, Sidebar as SidebarContainer, SidebarFooter, @@ -14,6 +16,11 @@ import { import { AppSelector } from './AppSelector' export function Sidebar({ render }: { render: () => void }) { + const goToDashboard = () => { + setSelectedApp(null) + render() + } + const toggleSidebar = () => { setSidebarCollapsed(!sidebarCollapsed) render() @@ -22,7 +29,11 @@ export function Sidebar({ render }: { render: () => void }) { return ( - {!sidebarCollapsed && 🐾 Toes} + {!sidebarCollapsed && ( + + 🐾 Toes + + )} diff --git a/src/client/index.tsx b/src/client/index.tsx index 33236b5..0495d55 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -45,7 +45,9 @@ narrowQuery.addEventListener('change', e => { const events = new EventSource('/api/apps/stream') events.onmessage = e => { setApps(JSON.parse(e.data)) - const valid = selectedApp && apps.some(a => a.name === selectedApp) - if (!valid && apps.length) setSelectedApp(apps[0]!.name) + // If selected app no longer exists, clear selection to show dashboard + if (selectedApp && !apps.some(a => a.name === selectedApp)) { + setSelectedApp(null) + } render() } diff --git a/src/client/styles/index.ts b/src/client/styles/index.ts index 42a6847..6be7e61 100644 --- a/src/client/styles/index.ts +++ b/src/client/styles/index.ts @@ -5,11 +5,16 @@ export { AppList, AppSelectorChevron, ClickableAppName, + DashboardContainer, + DashboardHeader, + DashboardSubtitle, + DashboardTitle, HamburgerButton, HamburgerLine, HeaderActions, Layout, Logo, + LogoLink, Main, MainContent, MainHeader, @@ -19,6 +24,10 @@ export { SectionTab, Sidebar, SidebarFooter, + StatCard, + StatLabel, + StatsGrid, + StatValue, } from './layout' export { LogLine, LogsContainer, LogTime } from './logs.tsx' export { diff --git a/src/client/styles/layout.ts b/src/client/styles/layout.ts index 593e65b..c8d93f2 100644 --- a/src/client/styles/layout.ts +++ b/src/client/styles/layout.ts @@ -28,6 +28,18 @@ export const Logo = define('Logo', { borderBottom: `1px solid ${theme('colors-border')}`, }) +export const LogoLink = define('LogoLink', { + cursor: 'pointer', + borderRadius: theme('radius-md'), + padding: '4px 8px', + margin: '-4px -8px', + selectors: { + '&:hover': { + background: theme('colors-bgHover'), + }, + }, +}) + export const HamburgerButton = define('HamburgerButton', { base: 'button', background: 'none', @@ -183,3 +195,58 @@ export const MainContent = define('MainContent', { padding: '10px 24px', overflow: 'auto', }) + +export const DashboardContainer = define('DashboardContainer', { + flex: 1, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + padding: 40, + gap: 40, +}) + +export const DashboardHeader = define('DashboardHeader', { + textAlign: 'center', +}) + +export const DashboardTitle = define('DashboardTitle', { + fontSize: 48, + fontWeight: 'bold', + margin: 0, + marginBottom: 8, +}) + +export const DashboardSubtitle = define('DashboardSubtitle', { + fontSize: 16, + color: theme('colors-textMuted'), + margin: 0, +}) + +export const StatsGrid = define('StatsGrid', { + display: 'flex', + gap: 24, +}) + +export const StatCard = define('StatCard', { + background: theme('colors-bgElement'), + border: `1px solid ${theme('colors-border')}`, + borderRadius: theme('radius-md'), + padding: '24px 40px', + textAlign: 'center', + minWidth: 120, +}) + +export const StatValue = define('StatValue', { + fontSize: 36, + fontWeight: 'bold', + color: theme('colors-text'), + marginBottom: 4, +}) + +export const StatLabel = define('StatLabel', { + fontSize: 14, + color: theme('colors-textMuted'), + textTransform: 'uppercase', + letterSpacing: '0.05em', +}) From 543b5d08bcb37a67136d15232c27d68f5d535010 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Thu, 12 Feb 2026 12:54:09 -0800 Subject: [PATCH 2/3] favicon --- src/server/shell.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/shell.tsx b/src/server/shell.tsx index 90a77bf..daf3879 100644 --- a/src/server/shell.tsx +++ b/src/server/shell.tsx @@ -2,6 +2,7 @@ export const Shell = () => ( Toes +