@usefragments/ui 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/dist/assets/ui.css +327 -274
  2. package/dist/components/Checkbox/Checkbox.module.scss.cjs +11 -11
  3. package/dist/components/Checkbox/Checkbox.module.scss.js +11 -11
  4. package/dist/components/Chip/Chip.module.scss.cjs +15 -15
  5. package/dist/components/Chip/Chip.module.scss.js +15 -15
  6. package/dist/components/Combobox/index.cjs +106 -9
  7. package/dist/components/Combobox/index.d.ts.map +1 -1
  8. package/dist/components/Combobox/index.js +106 -9
  9. package/dist/components/DataTable/DataTable.module.scss.cjs +37 -34
  10. package/dist/components/DataTable/DataTable.module.scss.js +37 -34
  11. package/dist/components/DataTable/index.d.ts.map +1 -1
  12. package/dist/components/Main/Main.module.scss.cjs +26 -0
  13. package/dist/components/Main/Main.module.scss.js +26 -0
  14. package/dist/components/Main/index.cjs +128 -0
  15. package/dist/components/Main/index.d.ts +22 -0
  16. package/dist/components/Main/index.d.ts.map +1 -0
  17. package/dist/components/Main/index.js +111 -0
  18. package/dist/components/Table/Table.module.scss.cjs +19 -19
  19. package/dist/components/Table/Table.module.scss.js +19 -19
  20. package/dist/components/TableOfContents/TableOfContents.module.scss.cjs +15 -15
  21. package/dist/components/TableOfContents/TableOfContents.module.scss.js +15 -15
  22. package/dist/components/TableOfContents/index.cjs +22 -42
  23. package/dist/components/TableOfContents/index.d.ts +3 -3
  24. package/dist/components/TableOfContents/index.d.ts.map +1 -1
  25. package/dist/components/TableOfContents/index.js +22 -42
  26. package/dist/{components/DataTable/DataTable.virtual.cjs → data-table-virtual.cjs} +1 -1
  27. package/dist/{components/DataTable/DataTable.virtual.js → data-table-virtual.js} +1 -1
  28. package/dist/data-table.cjs +27 -9
  29. package/dist/data-table.js +19 -1
  30. package/dist/index.cjs +87 -88
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +2 -3
  34. package/fragments.json +1 -1
  35. package/package.json +57 -2
  36. package/src/components/Checkbox/Checkbox.contract.json +5 -24
  37. package/src/components/Checkbox/Checkbox.module.scss +4 -2
  38. package/src/components/Chip/Chip.contract.json +11 -28
  39. package/src/components/Chip/Chip.module.scss +21 -45
  40. package/src/components/Combobox/Combobox.contract.json +6 -24
  41. package/src/components/Combobox/index.tsx +132 -6
  42. package/src/components/DataTable/DataTable.module.scss +31 -8
  43. package/src/components/DataTable/index.tsx +44 -16
  44. package/src/components/Main/Main.contract.json +79 -0
  45. package/src/components/Main/Main.module.scss +31 -0
  46. package/src/components/Main/index.tsx +124 -0
  47. package/src/components/Table/Table.module.scss +22 -5
  48. package/src/components/TableOfContents/TableOfContents.contract.json +6 -16
  49. package/src/components/TableOfContents/TableOfContents.module.scss +10 -13
  50. package/src/components/TableOfContents/index.tsx +27 -38
  51. package/src/index.ts +11 -9
  52. package/src/styles/styles.d.ts +8 -0
  53. package/src/tokens/_component-properties.scss +1 -0
  54. package/dist/components/Cloud/DashboardLayoutPrototypes.shared.d.ts +0 -33
  55. package/dist/components/Cloud/DashboardLayoutPrototypes.shared.d.ts.map +0 -1
  56. package/dist/components/Cloud/DashboardLayoutPrototypes.shell.d.ts +0 -11
  57. package/dist/components/Cloud/DashboardLayoutPrototypes.shell.d.ts.map +0 -1
  58. package/dist/components/Cloud/PullRequestsPrototypes.content.d.ts +0 -5
  59. package/dist/components/Cloud/PullRequestsPrototypes.content.d.ts.map +0 -1
  60. package/dist/components/Cloud/PullRequestsPrototypes.detail-panels.d.ts +0 -4
  61. package/dist/components/Cloud/PullRequestsPrototypes.detail-panels.d.ts.map +0 -1
  62. package/dist/components/Cloud/PullRequestsPrototypes.detail.d.ts +0 -3
  63. package/dist/components/Cloud/PullRequestsPrototypes.detail.d.ts.map +0 -1
  64. package/dist/components/Cloud/PullRequestsPrototypes.id-data.d.ts +0 -86
  65. package/dist/components/Cloud/PullRequestsPrototypes.id-data.d.ts.map +0 -1
  66. package/dist/components/Cloud/PullRequestsPrototypes.id-page.d.ts +0 -2
  67. package/dist/components/Cloud/PullRequestsPrototypes.id-page.d.ts.map +0 -1
  68. package/src/components/Accordion/Accordion.stories.tsx +0 -106
  69. package/src/components/Alert/Alert.stories.tsx +0 -119
  70. package/src/components/AppShell/AppShell.stories.tsx +0 -156
  71. package/src/components/Avatar/Avatar.stories.tsx +0 -74
  72. package/src/components/Badge/Badge.stories.tsx +0 -92
  73. package/src/components/BentoGrid/BentoGrid.stories.tsx +0 -98
  74. package/src/components/Box/Box.stories.tsx +0 -150
  75. package/src/components/Breadcrumbs/Breadcrumbs.stories.tsx +0 -87
  76. package/src/components/Button/Button.stories.tsx +0 -103
  77. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +0 -97
  78. package/src/components/Card/Card.stories.tsx +0 -144
  79. package/src/components/Chart/Chart.stories.tsx +0 -119
  80. package/src/components/Checkbox/Checkbox.stories.tsx +0 -68
  81. package/src/components/Chip/Chip.stories.tsx +0 -70
  82. package/src/components/Cloud/CloudGovernanceShell.module.scss +0 -88
  83. package/src/components/Cloud/CloudGovernanceShell.stories.tsx +0 -446
  84. package/src/components/Cloud/ControlSizing.module.scss +0 -49
  85. package/src/components/Cloud/ControlSizing.stories.tsx +0 -238
  86. package/src/components/Cloud/DashboardLayoutPrototypes.module.scss +0 -462
  87. package/src/components/Cloud/DashboardLayoutPrototypes.shared.tsx +0 -375
  88. package/src/components/Cloud/DashboardLayoutPrototypes.shell.tsx +0 -147
  89. package/src/components/Cloud/DashboardLayoutPrototypes.stories.tsx +0 -328
  90. package/src/components/Cloud/PullRequestsPrototypes.content.tsx +0 -283
  91. package/src/components/Cloud/PullRequestsPrototypes.detail-panels.tsx +0 -381
  92. package/src/components/Cloud/PullRequestsPrototypes.detail.tsx +0 -204
  93. package/src/components/Cloud/PullRequestsPrototypes.id-data.ts +0 -395
  94. package/src/components/Cloud/PullRequestsPrototypes.id-page.tsx +0 -349
  95. package/src/components/Cloud/PullRequestsPrototypes.stories.tsx +0 -81
  96. package/src/components/CodeBlock/CodeBlock.stories.tsx +0 -147
  97. package/src/components/Collapsible/Collapsible.stories.tsx +0 -94
  98. package/src/components/ColorPicker/ColorPicker.stories.tsx +0 -74
  99. package/src/components/Combobox/Combobox.stories.tsx +0 -133
  100. package/src/components/Command/Command.stories.tsx +0 -102
  101. package/src/components/ConversationList/ConversationList.stories.tsx +0 -93
  102. package/src/components/DataTable/DataTable.stories.tsx +0 -129
  103. package/src/components/DatePicker/DatePicker.stories.tsx +0 -129
  104. package/src/components/Dialog/Dialog.stories.tsx +0 -154
  105. package/src/components/Drawer/Drawer.stories.tsx +0 -144
  106. package/src/components/Editor/Editor.stories.tsx +0 -99
  107. package/src/components/EmptyState/EmptyState.stories.tsx +0 -97
  108. package/src/components/Field/Field.stories.tsx +0 -109
  109. package/src/components/Fieldset/Fieldset.stories.tsx +0 -116
  110. package/src/components/Form/Form.stories.tsx +0 -142
  111. package/src/components/Grid/Grid.stories.tsx +0 -125
  112. package/src/components/Header/Header.stories.tsx +0 -133
  113. package/src/components/Icon/Icon.stories.tsx +0 -80
  114. package/src/components/IconButton/IconButton.stories.tsx +0 -78
  115. package/src/components/Image/Image.stories.tsx +0 -109
  116. package/src/components/Input/Input.stories.tsx +0 -104
  117. package/src/components/Link/Link.stories.tsx +0 -67
  118. package/src/components/List/List.stories.tsx +0 -95
  119. package/src/components/Listbox/Listbox.stories.tsx +0 -81
  120. package/src/components/Loading/Loading.stories.tsx +0 -69
  121. package/src/components/Markdown/Markdown.stories.tsx +0 -75
  122. package/src/components/Menu/Menu.stories.tsx +0 -113
  123. package/src/components/Message/Message.stories.tsx +0 -85
  124. package/src/components/NavigationMenu/NavigationMenu.stories.tsx +0 -161
  125. package/src/components/Pagination/Pagination.stories.tsx +0 -81
  126. package/src/components/Popover/Popover.stories.tsx +0 -152
  127. package/src/components/Progress/Progress.stories.tsx +0 -64
  128. package/src/components/Prompt/Prompt.stories.tsx +0 -93
  129. package/src/components/RadioGroup/RadioGroup.stories.tsx +0 -107
  130. package/src/components/ScrollArea/ScrollArea.stories.tsx +0 -97
  131. package/src/components/Select/Select.stories.tsx +0 -127
  132. package/src/components/Separator/Separator.stories.tsx +0 -84
  133. package/src/components/Sidebar/Sidebar.stories.tsx +0 -122
  134. package/src/components/Skeleton/Skeleton.stories.tsx +0 -80
  135. package/src/components/Slider/Slider.stories.tsx +0 -73
  136. package/src/components/Stack/Stack.stories.tsx +0 -73
  137. package/src/components/Switch/Switch.stories.tsx +0 -59
  138. package/src/components/Table/Table.stories.tsx +0 -219
  139. package/src/components/TableOfContents/TableOfContents.stories.tsx +0 -120
  140. package/src/components/Tabs/Tabs.stories.tsx +0 -136
  141. package/src/components/Text/Text.stories.tsx +0 -133
  142. package/src/components/Textarea/Textarea.stories.tsx +0 -107
  143. package/src/components/Theme/Theme.stories.tsx +0 -95
  144. package/src/components/ThinkingIndicator/ThinkingIndicator.stories.tsx +0 -85
  145. package/src/components/Toast/Toast.stories.tsx +0 -91
  146. package/src/components/ToggleGroup/ToggleGroup.stories.tsx +0 -114
  147. package/src/components/Tooltip/Tooltip.stories.tsx +0 -95
  148. package/src/components/VisuallyHidden/VisuallyHidden.stories.tsx +0 -78
@@ -1,381 +0,0 @@
1
- import { Avatar } from "../Avatar";
2
- import { Badge } from "../Badge";
3
- import { Box } from "../Box";
4
- import { Button } from "../Button";
5
- import { Card } from "../Card";
6
- import { DataTable, type DataTableColumn } from "../DataTable";
7
- import { Select } from "../Select";
8
- import { Stack } from "../Stack";
9
- import { Text } from "../Text";
10
- import {
11
- blockingFindings,
12
- changedFiles,
13
- introducedFindings,
14
- prFindings,
15
- prIdPagePullRequest as pr,
16
- threadFindings,
17
- type ChangedFile,
18
- type PrFinding,
19
- } from "./PullRequestsPrototypes.id-data";
20
- import styles from "./DashboardLayoutPrototypes.module.scss";
21
-
22
- const legacyCount = prFindings.length - introducedFindings.length;
23
-
24
- function actionLabel(finding: PrFinding) {
25
- if (finding.fix === "Deterministic") return "Create fix";
26
- if (finding.severity === "Blocking") return "Request waiver";
27
- return "Mark intentional";
28
- }
29
-
30
- // ============================================================================
31
- // Findings tab — the table-first workbench
32
- // ============================================================================
33
-
34
- const findingColumns: DataTableColumn<PrFinding>[] = [
35
- {
36
- id: "severity",
37
- header: "Severity",
38
- size: 104,
39
- cell: (context) => {
40
- const finding = context.row.original as PrFinding;
41
- return (
42
- <Badge variant={finding.variant} size="sm">
43
- {finding.severity}
44
- </Badge>
45
- );
46
- },
47
- },
48
- {
49
- id: "finding",
50
- header: "Finding",
51
- minSize: 280,
52
- cell: (context) => {
53
- const finding = context.row.original as PrFinding;
54
- return (
55
- <Stack gap="none" className={styles.minWidthZero}>
56
- <Text size="sm" weight="medium" truncate>
57
- {finding.suggestion}
58
- </Text>
59
- <Text size="xs" color="tertiary" font="mono" truncate>
60
- {finding.code} · {finding.file}:{finding.line}
61
- </Text>
62
- </Stack>
63
- );
64
- },
65
- },
66
- { accessorKey: "rule", header: "Rule", size: 150, truncate: true },
67
- {
68
- id: "occurrences",
69
- header: "Sites",
70
- size: 72,
71
- align: "right",
72
- cell: (context) => (
73
- <Text size="xs" color="secondary" tabularNums>
74
- ×{(context.row.original as PrFinding).occurrences}
75
- </Text>
76
- ),
77
- },
78
- {
79
- id: "origin",
80
- header: "Origin",
81
- size: 104,
82
- cell: (context) => {
83
- const finding = context.row.original as PrFinding;
84
- return (
85
- <Text size="xs" color={finding.origin === "Introduced" ? "secondary" : "tertiary"}>
86
- {finding.origin}
87
- </Text>
88
- );
89
- },
90
- },
91
- {
92
- id: "fix",
93
- header: "Fix",
94
- size: 116,
95
- cell: (context) => (
96
- <Text size="xs" color="tertiary">
97
- {(context.row.original as PrFinding).fix}
98
- </Text>
99
- ),
100
- },
101
- {
102
- id: "actions",
103
- header: "",
104
- size: 132,
105
- align: "right",
106
- cell: (context) => (
107
- <Button variant="outlined" size="xs">
108
- {actionLabel(context.row.original as PrFinding)}
109
- </Button>
110
- ),
111
- },
112
- ];
113
-
114
- export function FindingsPanel() {
115
- return (
116
- <Stack gap="sm">
117
- <Box className={styles.prFindingsToolbar}>
118
- <Select aria-label="Group findings" defaultValue="rule" size="sm">
119
- <Select.Trigger />
120
- <Select.Content>
121
- <Select.Item value="rule">Group by rule</Select.Item>
122
- <Select.Item value="area">Group by area</Select.Item>
123
- <Select.Item value="severity">Group by severity</Select.Item>
124
- <Select.Item value="file">Group by file</Select.Item>
125
- </Select.Content>
126
- </Select>
127
- <Stack direction="row" gap="xs" align="center" wrap>
128
- <Button variant="secondary" size="sm">
129
- Create {pr.safeFixes} fixes
130
- </Button>
131
- <Button variant="ghost" size="sm">
132
- Mark intentional
133
- </Button>
134
- </Stack>
135
- </Box>
136
- <Stack direction="row" gap="xs" wrap>
137
- <Badge variant="dim" size="md" active>
138
- All {prFindings.length}
139
- </Badge>
140
- <Badge variant="dim" size="md">
141
- Blocking {blockingFindings.length}
142
- </Badge>
143
- <Badge variant="dim" size="md">
144
- Safe fixes {pr.safeFixes}
145
- </Badge>
146
- <Badge variant="dim" size="md">
147
- Introduced {introducedFindings.length}
148
- </Badge>
149
- <Badge variant="dim" size="md">
150
- Legacy {legacyCount}
151
- </Badge>
152
- </Stack>
153
- <DataTable
154
- columns={findingColumns}
155
- data={prFindings}
156
- getRowId={(row) => row.id}
157
- selectable
158
- showCheckbox
159
- density="condensed"
160
- bordered
161
- caption="Pull request findings"
162
- captionHidden
163
- wrapperClassName={styles.prTable}
164
- />
165
- <Text size="xs" color="tertiary">
166
- {prFindings.length} findings · {introducedFindings.length} introduced gate this PR ·{" "}
167
- {legacyCount} legacy shown for context
168
- </Text>
169
- </Stack>
170
- );
171
- }
172
-
173
- // ============================================================================
174
- // Conversation tab — the human-readable timeline on canonical Avatar + Card
175
- // ============================================================================
176
-
177
- export function ConversationPanel() {
178
- return (
179
- <Stack gap="md" className={styles.prIdTimeline}>
180
- <TimelineItem author={pr.author} meta="opened this pull request" avatarName={pr.author}>
181
- <Stack gap="sm">
182
- <Text size="sm">
183
- Refreshes the public launch cards for the June campaign. The branch changes hero CTA
184
- behavior, form danger states, and campaign-card spacing.
185
- </Text>
186
- <Box className={styles.prIdPrBodyTable}>
187
- <SummaryRow label="Area" value="Marketing / public launch" />
188
- <SummaryRow label="Designer" value="Growth design" />
189
- <SummaryRow label="Fragments gate" value="Blocked by contract" />
190
- </Box>
191
- </Stack>
192
- </TimelineItem>
193
-
194
- <TimelineItem
195
- author="fragments[bot]"
196
- meta="summarized the governance report"
197
- avatarName="Fragments bot"
198
- >
199
- <Stack gap="xs">
200
- <Text size="sm" weight="semibold">
201
- Fragments governance report
202
- </Text>
203
- <Text size="sm" color="secondary">
204
- {blockingFindings.length} blocking and {pr.safeFixes} safe-fix findings on a public
205
- marketing flow. Merge stays blocked until the blocking contract comments resolve — see
206
- Impacted areas for the area rollup.
207
- </Text>
208
- </Stack>
209
- </TimelineItem>
210
-
211
- {threadFindings.map((finding) => (
212
- <ReviewThread key={finding.id} finding={finding} />
213
- ))}
214
-
215
- <TimelineItem author="Noah Lee" meta="Growth design" avatarName="Noah Lee">
216
- <Text size="sm" color="secondary">
217
- I can approve the visual direction once the Button replacement and semantic danger token
218
- land. The spacing rhythm can be an intentional campaign exception.
219
- </Text>
220
- </TimelineItem>
221
- </Stack>
222
- );
223
- }
224
-
225
- function TimelineItem({
226
- author,
227
- meta,
228
- avatarName,
229
- children,
230
- }: {
231
- author: string;
232
- meta: string;
233
- avatarName: string;
234
- children: React.ReactNode;
235
- }) {
236
- return (
237
- <Box className={styles.prIdTimelineItem}>
238
- <Avatar name={avatarName} size="md" />
239
- <Card variant="panel" padding="none">
240
- <Card.Header divided>
241
- <Stack
242
- direction="row"
243
- gap="sm"
244
- align="baseline"
245
- justify="between"
246
- className={styles.full}
247
- >
248
- <Text size="sm" weight="semibold">
249
- {author}
250
- </Text>
251
- <Text size="xs" color="tertiary">
252
- {meta}
253
- </Text>
254
- </Stack>
255
- </Card.Header>
256
- <Card.Body padding="md">{children}</Card.Body>
257
- </Card>
258
- </Box>
259
- );
260
- }
261
-
262
- function ReviewThread({ finding }: { finding: PrFinding }) {
263
- return (
264
- <Box className={styles.prIdTimelineItem}>
265
- <Avatar name="Fragments bot" size="md" />
266
- <Card variant="panel" padding="none">
267
- <Card.Header divided>
268
- <Stack direction="row" gap="sm" align="center" justify="between" className={styles.full}>
269
- <Text size="xs" color="secondary" font="mono" truncate>
270
- {finding.file}:{finding.line}
271
- </Text>
272
- <Badge variant={finding.variant} size="sm">
273
- {finding.severity}
274
- </Badge>
275
- </Stack>
276
- </Card.Header>
277
- <Card.Body padding="md">
278
- <Stack gap="sm">
279
- <Text size="sm" color="secondary">
280
- {finding.body}
281
- </Text>
282
- {finding.designerSignal ? (
283
- <Text size="xs" color="tertiary">
284
- Designer signal: {finding.designerSignal}
285
- </Text>
286
- ) : null}
287
- <Stack direction="row" gap="sm" wrap>
288
- {finding.fix === "Deterministic" ? (
289
- <Button variant="outlined" size="xs">
290
- Create fix
291
- </Button>
292
- ) : null}
293
- <Button variant="ghost" size="xs">
294
- {finding.severity === "Blocking" ? "Request waiver" : "Mark intentional"}
295
- </Button>
296
- </Stack>
297
- </Stack>
298
- </Card.Body>
299
- </Card>
300
- </Box>
301
- );
302
- }
303
-
304
- function SummaryRow({ label, value }: { label: string; value: string }) {
305
- return (
306
- <Box className={styles.prIdSummaryRow}>
307
- <Text size="xs" color="tertiary">
308
- {label}
309
- </Text>
310
- <Text size="xs" color="secondary">
311
- {value}
312
- </Text>
313
- </Box>
314
- );
315
- }
316
-
317
- // ============================================================================
318
- // Changed files tab
319
- // ============================================================================
320
-
321
- const changedFileColumns: DataTableColumn<ChangedFile>[] = [
322
- {
323
- accessorKey: "path",
324
- header: "File",
325
- minSize: 320,
326
- truncate: true,
327
- cell: (context) => (
328
- <Text size="xs" font="mono" truncate>
329
- {(context.row.original as ChangedFile).path}
330
- </Text>
331
- ),
332
- },
333
- { accessorKey: "area", header: "Area", size: 120, truncate: true },
334
- {
335
- id: "delta",
336
- header: "Changes",
337
- size: 120,
338
- align: "right",
339
- cell: (context) => {
340
- const file = context.row.original as ChangedFile;
341
- return (
342
- <Text size="xs" color="secondary" tabularNums>
343
- +{file.additions} -{file.deletions}
344
- </Text>
345
- );
346
- },
347
- },
348
- {
349
- id: "findings",
350
- header: "Findings",
351
- size: 96,
352
- align: "right",
353
- cell: (context) => {
354
- const file = context.row.original as ChangedFile;
355
- return file.findings > 0 ? (
356
- <Badge variant="warning" size="sm">
357
- {file.findings}
358
- </Badge>
359
- ) : (
360
- <Text size="xs" color="tertiary">
361
- 0
362
- </Text>
363
- );
364
- },
365
- },
366
- ];
367
-
368
- export function ChangedFilesPanel() {
369
- return (
370
- <DataTable
371
- columns={changedFileColumns}
372
- data={changedFiles}
373
- getRowId={(row) => row.path}
374
- density="condensed"
375
- bordered
376
- caption="Changed files"
377
- captionHidden
378
- wrapperClassName={styles.prTable}
379
- />
380
- );
381
- }
@@ -1,204 +0,0 @@
1
- import { CheckCircle, GithubLogo, Warning, Wrench, XCircle } from "@phosphor-icons/react";
2
- import { Alert } from "../Alert";
3
- import { Box } from "../Box";
4
- import { Button } from "../Button";
5
- import { Card } from "../Card";
6
- import { Stack } from "../Stack";
7
- import { Tabs } from "../Tabs";
8
- import { Text } from "../Text";
9
- import {
10
- ChangedFilesPanel,
11
- ConversationPanel,
12
- FindingsPanel,
13
- } from "./PullRequestsPrototypes.detail-panels";
14
- import {
15
- blockingFindings,
16
- changedFiles,
17
- githubChecks,
18
- impactAreas,
19
- prFindings,
20
- prIdPagePullRequest as pr,
21
- reviewers,
22
- threadFindings,
23
- type GithubCheck,
24
- } from "./PullRequestsPrototypes.id-data";
25
- import styles from "./DashboardLayoutPrototypes.module.scss";
26
-
27
- const coverageDelta = pr.coverageAfter - pr.coverageBefore;
28
- // PR opened + governance report + designer reply wrap the inline review threads.
29
- const conversationCount = threadFindings.length + 3;
30
-
31
- // Gate-aware decision actions live in the shell header so the page title is the
32
- // real PR title — no second header, no generic "Pull Request" h1 above it.
33
- export function PullRequestDecisionActions() {
34
- return (
35
- <Stack direction="row" align="center" gap="sm" wrap>
36
- <Button variant="primary" size="sm">
37
- <Wrench size={14} weight="fill" />
38
- Create fix PR
39
- </Button>
40
- <Button variant="outlined" size="sm">
41
- Request changes
42
- </Button>
43
- <Button
44
- as="a"
45
- href="https://github.com/fragments-sdk/fragments/pull/248"
46
- target="_blank"
47
- rel="noopener noreferrer"
48
- variant="outlined"
49
- size="sm"
50
- >
51
- <GithubLogo size={14} weight="fill" />
52
- GitHub
53
- </Button>
54
- </Stack>
55
- );
56
- }
57
-
58
- export function PullRequestDetail() {
59
- return (
60
- <Stack gap="md">
61
- <GateBanner />
62
- <Box className={styles.prIdGithubLayout}>
63
- <Box className={styles.minWidthZero}>
64
- <Tabs defaultValue="findings" variant="pills">
65
- <Tabs.List>
66
- <Tabs.Tab value="findings">Findings {prFindings.length}</Tabs.Tab>
67
- <Tabs.Tab value="conversation">Conversation {conversationCount}</Tabs.Tab>
68
- <Tabs.Tab value="files">Changed files {changedFiles.length}</Tabs.Tab>
69
- </Tabs.List>
70
- <Tabs.Panel value="findings" flush>
71
- <FindingsPanel />
72
- </Tabs.Panel>
73
- <Tabs.Panel value="conversation" flush>
74
- <ConversationPanel />
75
- </Tabs.Panel>
76
- <Tabs.Panel value="files" flush>
77
- <ChangedFilesPanel />
78
- </Tabs.Panel>
79
- </Tabs>
80
- </Box>
81
- <DetailRail />
82
- </Box>
83
- </Stack>
84
- );
85
- }
86
-
87
- function GateBanner() {
88
- return (
89
- <Alert severity="error">
90
- <Alert.Icon />
91
- <Alert.Body>
92
- <Alert.Title>Merge blocked · fragments/contract-compliance</Alert.Title>
93
- <Alert.Content>
94
- {blockingFindings.length} blocking design-contract comments must be resolved before this
95
- PR can merge. Marketing contract coverage fell {pr.coverageBefore}% to {pr.coverageAfter}%
96
- ({coverageDelta} points), and {pr.safeFixes} of {prFindings.length} findings have
97
- deterministic fixes.
98
- </Alert.Content>
99
- </Alert.Body>
100
- </Alert>
101
- );
102
- }
103
-
104
- // ============================================================================
105
- // Sidebar status rail — every status fact has exactly one home here
106
- // ============================================================================
107
-
108
- function DetailRail() {
109
- return (
110
- <aside className={styles.prDetailRail} aria-label="Pull request status">
111
- <RailCard title="Merge gate">
112
- <Stack gap="sm">
113
- {githubChecks.map((check) => (
114
- <CheckRow key={check.name} check={check} />
115
- ))}
116
- </Stack>
117
- </RailCard>
118
- <RailCard title="Coverage">
119
- <Stack gap="xs">
120
- <RailRow label="Marketing coverage" value={`${pr.coverageAfter}%`} />
121
- <RailRow label="Coverage delta" value={`${coverageDelta} points`} variant="error" />
122
- <RailRow label="Safe fixes" value={String(pr.safeFixes)} />
123
- </Stack>
124
- </RailCard>
125
- <RailCard title="Impacted areas">
126
- <Stack gap="xs">
127
- {impactAreas.map((area) => (
128
- <RailRow key={area.area} label={area.area} value={area.review} variant={area.variant} />
129
- ))}
130
- </Stack>
131
- </RailCard>
132
- <RailCard title="Reviewers">
133
- <Stack gap="xs">
134
- {reviewers.map((reviewer) => (
135
- <RailRow
136
- key={reviewer.name}
137
- label={reviewer.name}
138
- value={reviewer.status}
139
- variant={reviewer.variant}
140
- />
141
- ))}
142
- </Stack>
143
- </RailCard>
144
- </aside>
145
- );
146
- }
147
-
148
- function RailCard({ title, children }: { title: string; children: React.ReactNode }) {
149
- return (
150
- <Card variant="panel" padding="none">
151
- <Card.Header divided>
152
- <Card.Title>{title}</Card.Title>
153
- </Card.Header>
154
- <Card.Body padding="md">{children}</Card.Body>
155
- </Card>
156
- );
157
- }
158
-
159
- function RailRow({
160
- label,
161
- value,
162
- variant,
163
- }: {
164
- label: string;
165
- value: string;
166
- variant?: GithubCheck["variant"];
167
- }) {
168
- return (
169
- <Box className={styles.prIdSidebarRow} data-variant={variant}>
170
- <Text size="xs" color="tertiary">
171
- {label}
172
- </Text>
173
- <Text size="xs" color="secondary">
174
- {value}
175
- </Text>
176
- </Box>
177
- );
178
- }
179
-
180
- function CheckRow({ check }: { check: GithubCheck }) {
181
- const Icon =
182
- check.state === "passed" ? CheckCircle : check.state === "failed" ? XCircle : Warning;
183
-
184
- return (
185
- <Box className={styles.prIdCheckSummary}>
186
- <span className={styles.prIdCheckIcon} data-state={check.state} aria-hidden>
187
- <Icon size={14} weight="fill" />
188
- </span>
189
- <Stack gap="none" className={styles.minWidthZero}>
190
- <Stack direction="row" gap="sm" align="baseline" justify="between" className={styles.full}>
191
- <Text size="xs" weight="medium" truncate>
192
- {check.name}
193
- </Text>
194
- <Text size="2xs" color="tertiary">
195
- {check.label}
196
- </Text>
197
- </Stack>
198
- <Text size="xs" color="tertiary" truncate>
199
- {check.summary}
200
- </Text>
201
- </Stack>
202
- </Box>
203
- );
204
- }