|
|
@@ -81,7 +81,6 @@ export function SessionSidePanel(props: {
|
|
|
}),
|
|
|
)
|
|
|
const open = createMemo(() => reviewOpen() || fileOpen())
|
|
|
- const rendered = createMemo<boolean>((previous) => previous || open(), false)
|
|
|
const reviewTab = createMemo(() => isDesktop())
|
|
|
const panelWidth = createMemo(() => {
|
|
|
if (!open()) return "0px"
|
|
|
@@ -164,10 +163,6 @@ export function SessionSidePanel(props: {
|
|
|
const openedTabs = tabState.openedTabs
|
|
|
const activeTab = tabState.activeTab
|
|
|
const activeFileTab = tabState.activeFileTab
|
|
|
- const reviewContentRendered = createMemo<boolean>(
|
|
|
- (previous) => previous || (reviewOpen() && activeTab() === "review"),
|
|
|
- false,
|
|
|
- )
|
|
|
|
|
|
const fileTreeTab = () => layout.fileTree.tab()
|
|
|
|
|
|
@@ -272,233 +267,220 @@ export function SessionSidePanel(props: {
|
|
|
}}
|
|
|
style={{ width: panelWidth() }}
|
|
|
>
|
|
|
- <Show when={rendered()}>
|
|
|
+ <Show when={open()}>
|
|
|
<div
|
|
|
class="size-full flex"
|
|
|
classList={{
|
|
|
"border-l border-border-weaker-base": !settings.general.newLayoutDesigns(),
|
|
|
}}
|
|
|
>
|
|
|
- <div
|
|
|
- aria-hidden={!reviewOpen()}
|
|
|
- inert={!reviewOpen()}
|
|
|
- class="relative min-w-0 h-full flex-1 overflow-hidden bg-background-base"
|
|
|
- classList={{
|
|
|
- "pointer-events-none": !reviewOpen(),
|
|
|
- }}
|
|
|
- >
|
|
|
- <div class="size-full min-w-0 h-full bg-background-base">
|
|
|
- <DragDropProvider
|
|
|
- onDragStart={handleDragStart}
|
|
|
- onDragEnd={handleDragEnd}
|
|
|
- onDragOver={handleDragOver}
|
|
|
- collisionDetector={closestCenter}
|
|
|
- >
|
|
|
- <DragDropSensors />
|
|
|
- <ConstrainDragYAxis />
|
|
|
- <Tabs value={activeTab()} onChange={activateTab}>
|
|
|
- <div class="sticky top-0 shrink-0 flex">
|
|
|
- <Tabs.List
|
|
|
- ref={(el: HTMLDivElement) => {
|
|
|
- const stop = createFileTabListSync({ el, contextOpen })
|
|
|
- onCleanup(stop)
|
|
|
- }}
|
|
|
- >
|
|
|
- <Show when={reviewTab() && props.canReview()}>
|
|
|
- <Tabs.Trigger
|
|
|
- value="review"
|
|
|
- id={reviewTabID}
|
|
|
- aria-controls={activeTab() === "review" ? reviewTabPanelID : undefined}
|
|
|
- >
|
|
|
- <div class="flex items-center gap-1.5">
|
|
|
- <div>{language.t("session.tab.review")}</div>
|
|
|
- <Show when={props.hasReview()}>
|
|
|
- <div>{props.reviewCount()}</div>
|
|
|
- </Show>
|
|
|
- </div>
|
|
|
- </Tabs.Trigger>
|
|
|
- </Show>
|
|
|
- <Show when={contextOpen()}>
|
|
|
- <Tabs.Trigger
|
|
|
- value="context"
|
|
|
- closeButton={
|
|
|
- <TooltipKeybind
|
|
|
- title={language.t("common.closeTab")}
|
|
|
- keybind={command.keybind("tab.close")}
|
|
|
- placement="bottom"
|
|
|
- gutter={10}
|
|
|
- >
|
|
|
- <IconButton
|
|
|
- icon="close-small"
|
|
|
- variant="ghost"
|
|
|
- class="h-5 w-5"
|
|
|
- onClick={() => tabs().close("context")}
|
|
|
- aria-label={language.t("common.closeTab")}
|
|
|
- />
|
|
|
- </TooltipKeybind>
|
|
|
- }
|
|
|
- hideCloseButton
|
|
|
- onMiddleClick={() => tabs().close("context")}
|
|
|
- >
|
|
|
- <div class="flex items-center gap-2">
|
|
|
- <SessionContextUsage variant="indicator" />
|
|
|
- <div>{language.t("session.tab.context")}</div>
|
|
|
- </div>
|
|
|
- </Tabs.Trigger>
|
|
|
- </Show>
|
|
|
- <SortableProvider ids={openedTabs()}>
|
|
|
- <For each={panelTabs()}>
|
|
|
- {(tab) => (
|
|
|
- <Show
|
|
|
- when={tab === SESSION_OPEN_FILE_TAB}
|
|
|
- fallback={
|
|
|
- <SortableTab
|
|
|
- tab={tab}
|
|
|
- temporary={temporaryTab() === tab}
|
|
|
- onTabClose={tabs().close}
|
|
|
- onTabDoubleClick={temporaryTab() === tab ? openTab : undefined}
|
|
|
+ <Show when={reviewOpen()}>
|
|
|
+ <div class="relative min-w-0 h-full flex-1 overflow-hidden bg-background-base">
|
|
|
+ <div class="size-full min-w-0 h-full bg-background-base">
|
|
|
+ <DragDropProvider
|
|
|
+ onDragStart={handleDragStart}
|
|
|
+ onDragEnd={handleDragEnd}
|
|
|
+ onDragOver={handleDragOver}
|
|
|
+ collisionDetector={closestCenter}
|
|
|
+ >
|
|
|
+ <DragDropSensors />
|
|
|
+ <ConstrainDragYAxis />
|
|
|
+ <Tabs value={activeTab()} onChange={activateTab}>
|
|
|
+ <div class="sticky top-0 shrink-0 flex">
|
|
|
+ <Tabs.List
|
|
|
+ ref={(el: HTMLDivElement) => {
|
|
|
+ const stop = createFileTabListSync({ el, contextOpen })
|
|
|
+ onCleanup(stop)
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Show when={reviewTab() && props.canReview()}>
|
|
|
+ <Tabs.Trigger
|
|
|
+ value="review"
|
|
|
+ id={reviewTabID}
|
|
|
+ aria-controls={activeTab() === "review" ? reviewTabPanelID : undefined}
|
|
|
+ >
|
|
|
+ <div class="flex items-center gap-1.5">
|
|
|
+ <div>{language.t("session.tab.review")}</div>
|
|
|
+ <Show when={props.hasReview()}>
|
|
|
+ <div>{props.reviewCount()}</div>
|
|
|
+ </Show>
|
|
|
+ </div>
|
|
|
+ </Tabs.Trigger>
|
|
|
+ </Show>
|
|
|
+ <Show when={contextOpen()}>
|
|
|
+ <Tabs.Trigger
|
|
|
+ value="context"
|
|
|
+ closeButton={
|
|
|
+ <TooltipKeybind
|
|
|
+ title={language.t("common.closeTab")}
|
|
|
+ keybind={command.keybind("tab.close")}
|
|
|
+ placement="bottom"
|
|
|
+ gutter={10}
|
|
|
+ >
|
|
|
+ <IconButton
|
|
|
+ icon="close-small"
|
|
|
+ variant="ghost"
|
|
|
+ class="h-5 w-5"
|
|
|
+ onClick={() => tabs().close("context")}
|
|
|
+ aria-label={language.t("common.closeTab")}
|
|
|
/>
|
|
|
- }
|
|
|
- >
|
|
|
- <Tabs.Trigger
|
|
|
- value={SESSION_OPEN_FILE_TAB}
|
|
|
- closeButton={
|
|
|
- <TooltipKeybind
|
|
|
- title={language.t("common.closeTab")}
|
|
|
- keybind={command.keybind("tab.close")}
|
|
|
- placement="bottom"
|
|
|
- gutter={10}
|
|
|
- >
|
|
|
- <IconButton
|
|
|
- icon="close-small"
|
|
|
- variant="ghost"
|
|
|
- class="h-5 w-5"
|
|
|
- onClick={() => tabs().close(SESSION_OPEN_FILE_TAB)}
|
|
|
- aria-label={language.t("common.closeTab")}
|
|
|
- />
|
|
|
- </TooltipKeybind>
|
|
|
+ </TooltipKeybind>
|
|
|
+ }
|
|
|
+ hideCloseButton
|
|
|
+ onMiddleClick={() => tabs().close("context")}
|
|
|
+ >
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <SessionContextUsage variant="indicator" />
|
|
|
+ <div>{language.t("session.tab.context")}</div>
|
|
|
+ </div>
|
|
|
+ </Tabs.Trigger>
|
|
|
+ </Show>
|
|
|
+ <SortableProvider ids={openedTabs()}>
|
|
|
+ <For each={panelTabs()}>
|
|
|
+ {(tab) => (
|
|
|
+ <Show
|
|
|
+ when={tab === SESSION_OPEN_FILE_TAB}
|
|
|
+ fallback={
|
|
|
+ <SortableTab
|
|
|
+ tab={tab}
|
|
|
+ temporary={temporaryTab() === tab}
|
|
|
+ onTabClose={tabs().close}
|
|
|
+ onTabDoubleClick={temporaryTab() === tab ? openTab : undefined}
|
|
|
+ />
|
|
|
}
|
|
|
- hideCloseButton
|
|
|
- onMiddleClick={() => tabs().close(SESSION_OPEN_FILE_TAB)}
|
|
|
>
|
|
|
- <div class="flex items-center gap-1.5 italic">
|
|
|
- <Icon name="open-file" size="small" />
|
|
|
- <span>{language.t("command.file.open")}</span>
|
|
|
- </div>
|
|
|
- </Tabs.Trigger>
|
|
|
- </Show>
|
|
|
- )}
|
|
|
- </For>
|
|
|
- </SortableProvider>
|
|
|
- <div class="bg-background-stronger h-full shrink-0 sticky right-0 z-10 flex items-center justify-center pr-3">
|
|
|
- <TooltipKeybind
|
|
|
- title={language.t("command.file.open")}
|
|
|
- keybind={command.keybind("file.open")}
|
|
|
- class="flex items-center"
|
|
|
- >
|
|
|
- <IconButton
|
|
|
- icon="plus-small"
|
|
|
- variant="ghost"
|
|
|
- iconSize="large"
|
|
|
- class="!rounded-md"
|
|
|
- onClick={() => {
|
|
|
- if (props.fileBrowserState) {
|
|
|
- openFileBrowser()
|
|
|
- return
|
|
|
- }
|
|
|
- void import("@/components/dialog-select-file").then((x) => {
|
|
|
- dialog.show(() => <x.DialogSelectFile mode="files" onOpenFile={showAllFiles} />)
|
|
|
- })
|
|
|
- }}
|
|
|
- aria-label={language.t("command.file.open")}
|
|
|
- />
|
|
|
- </TooltipKeybind>
|
|
|
- </div>
|
|
|
- </Tabs.List>
|
|
|
- </div>
|
|
|
-
|
|
|
- <Show when={reviewTab() && props.canReview() && reviewContentRendered()}>
|
|
|
- <div
|
|
|
- id={reviewTabPanelID}
|
|
|
- role="tabpanel"
|
|
|
- aria-labelledby={reviewTabID}
|
|
|
- aria-hidden={activeTab() !== "review"}
|
|
|
- inert={activeTab() !== "review"}
|
|
|
- tabIndex={props.reviewHasFocusableContent() ? undefined : 0}
|
|
|
- data-slot="tabs-content"
|
|
|
- class="flex flex-col h-full overflow-hidden contain-strict"
|
|
|
- classList={{ hidden: activeTab() !== "review" }}
|
|
|
- >
|
|
|
- {props.reviewPanel()}
|
|
|
+ <Tabs.Trigger
|
|
|
+ value={SESSION_OPEN_FILE_TAB}
|
|
|
+ closeButton={
|
|
|
+ <TooltipKeybind
|
|
|
+ title={language.t("common.closeTab")}
|
|
|
+ keybind={command.keybind("tab.close")}
|
|
|
+ placement="bottom"
|
|
|
+ gutter={10}
|
|
|
+ >
|
|
|
+ <IconButton
|
|
|
+ icon="close-small"
|
|
|
+ variant="ghost"
|
|
|
+ class="h-5 w-5"
|
|
|
+ onClick={() => tabs().close(SESSION_OPEN_FILE_TAB)}
|
|
|
+ aria-label={language.t("common.closeTab")}
|
|
|
+ />
|
|
|
+ </TooltipKeybind>
|
|
|
+ }
|
|
|
+ hideCloseButton
|
|
|
+ onMiddleClick={() => tabs().close(SESSION_OPEN_FILE_TAB)}
|
|
|
+ >
|
|
|
+ <div class="flex items-center gap-1.5 italic">
|
|
|
+ <Icon name="open-file" size="small" />
|
|
|
+ <span>{language.t("command.file.open")}</span>
|
|
|
+ </div>
|
|
|
+ </Tabs.Trigger>
|
|
|
+ </Show>
|
|
|
+ )}
|
|
|
+ </For>
|
|
|
+ </SortableProvider>
|
|
|
+ <div class="bg-background-stronger h-full shrink-0 sticky right-0 z-10 flex items-center justify-center pr-3">
|
|
|
+ <TooltipKeybind
|
|
|
+ title={language.t("command.file.open")}
|
|
|
+ keybind={command.keybind("file.open")}
|
|
|
+ class="flex items-center"
|
|
|
+ >
|
|
|
+ <IconButton
|
|
|
+ icon="plus-small"
|
|
|
+ variant="ghost"
|
|
|
+ iconSize="large"
|
|
|
+ class="!rounded-md"
|
|
|
+ onClick={() => {
|
|
|
+ if (props.fileBrowserState) {
|
|
|
+ openFileBrowser()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ void import("@/components/dialog-select-file").then((x) => {
|
|
|
+ dialog.show(() => <x.DialogSelectFile mode="files" onOpenFile={showAllFiles} />)
|
|
|
+ })
|
|
|
+ }}
|
|
|
+ aria-label={language.t("command.file.open")}
|
|
|
+ />
|
|
|
+ </TooltipKeybind>
|
|
|
+ </div>
|
|
|
+ </Tabs.List>
|
|
|
</div>
|
|
|
- </Show>
|
|
|
|
|
|
- <Tabs.Content value="empty" class="flex flex-col h-full overflow-hidden contain-strict">
|
|
|
+ <Show when={reviewTab() && props.canReview() && activeTab() === "review"}>
|
|
|
+ <div
|
|
|
+ id={reviewTabPanelID}
|
|
|
+ role="tabpanel"
|
|
|
+ aria-labelledby={reviewTabID}
|
|
|
+ tabIndex={props.reviewHasFocusableContent() ? undefined : 0}
|
|
|
+ data-slot="tabs-content"
|
|
|
+ class="flex flex-col h-full overflow-hidden contain-strict"
|
|
|
+ >
|
|
|
+ {props.reviewPanel()}
|
|
|
+ </div>
|
|
|
+ </Show>
|
|
|
+
|
|
|
<Show when={activeTab() === "empty"}>
|
|
|
- <div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
|
|
|
- <div class="h-full px-6 pb-42 -mt-4 flex flex-col items-center justify-center text-center gap-6">
|
|
|
- <Mark class="w-14 opacity-10" />
|
|
|
- <div class="text-14-regular text-text-weak max-w-56">
|
|
|
- {language.t("session.files.selectToOpen")}
|
|
|
+ <Tabs.Content value="empty" class="flex flex-col h-full overflow-hidden contain-strict">
|
|
|
+ <div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
|
|
|
+ <div class="h-full px-6 pb-42 -mt-4 flex flex-col items-center justify-center text-center gap-6">
|
|
|
+ <Mark class="w-14 opacity-10" />
|
|
|
+ <div class="text-14-regular text-text-weak max-w-56">
|
|
|
+ {language.t("session.files.selectToOpen")}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </Tabs.Content>
|
|
|
</Show>
|
|
|
- </Tabs.Content>
|
|
|
|
|
|
- <Show when={contextOpen()}>
|
|
|
- <Tabs.Content value="context" class="flex flex-col h-full overflow-hidden contain-strict">
|
|
|
- <Show when={activeTab() === "context"}>
|
|
|
+ <Show when={activeTab() === "context"}>
|
|
|
+ <Tabs.Content value="context" class="flex flex-col h-full overflow-hidden contain-strict">
|
|
|
<div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
|
|
|
<SessionContextTab />
|
|
|
</div>
|
|
|
- </Show>
|
|
|
- </Tabs.Content>
|
|
|
- </Show>
|
|
|
+ </Tabs.Content>
|
|
|
+ </Show>
|
|
|
|
|
|
- <Show when={browserTab()}>
|
|
|
- <SessionFileBrowserTab
|
|
|
- tab={browserTab()!}
|
|
|
- placeholder={browserTab() === SESSION_OPEN_FILE_TAB}
|
|
|
- active={file.pathFromTab(browserTab()!)}
|
|
|
- kinds={browserKinds()}
|
|
|
- state={props.fileBrowserState!}
|
|
|
- onSelect={(path) => previewTab(file.tab(path))}
|
|
|
- onSelectPermanent={(path) => openTab(file.tab(path))}
|
|
|
- filterRef={(element) => (fileFilter = element)}
|
|
|
- />
|
|
|
- </Show>
|
|
|
+ <Show when={browserTab()}>
|
|
|
+ <SessionFileBrowserTab
|
|
|
+ tab={browserTab()!}
|
|
|
+ placeholder={browserTab() === SESSION_OPEN_FILE_TAB}
|
|
|
+ active={file.pathFromTab(browserTab()!)}
|
|
|
+ kinds={browserKinds()}
|
|
|
+ state={props.fileBrowserState!}
|
|
|
+ onSelect={(path) => previewTab(file.tab(path))}
|
|
|
+ onSelectPermanent={(path) => openTab(file.tab(path))}
|
|
|
+ filterRef={(element) => (fileFilter = element)}
|
|
|
+ />
|
|
|
+ </Show>
|
|
|
|
|
|
- <Show when={!props.fileBrowserState && activeFileTab()} keyed>
|
|
|
- {(tab) => <FileTabContent tab={tab} />}
|
|
|
- </Show>
|
|
|
- </Tabs>
|
|
|
- <DragOverlay>
|
|
|
- <Show when={store.activeDraggable} keyed>
|
|
|
- {(tab) => {
|
|
|
- const path = file.pathFromTab(tab)
|
|
|
- return (
|
|
|
- <div data-component="tabs-drag-preview">
|
|
|
- <Show when={path}>
|
|
|
- {(p) => <FileVisual active path={p()} temporary={temporaryTab() === tab} />}
|
|
|
- </Show>
|
|
|
- </div>
|
|
|
- )
|
|
|
- }}
|
|
|
- </Show>
|
|
|
- </DragOverlay>
|
|
|
- </DragDropProvider>
|
|
|
+ <Show when={!props.fileBrowserState && activeFileTab()} keyed>
|
|
|
+ {(tab) => <FileTabContent tab={tab} />}
|
|
|
+ </Show>
|
|
|
+ </Tabs>
|
|
|
+ <DragOverlay>
|
|
|
+ <Show when={store.activeDraggable} keyed>
|
|
|
+ {(tab) => {
|
|
|
+ const path = file.pathFromTab(tab)
|
|
|
+ return (
|
|
|
+ <div data-component="tabs-drag-preview">
|
|
|
+ <Show when={path}>
|
|
|
+ {(p) => <FileVisual active path={p()} temporary={temporaryTab() === tab} />}
|
|
|
+ </Show>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ </Show>
|
|
|
+ </DragOverlay>
|
|
|
+ </DragDropProvider>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </Show>
|
|
|
|
|
|
- <Show when={shown()}>
|
|
|
+ <Show when={fileOpen()}>
|
|
|
<div
|
|
|
id="file-tree-panel"
|
|
|
- aria-hidden={!fileOpen()}
|
|
|
- inert={!fileOpen()}
|
|
|
class="relative min-w-0 h-full shrink-0 overflow-hidden"
|
|
|
classList={{
|
|
|
- "pointer-events-none": !fileOpen(),
|
|
|
"transition-[width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none":
|
|
|
!props.size.active(),
|
|
|
}}
|
|
|
@@ -526,45 +508,49 @@ export function SessionSidePanel(props: {
|
|
|
{language.t("session.files.all")}
|
|
|
</Tabs.Trigger>
|
|
|
</Tabs.List>
|
|
|
- <Tabs.Content value="changes" class="bg-background-stronger px-3 py-0">
|
|
|
- <Switch>
|
|
|
- <Match when={props.hasReview() || !props.diffsReady()}>
|
|
|
- <Show
|
|
|
- when={props.diffsReady()}
|
|
|
- fallback={
|
|
|
- <div class="px-2 py-2 text-12-regular text-text-weak">
|
|
|
- {language.t("common.loading")}
|
|
|
- {language.t("common.loading.ellipsis")}
|
|
|
- </div>
|
|
|
- }
|
|
|
- >
|
|
|
+ <Show when={fileTreeTab() === "changes"}>
|
|
|
+ <Tabs.Content value="changes" class="bg-background-stronger px-3 py-0">
|
|
|
+ <Switch>
|
|
|
+ <Match when={props.hasReview() || !props.diffsReady()}>
|
|
|
+ <Show
|
|
|
+ when={props.diffsReady()}
|
|
|
+ fallback={
|
|
|
+ <div class="px-2 py-2 text-12-regular text-text-weak">
|
|
|
+ {language.t("common.loading")}
|
|
|
+ {language.t("common.loading.ellipsis")}
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <FileTree
|
|
|
+ path=""
|
|
|
+ class="pt-3"
|
|
|
+ allowed={diffFiles()}
|
|
|
+ kinds={kinds()}
|
|
|
+ draggable={false}
|
|
|
+ active={props.activeDiff}
|
|
|
+ onFileClick={(node) => props.focusReviewDiff(node.path)}
|
|
|
+ />
|
|
|
+ </Show>
|
|
|
+ </Match>
|
|
|
+ </Switch>
|
|
|
+ </Tabs.Content>
|
|
|
+ </Show>
|
|
|
+ <Show when={fileTreeTab() === "all"}>
|
|
|
+ <Tabs.Content value="all" class="bg-background-stronger px-3 py-0">
|
|
|
+ <Switch>
|
|
|
+ <Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match>
|
|
|
+ <Match when={true}>
|
|
|
<FileTree
|
|
|
path=""
|
|
|
class="pt-3"
|
|
|
- allowed={diffFiles()}
|
|
|
+ modified={diffFiles()}
|
|
|
kinds={kinds()}
|
|
|
- draggable={false}
|
|
|
- active={props.activeDiff}
|
|
|
- onFileClick={(node) => props.focusReviewDiff(node.path)}
|
|
|
+ onFileClick={(node) => openTab(file.tab(node.path))}
|
|
|
/>
|
|
|
- </Show>
|
|
|
- </Match>
|
|
|
- </Switch>
|
|
|
- </Tabs.Content>
|
|
|
- <Tabs.Content value="all" class="bg-background-stronger px-3 py-0">
|
|
|
- <Switch>
|
|
|
- <Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match>
|
|
|
- <Match when={true}>
|
|
|
- <FileTree
|
|
|
- path=""
|
|
|
- class="pt-3"
|
|
|
- modified={diffFiles()}
|
|
|
- kinds={kinds()}
|
|
|
- onFileClick={(node) => openTab(file.tab(node.path))}
|
|
|
- />
|
|
|
- </Match>
|
|
|
- </Switch>
|
|
|
- </Tabs.Content>
|
|
|
+ </Match>
|
|
|
+ </Switch>
|
|
|
+ </Tabs.Content>
|
|
|
+ </Show>
|
|
|
</Tabs>
|
|
|
</div>
|
|
|
<Show when={fileOpen()}>
|