@backmatter/studio 0.0.6 → 0.0.8

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 (46) hide show
  1. package/dist/chunks/{EmbedPublishPage-DazYJLaD.js → EmbedPublishPage-CtIlaeGO.js} +1 -1
  2. package/dist/chunks/{UiKitPage-DyVyBp0I.js → UiKitPage-DcnSQ-Hf.js} +3 -3
  3. package/dist/chunks/{WorkspaceRoutes-CPvkgvxe.js → WorkspaceRoutes-DVpUOaMV.js} +20841 -18934
  4. package/dist/chunks/{dashboard-6aSS8oyj.js → dashboard-bNp6AbKE.js} +465 -443
  5. package/dist/chunks/{index-DgTNL4t3.js → index-DoDE-hwB.js} +2 -2
  6. package/dist/chunks/{status-bar-action-RNBujSgk.js → status-bar-action-C0fsAWvD.js} +5804 -5668
  7. package/dist/dashboard.js +2 -2
  8. package/dist/index.js +4 -4
  9. package/dist/site-widget.js +2 -2
  10. package/dist/studio.css +454 -62
  11. package/package.json +3 -2
  12. package/src/App.tsx +2 -0
  13. package/src/WorkspaceRoutes.tsx +2 -0
  14. package/src/api.ts +80 -0
  15. package/src/chat/ChatMessage.tsx +10 -3
  16. package/src/chat/Composer.tsx +18 -18
  17. package/src/chat/chat-helpers.ts +58 -1
  18. package/src/chrome/AppShell.tsx +47 -10
  19. package/src/chrome/AppSidebar.tsx +10 -160
  20. package/src/chrome/CommandPalette.tsx +211 -74
  21. package/src/chrome/ContentExplorerSidebar.tsx +1212 -0
  22. package/src/chrome/UserMenu.tsx +20 -3
  23. package/src/chrome/WorkspaceNavContext.tsx +1 -0
  24. package/src/chrome/command-palette-icons.tsx +152 -0
  25. package/src/chrome/content-path-tree.ts +95 -0
  26. package/src/chrome/content-repo-path.ts +52 -0
  27. package/src/chrome/explorer-icons.tsx +87 -0
  28. package/src/chrome/folder-create-context.ts +147 -0
  29. package/src/pages/BlockSettingsDialog.tsx +4 -0
  30. package/src/pages/CliAuthorizePage.tsx +43 -0
  31. package/src/pages/DocEditorPage.tsx +33 -4
  32. package/src/pages/MediaFieldInput.tsx +139 -0
  33. package/src/pages/MediaGalleryPage.tsx +748 -0
  34. package/src/pages/MediaLightbox.tsx +467 -0
  35. package/src/pages/SelectRepositoriesLink.tsx +28 -4
  36. package/src/pages/SettingsGeneralPage.tsx +25 -28
  37. package/src/pages/SettingsGithubPage.tsx +413 -124
  38. package/src/pages/SettingsUsagePage.tsx +19 -0
  39. package/src/pages/TypeDocsPage.tsx +2 -210
  40. package/src/pages/WorkspaceLayout.tsx +6 -1
  41. package/src/pages/media-grid.ts +190 -0
  42. package/src/pages/preview-url.ts +13 -2
  43. package/src/replica/useReplica.ts +9 -0
  44. package/src/ui/ConfirmDialog.tsx +1 -1
  45. package/src/workspace/permissions.ts +9 -0
  46. package/src/workspace-path.ts +27 -1
@@ -9,16 +9,15 @@ import {
9
9
  unbindGithub,
10
10
  } from "../api";
11
11
  import { Button, ButtonLink } from "../ui/Button";
12
- import { Field } from "../ui/Field";
13
12
  import { Input } from "../ui/Input";
14
13
  import { ConfirmDialog } from "../ui/ConfirmDialog";
15
- import { PageHeader, Panel, Stack } from "../ui/Page";
14
+ import { PageHeader } from "../ui/Page";
16
15
  import { Text } from "../ui/Text";
17
16
  import * as stylex from "@stylexjs/stylex";
18
17
  import { colors, space, type } from "../styles/tokens.stylex";
19
18
  import type { WorkspaceOutletContext } from "../workspace/types";
20
19
  import { githubConnectPath } from "../workspace-path";
21
- import { SelectRepositoriesLink } from "./SelectRepositoriesLink";
20
+ import { GithubRepositoryAccess } from "./SelectRepositoriesLink";
22
21
 
23
22
  export function SettingsGithubPage() {
24
23
  const { workspace, reload } = useOutletContext<WorkspaceOutletContext>();
@@ -34,6 +33,7 @@ export function SettingsGithubPage() {
34
33
  const [directory, setDirectory] = useState(workspace.githubDirectory ?? "");
35
34
  const [directoryError, setDirectoryError] = useState<string | null>(null);
36
35
  const [savingDirectory, setSavingDirectory] = useState(false);
36
+ const directoryDirty = directory !== (workspace.githubDirectory ?? "");
37
37
 
38
38
  useEffect(() => {
39
39
  setDirectory(workspace.githubDirectory ?? "");
@@ -119,121 +119,36 @@ export function SettingsGithubPage() {
119
119
  <Text tone="danger">{error}</Text>
120
120
  </div>
121
121
  ) : null}
122
- <Panel>
123
- {connected ? (
124
- <Stack>
125
- <dl {...stylex.props(styles.dl)}>
126
- <div>
127
- <dt {...stylex.props(styles.dt)}>Repository</dt>
128
- <dd {...stylex.props(styles.dd)}>{workspace.githubRepoFullName}</dd>
129
- </div>
130
- <div>
131
- <dt {...stylex.props(styles.dt)}>Branch</dt>
132
- <dd {...stylex.props(styles.dd)}>
133
- {workspace.githubDefaultBranch}
134
- </dd>
135
- </div>
136
- {!canEdit ? (
137
- <div>
138
- <dt {...stylex.props(styles.dt)}>Directory</dt>
139
- <dd {...stylex.props(styles.dd)}>
140
- {workspace.githubDirectory ?? "Repository root"}
141
- </dd>
142
- </div>
143
- ) : null}
144
- </dl>
145
- {canEdit ? (
146
- <form onSubmit={(e) => void onSaveDirectory(e)}>
147
- <Stack>
148
- <Field
149
- label="Directory"
150
- hint="Folder inside the repository that contains this site. Leave empty for the repository root."
151
- >
152
- <Input
153
- value={directory}
154
- onChange={(e) => setDirectory(e.target.value)}
155
- />
156
- </Field>
157
- {directoryError ? (
158
- <Text tone="danger">{directoryError}</Text>
159
- ) : null}
160
- <div>
161
- <Button type="submit" disabled={savingDirectory}>
162
- {savingDirectory ? "Saving…" : "Save"}
163
- </Button>
164
- </div>
165
- </Stack>
166
- </form>
167
- ) : null}
168
- {canEdit ? (
169
- <div {...stylex.props(styles.actions)}>
170
- <ButtonLink
171
- variant="secondary"
172
- to={githubConnectPath(workspace.slug)}
173
- >
174
- Change repository
175
- </ButtonLink>
176
- <SelectRepositoriesLink workspaceId={workspace.id} />
177
- <Button
178
- variant="danger"
179
- disabled={disconnecting}
180
- onClick={() => setConfirmDisconnect(true)}
181
- >
182
- Disconnect
183
- </Button>
184
- </div>
185
- ) : null}
186
- </Stack>
187
- ) : (
188
- <Stack>
189
- <Text tone="muted" size="sm">
190
- {workspace.githubInstallationId
191
- ? "The list only includes repositories this GitHub App can access. Select repositories on GitHub to grant more. Saving there does not return to Backmatter."
192
- : "Connect finds the backmatter CMS installation on your GitHub account and opens the repository list here. Saving on GitHub does not return to Backmatter."}
193
- </Text>
194
- {canEdit ? (
195
- <div {...stylex.props(styles.actions)}>
196
- {workspace.githubInstallationId ? (
197
- <ButtonLink to={githubConnectPath(workspace.slug)}>
198
- Choose repository
199
- </ButtonLink>
200
- ) : choices ? (
201
- choices.map((choice) => (
202
- <Button
203
- key={choice.id}
204
- disabled={connecting}
205
- onClick={() => void onConnect(choice.id)}
206
- >
207
- {choice.account ?? choice.id}
208
- </Button>
209
- ))
210
- ) : (
211
- <Button disabled={connecting} onClick={() => void onConnect()}>
212
- {connecting ? "Connecting…" : "Connect GitHub"}
213
- </Button>
214
- )}
215
- {workspace.githubInstallationId ? (
216
- <SelectRepositoriesLink workspaceId={workspace.id} />
217
- ) : null}
218
- {installUrl ? (
219
- <ButtonLink href={installUrl} newTab={false} variant="secondary">
220
- Install on GitHub
221
- </ButtonLink>
222
- ) : null}
223
- {workspace.githubInstallationId ? (
224
- <Button
225
- variant="danger"
226
- disabled={disconnecting}
227
- onClick={() => setConfirmDisconnect(true)}
228
- >
229
- Disconnect
230
- </Button>
231
- ) : null}
232
- </div>
233
- ) : null}
234
- </Stack>
235
- )}
236
- </Panel>
122
+ {connected ? (
123
+ <ConnectedGithub
124
+ repo={workspace.githubRepoFullName ?? ""}
125
+ branch={workspace.githubDefaultBranch ?? ""}
126
+ directory={directory}
127
+ directoryDirty={directoryDirty}
128
+ directoryError={directoryError}
129
+ savingDirectory={savingDirectory}
130
+ canEdit={canEdit}
131
+ changeTo={githubConnectPath(workspace.slug)}
132
+ workspaceId={workspace.id}
133
+ disconnecting={disconnecting}
134
+ onDirectoryChange={setDirectory}
135
+ onSaveDirectory={(e) => void onSaveDirectory(e)}
136
+ onDisconnect={() => setConfirmDisconnect(true)}
137
+ />
138
+ ) : (
139
+ <DisconnectedGithub
140
+ canEdit={canEdit}
141
+ connecting={connecting}
142
+ choices={choices}
143
+ installUrl={installUrl}
144
+ hasInstallation={Boolean(workspace.githubInstallationId)}
145
+ chooseTo={githubConnectPath(workspace.slug)}
146
+ workspaceId={workspace.id}
147
+ disconnecting={disconnecting}
148
+ onConnect={(id) => void onConnect(id)}
149
+ onDisconnect={() => setConfirmDisconnect(true)}
150
+ />
151
+ )}
237
152
  <ConfirmDialog
238
153
  open={confirmDisconnect}
239
154
  onOpenChange={(open) => {
@@ -254,28 +169,402 @@ export function SettingsGithubPage() {
254
169
  );
255
170
  }
256
171
 
172
+ function ConnectedGithub({
173
+ repo,
174
+ branch,
175
+ directory,
176
+ directoryDirty,
177
+ directoryError,
178
+ savingDirectory,
179
+ canEdit,
180
+ changeTo,
181
+ workspaceId,
182
+ disconnecting,
183
+ onDirectoryChange,
184
+ onSaveDirectory,
185
+ onDisconnect,
186
+ }: {
187
+ repo: string;
188
+ branch: string;
189
+ directory: string;
190
+ directoryDirty: boolean;
191
+ directoryError: string | null;
192
+ savingDirectory: boolean;
193
+ canEdit: boolean;
194
+ changeTo: string;
195
+ workspaceId: string;
196
+ disconnecting: boolean;
197
+ onDirectoryChange: (value: string) => void;
198
+ onSaveDirectory: (e: React.FormEvent) => void;
199
+ onDisconnect: () => void;
200
+ }) {
201
+ return (
202
+ <div {...stylex.props(styles.groups)}>
203
+ <SettingsGroup title="Connection" titleId="github-connection">
204
+ <SettingsRow
205
+ label="Repository"
206
+ control={
207
+ <>
208
+ <span {...stylex.props(styles.value)}>{repo}</span>
209
+ {canEdit ? (
210
+ <ButtonLink variant="secondary" to={changeTo}>
211
+ Change
212
+ </ButtonLink>
213
+ ) : null}
214
+ </>
215
+ }
216
+ />
217
+ <SettingsRow
218
+ label="Branch"
219
+ control={<span {...stylex.props(styles.value)}>{branch}</span>}
220
+ />
221
+ <SettingsRow
222
+ label="Directory"
223
+ htmlFor={canEdit ? "github-directory" : undefined}
224
+ description={
225
+ <>
226
+ Folder inside the repository. Empty means the repository root.
227
+ {directoryError ? <Text tone="danger">{directoryError}</Text> : null}
228
+ </>
229
+ }
230
+ control={
231
+ canEdit ? (
232
+ <form onSubmit={onSaveDirectory} {...stylex.props(styles.directoryForm)}>
233
+ <div {...stylex.props(styles.directoryField)}>
234
+ <Input
235
+ id="github-directory"
236
+ value={directory}
237
+ spellCheck={false}
238
+ autoCapitalize="off"
239
+ autoCorrect="off"
240
+ aria-invalid={directoryError ? true : undefined}
241
+ onChange={(e) => onDirectoryChange(e.target.value)}
242
+ />
243
+ </div>
244
+ {directoryDirty ? (
245
+ <Button type="submit" disabled={savingDirectory}>
246
+ {savingDirectory ? "Saving…" : "Save"}
247
+ </Button>
248
+ ) : null}
249
+ </form>
250
+ ) : (
251
+ <span {...stylex.props(styles.value)}>
252
+ {directory || "Repository root"}
253
+ </span>
254
+ )
255
+ }
256
+ />
257
+ </SettingsGroup>
258
+ {canEdit ? (
259
+ <SettingsGroup title="Access" titleId="github-access">
260
+ <SettingsRow
261
+ label="Repository access"
262
+ description="Repositories the app can see on GitHub. Saving there does not return here."
263
+ control={
264
+ <GithubRepositoryAccess workspaceId={workspaceId}>
265
+ {(url) => (
266
+ <ButtonLink href={url} variant="secondary">
267
+ Manage on GitHub
268
+ </ButtonLink>
269
+ )}
270
+ </GithubRepositoryAccess>
271
+ }
272
+ />
273
+ </SettingsGroup>
274
+ ) : null}
275
+ {canEdit ? (
276
+ <SettingsGroup separated>
277
+ <SettingsRow
278
+ label="Disconnect"
279
+ description="Stops commits and imports. Content already here stays."
280
+ control={
281
+ <Button variant="danger" disabled={disconnecting} onClick={onDisconnect}>
282
+ Disconnect
283
+ </Button>
284
+ }
285
+ />
286
+ </SettingsGroup>
287
+ ) : null}
288
+ </div>
289
+ );
290
+ }
291
+
292
+ function DisconnectedGithub({
293
+ canEdit,
294
+ connecting,
295
+ choices,
296
+ installUrl,
297
+ hasInstallation,
298
+ chooseTo,
299
+ workspaceId,
300
+ disconnecting,
301
+ onConnect,
302
+ onDisconnect,
303
+ }: {
304
+ canEdit: boolean;
305
+ connecting: boolean;
306
+ choices: GithubInstallationChoice[] | null;
307
+ installUrl: string | null;
308
+ hasInstallation: boolean;
309
+ chooseTo: string;
310
+ workspaceId: string;
311
+ disconnecting: boolean;
312
+ onConnect: (installationId?: string) => void;
313
+ onDisconnect: () => void;
314
+ }) {
315
+ if (choices) {
316
+ return (
317
+ <SettingsGroup
318
+ title="GitHub accounts"
319
+ titleId="github-accounts"
320
+ description="Connect finds the backmatter CMS installation on your GitHub account and opens the repository list here. Saving on GitHub does not return to Backmatter."
321
+ >
322
+ {choices.map((choice) => (
323
+ <SettingsRow
324
+ key={choice.id}
325
+ label={choice.account ?? choice.id}
326
+ control={
327
+ canEdit ? (
328
+ <Button
329
+ variant="secondary"
330
+ disabled={connecting}
331
+ onClick={() => onConnect(choice.id)}
332
+ >
333
+ Connect
334
+ </Button>
335
+ ) : null
336
+ }
337
+ />
338
+ ))}
339
+ </SettingsGroup>
340
+ );
341
+ }
342
+
343
+ if (hasInstallation) {
344
+ return (
345
+ <div {...stylex.props(styles.groups)}>
346
+ <SettingsGroup title="Connection" titleId="github-connection">
347
+ <SettingsRow
348
+ label="Repository"
349
+ description="The list only includes repositories this GitHub App can access."
350
+ control={
351
+ canEdit ? (
352
+ <ButtonLink to={chooseTo}>Choose repository</ButtonLink>
353
+ ) : null
354
+ }
355
+ />
356
+ </SettingsGroup>
357
+ {canEdit ? (
358
+ <SettingsGroup title="Access" titleId="github-access">
359
+ <SettingsRow
360
+ label="Repository access"
361
+ description="Grant more repositories on GitHub. Saving there does not return here."
362
+ control={
363
+ <GithubRepositoryAccess workspaceId={workspaceId}>
364
+ {(url) => (
365
+ <ButtonLink href={url} variant="secondary">
366
+ Manage on GitHub
367
+ </ButtonLink>
368
+ )}
369
+ </GithubRepositoryAccess>
370
+ }
371
+ />
372
+ </SettingsGroup>
373
+ ) : null}
374
+ {canEdit ? (
375
+ <SettingsGroup separated>
376
+ <SettingsRow
377
+ label="Disconnect"
378
+ description="Removes the GitHub App from this workspace. You can connect again later."
379
+ control={
380
+ <Button
381
+ variant="danger"
382
+ disabled={disconnecting}
383
+ onClick={onDisconnect}
384
+ >
385
+ Disconnect
386
+ </Button>
387
+ }
388
+ />
389
+ </SettingsGroup>
390
+ ) : null}
391
+ </div>
392
+ );
393
+ }
394
+
395
+ return (
396
+ <SettingsGroup>
397
+ <SettingsRow
398
+ label="Not connected"
399
+ description="Connect finds the backmatter CMS installation on your GitHub account and opens the repository list here. Saving on GitHub does not return to Backmatter."
400
+ control={
401
+ canEdit ? (
402
+ installUrl ? (
403
+ <ButtonLink href={installUrl} newTab={false}>
404
+ Install on GitHub
405
+ </ButtonLink>
406
+ ) : (
407
+ <Button disabled={connecting} onClick={() => onConnect()}>
408
+ {connecting ? "Connecting…" : "Connect GitHub"}
409
+ </Button>
410
+ )
411
+ ) : null
412
+ }
413
+ />
414
+ </SettingsGroup>
415
+ );
416
+ }
417
+
418
+ function SettingsGroup({
419
+ title,
420
+ titleId,
421
+ description,
422
+ separated,
423
+ children,
424
+ }: {
425
+ title?: string;
426
+ titleId?: string;
427
+ description?: string;
428
+ separated?: boolean;
429
+ children: React.ReactNode;
430
+ }) {
431
+ return (
432
+ <section
433
+ aria-labelledby={title ? titleId : undefined}
434
+ {...stylex.props(styles.group, separated && styles.groupSeparated)}
435
+ >
436
+ {title && titleId ? (
437
+ <h2 id={titleId} {...stylex.props(styles.groupTitle)}>
438
+ {title}
439
+ </h2>
440
+ ) : null}
441
+ {description ? (
442
+ <p {...stylex.props(styles.groupDescription)}>{description}</p>
443
+ ) : null}
444
+ <div {...stylex.props(styles.rows)}>{children}</div>
445
+ </section>
446
+ );
447
+ }
448
+
449
+ function SettingsRow({
450
+ label,
451
+ description,
452
+ htmlFor,
453
+ control,
454
+ }: {
455
+ label: string;
456
+ description?: React.ReactNode;
457
+ htmlFor?: string;
458
+ control?: React.ReactNode;
459
+ }) {
460
+ return (
461
+ <div {...stylex.props(styles.row)}>
462
+ <div {...stylex.props(styles.rowText)}>
463
+ {htmlFor ? (
464
+ <label htmlFor={htmlFor} {...stylex.props(styles.rowLabel)}>
465
+ {label}
466
+ </label>
467
+ ) : (
468
+ <div {...stylex.props(styles.rowLabel)}>{label}</div>
469
+ )}
470
+ {description ? (
471
+ <div {...stylex.props(styles.rowDescription)}>{description}</div>
472
+ ) : null}
473
+ </div>
474
+ {control ? <div {...stylex.props(styles.rowControl)}>{control}</div> : null}
475
+ </div>
476
+ );
477
+ }
478
+
257
479
  const styles = stylex.create({
258
- dl: {
480
+ groups: {
481
+ display: "flex",
482
+ flexDirection: "column",
483
+ gap: space.xxl,
484
+ },
485
+ group: {
486
+ display: "flex",
487
+ flexDirection: "column",
488
+ gap: space.xs,
489
+ },
490
+ groupSeparated: {
491
+ paddingTop: space.lg,
492
+ borderTopWidth: 1,
493
+ borderTopStyle: "solid",
494
+ borderTopColor: colors.border,
495
+ },
496
+ groupTitle: {
259
497
  margin: 0,
498
+ fontSize: type.sm,
499
+ fontWeight: 500,
500
+ color: colors.textMuted,
501
+ },
502
+ groupDescription: {
503
+ margin: 0,
504
+ color: colors.textMuted,
505
+ fontSize: type.sm,
506
+ lineHeight: 1.45,
507
+ },
508
+ rows: {
260
509
  display: "flex",
261
510
  flexDirection: "column",
511
+ },
512
+ row: {
513
+ display: "flex",
514
+ alignItems: "center",
515
+ justifyContent: "space-between",
516
+ flexWrap: "wrap",
262
517
  gap: space.lg,
518
+ minHeight: "44px",
519
+ paddingBlock: space.lg,
520
+ borderBottomWidth: 1,
521
+ borderBottomStyle: "solid",
522
+ borderBottomColor: colors.border,
523
+ ":last-child": {
524
+ borderBottomWidth: 0,
525
+ },
526
+ },
527
+ rowText: {
528
+ flex: "1 1 16rem",
529
+ minWidth: 0,
530
+ display: "flex",
531
+ flexDirection: "column",
532
+ gap: space.xs,
533
+ },
534
+ rowLabel: {
263
535
  fontSize: type.md,
536
+ fontWeight: 500,
537
+ color: colors.text,
264
538
  },
265
- dt: {
539
+ rowDescription: {
540
+ display: "flex",
541
+ flexDirection: "column",
542
+ gap: space.xs,
266
543
  color: colors.textMuted,
267
544
  fontSize: type.sm,
545
+ lineHeight: 1.45,
268
546
  },
269
- dd: {
270
- margin: 0,
547
+ rowControl: {
548
+ display: "flex",
549
+ alignItems: "center",
550
+ justifyContent: "flex-end",
551
+ flexShrink: 0,
552
+ gap: space.sm,
553
+ marginLeft: "auto",
554
+ },
555
+ value: {
556
+ fontSize: type.md,
271
557
  fontWeight: 500,
558
+ color: colors.text,
272
559
  },
273
- actions: {
560
+ directoryForm: {
274
561
  display: "flex",
275
- flexWrap: "wrap",
276
562
  alignItems: "center",
277
563
  gap: space.sm,
278
564
  },
565
+ directoryField: {
566
+ width: "240px",
567
+ },
279
568
  error: {
280
569
  marginBottom: space.lg,
281
570
  },
@@ -22,8 +22,16 @@ const WORK: { key: keyof WorkspaceUsage["work"]; label: string }[] = [
22
22
  { key: "imports", label: "Imports" },
23
23
  { key: "importFiles", label: "Files imported" },
24
24
  { key: "saves", label: "Saves" },
25
+ { key: "mediaTransforms", label: "Image transforms" },
25
26
  ];
26
27
 
28
+ function formatBytes(value: number): string {
29
+ if (value < 1024) return `${value} B`;
30
+ if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
31
+ if (value < 1024 * 1024 * 1024) return `${(value / (1024 * 1024)).toFixed(1)} MB`;
32
+ return `${(value / (1024 * 1024 * 1024)).toFixed(1)} GB`;
33
+ }
34
+
27
35
  function formatCount(value: number): string {
28
36
  return new Intl.NumberFormat("en-US").format(value);
29
37
  }
@@ -109,6 +117,17 @@ export function SettingsUsagePage() {
109
117
  ))}
110
118
  </dl>
111
119
  </Panel>
120
+ <Panel>
121
+ <Text as="h2" size="lg" weight="medium">
122
+ Media
123
+ </Text>
124
+ <dl {...stylex.props(styles.list)}>
125
+ <div {...stylex.props(styles.row)}>
126
+ <dt {...stylex.props(styles.label)}>Stored</dt>
127
+ <dd {...stylex.props(styles.value)}>{formatBytes(usage.mediaBytes)}</dd>
128
+ </div>
129
+ </dl>
130
+ </Panel>
112
131
  <Panel>
113
132
  <Text as="h2" size="lg" weight="medium">
114
133
  AI