@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
@@ -0,0 +1,467 @@
1
+ // packages/studio/src/pages/MediaLightbox.tsx
2
+ import { Menu } from "@base-ui/react/menu";
3
+ import {
4
+ IconSquareBehindSquare1,
5
+ IconTrashCanSimple,
6
+ } from "@central-icons-react/round-outlined-radius-2-stroke-1.5";
7
+ import { useEffect, useState } from "react";
8
+ import * as stylex from "@stylexjs/stylex";
9
+ import { colors, radius, space, type, z } from "../styles/tokens.stylex";
10
+ import { Text } from "../ui/Text";
11
+ import { cx, popup, popupClassName } from "../ui/popup";
12
+ import type { CatalogMedia } from "./media-grid";
13
+
14
+ const stack = "@media (max-width: 800px)";
15
+ const hover = "@media (hover: hover)";
16
+
17
+ export function MediaLightbox({
18
+ item,
19
+ index,
20
+ count,
21
+ onClose,
22
+ onPrev,
23
+ onNext,
24
+ onDelete,
25
+ }: {
26
+ item: CatalogMedia;
27
+ index: number;
28
+ count: number;
29
+ onClose: () => void;
30
+ onPrev: () => void;
31
+ onNext: () => void;
32
+ onDelete?: () => void;
33
+ }) {
34
+ const full = item.variants?.["1200"] ?? item.url;
35
+ const [copied, setCopied] = useState(false);
36
+
37
+ useEffect(() => {
38
+ setCopied(false);
39
+ }, [item.id]);
40
+
41
+ useEffect(() => {
42
+ const onKey = (event: KeyboardEvent) => {
43
+ if (document.querySelector('[role="menu"], [role="alertdialog"]')) return;
44
+ if (event.key === "Escape" || event.key === " ") {
45
+ event.preventDefault();
46
+ onClose();
47
+ }
48
+ if (event.key === "ArrowLeft") {
49
+ event.preventDefault();
50
+ onPrev();
51
+ }
52
+ if (event.key === "ArrowRight") {
53
+ event.preventDefault();
54
+ onNext();
55
+ }
56
+ };
57
+ window.addEventListener("keydown", onKey, true);
58
+ return () => window.removeEventListener("keydown", onKey, true);
59
+ }, [onClose, onPrev, onNext]);
60
+
61
+ return (
62
+ <div
63
+ {...stylex.props(styles.shell)}
64
+ role="dialog"
65
+ aria-modal="true"
66
+ aria-label={item.filename}
67
+ >
68
+ <div {...stylex.props(styles.stage)} onClick={onClose}>
69
+ <button
70
+ type="button"
71
+ aria-label="Previous image"
72
+ disabled={index <= 0}
73
+ {...stylex.props(styles.nav, styles.navPrev)}
74
+ onClick={(event) => {
75
+ event.stopPropagation();
76
+ onPrev();
77
+ }}
78
+ >
79
+ ‹
80
+ </button>
81
+ <div {...stylex.props(styles.frame)} onClick={(event) => event.stopPropagation()}>
82
+ <StageImage key={item.id} thumb={item.thumbUrl} full={full} alt={item.filename} />
83
+ </div>
84
+ <button
85
+ type="button"
86
+ aria-label="Next image"
87
+ disabled={index >= count - 1}
88
+ {...stylex.props(styles.nav, styles.navNext)}
89
+ onClick={(event) => {
90
+ event.stopPropagation();
91
+ onNext();
92
+ }}
93
+ >
94
+ ›
95
+ </button>
96
+ </div>
97
+ <aside {...stylex.props(styles.sidebar)}>
98
+ <div {...stylex.props(styles.sidebarTools)}>
99
+ <Menu.Root>
100
+ <Menu.Trigger aria-label="Image actions" className={cx(styles.sidebarTool)}>
101
+ <svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true">
102
+ <circle cx="3" cy="7" r="1.15" fill="currentColor" />
103
+ <circle cx="7" cy="7" r="1.15" fill="currentColor" />
104
+ <circle cx="11" cy="7" r="1.15" fill="currentColor" />
105
+ </svg>
106
+ </Menu.Trigger>
107
+ <Menu.Portal>
108
+ <Menu.Positioner side="bottom" align="end" sideOffset={6} className={cx(popup.positioner)}>
109
+ <Menu.Popup
110
+ aria-label="Image actions"
111
+ className={(state) => popupClassName(state, styles.menu)}
112
+ >
113
+ <Menu.Item
114
+ label="Copy path"
115
+ onClick={() => {
116
+ void navigator.clipboard.writeText(item.url);
117
+ }}
118
+ className={(state) =>
119
+ cx(popup.item, styles.menuItem, state.highlighted && popup.itemHighlighted)
120
+ }
121
+ >
122
+ <IconSquareBehindSquare1 size={14} ariaHidden style={{ flexShrink: 0 }} />
123
+ Copy path
124
+ </Menu.Item>
125
+ {onDelete ? (
126
+ <Menu.Item
127
+ label="Delete"
128
+ onClick={onDelete}
129
+ className={(state) =>
130
+ cx(popup.item, styles.menuItem, styles.menuDanger, state.highlighted && popup.itemHighlighted)
131
+ }
132
+ >
133
+ <IconTrashCanSimple size={14} ariaHidden style={{ flexShrink: 0 }} />
134
+ Delete
135
+ </Menu.Item>
136
+ ) : null}
137
+ </Menu.Popup>
138
+ </Menu.Positioner>
139
+ </Menu.Portal>
140
+ </Menu.Root>
141
+ <button type="button" aria-label="Close" {...stylex.props(styles.sidebarTool)} onClick={onClose}>
142
+ <svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true">
143
+ <path
144
+ d="M3.5 3.5l7 7M10.5 3.5l-7 7"
145
+ fill="none"
146
+ stroke="currentColor"
147
+ strokeWidth="1.5"
148
+ strokeLinecap="round"
149
+ />
150
+ </svg>
151
+ </button>
152
+ </div>
153
+ <div {...stylex.props(styles.sidebarBody)}>
154
+ <div {...stylex.props(styles.filename)}>
155
+ <Text as="h2" size="lg" weight="medium">
156
+ {item.filename}
157
+ </Text>
158
+ </div>
159
+ <dl {...stylex.props(styles.facts)}>
160
+ <Fact label="Dimensions" value={dimensions(item)} />
161
+ <Fact label="Size" value={item.byteSize === undefined ? "—" : formatBytes(item.byteSize)} />
162
+ <Fact label="Type" value={kindLabel(item.contentType)} />
163
+ <Fact label="Added" value={addedLabel(item.createdAt)} />
164
+ </dl>
165
+ <div {...stylex.props(styles.urlBlock)}>
166
+ <div {...stylex.props(styles.urlHead)}>
167
+ <Text size="xs" tone="muted">
168
+ Original URL
169
+ </Text>
170
+ <button
171
+ type="button"
172
+ aria-label={copied ? "Copied" : "Copy URL"}
173
+ {...stylex.props(styles.copy)}
174
+ onClick={() => {
175
+ void navigator.clipboard.writeText(item.url).then(() => setCopied(true));
176
+ }}
177
+ >
178
+ <svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true">
179
+ <rect
180
+ x="4.75"
181
+ y="4.75"
182
+ width="7"
183
+ height="7"
184
+ rx="1.25"
185
+ fill="none"
186
+ stroke="currentColor"
187
+ strokeWidth="1.5"
188
+ />
189
+ <path
190
+ d="M9.25 4.75V3.25A1.25 1.25 0 0 0 8 2H3.25A1.25 1.25 0 0 0 2 3.25V8A1.25 1.25 0 0 0 3.25 9.25H4.75"
191
+ fill="none"
192
+ stroke="currentColor"
193
+ strokeWidth="1.5"
194
+ />
195
+ </svg>
196
+ {copied ? "Copied" : "Copy"}
197
+ </button>
198
+ </div>
199
+ <p {...stylex.props(styles.url)}>{item.url}</p>
200
+ </div>
201
+ </div>
202
+ </aside>
203
+ </div>
204
+ );
205
+ }
206
+
207
+ function StageImage({ thumb, full, alt }: { thumb: string; full: string; alt: string }) {
208
+ const [ready, setReady] = useState(false);
209
+ return (
210
+ <>
211
+ <img src={thumb} alt="" {...stylex.props(styles.photo, styles.thumb)} />
212
+ <img
213
+ src={full}
214
+ alt={alt}
215
+ {...stylex.props(styles.photo, ready ? styles.shown : styles.hidden)}
216
+ onLoad={() => setReady(true)}
217
+ />
218
+ </>
219
+ );
220
+ }
221
+
222
+ function Fact({ label, value }: { label: string; value: string }) {
223
+ return (
224
+ <div {...stylex.props(styles.fact)}>
225
+ <dt {...stylex.props(styles.factLabel)}>{label}</dt>
226
+ <dd {...stylex.props(styles.factValue)}>{value}</dd>
227
+ </div>
228
+ );
229
+ }
230
+
231
+ function dimensions(item: CatalogMedia): string {
232
+ if (item.width === null || item.height === null || !item.width || !item.height) return "—";
233
+ return `${item.width} × ${item.height}`;
234
+ }
235
+
236
+ function kindLabel(contentType: string | undefined): string {
237
+ if (!contentType) return "—";
238
+ const subtype = contentType.split("/")[1] ?? contentType;
239
+ return subtype.toUpperCase();
240
+ }
241
+
242
+ function addedLabel(createdAt: string | undefined): string {
243
+ if (!createdAt) return "—";
244
+ const date = new Date(createdAt);
245
+ if (Number.isNaN(date.getTime())) return "—";
246
+ return date.toLocaleString(undefined, { dateStyle: "medium", timeStyle: "short" });
247
+ }
248
+
249
+ function formatBytes(value: number): string {
250
+ if (value < 1024) return `${value} B`;
251
+ if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
252
+ if (value < 1024 * 1024 * 1024) return `${(value / (1024 * 1024)).toFixed(1)} MB`;
253
+ return `${(value / (1024 * 1024 * 1024)).toFixed(1)} GB`;
254
+ }
255
+
256
+ const styles = stylex.create({
257
+ shell: {
258
+ position: "fixed",
259
+ inset: 0,
260
+ zIndex: z.palette,
261
+ display: "flex",
262
+ flexDirection: "row",
263
+ backgroundColor: "#0c0c0e",
264
+ [stack]: {
265
+ flexDirection: "column",
266
+ },
267
+ },
268
+ stage: {
269
+ position: "relative",
270
+ flex: 1,
271
+ minWidth: 0,
272
+ minHeight: 0,
273
+ display: "flex",
274
+ alignItems: "center",
275
+ justifyContent: "center",
276
+ [stack]: {
277
+ minHeight: "55vh",
278
+ },
279
+ },
280
+ frame: {
281
+ position: "relative",
282
+ width: "100%",
283
+ height: "100%",
284
+ },
285
+ photo: {
286
+ position: "absolute",
287
+ inset: 0,
288
+ width: "100%",
289
+ height: "100%",
290
+ objectFit: "contain",
291
+ padding: space.xxl,
292
+ boxSizing: "border-box",
293
+ },
294
+ thumb: {
295
+ opacity: 1,
296
+ },
297
+ shown: {
298
+ opacity: 1,
299
+ },
300
+ hidden: {
301
+ opacity: 0,
302
+ },
303
+ nav: {
304
+ position: "absolute",
305
+ top: "50%",
306
+ transform: "translateY(-50%)",
307
+ zIndex: 1,
308
+ width: "44px",
309
+ height: "44px",
310
+ borderWidth: 0,
311
+ borderRadius: radius.md,
312
+ backgroundColor: "rgba(255, 255, 255, 0.12)",
313
+ color: "#fafafa",
314
+ fontSize: "28px",
315
+ display: "flex",
316
+ alignItems: "center",
317
+ justifyContent: "center",
318
+ cursor: "pointer",
319
+ ":disabled": {
320
+ opacity: 0.35,
321
+ cursor: "default",
322
+ },
323
+ },
324
+ sidebarTools: {
325
+ display: "flex",
326
+ alignItems: "center",
327
+ justifyContent: "flex-end",
328
+ gap: space.xs,
329
+ },
330
+ sidebarTool: {
331
+ width: "32px",
332
+ height: "32px",
333
+ display: "flex",
334
+ alignItems: "center",
335
+ justifyContent: "center",
336
+ padding: 0,
337
+ borderWidth: 0,
338
+ borderRadius: radius.md,
339
+ backgroundColor: "transparent",
340
+ color: colors.textMuted,
341
+ cursor: "pointer",
342
+ [hover]: {
343
+ ":hover": {
344
+ backgroundColor: colors.bgHover,
345
+ color: colors.text,
346
+ },
347
+ },
348
+ ":focus-visible": {
349
+ outlineWidth: 2,
350
+ outlineStyle: "solid",
351
+ outlineColor: colors.focus,
352
+ outlineOffset: 1,
353
+ },
354
+ },
355
+ menu: {
356
+ minWidth: "8rem",
357
+ },
358
+ menuItem: {
359
+ cursor: "pointer",
360
+ },
361
+ menuDanger: {
362
+ color: colors.danger,
363
+ },
364
+ navPrev: {
365
+ left: space.lg,
366
+ },
367
+ navNext: {
368
+ right: space.lg,
369
+ },
370
+ sidebar: {
371
+ width: "320px",
372
+ flexShrink: 0,
373
+ display: "flex",
374
+ flexDirection: "column",
375
+ justifyContent: "space-between",
376
+ gap: space.xl,
377
+ padding: space.xl,
378
+ backgroundColor: colors.bgSurface,
379
+ color: colors.text,
380
+ borderLeftWidth: 1,
381
+ borderLeftStyle: "solid",
382
+ borderLeftColor: colors.border,
383
+ overflow: "auto",
384
+ [stack]: {
385
+ width: "100%",
386
+ borderLeftWidth: 0,
387
+ borderTopWidth: 1,
388
+ borderTopStyle: "solid",
389
+ borderTopColor: colors.border,
390
+ },
391
+ },
392
+ sidebarBody: {
393
+ display: "flex",
394
+ flexDirection: "column",
395
+ gap: space.xl,
396
+ minWidth: 0,
397
+ },
398
+ filename: {
399
+ minWidth: 0,
400
+ overflowWrap: "anywhere",
401
+ },
402
+ facts: {
403
+ display: "flex",
404
+ flexDirection: "column",
405
+ gap: space.lg,
406
+ margin: 0,
407
+ },
408
+ fact: {
409
+ display: "flex",
410
+ flexDirection: "column",
411
+ gap: space.xs,
412
+ },
413
+ factLabel: {
414
+ margin: 0,
415
+ color: colors.textMuted,
416
+ fontSize: type.xs,
417
+ },
418
+ factValue: {
419
+ margin: 0,
420
+ fontSize: type.md,
421
+ fontVariantNumeric: "tabular-nums",
422
+ },
423
+ urlBlock: {
424
+ display: "flex",
425
+ flexDirection: "column",
426
+ alignItems: "stretch",
427
+ gap: space.sm,
428
+ },
429
+ urlHead: {
430
+ display: "flex",
431
+ alignItems: "center",
432
+ justifyContent: "space-between",
433
+ gap: space.md,
434
+ },
435
+ copy: {
436
+ display: "inline-flex",
437
+ alignItems: "center",
438
+ justifyContent: "center",
439
+ gap: space.sm,
440
+ minHeight: "32px",
441
+ paddingInline: space.lg,
442
+ borderWidth: 1,
443
+ borderStyle: "solid",
444
+ borderColor: colors.border,
445
+ borderRadius: radius.md,
446
+ backgroundColor: colors.bgPanel,
447
+ color: colors.text,
448
+ fontFamily: type.sans,
449
+ fontSize: type.sm,
450
+ fontWeight: 500,
451
+ cursor: "pointer",
452
+ [hover]: {
453
+ ":hover": {
454
+ backgroundColor: colors.bgHover,
455
+ },
456
+ },
457
+ },
458
+ url: {
459
+ margin: 0,
460
+ width: "100%",
461
+ fontFamily: type.mono,
462
+ fontSize: type.xs,
463
+ lineHeight: 1.4,
464
+ wordBreak: "break-all",
465
+ color: colors.textMuted,
466
+ },
467
+ });
@@ -1,10 +1,9 @@
1
1
  // packages/studio/src/pages/SelectRepositoriesLink.tsx
2
- import { useEffect, useState } from "react";
2
+ import { useEffect, useState, type ReactNode } from "react";
3
3
  import { fetchGithubRepositoryAccess } from "../api";
4
4
  import { ButtonLink } from "../ui/Button";
5
5
 
6
- /** Opens the GitHub page where this installation's repository access is chosen. */
7
- export function SelectRepositoriesLink({ workspaceId }: { workspaceId: string }) {
6
+ function useRepositoryAccessUrl(workspaceId: string) {
8
7
  const [url, setUrl] = useState<string | null>(null);
9
8
 
10
9
  useEffect(() => {
@@ -21,10 +20,35 @@ export function SelectRepositoriesLink({ workspaceId }: { workspaceId: string })
21
20
  };
22
21
  }, [workspaceId]);
23
22
 
23
+ return url;
24
+ }
25
+
26
+ /** Opens the GitHub page where this installation's repository access is chosen. */
27
+ export function SelectRepositoriesLink({
28
+ workspaceId,
29
+ label = "Select repositories on GitHub",
30
+ }: {
31
+ workspaceId: string;
32
+ label?: string;
33
+ }) {
34
+ const url = useRepositoryAccessUrl(workspaceId);
24
35
  if (!url) return null;
25
36
  return (
26
37
  <ButtonLink href={url} variant="secondary">
27
- Select repositories on GitHub
38
+ {label}
28
39
  </ButtonLink>
29
40
  );
30
41
  }
42
+
43
+ /** Renders nothing until the GitHub App's repository-access URL is known. */
44
+ export function GithubRepositoryAccess({
45
+ workspaceId,
46
+ children,
47
+ }: {
48
+ workspaceId: string;
49
+ children: (url: string) => ReactNode;
50
+ }) {
51
+ const url = useRepositoryAccessUrl(workspaceId);
52
+ if (!url) return null;
53
+ return children(url);
54
+ }
@@ -11,7 +11,6 @@ import { hostEnvSnippet } from "./host-env";
11
11
  import { isStudioDev, publicApiUrl } from "../studio-config";
12
12
  import { revalidateWebhookUrl } from "./preview-url";
13
13
  import { Button } from "../ui/Button";
14
- import { Field } from "../ui/Field";
15
14
  import { Input } from "../ui/Input";
16
15
  import { PageHeader, Panel, Stack } from "../ui/Page";
17
16
  import { Text } from "../ui/Text";
@@ -147,40 +146,33 @@ export function SettingsGeneralPage() {
147
146
  </Text>
148
147
  <form onSubmit={(e) => void onSaveSiteUrl(e)}>
149
148
  <div {...stylex.props(styles.block)}>
150
- <Field
151
- label="Site URL"
152
- hint={
153
- webhookUrl
154
- ? `Preview origin. Pushes POST ${webhookUrl}`
155
- : "Preview origin. A content push POSTs the revalidate route on this origin."
156
- }
157
- >
158
- <Input
159
- type="url"
160
- value={siteUrl}
161
- readOnly={!canEdit}
162
- placeholder="https://www.example.com"
163
- autoComplete="off"
164
- spellCheck={false}
165
- data-lpignore="true"
166
- data-1p-ignore
167
- onChange={(e) => setSiteUrl(e.target.value)}
168
- />
169
- </Field>
149
+ <Input
150
+ type="url"
151
+ aria-label="Site URL"
152
+ value={siteUrl}
153
+ readOnly={!canEdit}
154
+ placeholder="https://www.example.com"
155
+ autoComplete="off"
156
+ spellCheck={false}
157
+ data-lpignore="true"
158
+ data-1p-ignore
159
+ onChange={(e) => setSiteUrl(e.target.value)}
160
+ />
170
161
  </div>
162
+ <p {...stylex.props(styles.caption)}>
163
+ {webhookUrl
164
+ ? `Preview origin. Pushes POST ${webhookUrl}`
165
+ : "Preview origin. A content push POSTs the revalidate route on this origin."}
166
+ </p>
167
+ <StudioVersions versions={workspace.studioVersions} />
171
168
  {canEdit ? (
172
- <div {...stylex.props(styles.block)}>
173
- <Button
174
- type="submit"
175
- variant="secondary"
176
- disabled={busy !== null}
177
- >
169
+ <div {...stylex.props(styles.actions)}>
170
+ <Button type="submit" variant="secondary" disabled={busy !== null}>
178
171
  {busy === "site-url" ? "Saving…" : "Save"}
179
172
  </Button>
180
173
  </div>
181
174
  ) : null}
182
175
  </form>
183
- <StudioVersions versions={workspace.studioVersions} />
184
176
  </Panel>
185
177
  <Panel>
186
178
  <Text as="h2" size="lg" weight="medium">
@@ -370,6 +362,11 @@ const styles = stylex.create({
370
362
  block: {
371
363
  marginTop: space.md,
372
364
  },
365
+ actions: {
366
+ display: "flex",
367
+ justifyContent: "flex-end",
368
+ marginTop: space.lg,
369
+ },
373
370
  idRow: {
374
371
  display: "flex",
375
372
  alignItems: "center",