@jetcrab/pi-desk 1.1.22-dev → 1.1.23-dev

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 (42) hide show
  1. package/package.json +1 -1
  2. package/src/client/l2_biz/project-preview/l2-project-preview-dialog.tsx +1 -1
  3. package/src/client/l2_biz/project-preview/l2-project-preview-page.tsx +1 -1
  4. package/src/client/l2_biz/project-preview/l2-project-preview.tsx +28 -34
  5. package/src/client/l3_modules/project-files/l3-project-document-view.tsx +162 -151
  6. package/src/client/l3_modules/project-files/l3-project-file-browser.module.css +30 -0
  7. package/src/client/l3_modules/project-files/l3-project-file-browser.tsx +137 -111
  8. package/src/client/l3_modules/project-files/l3-project-file-tabs.tsx +26 -6
  9. package/src/client/l3_modules/project-files/views/l3-project-search-controls.tsx +118 -123
  10. package/src/client/l3_modules/project-files/views/l3-project-search-results.tsx +29 -25
  11. package/temp/build/pi-desk/release/.next/BUILD_ID +1 -1
  12. package/temp/build/pi-desk/release/.next/build-manifest.json +3 -3
  13. package/temp/build/pi-desk/release/.next/required-server-files.js +2 -2
  14. package/temp/build/pi-desk/release/.next/required-server-files.json +2 -2
  15. package/temp/build/pi-desk/release/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  16. package/temp/build/pi-desk/release/.next/server/app/_global-error.html +1 -1
  17. package/temp/build/pi-desk/release/.next/server/app/_global-error.rsc +1 -1
  18. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  19. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  20. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  21. package/temp/build/pi-desk/release/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/temp/build/pi-desk/release/.next/server/app/api/health/route.js +1 -1
  23. package/temp/build/pi-desk/release/.next/server/app/login/page_client-reference-manifest.js +1 -1
  24. package/temp/build/pi-desk/release/.next/server/app/page.js +2 -2
  25. package/temp/build/pi-desk/release/.next/server/app/page_client-reference-manifest.js +1 -1
  26. package/temp/build/pi-desk/release/.next/server/app/project-preview/page.js +1 -1
  27. package/temp/build/pi-desk/release/.next/server/app/project-preview/page_client-reference-manifest.js +1 -1
  28. package/temp/build/pi-desk/release/.next/server/chunks/20460.js +2 -2
  29. package/temp/build/pi-desk/release/.next/server/middleware-build-manifest.js +1 -1
  30. package/temp/build/pi-desk/release/.next/server/pages/500.html +1 -1
  31. package/temp/build/pi-desk/release/.next/static/chunks/9038-05fd2688407b39c1.js +15 -0
  32. package/temp/build/pi-desk/release/.next/static/chunks/app/{page-e8a5274c115f528d.js → page-54040b9fd54ee8b3.js} +2 -2
  33. package/temp/build/pi-desk/release/.next/static/chunks/app/project-preview/{page-d70ee4e9409b970a.js → page-bc18765121950e65.js} +1 -1
  34. package/temp/build/pi-desk/release/.next/static/chunks/{webpack-b60891a214e0925d.js → webpack-48eecbb66781c006.js} +1 -1
  35. package/temp/build/pi-desk/release/.next/static/css/10e063cfb3cda7bd.css +1 -0
  36. package/temp/build/pi-desk/release/.next/static/css/2c3b0c0ff1f49c68.css +1 -0
  37. package/temp/build/pi-desk/release/.next/trace-build +1 -1
  38. package/temp/build/pi-desk/release/.next/static/chunks/9038-03144ed96d613f75.js +0 -15
  39. package/temp/build/pi-desk/release/.next/static/css/6dbae2922f88ca31.css +0 -1
  40. package/temp/build/pi-desk/release/.next/static/css/f646ca6c07245c4c.css +0 -1
  41. /package/temp/build/pi-desk/release/.next/static/{MV6_lBt7Mzmi1rBNI-3dx → gAYTx4KJJR3vTtGYexj4J}/_buildManifest.js +0 -0
  42. /package/temp/build/pi-desk/release/.next/static/{MV6_lBt7Mzmi1rBNI-3dx → gAYTx4KJJR3vTtGYexj4J}/_ssgManifest.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetcrab/pi-desk",
3
- "version": "1.1.22-dev",
3
+ "version": "1.1.23-dev",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -54,7 +54,7 @@ export function L2ProjectPreviewDialog({
54
54
  refreshOnFocus
55
55
  onEscape={onClose}
56
56
  title={
57
- <L4AppDialogTitle className="truncate" title={cwd}>
57
+ <L4AppDialogTitle className="truncate text-sm" title={cwd}>
58
58
  {projectName}
59
59
  </L4AppDialogTitle>
60
60
  }
@@ -45,7 +45,7 @@ export function L2ProjectPreviewPage({
45
45
  refreshOnFocus={false}
46
46
  onUnauthorized={onUnauthorized}
47
47
  actions={
48
- <Button size="sm" variant="outline" onClick={() => onSelect(null)}>
48
+ <Button size="sm" variant="ghost" onClick={() => onSelect(null)}>
49
49
  <FolderOpenIcon className="size-4" />
50
50
  <span>{t('switchProject')}</span>
51
51
  </Button>
@@ -78,6 +78,7 @@ export function L2ProjectPreview({
78
78
  <L3ProjectFileBrowser
79
79
  cwd={cwd}
80
80
  projectName={projectName}
81
+ showRootTitle={false}
81
82
  runtime={files}
82
83
  gitRuntime={git}
83
84
  onOpenGitBranches={openGit}
@@ -85,25 +86,26 @@ export function L2ProjectPreview({
85
86
  />
86
87
  )
87
88
  const code = (
88
- <div className="flex size-full min-h-0 min-w-0 flex-col">
89
- <L3ProjectFileTabs
90
- cwd={cwd}
91
- gitRuntime={git}
92
- paths={state.tabs}
93
- activePath={state.activePath}
94
- diffPath={diffPath}
95
- mobile={narrow}
96
- onActivate={(path) => files.openFile(path)}
97
- onClose={(path, scope) => files.closeTabs(path, scope)}
98
- />
99
- <L3ProjectDocumentView
100
- runtime={files}
101
- gitRuntime={git}
102
- compact={width < 1100}
103
- refreshOnFocus={refreshOnFocus}
104
- onEscape={onEscape}
105
- />
106
- </div>
89
+ <L3ProjectDocumentView
90
+ runtime={files}
91
+ gitRuntime={git}
92
+ compact={width < 1100}
93
+ refreshOnFocus={refreshOnFocus}
94
+ onEscape={onEscape}
95
+ renderHeader={(actions) => (
96
+ <L3ProjectFileTabs
97
+ cwd={cwd}
98
+ gitRuntime={git}
99
+ paths={state.tabs}
100
+ activePath={state.activePath}
101
+ diffPath={diffPath}
102
+ mobile={narrow}
103
+ actions={actions}
104
+ onActivate={(path) => files.openFile(path)}
105
+ onClose={(path, scope) => files.closeTabs(path, scope)}
106
+ />
107
+ )}
108
+ />
107
109
  )
108
110
  const gitView = (
109
111
  <div className="flex size-full min-h-0 min-w-0 flex-col">
@@ -226,7 +228,7 @@ export function L2ProjectPreview({
226
228
  className="flex size-full min-h-0 min-w-0 flex-col overflow-hidden"
227
229
  data-testid="project-preview"
228
230
  >
229
- <header className="flex min-h-14 shrink-0 flex-wrap items-center gap-2 border-b bg-muted px-3 py-2 pt-[max(8px,env(safe-area-inset-top))]">
231
+ <header className="flex min-h-9 shrink-0 items-center gap-1 bg-muted px-2 py-1 pt-[max(4px,env(safe-area-inset-top))]">
230
232
  {!stacked ? (
231
233
  <Button
232
234
  size="icon-sm"
@@ -241,15 +243,11 @@ export function L2ProjectPreview({
241
243
  )}
242
244
  </Button>
243
245
  ) : null}
244
- <div className="min-w-0 flex-1">
245
- {title ?? (
246
- <h1 className="truncate text-lg font-semibold" title={cwd}>
247
- {projectName}
248
- </h1>
249
- )}
250
- <p className="truncate text-xs text-muted-foreground" title={cwd}>
251
- {cwd}
252
- </p>
246
+ <div className="flex min-w-0 flex-1 items-baseline gap-3" title={cwd}>
247
+ <div className="min-w-0 shrink-0 max-w-[50%] max-sm:max-w-full max-sm:shrink">
248
+ {title ?? <h1 className="truncate text-sm font-semibold">{projectName}</h1>}
249
+ </div>
250
+ <p className="min-w-0 truncate text-xs text-muted-foreground max-sm:hidden">{cwd}</p>
253
251
  </div>
254
252
  <Button
255
253
  size="sm"
@@ -272,11 +270,7 @@ export function L2ProjectPreview({
272
270
  ) : null}
273
271
  {stacked ? (
274
272
  <>
275
- <div
276
- className="flex shrink-0 gap-1 border-b px-2 py-1"
277
- role="group"
278
- aria-label={t('previewArea')}
279
- >
273
+ <div className="flex shrink-0 gap-1 px-2 py-1" role="group" aria-label={t('previewArea')}>
280
274
  <Button
281
275
  size="sm"
282
276
  variant={page === 'files' ? 'secondary' : 'ghost'}
@@ -19,6 +19,7 @@ import {
19
19
  useRef,
20
20
  useState,
21
21
  useSyncExternalStore,
22
+ type ReactNode,
22
23
  type Ref
23
24
  } from 'react'
24
25
  import { useTranslation } from 'react-i18next'
@@ -55,7 +56,8 @@ export function L3ProjectDocumentView({
55
56
  visible = true,
56
57
  refreshOnFocus = true,
57
58
  onEscape,
58
- onSwitchPane
59
+ onSwitchPane,
60
+ renderHeader
59
61
  }: {
60
62
  ref?: Ref<L3ProjectDocumentHandle>
61
63
  runtime: L3ProjectFileRuntime
@@ -65,6 +67,7 @@ export function L3ProjectDocumentView({
65
67
  refreshOnFocus?: boolean
66
68
  onEscape: () => void
67
69
  onSwitchPane?: () => void
70
+ renderHeader?: (actions: ReactNode) => ReactNode
68
71
  }): React.JSX.Element {
69
72
  const { t } = useTranslation('projectFiles')
70
73
  const { wrapLines, diffViewMode, collapseUnchanged } = useL4CodePreferences()
@@ -149,6 +152,160 @@ export function L3ProjectDocumentView({
149
152
  else toast.error(t('copyContentFailed'))
150
153
  })
151
154
  }
155
+ const actions =
156
+ activeDiff || activePath ? (
157
+ <>
158
+ {activeDiff ? (
159
+ <>
160
+ <span className="mr-auto shrink-0 px-1 text-xs text-muted-foreground">
161
+ {activeDiff.label ?? t('headToWorking')}
162
+ {activeDiff.status === 'text' &&
163
+ activeDiff.original.content === activeDiff.modified.content
164
+ ? t('noDiffChanges')
165
+ : ''}
166
+ </span>
167
+ <L3CodeSurfaceToolbarButton
168
+ label={t('previousChange')}
169
+ onClick={() => diffRef.current?.previousChange()}
170
+ >
171
+ <ArrowUpIcon className="size-4" />
172
+ </L3CodeSurfaceToolbarButton>
173
+ <L3CodeSurfaceToolbarButton
174
+ label={t('nextChange')}
175
+ onClick={() => diffRef.current?.nextChange()}
176
+ >
177
+ <ArrowDownIcon className="size-4" />
178
+ </L3CodeSurfaceToolbarButton>
179
+ {!compact ? (
180
+ <L3CodeSurfaceToolbarButton
181
+ label={diffViewMode === 'side-by-side' ? t('inlineDiff') : t('sideBySideDiff')}
182
+ active={diffViewMode === 'inline'}
183
+ onClick={() =>
184
+ runtime.setDiffViewMode(
185
+ diffViewMode === 'side-by-side' ? 'inline' : 'side-by-side'
186
+ )
187
+ }
188
+ >
189
+ <Columns2Icon className="size-4" />
190
+ </L3CodeSurfaceToolbarButton>
191
+ ) : null}
192
+ <L3CodeSurfaceToolbarButton
193
+ label={t(wrapLines ? 'wrapOff' : 'wrapOn')}
194
+ active={wrapLines}
195
+ onClick={() => runtime.setDiffWrapLines(!wrapLines)}
196
+ >
197
+ <WrapTextIcon className="size-4" />
198
+ </L3CodeSurfaceToolbarButton>
199
+ <L3CodeSurfaceToolbarButton
200
+ label={t(collapseUnchanged ? 'expandUnchanged' : 'collapseUnchanged')}
201
+ active={collapseUnchanged}
202
+ onClick={() => runtime.setDiffCollapseUnchanged(!collapseUnchanged)}
203
+ >
204
+ <FoldVerticalIcon className="size-4" />
205
+ </L3CodeSurfaceToolbarButton>
206
+ <L3CodeSurfaceToolbarButton
207
+ label={t('reloadDiff')}
208
+ onClick={() => runtime.reloadDiff()}
209
+ >
210
+ <RefreshCwIcon className="size-4" />
211
+ </L3CodeSurfaceToolbarButton>
212
+ </>
213
+ ) : (
214
+ <>
215
+ {previewKind && document?.status === 'text' && activePath ? (
216
+ <div
217
+ className="mr-auto flex shrink-0"
218
+ role="group"
219
+ aria-label={t(previewKind === 'markdown' ? 'markdownMode' : 'htmlMode')}
220
+ >
221
+ {(['preview', 'source'] as const).map((mode) => (
222
+ <Button
223
+ key={mode}
224
+ variant={document.viewMode === mode ? 'secondary' : 'ghost'}
225
+ size="sm"
226
+ aria-pressed={document.viewMode === mode}
227
+ onClick={() => {
228
+ savePosition()
229
+ runtime.setTextViewMode(activePath, mode)
230
+ }}
231
+ >
232
+ {t(mode === 'preview' ? 'previewMode' : 'sourceMode')}
233
+ </Button>
234
+ ))}
235
+ </div>
236
+ ) : null}
237
+ {showSource && gitStatus ? (
238
+ <span
239
+ data-testid="file-git-status"
240
+ role="status"
241
+ className="mr-auto min-w-0 truncate text-xs text-muted-foreground"
242
+ title={comparison?.status === 'error' ? comparison.error : gitStatus}
243
+ >
244
+ {compact && comparison?.status === 'ready' && typeof count === 'number'
245
+ ? t('gitChangesCompact', { count })
246
+ : gitStatus}
247
+ </span>
248
+ ) : null}
249
+ {showSource && comparison?.status === 'ready' ? (
250
+ <>
251
+ {typeof count === 'number' && count > 0 ? (
252
+ <>
253
+ <L3CodeSurfaceToolbarButton
254
+ label={t('previousChange')}
255
+ onClick={() => previewRef.current?.previousChange()}
256
+ >
257
+ <ArrowUpIcon className="size-4" />
258
+ </L3CodeSurfaceToolbarButton>
259
+ <L3CodeSurfaceToolbarButton
260
+ label={t('nextChange')}
261
+ onClick={() => previewRef.current?.nextChange()}
262
+ >
263
+ <ArrowDownIcon className="size-4" />
264
+ </L3CodeSurfaceToolbarButton>
265
+ </>
266
+ ) : null}
267
+ <L3CodeSurfaceToolbarButton label={t('viewDiff')} onClick={() => openDiff()}>
268
+ <GitCompareArrowsIcon className="size-4" />
269
+ </L3CodeSurfaceToolbarButton>
270
+ </>
271
+ ) : null}
272
+ {showSource && activePath ? (
273
+ <>
274
+ <L3CodeSurfaceToolbarButton
275
+ label={t('findInFile')}
276
+ onClick={() => previewRef.current?.openSearch()}
277
+ >
278
+ <SearchIcon className="size-4" />
279
+ </L3CodeSurfaceToolbarButton>
280
+ {!compact ? (
281
+ <L3CodeSurfaceToolbarButton
282
+ label={t('goToLine')}
283
+ onClick={() => previewRef.current?.gotoLine()}
284
+ >
285
+ <ListOrderedIcon className="size-4" />
286
+ </L3CodeSurfaceToolbarButton>
287
+ ) : null}
288
+ <L3CodeSurfaceToolbarButton
289
+ label={t(wrapLines ? 'wrapOff' : 'wrapOn')}
290
+ active={wrapLines}
291
+ onClick={() => runtime.setWrapLines(activePath, !wrapLines)}
292
+ >
293
+ <WrapTextIcon className="size-4" />
294
+ </L3CodeSurfaceToolbarButton>
295
+ <L3CodeSurfaceToolbarButton label={t('copySelectionOrAll')} onClick={copyText}>
296
+ <CopyIcon className="size-4" />
297
+ </L3CodeSurfaceToolbarButton>
298
+ </>
299
+ ) : null}
300
+ {activePath ? (
301
+ <L3CodeSurfaceToolbarButton label={t('reloadCurrentFile')} onClick={refresh}>
302
+ <RefreshCwIcon className="size-4" />
303
+ </L3CodeSurfaceToolbarButton>
304
+ ) : null}
305
+ </>
306
+ )}
307
+ </>
308
+ ) : null
152
309
  return (
153
310
  <div
154
311
  ref={hostRef}
@@ -162,160 +319,14 @@ export function L3ProjectDocumentView({
162
319
  hostRef.current?.querySelector<HTMLElement>('[data-testid="markdown-preview"]')?.focus()
163
320
  }}
164
321
  >
165
- {activeDiff || activePath ? (
322
+ {renderHeader ? (
323
+ renderHeader(actions)
324
+ ) : actions ? (
166
325
  <div
167
326
  className="flex min-h-9 shrink-0 flex-wrap items-center justify-end gap-2 border-b px-3 py-1"
168
327
  aria-label={t('fileActions')}
169
328
  >
170
- {activeDiff ? (
171
- <>
172
- <span className="mr-auto shrink-0 px-1 text-xs text-muted-foreground">
173
- {activeDiff.label ?? t('headToWorking')}
174
- {activeDiff.status === 'text' &&
175
- activeDiff.original.content === activeDiff.modified.content
176
- ? t('noDiffChanges')
177
- : ''}
178
- </span>
179
- <L3CodeSurfaceToolbarButton
180
- label={t('previousChange')}
181
- onClick={() => diffRef.current?.previousChange()}
182
- >
183
- <ArrowUpIcon className="size-4" />
184
- </L3CodeSurfaceToolbarButton>
185
- <L3CodeSurfaceToolbarButton
186
- label={t('nextChange')}
187
- onClick={() => diffRef.current?.nextChange()}
188
- >
189
- <ArrowDownIcon className="size-4" />
190
- </L3CodeSurfaceToolbarButton>
191
- {!compact ? (
192
- <L3CodeSurfaceToolbarButton
193
- label={diffViewMode === 'side-by-side' ? t('inlineDiff') : t('sideBySideDiff')}
194
- active={diffViewMode === 'inline'}
195
- onClick={() =>
196
- runtime.setDiffViewMode(
197
- diffViewMode === 'side-by-side' ? 'inline' : 'side-by-side'
198
- )
199
- }
200
- >
201
- <Columns2Icon className="size-4" />
202
- </L3CodeSurfaceToolbarButton>
203
- ) : null}
204
- <L3CodeSurfaceToolbarButton
205
- label={t(wrapLines ? 'wrapOff' : 'wrapOn')}
206
- active={wrapLines}
207
- onClick={() => runtime.setDiffWrapLines(!wrapLines)}
208
- >
209
- <WrapTextIcon className="size-4" />
210
- </L3CodeSurfaceToolbarButton>
211
- <L3CodeSurfaceToolbarButton
212
- label={t(collapseUnchanged ? 'expandUnchanged' : 'collapseUnchanged')}
213
- active={collapseUnchanged}
214
- onClick={() => runtime.setDiffCollapseUnchanged(!collapseUnchanged)}
215
- >
216
- <FoldVerticalIcon className="size-4" />
217
- </L3CodeSurfaceToolbarButton>
218
- <L3CodeSurfaceToolbarButton
219
- label={t('reloadDiff')}
220
- onClick={() => runtime.reloadDiff()}
221
- >
222
- <RefreshCwIcon className="size-4" />
223
- </L3CodeSurfaceToolbarButton>
224
- </>
225
- ) : (
226
- <>
227
- {previewKind && document?.status === 'text' && activePath ? (
228
- <div
229
- className="mr-auto flex shrink-0"
230
- role="group"
231
- aria-label={t(previewKind === 'markdown' ? 'markdownMode' : 'htmlMode')}
232
- >
233
- {(['preview', 'source'] as const).map((mode) => (
234
- <Button
235
- key={mode}
236
- variant={document.viewMode === mode ? 'secondary' : 'ghost'}
237
- size="sm"
238
- aria-pressed={document.viewMode === mode}
239
- onClick={() => {
240
- savePosition()
241
- runtime.setTextViewMode(activePath, mode)
242
- }}
243
- >
244
- {t(mode === 'preview' ? 'previewMode' : 'sourceMode')}
245
- </Button>
246
- ))}
247
- </div>
248
- ) : null}
249
- {showSource && gitStatus ? (
250
- <span
251
- data-testid="file-git-status"
252
- role="status"
253
- className="mr-auto min-w-0 truncate text-xs text-muted-foreground"
254
- title={comparison?.status === 'error' ? comparison.error : gitStatus}
255
- >
256
- {compact && comparison?.status === 'ready' && typeof count === 'number'
257
- ? t('gitChangesCompact', { count })
258
- : gitStatus}
259
- </span>
260
- ) : null}
261
- {showSource && comparison?.status === 'ready' ? (
262
- <>
263
- {typeof count === 'number' && count > 0 ? (
264
- <>
265
- <L3CodeSurfaceToolbarButton
266
- label={t('previousChange')}
267
- onClick={() => previewRef.current?.previousChange()}
268
- >
269
- <ArrowUpIcon className="size-4" />
270
- </L3CodeSurfaceToolbarButton>
271
- <L3CodeSurfaceToolbarButton
272
- label={t('nextChange')}
273
- onClick={() => previewRef.current?.nextChange()}
274
- >
275
- <ArrowDownIcon className="size-4" />
276
- </L3CodeSurfaceToolbarButton>
277
- </>
278
- ) : null}
279
- <L3CodeSurfaceToolbarButton label={t('viewDiff')} onClick={() => openDiff()}>
280
- <GitCompareArrowsIcon className="size-4" />
281
- </L3CodeSurfaceToolbarButton>
282
- </>
283
- ) : null}
284
- {showSource && activePath ? (
285
- <>
286
- <L3CodeSurfaceToolbarButton
287
- label={t('findInFile')}
288
- onClick={() => previewRef.current?.openSearch()}
289
- >
290
- <SearchIcon className="size-4" />
291
- </L3CodeSurfaceToolbarButton>
292
- {!compact ? (
293
- <L3CodeSurfaceToolbarButton
294
- label={t('goToLine')}
295
- onClick={() => previewRef.current?.gotoLine()}
296
- >
297
- <ListOrderedIcon className="size-4" />
298
- </L3CodeSurfaceToolbarButton>
299
- ) : null}
300
- <L3CodeSurfaceToolbarButton
301
- label={t(wrapLines ? 'wrapOff' : 'wrapOn')}
302
- active={wrapLines}
303
- onClick={() => runtime.setWrapLines(activePath, !wrapLines)}
304
- >
305
- <WrapTextIcon className="size-4" />
306
- </L3CodeSurfaceToolbarButton>
307
- <L3CodeSurfaceToolbarButton label={t('copySelectionOrAll')} onClick={copyText}>
308
- <CopyIcon className="size-4" />
309
- </L3CodeSurfaceToolbarButton>
310
- </>
311
- ) : null}
312
- {activePath ? (
313
- <L3CodeSurfaceToolbarButton label={t('reloadCurrentFile')} onClick={refresh}>
314
- <RefreshCwIcon className="size-4" />
315
- </L3CodeSurfaceToolbarButton>
316
- ) : null}
317
- </>
318
- )}
329
+ {actions}
319
330
  </div>
320
331
  ) : null}
321
332
  <div className="min-h-0 flex-1 overflow-hidden pb-[env(safe-area-inset-bottom)]">
@@ -0,0 +1,30 @@
1
+ .tree [role='tree'] {
2
+ padding: 0;
3
+ }
4
+
5
+ .tree [role='tree'] > div {
6
+ padding: 0 4px;
7
+ }
8
+
9
+ .tree [data-slot='collapsible-content'] > div {
10
+ border-left-color: color-mix(in oklab, var(--border) 50%, transparent);
11
+ }
12
+
13
+ @media (pointer: fine) {
14
+ .tree [role='treeitem']:not([aria-expanded]),
15
+ .tree [role='treeitem'][aria-expanded] > div:first-child {
16
+ min-height: 24px;
17
+ gap: 4px;
18
+ padding: 0 4px;
19
+ }
20
+
21
+ .tree [role='treeitem'][aria-expanded] > div:first-child > button {
22
+ min-height: 24px;
23
+ gap: 4px;
24
+ }
25
+
26
+ .tree [data-slot='collapsible-content'] > div {
27
+ margin-left: 8px;
28
+ padding-left: 3px;
29
+ }
30
+ }