fix: sidebar refresh, context menu position, show-in-explorer for all items

Sidebar refresh:
- addFile/addFolder now use currentFolderId || selectedNode.id as parent
- startImport stores pendingImportParent; confirmImport uses it
- setNodeChildren also updates node.has_children for toggle arrow reactivity
- navigateToFolder expands the folder node in sidebar tree

Context menu position:
- FileTreeRow stores menuX/menuY from contextmenu event coords
- Menu uses position:fixed with cursor-relative left/top and window clamp

Show in explorer:
- Sidebar context menu uses file.showInExplorer label
- en.js: add file.showInExplorer key
This commit is contained in:
mirivlad 2026-06-03 04:46:42 +08:00
parent 3c9b9edf8c
commit cc3500c14f
6 changed files with 32 additions and 16 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -16,8 +16,8 @@
background: #13131f;
}
</style>
<script type="module" crossorigin src="/assets/main-BZ3I06Px.js"></script>
<link rel="stylesheet" crossorigin href="/assets/main-DsSP02cl.css">
<script type="module" crossorigin src="/assets/main-43Kzwqa7.js"></script>
<link rel="stylesheet" crossorigin href="/assets/main-D6qvckLy.css">
</head>
<body>
<div id="app"></div>

View File

@ -73,6 +73,7 @@
let importSummary = null
let showImportDialog = false
let pendingImportPath = ''
let pendingImportParent = ''
let pendingImportMode = 'copy'
let treeItems = []
let expanded = {}
@ -247,7 +248,6 @@
async function navigateToFolder(folderId) {
if (!selectedNode) return
// Get the folder node name for breadcrumbs
try {
const node = await wailsCall('GetNodeDetail', folderId)
if (node) {
@ -257,6 +257,10 @@
folderStack = [...folderStack, { id: folderId, name: '...' }]
}
currentFolderId = folderId
expanded = { ...expanded, [folderId]: true }
const children = await wailsCall('ListWorkspaceChildren', folderId) || []
setNodeChildren(workspaceTree, folderId, children)
workspaceTree = [...workspaceTree]
await loadFolder(folderId)
}
@ -681,6 +685,7 @@
for (const node of tree) {
if (node.id === nodeId) {
node.children = children
node.has_children = children.length > 0
return true
}
if (node.children && setNodeChildren(node.children, nodeId, children)) {
@ -877,21 +882,24 @@
async function addFile() {
const path = await wailsCall('PickFile')
if (!path) return
await startImport(selectedNode.id, path)
const parentId = currentFolderId || selectedNode.id
await startImport(parentId, path)
}
async function addFolder() {
const path = await wailsCall('PickDirectory')
if (!path) return
await startImport(selectedNode.id, path)
const parentId = currentFolderId || selectedNode.id
await startImport(parentId, path)
}
async function startImport(nodeID, sourcePath) {
async function startImport(parentID, sourcePath) {
importing = true
try {
const summary = await wailsCall('PreviewImport', sourcePath)
importSummary = summary
pendingImportPath = sourcePath
pendingImportParent = parentID
showImportDialog = true
} catch (e) {
error = String(e)
@ -901,17 +909,18 @@
async function confirmImport(mode) {
try {
const parentId = pendingImportParent || selectedNode.id
const result = mode === 'copy'
? await wailsCall('AddPathCopy', selectedNode.id, pendingImportPath)
: await wailsCall('AddPathLink', selectedNode.id, pendingImportPath)
? await wailsCall('AddPathCopy', parentId, pendingImportPath)
: await wailsCall('AddPathLink', parentId, pendingImportPath)
showImportDialog = false
importSummary = null
folderStack = []
currentFolderId = null
await Promise.all([
loadTabData(selectedNode.id),
loadFolder(selectedNode.id),
refreshParentNode(selectedNode.id),
loadTabData(parentId),
loadFolder(parentId),
refreshParentNode(parentId),
])
} catch (e) {
error = String(e)
@ -1656,7 +1665,7 @@
{t('common.delete')}
</button>
<button class="context-menu-item" on:click={() => openNodeFolder(contextMenu.node)}>
{t('nav.openFolder')}
{t('file.showInExplorer')}
</button>
</div>
</div>

View File

@ -16,6 +16,8 @@
const isFolder = item.type === 'folder'
const fileType = formatFileType(item)
let menuOpen = false
let menuX = 0
let menuY = 0
let clickTimer = null
function handleClick(e) {
@ -107,6 +109,8 @@
function oncontextmenu(e) {
e.preventDefault()
menuX = Math.min(e.clientX, window.innerWidth - 240)
menuY = Math.min(e.clientY, window.innerHeight - 320)
menuOpen = true
}
</script>
@ -189,7 +193,7 @@
{#if menuOpen}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="menu-backdrop" on:click|stopPropagation={closeMenu} role="presentation"></div>
<div class="menu" on:click|stopPropagation role="menu">
<div class="menu" style="left: {menuX}px; top: {menuY}px; position: fixed;" on:click|stopPropagation role="menu">
<button class="menu-item" on:click={handleOpen} role="menuitem">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
{t('common.open')}
@ -347,9 +351,7 @@
}
.menu {
position: absolute;
right: 12px;
margin-top: 4px;
position: fixed;
background: #1a1a28;
border: 1px solid #2a2a3c;
border-radius: 8px;

View File

@ -74,6 +74,7 @@ export default {
'file.preview': 'Preview',
'file.openExternal': 'Open in external program',
'file.openFolder': 'Open folder',
'file.showInExplorer': 'Show in explorer',
'file.delete': 'Delete',
'file.pickSingle': 'Select file',
'file.pickDirectory': 'Select folder',