feat: unify repository creation flow for desktop and mobile

- ProjectCard.tsx: add onAddRepository prop, show 'Add Repository' button in expanded view
- ProjectCard.tsx: add showBackButton/onBack props for mobile detail reuse
- ProjectsPage.tsx (desktop): wire onAddRepository to open RepositoryCreateDialog
- ProjectsPage.tsx (mobile): reuse ProjectCard for detail view instead of inline duplication
- pages/projects.css: add .project-add-repo style

Both platforms now use the same ProjectCard component and RepositoryCreateDialog
for adding repositories to projects.

Quality gates: tsc --noEmit pass, npm run build pass, 80/80 tests pass
This commit is contained in:
Developer
2026-06-09 09:22:36 +00:00
parent 64dcdc9d0d
commit c353bceb97
4 changed files with 121 additions and 174 deletions
@@ -8,7 +8,10 @@ interface Props {
deleteConfirm: boolean;
workspaceLoading: string | null;
showCreateForm: string | null;
onToggle: () => void;
/** Mobile detail mode: shows back button instead of chevron toggle. */
showBackButton?: boolean;
onToggle?: () => void;
onBack?: () => void;
onEdit: () => void;
onDelete: () => void;
onConfirmDelete: () => void;
@@ -19,6 +22,7 @@ interface Props {
workspace: WorkspaceSummary,
action: "sync" | "delete",
) => void;
onAddRepository?: () => void;
onCancelCreate: () => void;
onCreated: () => void;
}
@@ -29,39 +33,53 @@ export const ProjectCard = ({
deleteConfirm,
workspaceLoading,
showCreateForm,
showBackButton = false,
onToggle,
onBack,
onEdit,
onDelete,
onConfirmDelete,
onCancelDelete,
onCreateWorkspace,
onWorkspaceAction,
onAddRepository,
onCancelCreate,
onCreated,
}: Props) => {
return (
<article className="card project-card">
<div className="project-info-row">
<button
className="project-toggle"
onClick={onToggle}
type="button"
aria-expanded={expanded}
>
<Icon name={expanded ? "chevron-down" : "chevron-right"} size="sm" />
<div>
<h3>{project.name}</h3>
{project.description && (
<p className="muted project-description">{project.description}</p>
)}
</div>
{project.repositories?.length > 0 && (
<span className="repo-count">
{project.repositories.length} repo
{project.repositories.length > 1 ? "s" : ""}
</span>
{showBackButton ? (
<button
className="mobile-detail-back"
onClick={onBack}
type="button"
aria-label="Go back"
>
<Icon name="arrow-left" size="md" />
</button>
) : (
<button
className="project-toggle"
onClick={onToggle}
type="button"
aria-expanded={expanded}
>
<Icon name={expanded ? "chevron-down" : "chevron-right"} size="sm" />
</button>
)}
<div>
<h3>{project.name}</h3>
{project.description && (
<p className="muted project-description">{project.description}</p>
)}
</button>
</div>
{!showBackButton && project.repositories?.length > 0 && (
<span className="repo-count">
{project.repositories.length} repo
{project.repositories.length > 1 ? "s" : ""}
</span>
)}
<div className="project-actions">
<button className="ghost-button" onClick={onEdit} type="button">
<Icon name="edit" size="sm" /> Edit
@@ -170,6 +188,17 @@ export const ProjectCard = ({
))}
</div>
)}
{onAddRepository && (
<div className="project-add-repo">
<button
className="primary-button"
onClick={onAddRepository}
type="button"
>
<Icon name="add" size="sm" /> Add Repository
</button>
</div>
)}
</div>
)}
</article>