This commit is contained in:
Devon22 2025-04-09 00:22:38 +08:00
parent 8389bf04fc
commit a414b60cb0
10 changed files with 258 additions and 13 deletions

View file

@ -1,7 +1,7 @@
{
"id": "gridexplorer",
"name": "GridExplorer",
"version": "1.9.8",
"version": "1.9.9",
"minAppVersion": "1.1.0",
"description": "Browse note files in a grid view.",
"author": "Devon22",

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "gridexplorer",
"version": "1.9.8",
"version": "1.9.9",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gridexplorer",
"version": "1.9.8",
"version": "1.9.9",
"license": "MIT",
"devDependencies": {
"@types/node": "^16.11.6",

View file

@ -1,6 +1,6 @@
{
"name": "gridexplorer",
"version": "1.9.8",
"version": "1.9.9",
"description": "Browse note files in a grid view.",
"main": "main.js",
"scripts": {

View file

@ -86,6 +86,17 @@ export class FileWatcher {
}
})
);
// 監聽當前開啟的檔案變更,讀取反向連結
this.plugin.registerEvent(
this.app.workspace.on('file-open', (file) => {
if (file instanceof TFile) {
if (this.gridView.sourceMode === 'backlinks' && this.gridView.searchQuery === '') {
this.gridView.render();
}
}
})
);
}
}

84
src/FolderRenameModal.ts Normal file
View file

@ -0,0 +1,84 @@
import { App, Modal, Setting, TFolder } from 'obsidian';
import { t } from './translations';
import GridExplorerPlugin from '../main';
import { GridView } from './GridView';
export function showFolderRenameModal(app: App, plugin: GridExplorerPlugin, folder: TFolder, gridView: GridView) {
new FolderRenameModal(app, plugin, folder, gridView).open();
}
export class FolderRenameModal extends Modal {
plugin: GridExplorerPlugin;
folder: TFolder;
gridView: GridView;
newName: string;
constructor(app: App, plugin: GridExplorerPlugin, folder: TFolder, gridView: GridView) {
super(app);
this.plugin = plugin;
this.folder = folder;
this.gridView = gridView;
this.newName = folder.name;
}
onOpen() {
const { contentEl } = this;
contentEl.empty();
// 如果有 GridView 實例,禁用其鍵盤導航
if (this.gridView) {
this.gridView.disableKeyboardNavigation();
}
new Setting(contentEl)
.setName(t('rename_folder'))
.setDesc(t('enter_new_folder_name'))
.addText(text => {
text
.setValue(this.folder.name)
.onChange(value => {
this.newName = value;
});
});
new Setting(contentEl)
.addButton(button => {
button
.setButtonText(t('confirm'))
.setCta()
.onClick(() => {
this.renameFolder();
this.close();
});
})
.addButton(button => {
button
.setButtonText(t('cancel'))
.onClick(() => {
this.close();
});
});
}
async renameFolder() {
try {
await this.app.fileManager.renameFile(this.folder, this.newName);
// 重新渲染視圖
setTimeout(() => {
this.gridView.render();
}, 100);
} catch (error) {
console.error('Failed to rename folder', error);
}
}
onClose() {
const { contentEl } = this;
contentEl.empty();
// 如果有 GridView 實例,重新啟用其鍵盤導航
if (this.gridView) {
this.gridView.enableKeyboardNavigation();
}
}
}

View file

@ -1,4 +1,4 @@
import { App, Modal, Setting, Platform } from 'obsidian';
import { App, Modal, Platform } from 'obsidian';
import { GridView } from './GridView';
import { t } from './translations';
import GridExplorerPlugin from '../main';

View file

@ -5,6 +5,7 @@ import { findFirstImageInNote } from './mediaUtils';
import { MediaModal } from './MediaModal';
import { showFolderNoteSettingsModal } from './FolderNoteSettingsModal';
import { showNoteColorSettingsModal } from './NoteColorSettingsModal';
import { showFolderRenameModal } from './FolderRenameModal';
import { showSearchModal } from './SearchModal';
import { FileWatcher } from './FileWatcher';
import { t } from './translations';
@ -102,10 +103,10 @@ export class GridView extends ItemView {
}
}
async setSource(mode: string, path = '', resetScroll = false) {
async setSource(mode: string, path = '', resetScroll = false, recordHistory = true) {
// 記錄之前的狀態到歷史記錄中(如果有)
if (this.sourceMode) {
if (this.sourceMode && recordHistory) {
const previousState = JSON.stringify({ mode: this.sourceMode, path: this.sourcePath });
this.recentSources.unshift(previousState);
// 限制歷史記錄數量為10個
@ -170,6 +171,11 @@ export class GridView extends ItemView {
}
return [];
} else if (this.sourceMode === 'backlinks') {
if(this.searchQuery !== '') {
return [];
}
// 反向連結模式:找出所有引用當前筆記的檔案
const activeFile = this.app.workspace.getActiveFile();
if (!activeFile) {
@ -188,7 +194,7 @@ export class GridView extends ItemView {
}
}
return this.sortFiles(this.ignoredFiles(Array.from(backlinks) as TFile[]));
return this.sortFiles(Array.from(backlinks) as TFile[]);
} else if(this.sourceMode === 'bookmarks') {
// 書籤模式
const bookmarksPlugin = (this.app as any).internalPlugins.plugins.bookmarks;
@ -499,6 +505,64 @@ export class GridView extends ItemView {
});
setIcon(newNoteButton, 'square-pen');
newNoteButton.addEventListener('contextmenu', (event) => {
event.preventDefault();
const menu = new Menu();
// 新增筆記
menu.addItem((item) => {
item
.setTitle(t('new_note'))
.setIcon('square-pen')
.onClick(async () => {
let newFileName = `${t('untitled')}.md`;
let newFilePath = !this.sourcePath || this.sourcePath === '/' ? newFileName : `${this.sourcePath}/${newFileName}`;
// 檢查檔案是否已存在,如果存在則遞增編號
let counter = 1;
while (this.app.vault.getAbstractFileByPath(newFilePath)) {
newFileName = `${t('untitled')} ${counter}.md`;
newFilePath = !this.sourcePath || this.sourcePath === '/' ? newFileName : `${this.sourcePath}/${newFileName}`;
counter++;
}
try {
// 建立新筆記
const newFile = await this.app.vault.create(newFilePath, '');
// 開啟新筆記
await this.app.workspace.getLeaf().openFile(newFile);
} catch (error) {
console.error('An error occurred while creating a new note:', error);
}
});
});
// 新增資料夾
menu.addItem((item) => {
item.setTitle(t('new_folder'))
.setIcon('folder')
.onClick(async () => {
let newFolderName = `${t('untitled')}`;
let newFolderPath = !this.sourcePath || this.sourcePath === '/' ? newFolderName : `${this.sourcePath}/${newFolderName}`;
// 檢查資料夾是否已存在,如果存在則遞增編號
let counter = 1;
while (this.app.vault.getAbstractFileByPath(newFolderPath)) {
newFolderName = `${t('untitled')} ${counter}`;
newFolderPath = !this.sourcePath || this.sourcePath === '/' ? newFolderName : `${this.sourcePath}/${newFolderName}`;
counter++;
}
try {
// 建立新資料夾
await this.app.vault.createFolder(newFolderPath);
this.render(false);
} catch (error) {
console.error('An error occurred while creating a new folder:', error);
}
});
});
menu.showAtMouseEvent(event);
});
// 添加回上層按鈕(僅在資料夾模式且不在根目錄時顯示)
if (this.sourceMode === 'folder' && this.sourcePath !== '/' && this.searchQuery === '') {
const upButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('go_up') } });
@ -655,7 +719,18 @@ export class GridView extends ItemView {
.setTitle(`${displayText}`)
.setIcon(`${icon}`)
.onClick(() => {
this.setSource(mode, path, true);
// 找出當前點擊的紀錄索引
const clickedIndex = this.recentSources.findIndex(source => {
const parsed = JSON.parse(source);
return parsed.mode === mode && parsed.path === path;
});
// 如果找到點擊的紀錄,清除它之上的紀錄
if (clickedIndex !== -1) {
this.recentSources = this.recentSources.slice(clickedIndex + 1);
}
this.setSource(mode, path, true, false);
});
});
} catch (error) {
@ -792,6 +867,9 @@ export class GridView extends ItemView {
});
}
// 創建資料夾夾名稱區域
// headerButtonsDiv.createDiv('ge-foldername-content');
// 創建內容區域
const contentEl = this.containerEl.createDiv('view-content');
@ -851,6 +929,21 @@ export class GridView extends ItemView {
return;
}
// 如果是資料夾模式且沒有搜尋結果,顯示目前資料夾名稱
// if (this.sourceMode === 'folder' && this.searchQuery === '' && this.sourcePath !== '/') {
// const folderName = this.sourcePath.split('/').pop();
// const folderNameContainer = this.containerEl.querySelector('.ge-foldername-content') as HTMLElement;
// if (folderNameContainer) {
// folderNameContainer.createEl('span', { text: `📁 ${folderName}` });
// }
// } else {
// const folderNameContainer = this.containerEl.querySelector('.ge-foldername-content') as HTMLElement;
// if (folderNameContainer) {
// folderNameContainer.empty();
// folderNameContainer.style.display = 'none';
// }
// }
// 如果啟用了顯示"回上層資料夾"選項
if (this.sourceMode === 'folder' && this.searchQuery === '' &&
this.plugin.settings.showParentFolderItem && this.sourcePath !== '/') {
@ -992,10 +1085,9 @@ export class GridView extends ItemView {
});
//刪除資料夾筆記
menu.addItem((item) => {
(item as any).setWarning(true);
item
.setTitle(t('delete_folder_note'))
.setIcon('trash')
.setIcon('folder-x')
.onClick(() => {
this.app.fileManager.trashFile(noteFile as TFile);
// 重新渲染視圖
@ -1025,7 +1117,33 @@ export class GridView extends ItemView {
.onClick(() => {
this.plugin.settings.ignoredFolders.push(folder.path);
this.plugin.saveSettings();
this.render();
});
});
// 重新命名資料夾
menu.addItem((item) => {
item
.setTitle(t('rename_folder'))
.setIcon('file-cog')
.onClick(() => {
if (folder instanceof TFolder) {
showFolderRenameModal(this.app, this.plugin, folder, this);
}
});
});
//刪除資料夾
menu.addItem((item) => {
(item as any).setWarning(true);
item
.setTitle(t('delete_folder'))
.setIcon('trash')
.onClick(async () => {
if (folder instanceof TFolder) {
await this.app.fileManager.trashFile(folder);
// 重新渲染視圖
setTimeout(() => {
this.render();
}, 100);
}
});
});
menu.showAtMouseEvent(event);

View file

@ -34,6 +34,8 @@ export const TRANSLATIONS: Translations = {
'search_current_location_only': '僅搜尋目前位置',
'cancel': '取消',
'new_note': '新增筆記',
'new_folder': '新增資料夾',
'delete_folder': '刪除資料夾',
'untitled': '未命名',
'files': '個檔案',
'add': '新增',
@ -168,6 +170,8 @@ export const TRANSLATIONS: Translations = {
'note_color': '筆記顏色',
'note_color_desc': '設定此筆記的顯示顏色',
'set_note_color': '設定筆記顏色',
'rename_folder': '重新命名資料夾',
'enter_new_folder_name': '輸入新資料夾名稱',
},
'en': {
// Notifications
@ -184,6 +188,8 @@ export const TRANSLATIONS: Translations = {
'search_current_location_only': 'Search current location only',
'cancel': 'Cancel',
'new_note': 'New note',
'new_folder': 'New folder',
'delete_folder': 'Delete folder',
'untitled': 'Untitled',
'files': 'files',
'add': 'Add',
@ -318,6 +324,8 @@ export const TRANSLATIONS: Translations = {
'note_color': 'Note color',
'note_color_desc': 'Set the display color for this note',
'set_note_color': 'Set note color',
'rename_folder': 'Rename folder',
'enter_new_folder_name': 'Enter new folder name',
},
'zh': {
// 通知信息
@ -334,6 +342,8 @@ export const TRANSLATIONS: Translations = {
'search_current_location_only': '仅搜索当前位置',
'cancel': '取消',
'new_note': '新建笔记',
'new_folder': '新建文件夹',
'delete_folder': '删除文件夹',
'untitled': '未命名',
'files': '个文件',
'add': '添加',
@ -468,6 +478,8 @@ export const TRANSLATIONS: Translations = {
'note_color': '笔记颜色',
'note_color_desc': '设置此笔记的显示颜色',
'set_note_color': '设置笔记颜色',
'rename_folder': '重新命名文件夹',
'enter_new_folder_name': '输入新文件夹名称',
},
'ja': {
// 通知メッジ
@ -484,6 +496,8 @@ export const TRANSLATIONS: Translations = {
'search_current_location_only': '現在の場所のみ検索',
'cancel': 'キャンセル',
'new_note': '新規ノート',
'new_folder': '新規フォルダ',
'delete_folder': '削除フォルダ',
'untitled': '無題',
'files': 'ファイル',
'add': '追加',
@ -618,5 +632,7 @@ export const TRANSLATIONS: Translations = {
'note_color': 'ノート色',
'note_color_desc': 'このノートの表示色を設定',
'set_note_color': 'ノート色を設定',
'rename_folder': 'フォルダを再命名',
'enter_new_folder_name': '新しいフォルダ名を入力',
}
}

View file

@ -257,6 +257,22 @@
align-items: center;
}
/* .ge-foldername-content {
margin-top: 5px;
flex-basis: 100%;
order: 1;
display: flex;
justify-content: center;
background-color: var(--background-secondary);
border-radius: var(--button-radius);
}
.ge-foldername-content span {
display: inline-flex;
align-items: center;
justify-content: center;
} */
/* 搜尋對話框樣式 */
.ge-search-container {
margin-bottom: 8px;

View file

@ -1,3 +1,3 @@
{
"1.9.8": "1.1.0"
"1.9.9": "1.1.0"
}