Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

172 linesCodeBlameRaw
1/**
2 * The landing page's pictures of Home (routes/workspace/home.tsx), drawn
3 * from the same parts and words as the real cards in components/home.tsx
4 * and components/home-ask.tsx: What changed and Landed, for coming back to
5 * what happened; Settled for you, Where you're needed and Start here,
6 * for what still needs you. They are pictures, so nothing in them takes
7 * focus or a click (`inert`), and the page reads them as one image.
8 */
9import { ArrowRight, ArrowUp, CheckCheck, GitCommitHorizontal, GitMerge, GitPullRequest, RotateCcw, Rocket, Sparkles } from "lucide-react";
10import type { ReactNode } from "react";
11
12import { MarkGlyph } from "./logo";
13import { Badge } from "./ui/badge";
14import { Button } from "./ui/button";
15import { Card } from "./ui/card";
16
17/** One of Home's cards, as components/home.tsx draws it: a title, a few words under it, then its rows. */
18function HomeCard({ title, hint, children }: { title: ReactNode; hint?: string; children: ReactNode }) {
19 return (
20 <Card tone="bg" className="overflow-hidden rounded-2xl text-left shadow-sm">
21 <header className="px-4 pt-3.5 pb-2.5">
22 <p className="text-sm font-semibold text-fg">{title}</p>
23 {hint && <p className="mt-0.5 text-xs text-muted">{hint}</p>}
24 </header>
25 {children}
26 </Card>
27 );
28}
29
30const ROW = "flex items-center gap-3 border-t border-line px-4 py-2.5";
31
32/** A picture, not a control: kept out of the tab order and read as one image. */
33function Picture({ label, children }: { label: string; children: ReactNode }) {
34 return (
35 <div role="img" aria-label={label} className="space-y-3">
36 <div inert className="space-y-3">
37 {children}
38 </div>
39 </div>
40 );
41}
42
43/** Coming back: the Ask box, What changed in plain English, and Landed with whether each change is live. */
44export function WhatChangedArt() {
45 return (
46 <Picture label="Home: What are we building today? over a box that asks g1t, What changed summarizing in plain English what landed, and Landed with whether each change is live">
47 <div className="text-center">
48 <p className="text-lg font-semibold tracking-tight text-fg">What are we building today?</p>
49 <div className="mt-3 flex items-center gap-2 rounded-2xl border border-line bg-bg p-1.5 pl-3.5 text-left shadow-sm">
50 <MarkGlyph className="h-3.5 shrink-0" />
51 <span className="min-w-0 grow truncate text-[0.8125rem] text-faint">Ask g1t what changed, what&apos;s blocked, or what to do next</span>
52 <Button type="button" variant="accent" size="icon-xs" tabIndex={-1} aria-hidden="true">
53 <ArrowUp size={13} />
54 </Button>
55 </div>
56 <div className="mt-2.5 flex flex-wrap justify-center gap-1.5">
57 <Badge tone="accent" size="md" className="whitespace-normal">
58 Summarize what changed since I was last here
59 </Badge>
60 <Badge size="md" className="hidden sm:inline-flex">
61 What needs me first?
62 </Badge>
63 </div>
64 </div>
65
66 <HomeCard title="What changed" hint="In plain English, since I was last here">
67 <div className="space-y-2 px-4 pb-3.5 text-[0.8125rem] leading-relaxed text-fg-soft">
68 <p>
69 Two changes landed in <span className="font-medium text-fg">acme/web</span>. CSV exports now stream in batches of 1,000 rows, so the
70 largest accounts no longer time out; it went live 9 minutes after the merge queue merged it. Jordan pinned the build image's cache key, which fixed last night's failed deploy.
71 </p>
72 <div className="flex flex-wrap items-center gap-1.5 border-t border-line pt-2.5">
73 <Button type="button" variant="soft" size="xs" tabIndex={-1}>
74 <MarkGlyph className="h-2.5" />
75 Ask a follow-up
76 </Button>
77 <Button type="button" variant="ghost" size="xs" tabIndex={-1}>
78 <RotateCcw size={12} />
79 Summarize again
80 </Button>
81 </div>
82 </div>
83 </HomeCard>
84
85 <HomeCard title="Landed" hint="1 pull request merged · 1 push">
86 {[
87 { title: "Stream CSV exports in batches", detail: "web#431 · by priya", push: false, ship: <Badge tone="success"><Rocket size={10} aria-hidden="true" />Live 9 min after merge</Badge> },
88 { title: "Pin the build image's cache key", detail: "web · 1 push by jordan", push: true, ship: <Badge tone="success"><Rocket size={10} aria-hidden="true" />Live 4 min after push</Badge> },
89 ].map((row) => (
90 <div key={row.title} className={ROW}>
91 {row.push ? <GitCommitHorizontal size={15} className="shrink-0 text-muted" aria-hidden="true" /> : <GitMerge size={15} className="shrink-0 text-merged" aria-hidden="true" />}
92 <div className="min-w-0 grow">
93 <p className="truncate text-sm text-fg">{row.title}</p>
94 <div className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
95 <span className="truncate text-xs text-muted">{row.detail}</span>
96 {row.ship}
97 </div>
98 </div>
99 <span className="flex size-7 shrink-0 items-center justify-center rounded-md text-accent">
100 <Sparkles size={13} aria-hidden="true" />
101 </span>
102 </div>
103 ))}
104 </HomeCard>
105 </Picture>
106 );
107}
108
109/** What still needs you: what settled by itself, Where you're needed, and Start here. */
110export function NeedsYouArt() {
111 return (
112 <Picture label="Home: Settled for you lists notifications that settled themselves and why, Where you're needed lists a pull request ready to merge and a review asked of you, and Start here opens the one to do first">
113 <HomeCard title="Settled for you" hint="3 finished by themselves">
114 <div className="flex flex-wrap gap-1.5 px-4 pb-3">
115 <Badge tone="success" size="md">3 notifications settled</Badge>
116 <Badge tone="warn" size="md">2 things still need you</Badge>
117 </div>
118 {[
119 { title: "CI failed on main", why: "CI passed in run 330" },
120 { title: "Review requested: Cache the dependency graph", why: "Merged by @ana" },
121 ].map((row) => (
122 <div key={row.title} className={ROW}>
123 <CheckCheck size={15} className="shrink-0 text-success" aria-hidden="true" />
124 <div className="min-w-0 grow">
125 <p className="truncate text-sm text-fg">{row.title}</p>
126 <p className="truncate text-xs text-fg-soft">{row.why}</p>
127 </div>
128 </div>
129 ))}
130 </HomeCard>
131
132 <HomeCard title="Where you're needed">
133 {[
134 { icon: <GitMerge size={15} className="shrink-0 text-success" aria-hidden="true" />, title: "Retry webhook deliveries with backoff", detail: "acme/web #433 · Ready to land when you merge it.", stake: "Ready to merge", action: "Open" },
135 { icon: <GitPullRequest size={15} className="shrink-0 text-info" aria-hidden="true" />, title: "Add audit log export", detail: "acme/web #435 · Your review", stake: "+212 −40", action: "Review" },
136 ].map((row) => (
137 <div key={row.title} className={ROW}>
138 {row.icon}
139 <div className="min-w-0 grow">
140 <p className="truncate text-sm font-semibold text-fg">{row.title}</p>
141 <p className="truncate text-xs text-muted">{row.detail}</p>
142 </div>
143 <span className="hidden shrink-0 text-xs font-medium text-fg-soft sm:inline">{row.stake}</span>
144 <Button type="button" variant="outline" size="xs" tabIndex={-1} className="border-line-strong px-2.5 text-fg">
145 {row.action}
146 </Button>
147 </div>
148 ))}
149 </HomeCard>
150
151 <HomeCard
152 title={
153 <>
154 Start here <span className="font-normal text-faint">· picked by g1t</span>
155 </>
156 }
157 >
158 <div className="px-4 pb-4">
159 <p className="text-sm font-semibold text-fg">Retry webhook deliveries with backoff</p>
160 <p className="mt-2.5 rounded-lg bg-raised/60 px-3 py-2 text-xs leading-relaxed text-fg-soft">
161 <span className="font-medium text-fg">Why this one: </span>
162 Everything it needs is met; it lands when you merge it.
163 </p>
164 <Button type="button" variant="accent" size="sm" tabIndex={-1} className="mt-3">
165 Open pull request
166 <ArrowRight size={13} />
167 </Button>
168 </div>
169 </HomeCard>
170 </Picture>
171 );
172}