diff --git a/src/client/components/AppSelector.tsx b/src/client/components/AppSelector.tsx
new file mode 100644
index 0000000..19c8a82
--- /dev/null
+++ b/src/client/components/AppSelector.tsx
@@ -0,0 +1,76 @@
+import type { CSSProperties } from 'hono/jsx'
+import {
+ apps,
+ selectedApp,
+ setSelectedApp,
+ setSidebarSection,
+ sidebarSection,
+} from '../state'
+import {
+ AppItem,
+ AppList,
+ SectionSwitcher,
+ SectionTab,
+ StatusDot,
+} from '../styles'
+
+interface AppSelectorProps {
+ render: () => void
+ onSelect?: () => void
+ collapsed?: boolean
+ switcherStyle?: CSSProperties
+ listStyle?: CSSProperties
+}
+
+export function AppSelector({ render, onSelect, collapsed, switcherStyle, listStyle }: AppSelectorProps) {
+ const selectApp = (name: string) => {
+ setSelectedApp(name)
+ onSelect?.()
+ render()
+ }
+
+ const switchSection = (section: 'apps' | 'tools') => {
+ setSidebarSection(section)
+ render()
+ }
+
+ const regularApps = apps.filter(app => !app.tool)
+ const toolApps = apps.filter(app => app.tool)
+ const activeApps = sidebarSection === 'apps' ? regularApps : toolApps
+
+ return (
+ <>
+ {!collapsed && toolApps.length > 0 && (
+
+ switchSection('apps')}>
+ Apps
+
+ switchSection('tools')}>
+ Tools
+
+
+ )}
+
+ {activeApps.map(app => (
+ selectApp(app.name)}
+ selected={app.name === selectedApp ? true : undefined}
+ style={collapsed ? { justifyContent: 'center', padding: '10px 12px' } : undefined}
+ title={collapsed ? app.name : undefined}
+ >
+ {collapsed ? (
+ {app.icon}
+ ) : (
+ <>
+ {app.icon}
+ {app.name}
+
+ >
+ )}
+
+ ))}
+
+ >
+ )
+}