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
+25 -1
View File
@@ -168,8 +168,32 @@ export const ProjectsPage = () => {
items={projects.map((p) => ({
id: p.id,
title: p.name,
subtitle: `${p.repositories?.length ?? 0} repo${(p.repositories?.length ?? 0) !== 1 ? "s" : ""}${p.description ? " · " + p.description : ""}`,
}))}
renderItem={(item) => {
const project = projects.find((p) => p.id === item.id);
if (!project) return null;
return (
<div className="mobile-list-item-content mobile-list-item-content-rich">
<div className="mobile-list-item-title">{project.name}</div>
{project.description && (
<p className="mobile-list-item-description">
{project.description}
</p>
)}
<div className="mobile-list-item-chips">
{(project.repositories?.length ?? 0) === 0 ? (
<span className="mobile-list-item-chip muted">No repositories</span>
) : (
project.repositories.map((repo) => (
<span key={repo.id} className="mobile-list-item-chip">
{repo.name}
</span>
))
)}
</div>
</div>
);
}}
onItemClick={(id) => {
const project = projects.find((p) => p.id === id);
if (project) {