polish folder picker list and instance focus
This commit is contained in:
@@ -28,9 +28,18 @@ const FolderSelectionView: Component<FolderSelectionViewProps> = (props) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function scrollToIndex(index: number) {
|
function scrollToIndex(index: number) {
|
||||||
const element = recentListRef?.querySelector(`[data-folder-index="${index}"]`)
|
const container = recentListRef
|
||||||
if (element) {
|
if (!container) return
|
||||||
element.scrollIntoView({ block: "nearest", behavior: "auto" })
|
const element = container.querySelector(`[data-folder-index="${index}"]`) as HTMLElement | null
|
||||||
|
if (!element) return
|
||||||
|
|
||||||
|
const containerRect = container.getBoundingClientRect()
|
||||||
|
const elementRect = element.getBoundingClientRect()
|
||||||
|
|
||||||
|
if (elementRect.top < containerRect.top) {
|
||||||
|
container.scrollTop -= containerRect.top - elementRect.top
|
||||||
|
} else if (elementRect.bottom > containerRect.bottom) {
|
||||||
|
container.scrollTop += elementRect.bottom - containerRect.bottom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,59 +191,55 @@ const FolderSelectionView: Component<FolderSelectionViewProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div class="panel flex-1 min-h-0 overflow-hidden">
|
<div class="panel flex flex-col flex-1 min-h-0">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2 class="panel-title">Recent Folders</h2>
|
<h2 class="panel-title">Recent Folders</h2>
|
||||||
<p class="panel-subtitle">
|
<p class="panel-subtitle">
|
||||||
{folders().length} {folders().length === 1 ? "folder" : "folders"} available
|
{folders().length} {folders().length === 1 ? "folder" : "folders"} available
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="panel-list panel-list--fill flex-1 min-h-0 overflow-auto" ref={(el) => (recentListRef = el)}>
|
||||||
class="panel-list max-h-[50vh] overflow-y-auto pr-1"
|
<For each={folders()}>
|
||||||
ref={(el) => (recentListRef = el)}
|
{(folder, index) => (
|
||||||
>
|
<div
|
||||||
<For each={folders()}>
|
class="panel-list-item"
|
||||||
{(folder, index) => (
|
classList={{
|
||||||
<div
|
"panel-list-item-highlight": focusMode() === "recent" && selectedIndex() === index(),
|
||||||
data-folder-index={index()}
|
}}
|
||||||
class="panel-list-item"
|
>
|
||||||
classList={{
|
<div class="flex items-center gap-2 w-full px-1">
|
||||||
"panel-list-item-highlight": focusMode() === "recent" && selectedIndex() === index(),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
|
|
||||||
<div class="flex items-center w-full">
|
|
||||||
<button
|
<button
|
||||||
class="panel-list-item-content w-full"
|
data-folder-index={index()}
|
||||||
|
class="panel-list-item-content flex-1"
|
||||||
onClick={() => handleFolderSelect(folder.path)}
|
onClick={() => handleFolderSelect(folder.path)}
|
||||||
onMouseEnter={() => {
|
onMouseEnter={() => {
|
||||||
setFocusMode("recent")
|
setFocusMode("recent")
|
||||||
setSelectedIndex(index())
|
setSelectedIndex(index())
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="flex-1 min-w-0">
|
<div class="flex items-center justify-between gap-3 w-full">
|
||||||
<div class="flex items-center gap-2 mb-1">
|
<div class="flex-1 min-w-0">
|
||||||
<Folder class="w-4 h-4 flex-shrink-0 icon-muted" />
|
<div class="flex items-center gap-2 mb-1">
|
||||||
<span class="text-sm font-medium truncate text-primary">
|
<Folder class="w-4 h-4 flex-shrink-0 icon-muted" />
|
||||||
{folder.path.split("/").pop()}
|
<span class="text-sm font-medium truncate text-primary">
|
||||||
</span>
|
{folder.path.split("/").pop()}
|
||||||
</div>
|
</span>
|
||||||
<div class="text-xs font-mono truncate pl-6 text-muted">
|
</div>
|
||||||
{getDisplayPath(folder.path)}
|
<div class="text-xs font-mono truncate pl-6 text-muted">
|
||||||
</div>
|
{getDisplayPath(folder.path)}
|
||||||
<div class="text-xs mt-1 pl-6 text-muted">
|
</div>
|
||||||
{formatRelativeTime(folder.lastAccessed)}
|
<div class="text-xs mt-1 pl-6 text-muted">
|
||||||
|
{formatRelativeTime(folder.lastAccessed)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Show when={focusMode() === "recent" && selectedIndex() === index()}>
|
||||||
|
<kbd class="kbd">↵</kbd>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<Show when={focusMode() === "recent" && selectedIndex() === index()}>
|
|
||||||
<kbd class="kbd">
|
|
||||||
↵
|
|
||||||
</kbd>
|
|
||||||
</Show>
|
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => handleRemove(folder.path, e)}
|
onClick={(e) => handleRemove(folder.path, e)}
|
||||||
class="p-2.5 transition-all mr-2 hover:bg-red-100 dark:hover:bg-red-900/30 opacity-70 hover:opacity-100"
|
class="p-2 transition-all hover:bg-red-100 dark:hover:bg-red-900/30 opacity-70 hover:opacity-100 rounded"
|
||||||
title="Remove from recent"
|
title="Remove from recent"
|
||||||
>
|
>
|
||||||
<Trash2 class="w-3.5 h-3.5 transition-colors icon-muted hover:text-red-600 dark:hover:text-red-400" />
|
<Trash2 class="w-3.5 h-3.5 transition-colors icon-muted hover:text-red-600 dark:hover:text-red-400" />
|
||||||
|
|||||||
@@ -64,15 +64,34 @@ function updateInstance(id: string, updates: Partial<Instance>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeInstance(id: string) {
|
function removeInstance(id: string) {
|
||||||
|
let nextActiveId: string | null = null
|
||||||
|
|
||||||
setInstances((prev) => {
|
setInstances((prev) => {
|
||||||
|
if (!prev.has(id)) {
|
||||||
|
return prev
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = Array.from(prev.keys())
|
||||||
|
const index = keys.indexOf(id)
|
||||||
const next = new Map(prev)
|
const next = new Map(prev)
|
||||||
next.delete(id)
|
next.delete(id)
|
||||||
|
|
||||||
|
if (activeInstanceId() === id) {
|
||||||
|
if (index > 0) {
|
||||||
|
nextActiveId = keys[index - 1]
|
||||||
|
} else {
|
||||||
|
const remainingKeys = Array.from(next.keys())
|
||||||
|
nextActiveId = remainingKeys.length > 0 ? remainingKeys[0] : null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return next
|
return next
|
||||||
})
|
})
|
||||||
|
|
||||||
removeLogContainer(id)
|
removeLogContainer(id)
|
||||||
|
|
||||||
if (activeInstanceId() === id) {
|
if (activeInstanceId() === id) {
|
||||||
setActiveInstanceId(null)
|
setActiveInstanceId(nextActiveId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up session indexes and drafts for removed instance
|
// Clean up session indexes and drafts for removed instance
|
||||||
|
|||||||
Reference in New Issue
Block a user