Make close workspace modal responsive for mobile

- Reduce padding and text sizes on small screens (p-4/text-xs -> sm:p-6/sm:text-sm)
- Tighter spacing between sections on mobile (space-y-3 -> sm:space-y-4)
- Sticky footer so action buttons stay visible while scrolling
- Grid layout stays 2-col on all sizes for git status
- Add shrink-0 to loading spinner

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-04-04 09:55:10 -05:00
parent 35f2fc7230
commit 2615450afc

View file

@ -88,27 +88,27 @@ export function ExecutionWorkspaceCloseDialog({
<Dialog open={open} onOpenChange={(nextOpen) => {
if (!closeWorkspace.isPending) onOpenChange(nextOpen);
}}>
<DialogContent className="max-h-[85vh] overflow-y-auto sm:max-w-2xl">
<DialogContent className="max-h-[85vh] overflow-y-auto p-4 sm:max-w-2xl sm:p-6">
<DialogHeader>
<DialogTitle>{actionLabel}</DialogTitle>
<DialogDescription className="break-words">
<DialogDescription className="break-words text-xs sm:text-sm">
Archive <span className="font-medium text-foreground">{workspaceName}</span> and clean up any owned workspace
artifacts. Paperclip keeps the workspace record and issue history, but removes it from active workspace views.
</DialogDescription>
</DialogHeader>
{readinessQuery.isLoading ? (
<div className="flex items-center gap-2 rounded-xl border border-border bg-muted/30 px-4 py-3 text-sm text-muted-foreground">
<Loader2 className="h-4 w-4 animate-spin" />
<div className="flex items-center gap-2 rounded-xl border border-border bg-muted/30 px-3 py-2.5 text-xs sm:px-4 sm:py-3 sm:text-sm text-muted-foreground">
<Loader2 className="h-4 w-4 animate-spin shrink-0" />
Checking whether this workspace is safe to close...
</div>
) : readinessQuery.error ? (
<div className="rounded-xl border border-destructive/30 bg-destructive/5 px-4 py-3 text-sm text-destructive">
<div className="rounded-xl border border-destructive/30 bg-destructive/5 px-3 py-2.5 text-xs sm:px-4 sm:py-3 sm:text-sm text-destructive">
{readinessQuery.error instanceof Error ? readinessQuery.error.message : "Failed to inspect workspace close readiness."}
</div>
) : readiness ? (
<div className="space-y-4">
<div className={`rounded-xl border px-4 py-3 text-sm ${readinessTone(readiness.state)}`}>
<div className="space-y-3 sm:space-y-4">
<div className={`rounded-xl border px-3 py-2.5 text-xs sm:px-4 sm:py-3 sm:text-sm ${readinessTone(readiness.state)}`}>
<div className="font-medium">
{readiness.state === "blocked"
? "Close is blocked"
@ -129,10 +129,10 @@ export function ExecutionWorkspaceCloseDialog({
{blockingIssues.length > 0 ? (
<section className="space-y-2">
<h3 className="text-sm font-medium">Blocking issues</h3>
<div className="space-y-2">
<h3 className="text-xs font-medium sm:text-sm">Blocking issues</h3>
<div className="space-y-1.5 sm:space-y-2">
{blockingIssues.map((issue) => (
<div key={issue.id} className="rounded-xl border border-destructive/20 bg-destructive/5 px-4 py-3 text-sm">
<div key={issue.id} className="rounded-xl border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs sm:px-4 sm:py-3 sm:text-sm">
<div className="flex min-w-0 flex-wrap items-center justify-between gap-2">
<Link to={issueUrl(issue)} className="min-w-0 break-words font-medium hover:underline">
{issue.identifier ?? issue.id} · {issue.title}
@ -147,10 +147,10 @@ export function ExecutionWorkspaceCloseDialog({
{readiness.blockingReasons.length > 0 ? (
<section className="space-y-2">
<h3 className="text-sm font-medium">Blocking reasons</h3>
<ul className="space-y-2 text-sm text-muted-foreground">
<h3 className="text-xs font-medium sm:text-sm">Blocking reasons</h3>
<ul className="space-y-1.5 text-xs sm:space-y-2 sm:text-sm text-muted-foreground">
{readiness.blockingReasons.map((reason, idx) => (
<li key={`blocking-${idx}`} className="break-words rounded-lg border border-destructive/20 bg-destructive/5 px-3 py-2 text-destructive">
<li key={`blocking-${idx}`} className="break-words rounded-lg border border-destructive/20 bg-destructive/5 px-2.5 py-1.5 sm:px-3 sm:py-2 text-destructive">
{reason}
</li>
))}
@ -160,10 +160,10 @@ export function ExecutionWorkspaceCloseDialog({
{readiness.warnings.length > 0 ? (
<section className="space-y-2">
<h3 className="text-sm font-medium">Warnings</h3>
<ul className="space-y-2 text-sm text-muted-foreground">
<h3 className="text-xs font-medium sm:text-sm">Warnings</h3>
<ul className="space-y-1.5 text-xs sm:space-y-2 sm:text-sm text-muted-foreground">
{readiness.warnings.map((warning, idx) => (
<li key={`warning-${idx}`} className="break-words rounded-lg border border-amber-500/20 bg-amber-500/5 px-3 py-2">
<li key={`warning-${idx}`} className="break-words rounded-lg border border-amber-500/20 bg-amber-500/5 px-2.5 py-1.5 sm:px-3 sm:py-2">
{warning}
</li>
))}
@ -173,9 +173,9 @@ export function ExecutionWorkspaceCloseDialog({
{readiness.git ? (
<section className="space-y-2">
<h3 className="text-sm font-medium">Git status</h3>
<div className="rounded-xl border border-border bg-muted/20 px-4 py-3 text-sm">
<div className="grid gap-2 sm:grid-cols-2">
<h3 className="text-xs font-medium sm:text-sm">Git status</h3>
<div className="rounded-xl border border-border bg-muted/20 px-3 py-2.5 text-xs sm:px-4 sm:py-3 sm:text-sm">
<div className="grid grid-cols-2 gap-2">
<div>
<div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">Branch</div>
<div className="font-mono text-xs">{readiness.git.branchName ?? "Unknown"}</div>
@ -209,10 +209,10 @@ export function ExecutionWorkspaceCloseDialog({
{otherLinkedIssues.length > 0 ? (
<section className="space-y-2">
<h3 className="text-sm font-medium">Other linked issues</h3>
<div className="space-y-2">
<h3 className="text-xs font-medium sm:text-sm">Other linked issues</h3>
<div className="space-y-1.5 sm:space-y-2">
{otherLinkedIssues.map((issue) => (
<div key={issue.id} className="rounded-xl border border-border bg-muted/20 px-4 py-3 text-sm">
<div key={issue.id} className="rounded-xl border border-border bg-muted/20 px-3 py-2 text-xs sm:px-4 sm:py-3 sm:text-sm">
<div className="flex min-w-0 flex-wrap items-center justify-between gap-2">
<Link to={issueUrl(issue)} className="min-w-0 break-words font-medium hover:underline">
{issue.identifier ?? issue.id} · {issue.title}
@ -227,10 +227,10 @@ export function ExecutionWorkspaceCloseDialog({
{readiness.runtimeServices.length > 0 ? (
<section className="space-y-2">
<h3 className="text-sm font-medium">Attached runtime services</h3>
<div className="space-y-2">
<h3 className="text-xs font-medium sm:text-sm">Attached runtime services</h3>
<div className="space-y-1.5 sm:space-y-2">
{readiness.runtimeServices.map((service) => (
<div key={service.id} className="rounded-xl border border-border bg-muted/20 px-4 py-3 text-sm">
<div key={service.id} className="rounded-xl border border-border bg-muted/20 px-3 py-2 text-xs sm:px-4 sm:py-3 sm:text-sm">
<div className="flex min-w-0 flex-wrap items-center justify-between gap-2">
<span className="font-medium">{service.serviceName}</span>
<span className="text-xs text-muted-foreground">{service.status} · {service.lifecycle}</span>
@ -245,10 +245,10 @@ export function ExecutionWorkspaceCloseDialog({
) : null}
<section className="space-y-2">
<h3 className="text-sm font-medium">Cleanup actions</h3>
<div className="space-y-2">
<h3 className="text-xs font-medium sm:text-sm">Cleanup actions</h3>
<div className="space-y-1.5 sm:space-y-2">
{readiness.plannedActions.map((action, index) => (
<div key={`${action.kind}-${index}`} className="rounded-xl border border-border bg-muted/20 px-4 py-3 text-sm">
<div key={`${action.kind}-${index}`} className="rounded-xl border border-border bg-muted/20 px-3 py-2 text-xs sm:px-4 sm:py-3 sm:text-sm">
<div className="font-medium">{action.label}</div>
<div className="mt-1 break-words text-muted-foreground">{action.description}</div>
{action.command ? (
@ -262,14 +262,14 @@ export function ExecutionWorkspaceCloseDialog({
</section>
{currentStatus === "cleanup_failed" ? (
<div className="rounded-xl border border-amber-500/20 bg-amber-500/5 px-4 py-3 text-sm text-muted-foreground">
<div className="rounded-xl border border-amber-500/20 bg-amber-500/5 px-3 py-2.5 text-xs sm:px-4 sm:py-3 sm:text-sm text-muted-foreground">
Cleanup previously failed on this workspace. Retrying close will rerun the cleanup flow and update the
workspace status if it succeeds.
</div>
) : null}
{currentStatus === "archived" ? (
<div className="rounded-xl border border-border bg-muted/20 px-4 py-3 text-sm text-muted-foreground">
<div className="rounded-xl border border-border bg-muted/20 px-3 py-2.5 text-xs sm:px-4 sm:py-3 sm:text-sm text-muted-foreground">
This workspace is already archived.
</div>
) : null}
@ -291,7 +291,7 @@ export function ExecutionWorkspaceCloseDialog({
</div>
) : null}
<DialogFooter>
<DialogFooter className="sticky bottom-0 -mx-4 -mb-4 rounded-b-lg border-t border-border bg-background px-4 py-3 sm:-mx-6 sm:-mb-6 sm:px-6 sm:py-4">
<Button
variant="outline"
onClick={() => onOpenChange(false)}