diff --git a/src/client/index.tsx b/src/client/index.tsx
index 5d737bf..6439b94 100644
--- a/src/client/index.tsx
+++ b/src/client/index.tsx
@@ -5,6 +5,7 @@ import { theme } from './themes'
// UI state (survives re-renders)
let selectedApp: string | null = localStorage.getItem('selectedApp')
+let sidebarCollapsed: boolean = localStorage.getItem('sidebarCollapsed') === 'true'
// Server state (from SSE)
let apps: App[] = []
@@ -30,12 +31,36 @@ const Logo = define('Logo', {
height: 64,
display: 'flex',
alignItems: 'center',
+ justifyContent: 'space-between',
padding: '0 16px',
fontSize: 20,
fontWeight: 'bold',
borderBottom: `1px solid ${theme('colors-border')}`,
})
+const HamburgerButton = define('HamburgerButton', {
+ base: 'button',
+ background: 'none',
+ border: 'none',
+ cursor: 'pointer',
+ padding: 4,
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ gap: 4,
+ selectors: {
+ '&:hover span': { background: theme('colors-text') },
+ },
+})
+
+const HamburgerLine = define('HamburgerLine', {
+ width: 18,
+ height: 2,
+ background: theme('colors-textMuted'),
+ borderRadius: 1,
+ transition: 'background 0.15s',
+})
+
const SectionLabel = define('SectionLabel', {
padding: '16px 16px 8px',
fontSize: 12,
@@ -141,7 +166,7 @@ const HeaderActions = define('HeaderActions', {
const MainContent = define('MainContent', {
flex: 1,
- padding: 24,
+ padding: '10px 24px',
overflow: 'auto',
})
@@ -251,6 +276,40 @@ const LogTime = define('LogTime', {
display: 'inline',
})
+let selectedTab: 'overview' | 'todo' = 'overview'
+
+const TabContent = define('TabContent', {
+ display: 'none',
+
+ variants: {
+ active: {
+ display: 'block'
+ }
+ }
+})
+
+const NavButton = define('NavButton', {
+ render({ props }) {
+ return (
+
+ )
+ }
+})
+
+function setSelectedTab(tab: 'overview' | 'todo') {
+ selectedTab = tab
+ render()
+}
+
+const Nav = () => {
+ return <>
+ setSelectedTab('overview')}>Overview
+ setSelectedTab('todo')}>TODO
+ >
+}
+
const stateLabels: Record = {
invalid: 'Invalid',
stopped: 'Stopped',
@@ -270,6 +329,12 @@ const selectApp = (name: string) => {
render()
}
+const toggleSidebar = () => {
+ sidebarCollapsed = !sidebarCollapsed
+ localStorage.setItem('sidebarCollapsed', String(sidebarCollapsed))
+ render()
+}
+
const AppDetail = ({ app }: { app: App }) => (
<>
@@ -284,79 +349,87 @@ const AppDetail = ({ app }: { app: App }) => (
-
- Status
-
- State
-
-
- {stateLabels[app.state]}
- {app.port ? ` on :${app.port}` : ''}
-
-
- {app.state === 'running' && app.port && (
+
+
+
+
+ Status
- URL
+ State
-
- http://localhost:{app.port}
-
+
+ {stateLabels[app.state]}
+ {app.port ? ` on :${app.port}` : ''}
- )}
- {app.started && (
-
- Started
- {new Date(app.started).toLocaleString()}
-
- )}
- {app.error && (
-
- Error
-
- {app.error}
-
-
- )}
-
-
-
- Logs
-
- {app.logs?.length ? (
- app.logs.map((line, i) => (
-
- {new Date(line.time).toLocaleTimeString()}
- {line.text}
-
- ))
- ) : (
-
- --:--:--
- No logs yet
-
+ {app.state === 'running' && app.port && (
+
+ URL
+
+
+ http://localhost:{app.port}
+
+
+
)}
-
-
+ {app.started && (
+
+ Started
+ {new Date(app.started).toLocaleString()}
+
+ )}
+ {app.error && (
+
+ Error
+
+ {app.error}
+
+
+ )}
+
-
- {app.state === 'stopped' && (
-
- )}
- {app.state === 'running' && (
- <>
-
-
+
+
+
+ hardy har har
+
>
)
@@ -367,28 +440,39 @@ const Dashboard = () => {
return (
-
- 🐾 Toes
- Apps
+
+
+ {!sidebarCollapsed && 🐾 Toes}
+
+
+
+
+
+
+ {!sidebarCollapsed && Apps}
{apps.map(app => (
selectApp(app.name)}
selected={app.name === selectedApp ? true : undefined}
+ style={sidebarCollapsed ? { justifyContent: 'center', padding: '10px 12px' } : undefined}
+ title={sidebarCollapsed ? app.name : undefined}
>
{app.state === 'running' && app.icon ? (
- {app.icon}
+ {app.icon}
) : (
)}
- {app.name}
+ {!sidebarCollapsed && app.name}
))}
-
- + New App
-
+ {!sidebarCollapsed && (
+
+ + New App
+
+ )}
{selected ? (