feat: mobile Spaces nav and list-based project/workspace views

- Combine Projects and Workspaces into a single 'Spaces' grouped mobile
  nav item that opens a bottom-sheet menu.
- Add SpacesBottomSheet component with Projects/Workspaces options.
- Extend MobileListView with optional renderItem prop for rich rows.
- Redesign mobile ProjectsPage rows to show project description and
  repository chips.
- Replace mobile WorkspacesPage list with compact WorkspaceCard grid,
  matching desktop card content.
- Add mobile-list-* CSS and mobile-workspaces-list spacing.

Quality gates: npm run typecheck, npm run lint clean,
npm test -- --run 87 passed.
This commit is contained in:
Developer
2026-06-13 19:32:16 +00:00
parent e6ab77d123
commit 530225d37c
27 changed files with 346 additions and 113 deletions
@@ -1,3 +1,4 @@
import type { ReactNode } from "react";
import { Icon } from "../../icon";
import type { IconName } from "../../../utils/icons";
@@ -17,6 +18,7 @@ interface MobileListViewProps {
emptyMessage?: string;
searchPlaceholder?: string;
onSearch?: (query: string) => void;
renderItem?: (item: MobileListItem) => ReactNode;
}
export const MobileListView: React.FC<MobileListViewProps> = ({
@@ -25,6 +27,7 @@ export const MobileListView: React.FC<MobileListViewProps> = ({
emptyMessage = "No items found",
searchPlaceholder = "Search...",
onSearch,
renderItem,
}) => {
return (
<div className="mobile-list-view">
@@ -58,12 +61,16 @@ export const MobileListView: React.FC<MobileListViewProps> = ({
<Icon name={item.icon as IconName} size="md" />
</div>
)}
<div className="mobile-list-item-content">
<div className="mobile-list-item-title">{item.title}</div>
{item.subtitle && (
<div className="mobile-list-item-subtitle">{item.subtitle}</div>
)}
</div>
{renderItem ? (
renderItem(item)
) : (
<div className="mobile-list-item-content">
<div className="mobile-list-item-title">{item.title}</div>
{item.subtitle && (
<div className="mobile-list-item-subtitle">{item.subtitle}</div>
)}
</div>
)}
<div className="mobile-list-item-actions" style={{ transform: "rotate(180deg)" }}>
<Icon name="arrow-left" size="sm" />
</div>