fix: make workspace project name visible on mobile and desktop cards

- Move the project name below the workspace title row so it reads as a
  distinct line with a project icon.
- Move the status badge into the title row next to the workspace name,
  preventing it from crowding the project label.
- Add .workspace-title-row flex styles and update .workspace-project-name
  to display inline-flex with a brand-colored project icon.

Quality gates: npm run typecheck, npm run lint clean,
npm test -- --run 87 passed.
This commit is contained in:
Developer
2026-06-13 19:53:43 +00:00
parent 86360661e9
commit 4913cc7297
21 changed files with 300 additions and 284 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
dir: apps/web
## role
Frontend web application providing a React-based UI with code editing, terminal, and routing capabilities for the "headquarter" project.
Frontend web application providing a browser-based React/TypeScript UI with code editing, terminal, and routing capabilities.
## parent
index: apps/.pi-map.index.md
map: apps/.pi-map.md
+2 -2
View File
@@ -4,7 +4,7 @@ dir: apps/web
index: apps/web/.pi-map.index.md
## role
Frontend web application providing a React-based UI with code editing, terminal, and routing capabilities for the "headquarter" project.
Frontend web application providing a browser-based React/TypeScript UI with code editing, terminal, and routing capabilities.
## files
- .env.example | Template file defining example environment variables for frontend API and application URL configuration
- .eslintrc.cjs | Configures ESLint for a TypeScript browser project with modern ECMAScript module support | dep: @typescript-eslint/parser, @typescript-eslint/eslint-plugin, eslint
@@ -16,7 +16,7 @@ Frontend web application providing a React-based UI with code editing, terminal,
- tsconfig.json | TypeScript configuration file for a React project using Vite with modern ES2020 target and bundler module resolution | dep: typescript, react, vite
- vite.config.ts | Configures Vite build tool for a React project with custom dev server port and Vitest test settings. | dep: vite, @vitejs/plugin-react
## arch
Modern React SPA built with Vite and TypeScript, containerized via multi-stage Docker with nginx serving, featuring client-side routing and optimized static asset delivery.
Modern Vite-based SPA architecture with TypeScript, nginx static serving, multi-stage Docker containerization, and client-side routing.
## tags
react, eslint, vite, typescript, dom, application, nginx, web
## symbols
+1 -1
View File
@@ -10,7 +10,7 @@ Entry point and core infrastructure for a React web application handling routing
- router.tsx | Defines the React Router configuration for a web application with protected routes, nested layouts, and redirects. | exp: AppRouter | dep: react-router-dom, ./components/app-shell, ./components/protected-route, ./pages/DashboardPage, ./pages/PlaceholderPage, ./pages/ProfilePage, ./pages/ProjectsPage, ./pages/GitRepositoriesPage, ./pages/GitHistoryPage, ./pages/ProjectSettingsPage, ./pages/SettingsPage, ./pages/TerminalPage, ./pages/ToolWorkshopPage, ./pages/SshKeysPage, ./pages/ConfigProfilesPage, ./pages/SessionsPage, ./pages/WorkspacesPage, ./pages/WorkspaceDetailPage
- types.ts | Defines TypeScript type definitions for user sessions, projects, repositories, and workspaces in an application. | exp: SessionUser, SessionPayload, Project, WorkspaceSummary, RepositorySummary, ProjectWithRepos
## arch
Modular React SPA with provider pattern for auth/session state, declarative routing with nested layouts and route guards, and centralized TypeScript type definitions for domain models.
Provider composition pattern with React Router v6 (nested routes, layout routes, protected route guards), context-based auth/session management, and centralized TypeScript domain models.
## tags
pages, styles, css, router, react, session, dom, project
## symbols
+1 -1
View File
@@ -2,7 +2,7 @@
dir: apps/web/src/components
## role
Provides reusable, accessible React UI components and utilities for the web application including layout shell, data states, icons, code display, authentication guards, and toast notifications.
Provides reusable, accessible UI primitives and layout components for the web application, including navigation, feedback states, icons, code display, and authentication guards.
## parent
index: apps/web/src/.pi-map.index.md
map: apps/web/src/.pi-map.md
+3 -3
View File
@@ -4,9 +4,9 @@ dir: apps/web/src/components
index: apps/web/src/components/.pi-map.index.md
## role
Provides reusable, accessible React UI components and utilities for the web application including layout shell, data states, icons, code display, authentication guards, and toast notifications.
Provides reusable, accessible UI primitives and layout components for the web application, including navigation, feedback states, icons, code display, and authentication guards.
## files
- app-shell.tsx | Renders the main application shell layout with navigation, session management, and responsive mobile/desktop views for a React Router-based application. | exp: AppShell | dep: react-router-dom, ../api/sessions, ../hooks/use-theme, ../state/auth, ../state/sessions, ../hooks/use-mobile-viewport, ../state/events, ../state/toast, ../state/notifications, ./features/notification/event-toast-bridge, ./features/notification/notification-center, ./icon, ./features/mobile/mobile-nav, ./features/tool/start-tool-fab, ../utils/icons
- app-shell.tsx | Renders the main application shell layout with navigation, header, session management, and mobile-responsive behavior for a React Router-based SPA. | exp: AppShell | dep: react-router-dom, ../api/sessions, ../hooks/use-theme, ../state/auth, ../state/sessions, ../hooks/use-mobile-viewport, ../state/events, ../state/toast, ../state/notifications, ./features/notification/event-toast-bridge, ./features/notification/notification-center, ./icon, ./features/mobile/mobile-nav, ./features/tool/start-tool-fab, ../utils/icons
- code-editor.tsx | A React component that renders a syntax-highlighted code editor with line numbers using react-simple-code-editor. | exp: CodeEditor | dep: react, react-simple-code-editor, ../utils/language
- data-states.tsx | Provides reusable React components for displaying loading, error, and empty data states in a UI. | exp: LoadingState, ErrorState, EmptyState | dep: ./icon, icon
- icon.tsx | Provides a centralized, type-safe React icon component that maps semantic names to Phosphor icons with configurable size, weight, color, and accessibility attributes. | exp: IconName, IconProps, Icon | dep: react, @phosphor-icons/react
@@ -17,7 +17,7 @@ Provides reusable, accessible React UI components and utilities for the web appl
- toast-rules.test.ts | Unit tests for mapping instance events to toast notification categories and severities | dep: vitest, ./toast-rules, ../types/events
- toast-rules.ts | Maps instance events to toast notifications with deduplication logic to prevent spam | exp: func:mapEventToCategory(event: InstanceEventPayload) → string, call:event.event.startsWith, func:mapEventToSeverity(event: InstanceEventPayload) → "info" | "warning" | "error" | "success", func:handleEventToast(event: InstanceEventPayload) → void, call:shouldShowToast, call:toast.info, call:toast.success, call:toast.warning, call:toast.error, func:clearToastDedup() → void, call:lastToastTime.clear | dep: ../state/toast, ../types/events, toast state module, InstanceEventPayload type
## arch
Component-based architecture with functional React components, custom hooks for state management, centralized icon mapping with type safety, test-driven development for business logic (toast rules, protected routes), and separation of concerns between presentation (UI components) and behavior (utility modules).
Component-based React architecture with functional components, composition patterns, separation of concerns (presentation vs logic), utility-first modules, and test co-location; integrates third-party libraries (Phosphor icons, react-simple-code-editor) with thin abstraction wrappers.
## tags
toast, icon, react, state, code, loading, event, editor
## symbols
+146 -146
View File
@@ -16,166 +16,166 @@ import { StartToolFAB } from "./features/tool/start-tool-fab";
import type { IconName } from "../utils/icons";
const NAV_ITEMS: {
to: string;
label: string;
icon: IconName;
badge?: "sessions";
to: string;
label: string;
icon: IconName;
badge?: "sessions";
}[] = [
{ to: "/", label: "Home", icon: "dashboard" },
{ to: "/projects", label: "Projects", icon: "projects" },
{ to: "/workspaces", label: "Workspaces", icon: "folder" },
{ to: "/sessions", label: "Sessions", icon: "terminal", badge: "sessions" },
{ to: "/tool-workshop", label: "Tool Workshop", icon: "settings" },
{ to: "/config-profiles", label: "Config Profiles", icon: "folder" },
{ to: "/settings", label: "Settings", icon: "settings" },
{ to: "/", label: "Home", icon: "dashboard" },
{ to: "/projects", label: "Projects", icon: "projects" },
{ to: "/workspaces", label: "Workspaces", icon: "folder" },
{ to: "/sessions", label: "Sessions", icon: "terminal", badge: "sessions" },
{ to: "/tool-workshop", label: "Tool Workshop", icon: "settings" },
{ to: "/config-profiles", label: "Config Profiles", icon: "folder" },
{ to: "/settings", label: "Settings", icon: "settings" },
];
const SessionItem = ({ session }: { session: Session }) => {
const isRunning = session.status === "running";
const isRunning = session.status === "running";
// Determine the link target:
// - Web tools open their tunnel URL
// - Terminal tools open the terminal page
// - Everything else falls back to the project page
const hasTerminal = session.tool_type_interfaces.includes("terminal");
const hasWeb = session.tool_type_interfaces.includes("web");
const href =
session.url && hasWeb
? session.url
: hasTerminal
? `/instances/${session.id}/terminal`
: `/projects/${session.project_id}`;
// Determine the link target:
// - Web tools open their tunnel URL
// - Terminal tools open the terminal page
// - Everything else falls back to the project page
const hasTerminal = session.tool_type_interfaces.includes("terminal");
const hasWeb = session.tool_type_interfaces.includes("web");
const href =
session.url && hasWeb
? session.url
: hasTerminal
? `/instances/${session.id}/terminal`
: `/projects/${session.project_id}`;
const tooltipParts = [session.display_name, session.project_name];
if (session.workspace_name) tooltipParts.push(session.workspace_name);
else if (session.repository_name) tooltipParts.push(session.repository_name);
tooltipParts.push(`(${session.status})`);
const tooltipParts = [session.display_name, session.project_name];
if (session.workspace_name) tooltipParts.push(session.workspace_name);
else if (session.repository_name) tooltipParts.push(session.repository_name);
tooltipParts.push(`(${session.status})`);
return (
<a
href={href}
target={`session-${session.id}`}
rel="noreferrer"
className="nav-item session-item"
title={tooltipParts.join(" ")}
>
<span className={`session-status ${isRunning ? "running" : ""}`} />
<Icon name={session.tool_icon as IconName} size="sm" />
<span className="session-name">
{session.display_name}
<span className="session-tool">{session.tool_type_name}</span>
</span>
</a>
);
return (
<a
href={href}
target={`session-${session.id}`}
rel="noreferrer"
className="nav-item session-item"
title={tooltipParts.join(" ")}
>
<span className={`session-status ${isRunning ? "running" : ""}`} />
<Icon name={session.tool_icon as IconName} size="sm" />
<span className="session-name">
{session.display_name}
<span className="session-tool">{session.tool_type_name}</span>
</span>
</a>
);
};
export const AppShell = () => {
useTheme();
const { user, logout } = useAuth();
const { sessions } = useSessions();
const location = useLocation();
const isMobile = useMobileViewport();
const isMobileTerminal =
isMobile &&
location.pathname.includes("/instances/") &&
location.pathname.includes("/terminal");
useTheme();
const { user, logout } = useAuth();
const { sessions } = useSessions();
const location = useLocation();
const isMobile = useMobileViewport();
const isMobileTerminal =
isMobile &&
location.pathname.includes("/instances/") &&
location.pathname.includes("/terminal");
if (isMobileTerminal) {
return (
<EventProvider>
<ToastProvider>
<NotificationProvider>
<EventToastBridge />
<div className="shell mobile-terminal-shell">
<Outlet />
</div>
</NotificationProvider>
</ToastProvider>
</EventProvider>
);
}
if (isMobileTerminal) {
return (
<EventProvider>
<ToastProvider>
<NotificationProvider>
<EventToastBridge />
<div className="shell mobile-terminal-shell">
<Outlet />
</div>
</NotificationProvider>
</ToastProvider>
</EventProvider>
);
}
return (
<EventProvider>
<ToastProvider>
<NotificationProvider>
<EventToastBridge />
<div className="shell">
<header className="shell-header">
<Link className="brand" to="/">
Headquarter
</Link>
<div className="header-actions">
<NotificationCenter isMobileTerminal={isMobileTerminal} />
<Link className="user-chip" to="/profile">
{user?.name ?? "User"}
</Link>
<button
className="ghost-button"
onClick={() => {
void logout();
}}
type="button"
>
<Icon name="logout" size="sm" />
Logout
</button>
</div>
</header>
return (
<EventProvider>
<ToastProvider>
<NotificationProvider>
<EventToastBridge />
<div className="shell">
<header className="shell-header">
<Link className="brand" to="/">
Headquarter
</Link>
<div className="header-actions">
<NotificationCenter isMobileTerminal={isMobileTerminal} />
<Link className="user-chip" to="/profile">
{user?.name ?? "User"}
</Link>
<button
className="ghost-button"
onClick={() => {
void logout();
}}
type="button"
>
<Icon name="logout" size="sm" />
Logout
</button>
</div>
</header>
<div className="shell-body">
{!isMobile && (
<aside className="shell-nav" aria-label="Primary navigation">
{NAV_ITEMS.map((item) => {
const activeCount = sessions.filter(
(s) => s.status === "running",
).length;
return (
<NavLink
key={item.to}
to={item.to}
className={({ isActive }) =>
isActive ? "nav-item nav-item-active" : "nav-item"
}
end={item.to === "/"}
>
<Icon name={item.icon} size="sm" />
{item.label}
{item.badge === "sessions" && activeCount > 0 && (
<span className="nav-badge">{activeCount}</span>
)}
</NavLink>
);
})}
<div className="shell-body">
{!isMobile && (
<aside className="shell-nav" aria-label="Primary navigation">
{NAV_ITEMS.map((item) => {
const activeCount = sessions.filter(
(s) => s.status === "running",
).length;
return (
<NavLink
key={item.to}
to={item.to}
className={({ isActive }) =>
isActive ? "nav-item nav-item-active" : "nav-item"
}
end={item.to === "/"}
>
<Icon name={item.icon} size="sm" />
{item.label}
{item.badge === "sessions" && activeCount > 0 && (
<span className="nav-badge">{activeCount}</span>
)}
</NavLink>
);
})}
{sessions.length > 0 && (
<>
<div className="nav-divider" />
<div className="nav-section-title">Live sessions</div>
{sessions.map((session) => (
<SessionItem key={session.id} session={session} />
))}
</>
)}
</aside>
)}
{sessions.length > 0 && (
<>
<div className="nav-divider" />
<div className="nav-section-title">Live sessions</div>
{sessions.map((session) => (
<SessionItem key={session.id} session={session} />
))}
</>
)}
</aside>
)}
<main className={`shell-content ${isMobile ? "mobile" : ""}`}>
<Outlet />
</main>
</div>
<main className={`shell-content ${isMobile ? "mobile" : ""}`}>
<Outlet />
</main>
</div>
{isMobile && (
<MobileNav
sessionCount={
sessions.filter((s) => s.status === "running").length
}
/>
)}
<StartToolFAB />
</div>
</NotificationProvider>
</ToastProvider>
</EventProvider>
);
{isMobile && (
<MobileNav
sessionCount={
sessions.filter((s) => s.status === "running").length
}
/>
)}
<StartToolFAB />
</div>
</NotificationProvider>
</ToastProvider>
</EventProvider>
);
};
@@ -2,7 +2,7 @@
dir: apps/web/src/components/features
## role
Contains reusable React components organized by feature domains for the web application UI.
Contains reusable React components that implement specific product features and business logic for the web application.
## parent
index: apps/web/src/components/.pi-map.index.md
map: apps/web/src/components/.pi-map.md
+2 -2
View File
@@ -4,10 +4,10 @@ dir: apps/web/src/components/features
index: apps/web/src/components/features/.pi-map.index.md
## role
Contains reusable React components organized by feature domains for the web application UI.
Contains reusable React components that implement specific product features and business logic for the web application.
## files
## arch
Feature-based component colocation with domain-driven folder structure, separating UI concerns by business capability rather than technical layer.
Feature-based component organization following domain-driven design principles, likely with co-located components, hooks, and utilities per feature area.
## tags
-
## symbols
@@ -6,114 +6,114 @@ import { SpacesBottomSheet } from "./spaces-bottom-sheet";
import type { IconName } from "../../../utils/icons";
interface MobileNavProps {
sessionCount?: number;
sessionCount?: number;
}
interface NavItem {
to: string;
label: string;
icon: IconName;
isGroup?: boolean;
group?: "tools" | "spaces";
to: string;
label: string;
icon: IconName;
isGroup?: boolean;
group?: "tools" | "spaces";
}
const MOBILE_NAV_ITEMS: NavItem[] = [
{ to: "/", label: "Home", icon: "dashboard" },
{
to: "/spaces",
label: "Spaces",
icon: "projects",
isGroup: true,
group: "spaces",
},
{ to: "/sessions", label: "Sessions", icon: "terminal" },
{
to: "/tools",
label: "Tools",
icon: "settings",
isGroup: true,
group: "tools",
},
{ to: "/settings", label: "Settings", icon: "settings" },
{ to: "/", label: "Home", icon: "dashboard" },
{
to: "/spaces",
label: "Spaces",
icon: "projects",
isGroup: true,
group: "spaces",
},
{ to: "/sessions", label: "Sessions", icon: "terminal" },
{
to: "/tools",
label: "Tools",
icon: "settings",
isGroup: true,
group: "tools",
},
{ to: "/settings", label: "Settings", icon: "settings" },
];
export const MobileNav: React.FC<MobileNavProps> = ({ sessionCount }) => {
const location = useLocation();
const [toolsSheetOpen, setToolsSheetOpen] = useState(false);
const [spacesSheetOpen, setSpacesSheetOpen] = useState(false);
const location = useLocation();
const [toolsSheetOpen, setToolsSheetOpen] = useState(false);
const [spacesSheetOpen, setSpacesSheetOpen] = useState(false);
const isToolsActive =
location.pathname === "/tool-workshop" ||
location.pathname === "/config-profiles";
const isToolsActive =
location.pathname === "/tool-workshop" ||
location.pathname === "/config-profiles";
const isSpacesActive =
location.pathname.startsWith("/projects") ||
location.pathname.startsWith("/workspaces");
const isSpacesActive =
location.pathname.startsWith("/projects") ||
location.pathname.startsWith("/workspaces");
const handleNavClick = (item: NavItem) => {
if (!item.isGroup) return;
if (item.group === "spaces") {
setSpacesSheetOpen(true);
} else {
setToolsSheetOpen(true);
}
};
const handleNavClick = (item: NavItem) => {
if (!item.isGroup) return;
if (item.group === "spaces") {
setSpacesSheetOpen(true);
} else {
setToolsSheetOpen(true);
}
};
return (
<>
<nav
className="mobile-nav"
role="navigation"
aria-label="Mobile navigation"
>
{MOBILE_NAV_ITEMS.map((item) => {
if (item.isGroup) {
const isActive =
item.group === "spaces" ? isSpacesActive : isToolsActive;
return (
<button
key={item.to}
className={`mobile-nav-item ${isActive ? "active" : ""}`}
onClick={() => handleNavClick(item)}
type="button"
>
<div className="mobile-nav-icon-wrapper">
<Icon name={item.icon} size="md" />
</div>
<span className="mobile-nav-label">{item.label}</span>
</button>
);
}
return (
<>
<nav
className="mobile-nav"
role="navigation"
aria-label="Mobile navigation"
>
{MOBILE_NAV_ITEMS.map((item) => {
if (item.isGroup) {
const isActive =
item.group === "spaces" ? isSpacesActive : isToolsActive;
return (
<button
key={item.to}
className={`mobile-nav-item ${isActive ? "active" : ""}`}
onClick={() => handleNavClick(item)}
type="button"
>
<div className="mobile-nav-icon-wrapper">
<Icon name={item.icon} size="md" />
</div>
<span className="mobile-nav-label">{item.label}</span>
</button>
);
}
return (
<NavLink
key={item.to}
to={item.to}
className={({ isActive }) =>
`mobile-nav-item ${isActive ? "active" : ""}`
}
end={item.to === "/"}
>
<div className="mobile-nav-icon-wrapper">
<Icon name={item.icon} size="md" />
{item.to === "/sessions" && sessionCount ? (
<span className="mobile-nav-badge">{sessionCount}</span>
) : null}
</div>
<span className="mobile-nav-label">{item.label}</span>
</NavLink>
);
})}
</nav>
return (
<NavLink
key={item.to}
to={item.to}
className={({ isActive }) =>
`mobile-nav-item ${isActive ? "active" : ""}`
}
end={item.to === "/"}
>
<div className="mobile-nav-icon-wrapper">
<Icon name={item.icon} size="md" />
{item.to === "/sessions" && sessionCount ? (
<span className="mobile-nav-badge">{sessionCount}</span>
) : null}
</div>
<span className="mobile-nav-label">{item.label}</span>
</NavLink>
);
})}
</nav>
<ToolsBottomSheet
isOpen={toolsSheetOpen}
onClose={() => setToolsSheetOpen(false)}
/>
<SpacesBottomSheet
isOpen={spacesSheetOpen}
onClose={() => setSpacesSheetOpen(false)}
/>
</>
);
<ToolsBottomSheet
isOpen={toolsSheetOpen}
onClose={() => setToolsSheetOpen(false)}
/>
<SpacesBottomSheet
isOpen={spacesSheetOpen}
onClose={() => setSpacesSheetOpen(false)}
/>
</>
);
};
@@ -2,7 +2,7 @@
dir: apps/web/src/components/features/workspace
## role
Provides React UI components for workspace management, navigation, and detail views in a web-based development environment.
Provides the complete UI component suite for workspace management, including creation, detail viewing, file editing, Git operations, tool management, and settings.
## parent
index: apps/web/src/components/features/.pi-map.index.md
map: apps/web/src/components/features/.pi-map.md
@@ -4,9 +4,9 @@ dir: apps/web/src/components/features/workspace
index: apps/web/src/components/features/workspace/.pi-map.index.md
## role
Provides React UI components for workspace management, navigation, and detail views in a web-based development environment.
Provides the complete UI component suite for workspace management, including creation, detail viewing, file editing, Git operations, tool management, and settings.
## files
- workspace-card.tsx | React card component that displays workspace information with status, metadata, and action buttons | exp: WorkspaceCardProps, func:WorkspaceCard({ workspace, loading = false, onStartTool, onSync, onDelete, }: WorkspaceCardProps), call:onStartTool, call:onSync, call:onDelete | dep: react-router-dom, ../../icon, ./workspace-instance-chips, ../../../types/workspace
- workspace-card.tsx | React component that renders a card displaying workspace information with status, metadata, and action buttons. | exp: WorkspaceCardProps, func:WorkspaceCard({ workspace, loading = false, onStartTool, onSync, onDelete, }: WorkspaceCardProps), call:onStartTool, call:onSync, call:onDelete | dep: react-router-dom, ../../icon, ./workspace-instance-chips, ../../../types/workspace
- workspace-create-form.tsx | React form component for creating workspaces with cascading project/repository/branch selectors and support for both contextual and standalone modes | exp: WorkspaceCreateFormProps, func:WorkspaceCreateForm({ onSubmit, onCancel, defaultProjectId, defaultRepoId, }: WorkspaceCreateFormProps), call:Boolean, call:useState, call:useGitRepo, call:useEffect, call:git.branches.includes, call:setSelectedBranch, call:setIsNewBranch, call:useCallback, call:listProjects, call:setProjects, call:setSelectedProject, call:setError, call:setFetchingProjects, call:loadProjects, call:setRepos, call:setSelectedRepo, call:listRepositories, call:loadRepos, call:setNewBranchName, call:e.preventDefault, call:name.trim, call:newBranchName.trim, call:setSubmitting, call:createWorkspaceTopLevel, call:onSubmit, call:projects.map, call:repos.map, call:setName, call:handleBranchChange, call:git.branches.map | dep: react, ../../icon, ../../../api/projects, ../../../api/git-repositories, ../../../api/workspaces, ../../../hooks/use-git-repo, ../../../types, icon, api/projects, api/git-repositories, api/workspaces, hooks/use-git-repo, types
- workspace-detail-header.tsx | Renders a header component for a workspace detail page showing breadcrumb navigation and branch information. | exp: WorkspaceDetailHeaderProps, func:WorkspaceDetailHeader({ workspace, }: WorkspaceDetailHeaderProps) | dep: ../../icon, react
- workspace-file-panel.tsx | Renders a file browser and editor panel with Git integration for a workspace detail page. | exp: func:WorkspaceFilePanel({ workspaceId }: WorkspaceFilePanelProps), call:useWorkspaceFiles, call:useWorkspaceGit, call:useState, call:setSelectedPath, call:setIsEditing, call:setEditContent, call:navigateTo, call:loadFile, call:currentPath.split("/").slice(0, -1).join, call:saveFile, call:setCommitMessage, call:commit, call:entries.map, call:handleSelect | dep: react, ../../icon, ../../../hooks/use-workspace-files, ../../../hooks/use-workspace-git, ../../../api/workspace-files
@@ -17,7 +17,7 @@ Provides React UI components for workspace management, navigation, and detail vi
- workspace-tab-bar.tsx | Renders desktop and mobile tab bar components for workspace navigation with files, git, tools, and settings tabs. | exp: WorkspaceTab, func:WorkspaceTabBar({ active, onChange }: WorkspaceTabBarProps), call:TABS.map, call:onChange, func:WorkspaceMobileTabBar({ active, onChange, }: WorkspaceTabBarProps), call:TABS.map, call:onChange | dep: ../../icon, react
- workspace-tools-panel.tsx | Renders a tools management panel for a workspace that displays running tool instances and allows starting new tools via a modal | exp: func:WorkspaceToolsPanel({ workspace }: WorkspaceToolsPanelProps), call:useWorkspaceInstances, call:useState, call:setShowModal, call:instances.map, call:e.stopPropagation, call:refresh | dep: react, ../../icon, ../tool/tool-starter, ../../../hooks/use-workspace-instances, ../../../types/workspace, icon, tool-starter, use-workspace-instances, workspace types
## arch
Feature-based component organization with page-specific composite components (header/detail/settings) and reusable atomic pieces (cards, chips, forms), following a panel/tab architecture for workspace detail layout.
Feature-based component organization with compound page pattern (header/tab-bar/panels), form abstraction for creation, and modal-driven tool management with responsive mobile/desktop tab navigation.
## tags
workspace, call:set, call:use, panel, git, branch, react, call:on
## symbols
@@ -35,15 +35,18 @@ export function WorkspaceCard({
className="workspace-title-link"
>
<div className="workspace-title-stack">
<div className="workspace-title-row">
<h4 className="workspace-name">{workspace.name}</h4>
<span className={`status-badge ${statusClass}`}>
{workspace.status}
</span>
</div>
<span className="workspace-project-name">
<Icon name="projects" size="sm" />
{workspace.project_name}
</span>
<h4 className="workspace-name">{workspace.name}</h4>
</div>
</Link>
<span className={`status-badge ${statusClass}`}>
{workspace.status}
</span>
</div>
<div className="workspace-card-body">
+1 -1
View File
@@ -2,7 +2,7 @@
dir: apps/web/src/styles
## role
Houses the complete CSS styling system for a web application, including design tokens, global styles, syntax highlighting themes, and utility classes.
Provides the complete visual design system and styling foundation for a web application, including themes, utilities, and component-specific styles.
## parent
index: apps/web/src/.pi-map.index.md
map: apps/web/src/.pi-map.md
+2 -2
View File
@@ -4,14 +4,14 @@ dir: apps/web/src/styles
index: apps/web/src/styles/.pi-map.index.md
## role
Houses the complete CSS styling system for a web application, including design tokens, global styles, syntax highlighting themes, and utility classes.
Provides the complete visual design system and styling foundation for a web application, including themes, utilities, and component-specific styles.
## files
- global.css | Defines global CSS styles for a web application shell layout, navigation, cards, forms, dialogs, settings pages, and responsive design patterns. | dep: CSS custom properties (CSS variables: --border, --panel, --brand, --muted, --ink, --bg, --danger, --success, --warning, --font-size-xs, --font-size-sm, --space-2, --space-3, --space-4, --space-5)
- syntax-highlight.css | Stylesheet for a syntax highlighting component with toolbar, line numbers, code display, and Prism.js theme integration | dep: Prism.js
- tokens.css | Defines a comprehensive CSS design token system with light/dark themes, spacing scales, breakpoints, and fluid typography for a web application.
- utilities.css | Provides a comprehensive responsive CSS utility system with terminal-specific styling, mobile adaptations, and component patterns for a web application. | dep: CSS custom properties (var(--space-*), var(--border), var(--bg), var(--text), var(--brand), var(--muted), var(--success), var(--danger), var(--danger-light)), xterm.js (terminal integration)
## arch
Token-driven CSS architecture using CSS custom properties for themeable light/dark modes, utility-first responsive patterns, and component-scoped stylesheets with Prism.js integration for syntax highlighting.
Token-based CSS architecture using CSS custom properties for light/dark theming, with layered stylesheets separating tokens, global styles, utilities, and component-specific styling, supporting responsive and fluid design patterns.
## tags
var(, space, global, css, web, application, syntax, defines
## symbols
+1 -1
View File
@@ -2,7 +2,7 @@
dir: apps/web/src/styles/pages
## role
Package containing page-specific CSS stylesheets for individual web application views
Contains page-specific CSS stylesheets for individual application views in the web frontend, providing scoped styling for distinct feature areas.
## parent
index: apps/web/src/styles/.pi-map.index.md
map: apps/web/src/styles/.pi-map.md
+4 -4
View File
@@ -4,18 +4,18 @@ dir: apps/web/src/styles/pages
index: apps/web/src/styles/pages/.pi-map.index.md
## role
Package containing page-specific CSS stylesheets for individual web application views
Contains page-specific CSS stylesheets for individual application views in the web frontend, providing scoped styling for distinct feature areas.
## files
- git-history.css | Stylesheet for a Git history visualization page with commit list, branch selector, and detail panel layout | dep: CSS custom properties (var(--border), var(--panel), var(--ink), var(--brand), var(--muted))
- projects.css | Stylesheet for a projects page UI featuring expandable project toggles, repository listings, workspace grids, and repository creation radio controls. | dep: CSS custom properties (variables)
- sessions.css | Stylesheet for session management UI components including cards, dropdowns, forms, and responsive mobile layouts. | dep: CSS custom properties/variables (var(--border), var(--panel), var(--text), var(--space-*), var(--danger), var(--color-border))
- ssh-keys.css | Styles a responsive SSH key list component that stacks vertically on mobile and switches to horizontal layout on larger screens | dep: CSS custom properties (var(--space-3), var(--space-2), var(--space-4), var(--bg), var(--border))
- workspace-detail.css | Stylesheet for a workspace detail page with tabbed interface including files, git, tools, and settings views, plus a workspace creation form | dep: CSS custom properties (variables for colors, spacing, typography)
- workspaces.css | Styles a workspaces page with responsive card grid layout, status badges, and instance chips | dep: CSS custom properties (var(--space-*), var(--border), var(--brand), var(--panel), var(--ink), var(--muted), var(--bg), var(--success), var(--warning), var(--danger), var(--font-size-*))
- workspaces.css | Stylesheet for a workspaces management page featuring responsive grid layout, workspace cards with status badges, instance chips, and mobile adaptations. | dep: CSS custom properties (design tokens: --space-*, --border, --panel, --brand, --ink, --muted, --bg, --success, --warning, --danger, --font-size-*)
## arch
Modular CSS architecture with dedicated stylesheets per page domain, featuring responsive design patterns, component-based styling, and mobile-first breakpoint strategies
Modular CSS architecture with page-level style separation, responsive design patterns using media queries for mobile adaptation, and component-scoped styling organized by feature domain rather than shared component library.
## tags
var(, workspace, space, stylesheet, git, page, detail, history
var(, workspace, stylesheet, space, git, page, detail, history
## symbols
-
## workflows
+23 -10
View File
@@ -40,7 +40,6 @@
.workspace-card-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--space-3);
}
@@ -63,15 +62,11 @@
min-width: 0;
}
.workspace-project-name {
font-size: var(--font-size-sm);
font-weight: 500;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.04em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.workspace-title-row {
display: flex;
align-items: center;
gap: var(--space-2);
min-width: 0;
}
.workspace-name {
@@ -82,6 +77,24 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
min-width: 0;
}
.workspace-project-name {
display: inline-flex;
align-items: center;
gap: var(--space-1);
font-size: var(--font-size-sm);
font-weight: 500;
color: var(--muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.workspace-project-name .icon {
color: var(--brand);
}
/* Body: meta row + instance chips */