diff --git a/README.md b/README.md index ab851aa..fca2128 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,10 @@ Available colors: - purple - pink + +CSS Class: `.ge-grid-item.ge-foldernote` + + ## Settings In the plugin's settings page, you can: diff --git a/README_ja.md b/README_ja.md index 5faee42..3ac98b4 100644 --- a/README_ja.md +++ b/README_ja.md @@ -61,6 +61,10 @@ color: red - purple - pink + +CSS Class: `.ge-grid-item.ge-foldernote` + + ## 設定 プラグインの設定ページでは、以下のことができます: diff --git a/README_zhTW.md b/README_zhTW.md index ff71041..a6bf080 100644 --- a/README_zhTW.md +++ b/README_zhTW.md @@ -61,6 +61,10 @@ color: red - purple - pink + +CSS Class: `.ge-grid-item.ge-foldernote` + + ## 設定 在插件的設定頁面中,您可以: diff --git a/manifest.json b/manifest.json index bdd2078..8ddc40b 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "gridexplorer", "name": "GridExplorer", - "version": "2.3.0", + "version": "2.4.0", "minAppVersion": "1.1.0", "description": "Browse note files in a grid view.", "author": "Devon22", diff --git a/package-lock.json b/package-lock.json index c6358da..a1e26fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gridexplorer", - "version": "2.3.0", + "version": "2.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gridexplorer", - "version": "2.3.0", + "version": "2.4.0", "license": "MIT", "devDependencies": { "@types/node": "^16.11.6", diff --git a/package.json b/package.json index fce1c1f..fc7eecd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gridexplorer", - "version": "2.3.0", + "version": "2.4.0", "description": "Browse note files in a grid view.", "main": "main.js", "scripts": { diff --git a/src/FolderNoteSettingsModal.ts b/src/FolderNoteSettingsModal.ts index 2fec7a5..82186c6 100644 --- a/src/FolderNoteSettingsModal.ts +++ b/src/FolderNoteSettingsModal.ts @@ -7,6 +7,7 @@ export interface FolderNoteSettings { sort: string; color: string; icon: string; + isPinned: boolean; } export function showFolderNoteSettingsModal(app: App, plugin: GridExplorerPlugin, folder: TFolder, gridView: GridView) { @@ -20,7 +21,8 @@ export class FolderNoteSettingsModal extends Modal { settings: FolderNoteSettings = { sort: '', color: '', - icon: '📁' + icon: '📁', + isPinned: false }; existingFile: TFile | null = null; @@ -105,6 +107,19 @@ export class FolderNoteSettingsModal extends Modal { }); }); + // 置頂勾選框 + new Setting(contentEl) + .setName(t('pinned')) + .setDesc(t('pinned_desc')) + .addToggle(toggle => { + toggle + .setValue(this.settings.isPinned) + .onChange(value => { + this.settings.isPinned = value; + }); + }); + + // 按鈕區域 const buttonSetting = new Setting(contentEl); @@ -142,6 +157,16 @@ export class FolderNoteSettingsModal extends Modal { if ('icon' in fileCache.frontmatter) { this.settings.icon = fileCache.frontmatter.icon || '📁'; } + + // 讀取置頂設定 + if (fileCache.frontmatter?.pinned && Array.isArray(fileCache.frontmatter.pinned)) { + this.settings.isPinned = fileCache.frontmatter.pinned.some((item: any) => { + if (!item) return false; + const pinnedName = item.toString(); + const pinnedNameWithoutExt = pinnedName.replace(/\.\w+$/, ''); + return pinnedNameWithoutExt === this.folder.name; + }); + } } } catch (error) { console.error('無法讀取資料夾筆記設定', error); @@ -184,6 +209,27 @@ export class FolderNoteSettingsModal extends Modal { } else { delete frontmatter['icon']; } + const folderName = `${this.folder.name}.md`; + if (this.settings.isPinned) { + // 如果原本就有 pinned 陣列,則添加或更新 + if (Array.isArray(frontmatter['pinned'])) { + if (!frontmatter['pinned'].includes(folderName)) { + frontmatter['pinned'] = [folderName, ...frontmatter['pinned']]; + } + } else { + // 如果沒有 pinned 陣列,則創建一個新的 + frontmatter['pinned'] = [folderName]; + } + } else if (Array.isArray(frontmatter['pinned'])) { + // 如果取消置頂,則從陣列中移除 + frontmatter['pinned'] = frontmatter['pinned'].filter( + (item: any) => item !== folderName + ); + // 如果陣列為空,則刪除該欄位 + if (frontmatter['pinned'].length === 0) { + delete frontmatter['pinned']; + } + } }); // 強制更新 metadata cache diff --git a/src/FolderRenameModal.ts b/src/FolderRenameModal.ts index ad3683c..be177cb 100644 --- a/src/FolderRenameModal.ts +++ b/src/FolderRenameModal.ts @@ -1,4 +1,4 @@ -import { App, Modal, Setting, TFolder } from 'obsidian'; +import { App, Modal, Setting, TFolder, normalizePath } from 'obsidian'; import { t } from './translations'; import GridExplorerPlugin from '../main'; import { GridView } from './GridView'; @@ -57,7 +57,9 @@ export class FolderRenameModal extends Modal { async renameFolder() { try { - await this.app.fileManager.renameFile(this.folder, this.newName); + const parentPath = this.folder.parent ? this.folder.parent.path : ''; + const newPath = normalizePath(parentPath ? `${parentPath}/${this.newName}` : this.newName); + await this.app.fileManager.renameFile(this.folder, newPath); // 重新渲染視圖 setTimeout(() => { this.gridView.render(); diff --git a/src/FolderSelectionModal.ts b/src/FolderSelectionModal.ts index efcf068..f5e4394 100644 --- a/src/FolderSelectionModal.ts +++ b/src/FolderSelectionModal.ts @@ -246,10 +246,32 @@ export class FolderSelectionModal extends Modal { // 建立資料夾選項 folders.forEach(folder => { + // 計算資料夾層級 + const depth = (folder.path.match(/\//g) || []).length; + const displayName = folder.path.split('/').pop() || '/'; + const folderOption = this.folderOptionsContainer.createEl('div', { cls: 'ge-grid-view-folder-option', - text: `📁 ${folder.path || '/'}` + attr: { + 'data-depth': depth.toString(), + 'data-path': folder.path + } }); + + // 產生 ascii tree 前綴 + const prefixSpan = document.createElement('span'); + prefixSpan.className = 'ge-folder-tree-prefix'; + prefixSpan.textContent = depth > 0 ? ' '.repeat(depth - 1) + '└ ' : ''; + folderOption.appendChild(prefixSpan); + + // 資料夾圖示與名稱 + const icon = document.createElement('span'); + icon.textContent = '📁 '; + folderOption.appendChild(icon); + + const nameSpan = document.createElement('span'); + nameSpan.textContent = displayName; + folderOption.appendChild(nameSpan); folderOption.addEventListener('click', () => { if (this.activeView) { @@ -359,7 +381,8 @@ export class FolderSelectionModal extends Modal { this.folderOptions.forEach(option => { const text = option.textContent?.toLowerCase() || ''; - if (searchTerm === '' || text.includes(searchTerm)) { + const fullPath = option.getAttribute('data-path')?.toLowerCase() || ''; + if (searchTerm === '' || text.includes(searchTerm) || fullPath.includes(searchTerm)) { option.style.display = 'block'; hasVisibleOptions = true; } else { diff --git a/src/GridView.ts b/src/GridView.ts index f788c80..1c10354 100644 --- a/src/GridView.ts +++ b/src/GridView.ts @@ -1,4 +1,4 @@ -import { WorkspaceLeaf, ItemView, TFolder, TFile, Menu, Notice, Platform, setIcon, getFrontMatterInfo, FrontMatterCache } from 'obsidian'; +import { WorkspaceLeaf, ItemView, TFolder, TFile, Menu, Notice, Platform, setIcon, getFrontMatterInfo, FrontMatterCache, normalizePath } from 'obsidian'; import { showFolderSelectionModal } from './FolderSelectionModal'; import { findFirstImageInNote } from './mediaUtils'; import { MediaModal } from './MediaModal'; @@ -186,100 +186,7 @@ export class GridView extends ItemView { } } }); - - // 為頂部按鈕區域添加右鍵選單事件 - headerButtonsDiv.addEventListener('contextmenu', (event: MouseEvent) => { - // 只有當點擊的是頂部按鈕區域本身(而不是其中的按鈕)時才觸發捲動 - if (event.target === headerButtonsDiv) { - event.preventDefault(); - const menu = new Menu(); - menu.addItem((item) => { - item - .setTitle(t('open_new_grid_view')) - .setIcon('grid') - .onClick(() => { - const { workspace } = this.app; - let leaf = null; - workspace.getLeavesOfType('grid-view'); - switch (this.plugin.settings.defaultOpenLocation) { - case 'left': - leaf = workspace.getLeftLeaf(false); - break; - case 'right': - leaf = workspace.getRightLeaf(false); - break; - case 'tab': - default: - leaf = workspace.getLeaf('tab'); - break; - } - if (!leaf) { - // 如果無法獲取指定位置的 leaf,則回退到新分頁 - leaf = workspace.getLeaf('tab'); - } - leaf.setViewState({ type: 'grid-view', active: true }); - // 設定資料來源 - if (leaf.view instanceof GridView) { - leaf.view.setSource('folder', '/'); - } - // 確保視圖是活躍的 - workspace.revealLeaf(leaf); - }); - }); - //如果目前是資料夾模式且有資料夾筆記,則增加"打開資料夾筆記"選項 - if (this.sourceMode === 'folder' && this.sourcePath && this.sourcePath !== '/') { - const folderName = this.sourcePath.split('/').pop() || ''; - const notePath = `${this.sourcePath}/${folderName}.md`; - const noteFile = this.app.vault.getAbstractFileByPath(notePath); - if (noteFile instanceof TFile) { - menu.addItem((item) => { - item - .setTitle(t('open_folder_note')) - .setIcon('panel-left-open') - .onClick(() => { - this.app.workspace.getLeaf().openFile(noteFile); - }); - }); - } - } - // 最小化模式選項 - menu.addItem((item) => { - item - .setTitle(t('min_mode')) - .setIcon('minimize-2') - .setChecked(this.minMode) - .onClick(() => { - this.minMode = !this.minMode; - this.app.workspace.requestSaveLayout(); - this.render(); - }); - }); - // 顯示忽略資料夾選項 - menu.addItem((item) => { - item - .setTitle(t('show_ignored_folders')) - .setIcon('folder-open-dot') - .setChecked(this.showIgnoredFolders) - .onClick(() => { - this.showIgnoredFolders = !this.showIgnoredFolders; - this.app.workspace.requestSaveLayout(); - this.render(); - }); - }); - menu.addItem((item) => { - item - .setTitle(t('open_settings')) - .setIcon('settings') - .onClick(() => { - // 打開插件設定頁面 - (this.app as any).setting.open(); - (this.app as any).setting.openTabById(this.plugin.manifest.id); - }); - }); - menu.showAtMouseEvent(event); - } - }); - + // 添加新增筆記按鈕 const newNoteButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('new_note') } }); newNoteButton.addEventListener('click', async () => { @@ -363,97 +270,6 @@ export class GridView extends ItemView { menu.showAtMouseEvent(event); }); - // 添加回上層按鈕(僅在資料夾模式且不在根目錄時顯示) - if (this.sourceMode === 'folder' && this.sourcePath !== '/' && this.searchQuery === '') { - const upButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('go_up') } }); - upButton.addEventListener('click', () => { - const parentPath = this.sourcePath.split('/').slice(0, -1).join('/') || '/'; - this.setSource('folder', parentPath, true); - this.clearSelection(); - }); - setIcon(upButton, 'arrow-up'); - - if(Platform.isDesktop) { - // 為上層按鈕添加拖曳目標功能 - upButton.addEventListener('dragover', (event) => { - // 防止預設行為以允許放置 - event.preventDefault(); - // 設定拖曳效果為移動 - event.dataTransfer!.dropEffect = 'move'; - // 顯示可放置的視覺提示 - upButton.addClass('ge-dragover'); - }); - - upButton.addEventListener('dragleave', () => { - // 移除視覺提示 - upButton.removeClass('ge-dragover'); - }); - - upButton.addEventListener('drop', async (event) => { - // 防止預設行為 - event.preventDefault(); - // 移除視覺提示 - upButton.removeClass('ge-dragover'); - - // 獲取上一層資料夾路徑 - const parentPath = this.sourcePath.split('/').slice(0, -1).join('/') || '/'; - if (!parentPath) return; - - // 獲取資料夾物件 - const folder = this.app.vault.getAbstractFileByPath(parentPath); - if (!(folder instanceof TFolder)) return; - - // 檢查是否有多個檔案被拖曳 - const filesData = event.dataTransfer?.getData('application/obsidian-grid-explorer-files'); - if (filesData) { - try { - // 解析檔案路徑列表 - const filePaths = JSON.parse(filesData); - - // 移動所有檔案 - for (const filePath of filePaths) { - const file = this.app.vault.getAbstractFileByPath(filePath); - if (file instanceof TFile) { - // 計算新的檔案路徑 - const newPath = `${parentPath}/${file.name}`; - // 移動檔案 - await this.app.fileManager.renameFile(file, newPath); - } - } - - // 重新渲染視圖 - this.render(); - } catch (error) { - console.error('An error occurred while moving multiple files to parent folder:', error); - } - return; - } - - // 如果沒有多個檔案資料,嘗試獲取單個檔案路徑(向後兼容) - const filePath = event.dataTransfer?.getData('text/plain'); - if (!filePath) return; - - const cleanedFilePath = filePath.replace(/!?\[\[(.*?)\]\]/, '$1'); - - // 獲取檔案物件 - const file = this.app.vault.getAbstractFileByPath(cleanedFilePath); - - if (file instanceof TFile) { - try { - // 計算新的檔案路徑 - const newPath = `${parentPath}/${file.name}`; - // 移動檔案 - await this.app.fileManager.renameFile(file, newPath); - // 重新渲染視圖 - this.render(); - } catch (error) { - console.error('An error occurred while moving the file to parent folder:', error); - } - } - }); - } - } - // 添加重新選擇資料夾按鈕 const reselectButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('reselect') } }); reselectButton.addEventListener('click', () => { @@ -722,6 +538,226 @@ export class GridView extends ItemView { }); } + // 添加設定按鈕 + if (this.searchQuery === '') { + const moreOptionsButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('more_options') } }); + setIcon(moreOptionsButton, 'ellipsis-vertical'); + const menu = new Menu(); + menu.addItem((item) => { + item + .setTitle(t('open_new_grid_view')) + .setIcon('grid') + .onClick(() => { + const { workspace } = this.app; + let leaf = null; + workspace.getLeavesOfType('grid-view'); + switch (this.plugin.settings.defaultOpenLocation) { + case 'left': + leaf = workspace.getLeftLeaf(false); + break; + case 'right': + leaf = workspace.getRightLeaf(false); + break; + case 'tab': + default: + leaf = workspace.getLeaf('tab'); + break; + } + if (!leaf) { + // 如果無法獲取指定位置的 leaf,則回退到新分頁 + leaf = workspace.getLeaf('tab'); + } + leaf.setViewState({ type: 'grid-view', active: true }); + // 設定資料來源 + if (leaf.view instanceof GridView) { + leaf.view.setSource('folder', '/'); + } + // 確保視圖是活躍的 + workspace.revealLeaf(leaf); + }); + }); + //如果目前是資料夾模式且有資料夾筆記,則增加"打開資料夾筆記"選項 + if (this.sourceMode === 'folder' && this.sourcePath && this.sourcePath !== '/') { + const folder = this.app.vault.getAbstractFileByPath(this.sourcePath); + const folderName = this.sourcePath.split('/').pop() || ''; + const notePath = `${this.sourcePath}/${folderName}.md`; + const noteFile = this.app.vault.getAbstractFileByPath(notePath); + if (noteFile instanceof TFile) { + //打開資料夾筆記 + menu.addItem((item) => { + item + .setTitle(t('open_folder_note')) + .setIcon('panel-left-open') + .onClick(() => { + this.app.workspace.getLeaf().openFile(noteFile); + }); + }); + //編輯資料夾筆記設定 + menu.addItem((item) => { + item + .setTitle(t('edit_folder_note_settings')) + .setIcon('settings-2') + .onClick(() => { + if (folder instanceof TFolder) { + showFolderNoteSettingsModal(this.app, this.plugin, folder, this); + } + }); + }); + //刪除資料夾筆記 + menu.addItem((item) => { + item + .setTitle(t('delete_folder_note')) + .setIcon('folder-x') + .onClick(() => { + this.app.fileManager.trashFile(noteFile as TFile); + }); + }); + } else { + //建立Folder note + menu.addItem((item) => { + item + .setTitle(t('create_folder_note')) + .setIcon('file-cog') + .onClick(() => { + if (folder instanceof TFolder) { + showFolderNoteSettingsModal(this.app, this.plugin, folder, this); + } + }); + }); + } + } + // 最小化模式選項 + menu.addItem((item) => { + item + .setTitle(t('min_mode')) + .setIcon('minimize-2') + .setChecked(this.minMode) + .onClick(() => { + this.minMode = !this.minMode; + this.app.workspace.requestSaveLayout(); + this.render(); + }); + }); + // 顯示忽略資料夾選項 + menu.addItem((item) => { + item + .setTitle(t('show_ignored_folders')) + .setIcon('folder-open-dot') + .setChecked(this.showIgnoredFolders) + .onClick(() => { + this.showIgnoredFolders = !this.showIgnoredFolders; + this.app.workspace.requestSaveLayout(); + this.render(); + }); + }); + menu.addItem((item) => { + item + .setTitle(t('open_settings')) + .setIcon('settings') + .onClick(() => { + // 打開插件設定頁面 + (this.app as any).setting.open(); + (this.app as any).setting.openTabById(this.plugin.manifest.id); + }); + }); + + moreOptionsButton.addEventListener('click', (event) => { + menu.showAtMouseEvent(event); + }); + } + + // 如果是資料夾模式且沒有搜尋結果,顯示目前資料夾名稱 + if (this.sourceMode === 'folder' && this.searchQuery === '' && this.sourcePath !== '/') { + const pathParts = this.sourcePath.split('/'); + const parentPath = pathParts.slice(0, -1).join('/') || '/'; + let parentFolderName = pathParts.slice(-2, -1)[0] || '/'; + const currentFolderName = pathParts.pop() || t('root'); + + // 若為根目錄,以 'root' 顯示 + if (parentPath === '/' || parentFolderName === '/' || parentFolderName === '') { + parentFolderName = t('root'); + } + + const folderNameContainer = this.containerEl.createDiv('ge-foldername-content'); + + // 建立可點擊的上層資料夾名稱 + const customFolderIcon = this.plugin.settings.customFolderIcon; + const parentFolderLink = folderNameContainer.createEl('a', { + text: `${customFolderIcon} ${parentFolderName}`.trim(), + cls: 'ge-parent-folder-link' + }); + + parentFolderLink.addEventListener('click', (event) => { + event.preventDefault(); + event.stopPropagation(); + this.setSource('folder', parentPath, true); + this.clearSelection(); + }); + + // 分隔符號 + folderNameContainer.createEl('span', { text: ' > ' }); + + // 目前資料夾名稱 + folderNameContainer.createEl('span', { text: currentFolderName }); + + if (Platform.isDesktop) { + // 為上層按鈕添加拖曳目標功能 + parentFolderLink.addEventListener('dragover', (event) => { + event.preventDefault(); + event.dataTransfer!.dropEffect = 'move'; + parentFolderLink.addClass('ge-dragover'); + }); + + parentFolderLink.addEventListener('dragleave', () => { + parentFolderLink.removeClass('ge-dragover'); + }); + + parentFolderLink.addEventListener('drop', async (event) => { + event.preventDefault(); + parentFolderLink.removeClass('ge-dragover'); + + const parentPath = this.sourcePath.split('/').slice(0, -1).join('/') || '/'; + if (!parentPath) return; + + const folder = this.app.vault.getAbstractFileByPath(parentPath); + if (!(folder instanceof TFolder)) return; + + const filesData = event.dataTransfer?.getData('application/obsidian-grid-explorer-files'); + if (filesData) { + try { + const filePaths = JSON.parse(filesData); + for (const filePath of filePaths) { + const file = this.app.vault.getAbstractFileByPath(filePath); + if (file instanceof TFile) { + const newPath = normalizePath(`${parentPath}/${file.name}`); + await this.app.fileManager.renameFile(file, newPath); + } + } + } catch (error) { + console.error('An error occurred while moving multiple files to parent folder:', error); + } + return; + } + + const filePath = event.dataTransfer?.getData('text/plain'); + if (!filePath) return; + + const cleanedFilePath = filePath.replace(/!?\[\[(.*?)\]\]/, '$1'); + const file = this.app.vault.getAbstractFileByPath(cleanedFilePath); + + if (file instanceof TFile) { + try { + const newPath = normalizePath(`${parentPath}/${file.name}`); + await this.app.fileManager.renameFile(file, newPath); + this.render(); + } catch (error) { + console.error('An error occurred while moving the file to parent folder:', error); + } + } + }); + } + } + // 創建內容區域 const contentEl = this.containerEl.createDiv('view-content'); @@ -735,8 +771,20 @@ export class GridView extends ItemView { const noteFile = this.app.vault.getAbstractFileByPath(notePath); if (noteFile instanceof TFile) { const metadata = this.app.metadataCache.getFileCache(noteFile)?.frontmatter; - if (metadata && Array.isArray(metadata['pinned'])) { - this.pinnedList = metadata['pinned'] as string[]; + if (metadata) { + if (Array.isArray(metadata['pinned'])) { + if (this.plugin.settings.folderNoteDisplaySettings === 'pinned') { + // 先過濾掉所有重複的資料夾筆記 + this.pinnedList = metadata['pinned'].filter((name: string) => name !== `${folderName}.md`); + // 將資料夾筆記添加到最前面 + this.pinnedList.unshift(`${folderName}.md`); + } else { + this.pinnedList = metadata['pinned']; + } + } else if (this.plugin.settings.folderNoteDisplaySettings === 'pinned') { + // 如果沒有置頂清單,則建立一個僅包含資料夾筆記的清單 + this.pinnedList = [`${folderName}.md`]; + } } else { this.pinnedList = []; } @@ -762,7 +810,7 @@ export class GridView extends ItemView { } async grid_render() { - const container = this.containerEl.children[1] as HTMLElement; + const container = this.containerEl.querySelector('.view-content') as HTMLElement; container.empty(); container.addClass('ge-grid-container'); @@ -805,45 +853,6 @@ export class GridView extends ItemView { return; } - // 如果是資料夾模式且沒有搜尋結果,顯示目前資料夾名稱 - if (this.sourceMode === 'folder' && this.searchQuery === '' && - this.plugin.settings.showParentFolderItem && this.sourcePath !== '/') { - const pathParts = this.sourcePath.split('/'); - const parentPath = pathParts.slice(0, -1).join('/') || '/'; - let parentFolderName = pathParts.slice(-2, -1)[0] || '/'; - const currentFolderName = pathParts.pop() || t('root'); - - // 若為根目錄,以 'root' 顯示 - if (parentPath === '/' || parentFolderName === '/' || parentFolderName === '') { - parentFolderName = t('root'); - } - - const folderNameContainer = container.createDiv('ge-foldername-content'); - - if (folderNameContainer) { - // 建立可點擊的上層資料夾名稱 - const customFolderIcon = this.plugin.settings.customFolderIcon; - const parentFolderLink = folderNameContainer.createEl('a', { - text: `${customFolderIcon} ${parentFolderName}`.trim(), - cls: 'ge-parent-folder-link' - }); - - // 點擊後跳轉到上層資料夾 - parentFolderLink.addEventListener('click', (event) => { - event.preventDefault(); - event.stopPropagation(); - this.setSource('folder', parentPath, true); - this.clearSelection(); - }); - - // 分隔符號 - folderNameContainer.createEl('span', { text: ' > ' }); - - // 目前資料夾名稱 - folderNameContainer.createEl('span', { text: currentFolderName }); - } - } - // 如果是資料夾模式,先顯示所有子資料夾 if (this.sourceMode === 'folder' && this.searchQuery === '') { const currentFolder = this.app.vault.getAbstractFileByPath(this.sourcePath || '/'); @@ -989,6 +998,7 @@ export class GridView extends ItemView { const notePath = `${folder.path}/${folder.name}.md`; let noteFile = this.app.vault.getAbstractFileByPath(notePath); if (noteFile instanceof TFile) { + //打開資料夾筆記 menu.addItem((item) => { item .setTitle(t('open_folder_note')) @@ -997,6 +1007,7 @@ export class GridView extends ItemView { this.app.workspace.getLeaf().openFile(noteFile); }); }); + //編輯資料夾筆記設定 menu.addItem((item) => { item .setTitle(t('edit_folder_note_settings')) @@ -1014,10 +1025,6 @@ export class GridView extends ItemView { .setIcon('folder-x') .onClick(() => { this.app.fileManager.trashFile(noteFile as TFile); - // 重新渲染視圖 - setTimeout(() => { - this.render(); - }, 100); }); }); } else { @@ -1087,8 +1094,8 @@ export class GridView extends ItemView { }); } - // 資料夾渲染完插入 break(僅當有資料夾時或有顯示回上一層資料夾項目時) - if (subfolders.length > 0 || (subfolders.length === 0 && this.plugin.settings.dateDividerMode !== 'none' && this.plugin.settings.showParentFolderItem)) { + // 資料夾渲染完插入 break(僅當有資料夾) + if (subfolders.length > 0) { container.createDiv('ge-break'); } } @@ -1224,6 +1231,16 @@ export class GridView extends ItemView { const otherFiles = files.filter(f => !this.pinnedList.includes(f.name)); files = [...pinnedFiles, ...otherFiles]; } + + if (this.sourceMode === 'folder' && this.sourcePath !== '/') { + if (this.plugin.settings.folderNoteDisplaySettings === 'hidden') { + const currentFolder = this.app.vault.getAbstractFileByPath(this.sourcePath); + if (currentFolder instanceof TFolder) { + const folderName = currentFolder.name; + files = files.filter(f => f.name !== `${folderName}.md`); + } + } + } // 創建 Intersection Observer const observer = new IntersectionObserver((entries, observer) => { @@ -1599,6 +1616,14 @@ export class GridView extends ItemView { this.gridItems.push(fileEl); // 添加到網格項目數組 fileEl.dataset.filePath = file.path; + // 如果檔案與父資料夾同名,添加 ge-foldernote 類別 + const parentPath = file.parent?.path || ''; + const parentName = parentPath.split('/').pop() || ''; + const fileName = file.basename; + if (parentName === fileName) { + fileEl.addClass('ge-foldernote'); + } + // 創建左側內容區,包含圖示和標題 const contentArea = fileEl.createDiv('ge-content-area'); @@ -1897,7 +1922,7 @@ export class GridView extends ItemView { if (file instanceof TFile) { try { // 計算新的檔案路徑 - const newPath = `${folderPath}/${file.name}`; + const newPath = normalizePath(`${folderPath}/${file.name}`); // 移動檔案 await this.app.fileManager.renameFile(file, newPath); } catch (error) { @@ -1905,10 +1930,9 @@ export class GridView extends ItemView { } } } - - // 重新渲染視圖 - // this.render(); + return; + } catch (error) { console.error('Error parsing dragged files data:', error); } @@ -1931,11 +1955,10 @@ export class GridView extends ItemView { if (file instanceof TFile && folder instanceof TFolder) { try { // 計算新的檔案路徑 - const newPath = `${folderPath}/${file.name}`; + const newPath = normalizePath(`${folderPath}/${file.name}`); // 移動檔案 await this.app.fileManager.renameFile(file, newPath); - // 重新渲染視圖 - // this.render(); + } catch (error) { console.error('An error occurred while moving the file:', error); } diff --git a/src/settings.ts b/src/settings.ts index 998c457..b9f8b98 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -16,7 +16,6 @@ export interface GallerySettings { showMediaFiles: boolean; // 是否顯示圖片和影片 showVideoThumbnails: boolean; // 是否顯示影片縮圖 defaultOpenLocation: string; // 預設開啟位置 - showParentFolderItem: boolean; // 是否显示"返回上级文件夹"选项 reuseExistingLeaf: boolean; // 是否重用現有的網格視圖 showBookmarksMode: boolean; // 是否顯示書籤模式 showSearchMode: boolean; // 是否顯示搜尋結果模式 @@ -38,6 +37,7 @@ export interface GallerySettings { showNoteTags: boolean; // 是否顯示筆記標籤 dateDividerMode: string; // 日期分隔器模式:none, year, month, day showCodeBlocksInSummary: boolean; // 是否在摘要中顯示程式碼區塊 + folderNoteDisplaySettings: string; // 資料夾筆記設定 } // 預設設定 @@ -55,7 +55,6 @@ export const DEFAULT_SETTINGS: GallerySettings = { showMediaFiles: true, // 預設顯示圖片和影片 showVideoThumbnails: true, // 預設顯示影片縮圖 defaultOpenLocation: 'tab', // 預設開啟位置:新分頁 - showParentFolderItem: false, // 預設不顯示"返回上層資料夾"選項 reuseExistingLeaf: false, // 預設不重用現有的網格視圖 showBookmarksMode: true, // 預設顯示書籤模式 showSearchMode: true, // 預設顯示搜尋結果模式 @@ -77,6 +76,7 @@ export const DEFAULT_SETTINGS: GallerySettings = { showNoteTags: false, // 預設不顯示筆記標籤 dateDividerMode: 'none', // 預設不使用日期分隔器 showCodeBlocksInSummary: false, // 預設不在摘要中顯示程式碼區塊 + folderNoteDisplaySettings: 'default', // 預設不處理資料夾筆記 }; // 設定頁面類別 @@ -436,19 +436,6 @@ export class GridExplorerSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); }); }); - - // 顯示"回上層資料夾"選項設定 - new Setting(containerEl) - .setName(t('show_parent_folder_item')) - .setDesc(t('show_parent_folder_item_desc')) - .addToggle(toggle => { - toggle - .setValue(this.plugin.settings.showParentFolderItem) - .onChange(async (value) => { - this.plugin.settings.showParentFolderItem = value; - await this.plugin.saveSettings(); - }); - }); // 顯示筆記標籤設定 new Setting(containerEl) @@ -565,7 +552,25 @@ export class GridExplorerSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); })); + // 資料夾筆記設定區域 + containerEl.createEl('h3', { text: t('folder_note_settings') }); + // 資料夾筆記設定 (預設、置頂、隱藏) + new Setting(containerEl) + .setName(t('foldernote_display_settings')) + .setDesc(t('foldernote_display_settings_desc')) + .addDropdown(dropdown => { + dropdown + .addOption('default', t('default')) + .addOption('pinned', t('pinned')) + .addOption('hidden', t('hidden')) + .setValue(this.plugin.settings.folderNoteDisplaySettings) + .onChange(async (value) => { + this.plugin.settings.folderNoteDisplaySettings = value; + await this.plugin.saveSettings(); + }); + }); + // 忽略資料夾設定區域 containerEl.createEl('h3', { text: t('ignored_folders_settings') }); diff --git a/src/translations.ts b/src/translations.ts index 412fda9..62bbe3e 100644 --- a/src/translations.ts +++ b/src/translations.ts @@ -43,6 +43,7 @@ export const TRANSLATIONS: Translations = { 'files': '個檔案', 'add': '新增', 'root': '根目錄', + 'more_options': '更多選項', // 視圖標題 'grid_view_title': '網格視圖', @@ -130,7 +131,11 @@ export const TRANSLATIONS: Translations = { 'task_filter': '任務分類', 'uncompleted': '未完成', 'completed': '已完成', + 'foldernote_display_settings': '資料夾筆記顯示設定', + 'foldernote_display_settings_desc': '設定資料夾筆記的顯示方式', 'all': '全部', + 'default': '預設', + 'hidden': '隱藏', // 顯示"返回上層資料夾"選項設定 'show_parent_folder_item': '顯示「返回上層資料夾」', @@ -243,6 +248,7 @@ export const TRANSLATIONS: Translations = { 'files': 'files', 'add': 'Add', 'root': 'Root', + 'more_options': 'More options', // View Titles 'grid_view_title': 'Grid view', @@ -330,7 +336,11 @@ export const TRANSLATIONS: Translations = { 'task_filter': 'Task filter', 'uncompleted': 'Uncompleted', 'completed': 'Completed', + 'foldernote_display_settings': 'Folder note display settings', + 'foldernote_display_settings_desc': 'Set the display mode of folder notes', 'all': 'All', + 'default': 'Default', + 'hidden': 'Hidden', // Show "Parent Folder" option setting 'show_parent_folder_item': 'Show "Parent Folder" item', @@ -443,6 +453,7 @@ export const TRANSLATIONS: Translations = { 'files': '个文件', 'add': '添加', 'root': '根目录', + 'more_options': '更多选项', // 视图标题 'grid_view_title': '网格视图', @@ -530,7 +541,11 @@ export const TRANSLATIONS: Translations = { 'task_filter': '任务分类', 'uncompleted': '未完成', 'completed': '已完成', + 'foldernote_display_settings': '文件夹笔记显示设置', + 'foldernote_display_settings_desc': '设置文件夹笔记的显示方式', 'all': '全部', + 'default': '默认', + 'hidden': '隐藏', // 显示"返回上级文件夹"选项设置 'show_parent_folder_item': '显示「返回上级文件夹」', @@ -643,6 +658,7 @@ export const TRANSLATIONS: Translations = { 'files': 'ファイル', 'add': '追加', 'root': 'ルート', + 'more_options': 'もっと選択肢', // ビュータイトル 'grid_view_title': 'グリッドビュー', @@ -730,7 +746,11 @@ export const TRANSLATIONS: Translations = { 'task_filter': 'タスクフィルタ', 'uncompleted': '未完了', 'completed': '完了', + 'foldernote_display_settings': 'フォルダノートの表示設定', + 'foldernote_display_settings_desc': 'フォルダノートの表示方法を設定します', 'all': 'すべて', + 'default': 'デフォルト', + 'hidden': '隠す', // "親フォルダ"オプション設定を表示 'show_parent_folder_item': '「親フォルダ」項目を表示', @@ -843,6 +863,7 @@ export const TRANSLATIONS: Translations = { 'files': 'файлы', 'add': 'Добавить', 'root': 'Корень', + 'more_options': 'Больше опций', // View Titles 'grid_view_title': 'Сеточный вид', @@ -930,7 +951,11 @@ export const TRANSLATIONS: Translations = { 'task_filter': 'Фильтр задач', 'uncompleted': 'Незавершенные', 'completed': 'Завершенные', + 'foldernote_display_settings': 'Настройки отображения заметок папок', + 'foldernote_display_settings_desc': 'Установить режим отображения заметок папок', 'all': 'Все', + 'default': 'По умолчанию', + 'hidden': 'Скрытые', // Show "Parent Folder" option setting 'show_parent_folder_item': 'Показывать элемент "Родительская папка"', @@ -1043,6 +1068,7 @@ export const TRANSLATIONS: Translations = { 'files': 'файли', 'add': 'Додати', 'root': 'Корень', + 'more_options': 'Більше опцій', // View Titles 'grid_view_title': 'Сітковий вигляд', @@ -1130,7 +1156,11 @@ export const TRANSLATIONS: Translations = { 'task_filter': 'Фільтр завдань', 'uncompleted': 'Незавершені', 'completed': 'Завершені', + 'foldernote_display_settings': 'Налаштування відображення нотаток папки', + 'foldernote_display_settings_desc': 'Встановіть режим відображення нотаток папки', 'all': 'Всі', + 'default': 'По умолчанию', + 'hidden': 'Сховати', // Show "Parent Folder" option setting 'show_parent_folder_item': 'Показувати елемент "Батьківська папка"', diff --git a/styles.css b/styles.css index bc8957c..cb4c277 100644 --- a/styles.css +++ b/styles.css @@ -16,6 +16,13 @@ background-color: var(--background-modifier-hover); } +/* ascii tree prefix */ +.ge-folder-tree-prefix { + font-family: monospace; + white-space: pre; + color: var(--text-muted); +} + /* Grid 樣式 */ .ge-grid-container { display: grid; @@ -327,11 +334,10 @@ } .ge-foldername-content { - grid-column: 1 / -1; - margin-top: -2px; - margin-bottom: -3px; - margin-left: 7px; justify-content: center; + padding: 8px; + background-color: var(--background-secondary); + border-bottom: 1px solid var(--background-modifier-border); } .ge-foldername-content span { @@ -341,6 +347,7 @@ /* 為資料夾名稱、分隔符等元素添加間距 */ .ge-foldername-content > *:nth-child(1) { + margin-left: 11px; margin-right: 3px; } @@ -359,6 +366,11 @@ text-decoration: none; } +.ge-parent-folder-link.ge-dragover { + border: 2px dashed var(--interactive-accent); + transform: scale(1.05); +} + /* 搜尋對話框樣式 */ .ge-search-container { margin-bottom: 8px; diff --git a/versions.json b/versions.json index 14ee751..b293a73 100644 --- a/versions.json +++ b/versions.json @@ -1,3 +1,3 @@ { - "2.3.0": "1.1.0" + "2.4.0": "1.1.0" } \ No newline at end of file