@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.
- package/dist/chunks/{EmbedPublishPage-DazYJLaD.js → EmbedPublishPage-CtIlaeGO.js} +1 -1
- package/dist/chunks/{UiKitPage-DyVyBp0I.js → UiKitPage-DcnSQ-Hf.js} +3 -3
- package/dist/chunks/{WorkspaceRoutes-CPvkgvxe.js → WorkspaceRoutes-DVpUOaMV.js} +20841 -18934
- package/dist/chunks/{dashboard-6aSS8oyj.js → dashboard-bNp6AbKE.js} +465 -443
- package/dist/chunks/{index-DgTNL4t3.js → index-DoDE-hwB.js} +2 -2
- package/dist/chunks/{status-bar-action-RNBujSgk.js → status-bar-action-C0fsAWvD.js} +5804 -5668
- package/dist/dashboard.js +2 -2
- package/dist/index.js +4 -4
- package/dist/site-widget.js +2 -2
- package/dist/studio.css +454 -62
- package/package.json +3 -2
- package/src/App.tsx +2 -0
- package/src/WorkspaceRoutes.tsx +2 -0
- package/src/api.ts +80 -0
- package/src/chat/ChatMessage.tsx +10 -3
- package/src/chat/Composer.tsx +18 -18
- package/src/chat/chat-helpers.ts +58 -1
- package/src/chrome/AppShell.tsx +47 -10
- package/src/chrome/AppSidebar.tsx +10 -160
- package/src/chrome/CommandPalette.tsx +211 -74
- package/src/chrome/ContentExplorerSidebar.tsx +1212 -0
- package/src/chrome/UserMenu.tsx +20 -3
- package/src/chrome/WorkspaceNavContext.tsx +1 -0
- package/src/chrome/command-palette-icons.tsx +152 -0
- package/src/chrome/content-path-tree.ts +95 -0
- package/src/chrome/content-repo-path.ts +52 -0
- package/src/chrome/explorer-icons.tsx +87 -0
- package/src/chrome/folder-create-context.ts +147 -0
- package/src/pages/BlockSettingsDialog.tsx +4 -0
- package/src/pages/CliAuthorizePage.tsx +43 -0
- package/src/pages/DocEditorPage.tsx +33 -4
- package/src/pages/MediaFieldInput.tsx +139 -0
- package/src/pages/MediaGalleryPage.tsx +748 -0
- package/src/pages/MediaLightbox.tsx +467 -0
- package/src/pages/SelectRepositoriesLink.tsx +28 -4
- package/src/pages/SettingsGeneralPage.tsx +25 -28
- package/src/pages/SettingsGithubPage.tsx +413 -124
- package/src/pages/SettingsUsagePage.tsx +19 -0
- package/src/pages/TypeDocsPage.tsx +2 -210
- package/src/pages/WorkspaceLayout.tsx +6 -1
- package/src/pages/media-grid.ts +190 -0
- package/src/pages/preview-url.ts +13 -2
- package/src/replica/useReplica.ts +9 -0
- package/src/ui/ConfirmDialog.tsx +1 -1
- package/src/workspace/permissions.ts +9 -0
- 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
|
|
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 {
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
270
|
-
|
|
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
|
-
|
|
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
|