Make execution workspace detail page responsive for mobile

- Reduce card padding on small screens (p-4 → p-4 sm:p-5)
- Reduce spacing between sections on mobile (space-y-4 sm:space-y-6)
- Scale heading text (text-xl sm:text-2xl)
- Truncate long description on mobile, show full on sm+
- Reduce textarea min-heights on mobile (sm: prefix for larger sizes)
- Stack linked issue cards vertically on mobile, horizontal scroll on sm+
- Remove min-width constraint on linked issue cards on mobile

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-04-05 07:35:33 -05:00
parent 68499eb2f4
commit 612bab1eb6

View file

@ -378,7 +378,7 @@ export function ExecutionWorkspaceDetail() {
return ( return (
<> <>
<div className="mx-auto max-w-5xl space-y-6"> <div className="mx-auto max-w-5xl space-y-4 sm:space-y-6">
<div className="flex flex-wrap items-center gap-3"> <div className="flex flex-wrap items-center gap-3">
<Button variant="ghost" size="sm" asChild> <Button variant="ghost" size="sm" asChild>
<Link to={project ? `/projects/${projectRef}/workspaces` : "/projects"}> <Link to={project ? `/projects/${projectRef}/workspaces` : "/projects"}>
@ -393,19 +393,20 @@ export function ExecutionWorkspaceDetail() {
</StatusPill> </StatusPill>
</div> </div>
<div className="grid gap-6 lg:grid-cols-[minmax(0,1.4fr)_minmax(18rem,0.95fr)]"> <div className="grid gap-4 sm:gap-6 lg:grid-cols-[minmax(0,1.4fr)_minmax(18rem,0.95fr)]">
<div className="space-y-6"> <div className="space-y-4 sm:space-y-6">
<div className="rounded-2xl border border-border bg-card p-5"> <div className="rounded-2xl border border-border bg-card p-4 sm:p-5">
<div className="flex flex-col gap-4 sm:flex-row sm:flex-wrap sm:items-start sm:justify-between"> <div className="flex flex-col gap-4 sm:flex-row sm:flex-wrap sm:items-start sm:justify-between">
<div className="space-y-2"> <div className="space-y-2">
<div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground"> <div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">
Execution workspace Execution workspace
</div> </div>
<h1 className="text-2xl font-semibold">{workspace.name}</h1> <h1 className="text-xl font-semibold sm:text-2xl">{workspace.name}</h1>
<p className="max-w-2xl text-sm text-muted-foreground"> <p className="max-w-2xl text-sm text-muted-foreground">
Configure the concrete runtime workspace that Paperclip reuses for this issue flow. These settings stay Configure the concrete runtime workspace that Paperclip reuses for this issue flow.
<span className="hidden sm:inline"> These settings stay
attached to the execution workspace so future runs can keep local paths, repo refs, provisioning, teardown, attached to the execution workspace so future runs can keep local paths, repo refs, provisioning, teardown,
and runtime-service behavior in sync with the actual workspace being reused. and runtime-service behavior in sync with the actual workspace being reused.</span>
</p> </p>
</div> </div>
<div className="flex w-full shrink-0 items-center gap-2 sm:w-auto"> <div className="flex w-full shrink-0 items-center gap-2 sm:w-auto">
@ -482,7 +483,7 @@ export function ExecutionWorkspaceDetail() {
<div className="mt-4 grid gap-4 md:grid-cols-2"> <div className="mt-4 grid gap-4 md:grid-cols-2">
<Field label="Provision command" hint="Runs when Paperclip prepares this execution workspace"> <Field label="Provision command" hint="Runs when Paperclip prepares this execution workspace">
<textarea <textarea
className="min-h-28 w-full rounded-lg border border-border bg-background px-3 py-2 font-mono text-sm outline-none" className="min-h-20 w-full rounded-lg border border-border bg-background px-3 py-2 font-mono text-sm outline-none sm:min-h-28"
value={form.provisionCommand} value={form.provisionCommand}
onChange={(event) => setForm((current) => current ? { ...current, provisionCommand: event.target.value } : current)} onChange={(event) => setForm((current) => current ? { ...current, provisionCommand: event.target.value } : current)}
placeholder="bash ./scripts/provision-worktree.sh" placeholder="bash ./scripts/provision-worktree.sh"
@ -490,7 +491,7 @@ export function ExecutionWorkspaceDetail() {
</Field> </Field>
<Field label="Teardown command" hint="Runs when the execution workspace is archived or cleaned up"> <Field label="Teardown command" hint="Runs when the execution workspace is archived or cleaned up">
<textarea <textarea
className="min-h-28 w-full rounded-lg border border-border bg-background px-3 py-2 font-mono text-sm outline-none" className="min-h-20 w-full rounded-lg border border-border bg-background px-3 py-2 font-mono text-sm outline-none sm:min-h-28"
value={form.teardownCommand} value={form.teardownCommand}
onChange={(event) => setForm((current) => current ? { ...current, teardownCommand: event.target.value } : current)} onChange={(event) => setForm((current) => current ? { ...current, teardownCommand: event.target.value } : current)}
placeholder="bash ./scripts/teardown-worktree.sh" placeholder="bash ./scripts/teardown-worktree.sh"
@ -501,7 +502,7 @@ export function ExecutionWorkspaceDetail() {
<div className="mt-4 grid gap-4"> <div className="mt-4 grid gap-4">
<Field label="Cleanup command" hint="Workspace-specific cleanup before teardown"> <Field label="Cleanup command" hint="Workspace-specific cleanup before teardown">
<textarea <textarea
className="min-h-24 w-full rounded-lg border border-border bg-background px-3 py-2 font-mono text-sm outline-none" className="min-h-16 w-full rounded-lg border border-border bg-background px-3 py-2 font-mono text-sm outline-none sm:min-h-24"
value={form.cleanupCommand} value={form.cleanupCommand}
onChange={(event) => setForm((current) => current ? { ...current, cleanupCommand: event.target.value } : current)} onChange={(event) => setForm((current) => current ? { ...current, cleanupCommand: event.target.value } : current)}
placeholder="pkill -f vite || true" placeholder="pkill -f vite || true"
@ -553,7 +554,7 @@ export function ExecutionWorkspaceDetail() {
<label htmlFor="inherit-runtime-config">Inherit project workspace runtime config</label> <label htmlFor="inherit-runtime-config">Inherit project workspace runtime config</label>
</div> </div>
<textarea <textarea
className="min-h-48 w-full rounded-lg border border-border bg-background px-3 py-2 font-mono text-sm outline-none disabled:cursor-not-allowed disabled:opacity-60" className="min-h-32 w-full rounded-lg border border-border bg-background px-3 py-2 font-mono text-sm outline-none disabled:cursor-not-allowed disabled:opacity-60 sm:min-h-48"
value={form.workspaceRuntime} value={form.workspaceRuntime}
onChange={(event) => setForm((current) => current ? { ...current, workspaceRuntime: event.target.value } : current)} onChange={(event) => setForm((current) => current ? { ...current, workspaceRuntime: event.target.value } : current)}
disabled={form.inheritRuntime} disabled={form.inheritRuntime}
@ -586,8 +587,8 @@ export function ExecutionWorkspaceDetail() {
</div> </div>
</div> </div>
<div className="space-y-6"> <div className="space-y-4 sm:space-y-6">
<div className="rounded-2xl border border-border bg-card p-5"> <div className="rounded-2xl border border-border bg-card p-4 sm:p-5">
<div className="space-y-1"> <div className="space-y-1">
<div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Linked objects</div> <div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Linked objects</div>
<h2 className="text-lg font-semibold">Workspace context</h2> <h2 className="text-lg font-semibold">Workspace context</h2>
@ -632,7 +633,7 @@ export function ExecutionWorkspaceDetail() {
</DetailRow> </DetailRow>
</div> </div>
<div className="rounded-2xl border border-border bg-card p-5"> <div className="rounded-2xl border border-border bg-card p-4 sm:p-5">
<div className="space-y-1"> <div className="space-y-1">
<div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Paths and refs</div> <div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Paths and refs</div>
<h2 className="text-lg font-semibold">Concrete location</h2> <h2 className="text-lg font-semibold">Concrete location</h2>
@ -676,7 +677,7 @@ export function ExecutionWorkspaceDetail() {
</DetailRow> </DetailRow>
</div> </div>
<div className="rounded-2xl border border-border bg-card p-5"> <div className="rounded-2xl border border-border bg-card p-4 sm:p-5">
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between"> <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<div className="space-y-1"> <div className="space-y-1">
<div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Runtime services</div> <div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Runtime services</div>
@ -755,7 +756,7 @@ export function ExecutionWorkspaceDetail() {
)} )}
</div> </div>
<div className="rounded-2xl border border-border bg-card p-5"> <div className="rounded-2xl border border-border bg-card p-4 sm:p-5">
<div className="space-y-1"> <div className="space-y-1">
<div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Recent operations</div> <div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Recent operations</div>
<h2 className="text-lg font-semibold">Runtime and cleanup logs</h2> <h2 className="text-lg font-semibold">Runtime and cleanup logs</h2>
@ -798,7 +799,7 @@ export function ExecutionWorkspaceDetail() {
</div> </div>
</div> </div>
<div className="rounded-2xl border border-border bg-card p-5"> <div className="rounded-2xl border border-border bg-card p-4 sm:p-5">
<div className="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between"> <div className="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
<div className="space-y-1"> <div className="space-y-1">
<div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Linked issues</div> <div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Linked issues</div>
@ -819,12 +820,12 @@ export function ExecutionWorkspaceDetail() {
: "Failed to load linked issues."} : "Failed to load linked issues."}
</p> </p>
) : linkedIssues.length > 0 ? ( ) : linkedIssues.length > 0 ? (
<div className="-mx-1 flex gap-3 overflow-x-auto px-1 pb-1"> <div className="-mx-1 flex flex-col gap-3 px-1 pb-1 sm:flex-row sm:overflow-x-auto">
{linkedIssues.map((issue) => ( {linkedIssues.map((issue) => (
<Link <Link
key={issue.id} key={issue.id}
to={issueUrl(issue)} to={issueUrl(issue)}
className="min-w-72 rounded-xl border border-border/80 bg-background px-4 py-3 transition-colors hover:bg-accent/20" className="rounded-xl border border-border/80 bg-background px-4 py-3 transition-colors hover:bg-accent/20 sm:min-w-72"
> >
<div className="flex items-start justify-between gap-3"> <div className="flex items-start justify-between gap-3">
<div className="min-w-0 space-y-1"> <div className="min-w-0 space-y-1">