From 379976aba7b11b8c74748d7df68e76d87d0d9ac5 Mon Sep 17 00:00:00 2001 From: SuperComboGamer Date: Tue, 23 Dec 2025 16:38:49 -0500 Subject: [PATCH] feat: implement new layout components and enhance UI with glassmorphism This commit introduces a new app layout structure with an AppLayout component, a TopHeader for improved navigation, and a Sidebar for project management. Additionally, it adds GlassPanel and GlassCard components to enhance the UI with a glassmorphism effect. The Kanban board and agent views have been updated to utilize these new components, improving the overall user experience and visual consistency across the application. --- apps/ui/src/components/layout/app-layout.tsx | 36 + apps/ui/src/components/layout/sidebar.tsx | 550 +++----- apps/ui/src/components/layout/top-header.tsx | 38 + apps/ui/src/components/ui/glass-card.tsx | 26 + apps/ui/src/components/ui/glass-panel.tsx | 28 + .../src/components/views/agent-tools-view.tsx | 530 +++---- apps/ui/src/components/views/agent-view.tsx | 901 ++++++------ apps/ui/src/components/views/board-view.tsx | 30 +- .../components/kanban-card/card-header.tsx | 2 + .../components/kanban-card/kanban-card.tsx | 141 +- .../board-view/components/kanban-column.tsx | 86 +- .../components/views/board-view/constants.ts | 12 +- .../hooks/use-board-column-features.ts | 6 +- .../views/board-view/kanban-board.tsx | 1 + .../components/worktree-tab.tsx | 3 +- .../components/views/running-agents-view.tsx | 203 +-- .../ui/src/components/views/settings-view.tsx | 2 +- .../ui/src/components/views/terminal-view.tsx | 428 +++--- .../views/terminal-view/terminal-panel.tsx | 1 + apps/ui/src/config/terminal-themes.ts | 2 +- apps/ui/src/routes/__root.tsx | 11 +- apps/ui/src/store/app-store.ts | 31 +- apps/ui/src/styles/global.css | 1249 ++--------------- index (28).html | 1065 ++++++++++++++ package-lock.json | 88 +- 25 files changed, 2823 insertions(+), 2647 deletions(-) create mode 100644 apps/ui/src/components/layout/app-layout.tsx create mode 100644 apps/ui/src/components/layout/top-header.tsx create mode 100644 apps/ui/src/components/ui/glass-card.tsx create mode 100644 apps/ui/src/components/ui/glass-panel.tsx create mode 100644 index (28).html diff --git a/apps/ui/src/components/layout/app-layout.tsx b/apps/ui/src/components/layout/app-layout.tsx new file mode 100644 index 00000000..a86fbd09 --- /dev/null +++ b/apps/ui/src/components/layout/app-layout.tsx @@ -0,0 +1,36 @@ +import { ReactNode } from 'react'; +import { Sidebar } from './sidebar'; +// TopHeader removed from layout to be view-specific + +interface AppLayoutProps { + children: ReactNode; +} + +export function AppLayout({ children }: AppLayoutProps) { + return ( +
+ {/* Ambient Background */} +
+
+ + + +
+
{children}
+
+
+ ); +} diff --git a/apps/ui/src/components/layout/sidebar.tsx b/apps/ui/src/components/layout/sidebar.tsx index 0e87d03b..fda9c27c 100644 --- a/apps/ui/src/components/layout/sidebar.tsx +++ b/apps/ui/src/components/layout/sidebar.tsx @@ -1,367 +1,213 @@ -import { useState, useCallback } from 'react'; -import { useNavigate, useLocation } from '@tanstack/react-router'; +import React from 'react'; +import { + Code2, + PanelLeft, + Plus, + Folder, + Bell, + FolderOpen, + MoreVertical, + LayoutGrid, + Bot, + FileJson, + BookOpen, + UserCircle, + TerminalSquare, + Book, + Activity, + Settings, +} from 'lucide-react'; import { cn } from '@/lib/utils'; -import { useAppStore, type ThemeMode } from '@/store/app-store'; -import { useKeyboardShortcuts, useKeyboardShortcutsConfig } from '@/hooks/use-keyboard-shortcuts'; -import { getElectronAPI } from '@/lib/electron'; -import { initializeProject, hasAppSpec, hasAutomakerDir } from '@/lib/project-init'; -import { toast } from 'sonner'; -import { DeleteProjectDialog } from '@/components/views/settings-view/components/delete-project-dialog'; -import { NewProjectModal } from '@/components/dialogs/new-project-modal'; -import { CreateSpecDialog } from '@/components/views/spec-view/dialogs'; - -// Local imports from subfolder -import { - CollapseToggleButton, - SidebarHeader, - ProjectActions, - SidebarNavigation, - ProjectSelectorWithOptions, - SidebarFooter, -} from './sidebar/components'; -import { TrashDialog, OnboardingDialog } from './sidebar/dialogs'; -import { SIDEBAR_FEATURE_FLAGS } from './sidebar/constants'; -import { - useSidebarAutoCollapse, - useRunningAgents, - useSpecRegeneration, - useNavigation, - useProjectCreation, - useSetupDialog, - useTrashDialog, - useProjectTheme, -} from './sidebar/hooks'; +import { Link, useLocation } from '@tanstack/react-router'; export function Sidebar() { - const navigate = useNavigate(); const location = useLocation(); - const { - projects, - trashedProjects, - currentProject, - sidebarOpen, - projectHistory, - upsertAndSetCurrentProject, - toggleSidebar, - restoreTrashedProject, - deleteTrashedProject, - emptyTrash, - cyclePrevProject, - cycleNextProject, - moveProjectToTrash, - specCreatingForProject, - setSpecCreatingForProject, - } = useAppStore(); - - // Environment variable flags for hiding sidebar items - const { hideTerminal, hideWiki, hideRunningAgents, hideContext, hideSpecEditor, hideAiProfiles } = - SIDEBAR_FEATURE_FLAGS; - - // Get customizable keyboard shortcuts - const shortcuts = useKeyboardShortcutsConfig(); - - // State for project picker (needed for keyboard shortcuts) - const [isProjectPickerOpen, setIsProjectPickerOpen] = useState(false); - - // State for delete project confirmation dialog - const [showDeleteProjectDialog, setShowDeleteProjectDialog] = useState(false); - - // Project theme management (must come before useProjectCreation which uses globalTheme) - const { globalTheme } = useProjectTheme(); - - // Project creation state and handlers - const { - showNewProjectModal, - setShowNewProjectModal, - isCreatingProject, - showOnboardingDialog, - setShowOnboardingDialog, - newProjectName, - setNewProjectName, - newProjectPath, - setNewProjectPath, - handleCreateBlankProject, - handleCreateFromTemplate, - handleCreateFromCustomUrl, - } = useProjectCreation({ - trashedProjects, - currentProject, - globalTheme, - upsertAndSetCurrentProject, - }); - - // Setup dialog state and handlers - const { - showSetupDialog, - setShowSetupDialog, - setupProjectPath, - setSetupProjectPath, - projectOverview, - setProjectOverview, - generateFeatures, - setGenerateFeatures, - analyzeProject, - setAnalyzeProject, - featureCount, - setFeatureCount, - handleCreateInitialSpec, - handleSkipSetup, - handleOnboardingGenerateSpec, - handleOnboardingSkip, - } = useSetupDialog({ - setSpecCreatingForProject, - newProjectPath, - setNewProjectName, - setNewProjectPath, - setShowOnboardingDialog, - }); - - // Derive isCreatingSpec from store state - const isCreatingSpec = specCreatingForProject !== null; - const creatingSpecProjectPath = specCreatingForProject; - - // Auto-collapse sidebar on small screens and update Electron window minWidth - useSidebarAutoCollapse({ sidebarOpen, toggleSidebar }); - - // Running agents count - const { runningAgentsCount } = useRunningAgents(); - - // Trash dialog and operations - const { - showTrashDialog, - setShowTrashDialog, - activeTrashId, - isEmptyingTrash, - handleRestoreProject, - handleDeleteProjectFromDisk, - handleEmptyTrash, - } = useTrashDialog({ - restoreTrashedProject, - deleteTrashedProject, - emptyTrash, - trashedProjects, - }); - - // Spec regeneration events - useSpecRegeneration({ - creatingSpecProjectPath, - setupProjectPath, - setSpecCreatingForProject, - setShowSetupDialog, - setProjectOverview, - setSetupProjectPath, - setNewProjectName, - setNewProjectPath, - }); - - /** - * Opens the system folder selection dialog and initializes the selected project. - * Used by both the 'O' keyboard shortcut and the folder icon button. - */ - const handleOpenFolder = useCallback(async () => { - const api = getElectronAPI(); - const result = await api.openDirectory(); - - if (!result.canceled && result.filePaths[0]) { - const path = result.filePaths[0]; - // Extract folder name from path (works on both Windows and Mac/Linux) - const name = path.split(/[/\\]/).filter(Boolean).pop() || 'Untitled Project'; - - try { - // Check if this is a brand new project (no .automaker directory) - const hadAutomakerDir = await hasAutomakerDir(path); - - // Initialize the .automaker directory structure - const initResult = await initializeProject(path); - - if (!initResult.success) { - toast.error('Failed to initialize project', { - description: initResult.error || 'Unknown error occurred', - }); - return; - } - - // Upsert project and set as current (handles both create and update cases) - // Theme preservation is handled by the store action - const trashedProject = trashedProjects.find((p) => p.path === path); - const effectiveTheme = - (trashedProject?.theme as ThemeMode | undefined) || - (currentProject?.theme as ThemeMode | undefined) || - globalTheme; - upsertAndSetCurrentProject(path, name, effectiveTheme); - - // Check if app_spec.txt exists - const specExists = await hasAppSpec(path); - - if (!hadAutomakerDir && !specExists) { - // This is a brand new project - show setup dialog - setSetupProjectPath(path); - setShowSetupDialog(true); - toast.success('Project opened', { - description: `Opened ${name}. Let's set up your app specification!`, - }); - } else if (initResult.createdFiles && initResult.createdFiles.length > 0) { - toast.success(initResult.isNewProject ? 'Project initialized' : 'Project updated', { - description: `Set up ${initResult.createdFiles.length} file(s) in .automaker`, - }); - } else { - toast.success('Project opened', { - description: `Opened ${name}`, - }); - } - } catch (error) { - console.error('[Sidebar] Failed to open project:', error); - toast.error('Failed to open project', { - description: error instanceof Error ? error.message : 'Unknown error', - }); - } - } - }, [trashedProjects, upsertAndSetCurrentProject, currentProject, globalTheme]); - - // Navigation sections and keyboard shortcuts (defined after handlers) - const { navSections, navigationShortcuts } = useNavigation({ - shortcuts, - hideSpecEditor, - hideContext, - hideTerminal, - hideAiProfiles, - currentProject, - projects, - projectHistory, - navigate, - toggleSidebar, - handleOpenFolder, - setIsProjectPickerOpen, - cyclePrevProject, - cycleNextProject, - }); - - // Register keyboard shortcuts - useKeyboardShortcuts(navigationShortcuts); - - const isActiveRoute = (id: string) => { - // Map view IDs to route paths - const routePath = id === 'welcome' ? '/' : `/${id}`; - return location.pathname === routePath; - }; - return ( -