mirror of
https://github.com/devon22/obsidian-gridexplorer.git
synced 2026-07-22 12:00:25 +00:00
Add files via upload
This commit is contained in:
parent
2f1f16b4e3
commit
f8ed01b549
3 changed files with 257 additions and 32 deletions
|
|
@ -11,6 +11,11 @@ export function showFolderSelectionModal(app: App, plugin: GridExplorerPlugin, a
|
|||
export class FolderSelectionModal extends Modal {
|
||||
plugin: GridExplorerPlugin;
|
||||
activeView: GridView | undefined;
|
||||
folderOptionsContainer: HTMLElement;
|
||||
folderOptions: HTMLElement[] = [];
|
||||
selectedIndex: number = -1; // 當前選中的選項索引
|
||||
searchInput: HTMLInputElement;
|
||||
|
||||
constructor(app: App, plugin: GridExplorerPlugin, activeView?: GridView) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
|
|
@ -22,11 +27,33 @@ export class FolderSelectionModal extends Modal {
|
|||
contentEl.empty();
|
||||
new Setting(contentEl).setName(t('select_folders')).setHeading();
|
||||
|
||||
// 添加搜尋輸入框
|
||||
const searchContainer = contentEl.createEl('div', { cls: 'ge-folder-search-container' });
|
||||
this.searchInput = searchContainer.createEl('input', {
|
||||
cls: 'ge-folder-search-input',
|
||||
attr: {
|
||||
type: 'text',
|
||||
placeholder: t('filter_folders')
|
||||
}
|
||||
});
|
||||
|
||||
// 創建一個容器來存放所有資料夾選項
|
||||
this.folderOptionsContainer = contentEl.createEl('div', { cls: 'ge-folder-options-container' });
|
||||
|
||||
// 搜尋輸入事件處理
|
||||
this.searchInput.addEventListener('input', () => {
|
||||
const searchTerm = this.searchInput.value.toLowerCase();
|
||||
this.filterFolderOptions(searchTerm);
|
||||
});
|
||||
|
||||
// 鍵盤事件處理
|
||||
this.searchInput.addEventListener('keydown', this.handleKeyDown.bind(this));
|
||||
|
||||
// 建立書籤選項
|
||||
const bookmarksPlugin = (this.app as any).internalPlugins.plugins.bookmarks;
|
||||
if (bookmarksPlugin?.enabled) {
|
||||
const bookmarkOption = contentEl.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option',
|
||||
const bookmarkOption = this.folderOptionsContainer.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option ge-special-option',
|
||||
text: `📑 ${t('bookmarks_mode')}`
|
||||
});
|
||||
|
||||
|
|
@ -38,18 +65,19 @@ export class FolderSelectionModal extends Modal {
|
|||
}
|
||||
this.close();
|
||||
});
|
||||
this.folderOptions.push(bookmarkOption);
|
||||
}
|
||||
|
||||
// 建立搜尋結果選項
|
||||
const searchLeaf = (this.app as any).workspace.getLeavesOfType('search')[0];
|
||||
if (searchLeaf) {
|
||||
const searchView = searchLeaf.view;
|
||||
const searchInput = searchView.searchComponent ? searchView.searchComponent.inputEl : null;
|
||||
if(searchInput) {
|
||||
if (searchInput.value.trim().length > 0) {
|
||||
const searchOption = contentEl.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option',
|
||||
text: `🔍 ${t('search_results')}: ${searchInput.value}`
|
||||
const searchInputEl = searchView.searchComponent ? searchView.searchComponent.inputEl : null;
|
||||
if(searchInputEl) {
|
||||
if (searchInputEl.value.trim().length > 0) {
|
||||
const searchOption = this.folderOptionsContainer.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option ge-special-option',
|
||||
text: `🔍 ${t('search_results')}: ${searchInputEl.value}`
|
||||
});
|
||||
|
||||
searchOption.addEventListener('click', () => {
|
||||
|
|
@ -60,6 +88,7 @@ export class FolderSelectionModal extends Modal {
|
|||
}
|
||||
this.close();
|
||||
});
|
||||
this.folderOptions.push(searchOption);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -68,8 +97,8 @@ export class FolderSelectionModal extends Modal {
|
|||
const activeFile = this.app.workspace.getActiveFile();
|
||||
if (activeFile) {
|
||||
const activeFileName = activeFile ? `: ${activeFile.basename}` : '';
|
||||
const backlinksOption = contentEl.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option',
|
||||
const backlinksOption = this.folderOptionsContainer.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option ge-special-option',
|
||||
text: `🔗 ${t('backlinks_mode')}${activeFileName}`
|
||||
});
|
||||
|
||||
|
|
@ -81,11 +110,12 @@ export class FolderSelectionModal extends Modal {
|
|||
}
|
||||
this.close();
|
||||
});
|
||||
this.folderOptions.push(backlinksOption);
|
||||
}
|
||||
|
||||
// 建立所有筆記選項
|
||||
const allNotesOption = contentEl.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option',
|
||||
const allNotesOption = this.folderOptionsContainer.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option ge-special-option',
|
||||
text: `📔 ${t('all_notes_mode')}`
|
||||
});
|
||||
|
||||
|
|
@ -97,9 +127,10 @@ export class FolderSelectionModal extends Modal {
|
|||
}
|
||||
this.close();
|
||||
});
|
||||
this.folderOptions.push(allNotesOption);
|
||||
|
||||
// 建立根目錄選項
|
||||
const rootFolderOption = contentEl.createEl('div', {
|
||||
const rootFolderOption = this.folderOptionsContainer.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option',
|
||||
text: `📁 /`
|
||||
});
|
||||
|
|
@ -112,6 +143,7 @@ export class FolderSelectionModal extends Modal {
|
|||
}
|
||||
this.close();
|
||||
});
|
||||
this.folderOptions.push(rootFolderOption);
|
||||
|
||||
// 取得所有資料夾(排除被忽略的資料夾)
|
||||
const folders = this.app.vault.getAllFolders()
|
||||
|
|
@ -125,7 +157,7 @@ export class FolderSelectionModal extends Modal {
|
|||
|
||||
// 建立資料夾選項
|
||||
folders.forEach(folder => {
|
||||
const folderOption = contentEl.createEl('div', {
|
||||
const folderOption = this.folderOptionsContainer.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option',
|
||||
text: `📁 ${folder.path || '/'}`
|
||||
});
|
||||
|
|
@ -138,7 +170,127 @@ export class FolderSelectionModal extends Modal {
|
|||
}
|
||||
this.close();
|
||||
});
|
||||
this.folderOptions.push(folderOption);
|
||||
});
|
||||
|
||||
// 為每個選項添加滑鼠事件
|
||||
this.folderOptions.forEach((option, index) => {
|
||||
option.addEventListener('mouseenter', () => {
|
||||
this.updateSelection(index);
|
||||
});
|
||||
});
|
||||
|
||||
// 設置初始焦點到搜尋輸入框
|
||||
this.searchInput.focus();
|
||||
}
|
||||
|
||||
// 處理鍵盤事件
|
||||
handleKeyDown(event: KeyboardEvent) {
|
||||
const visibleOptions = this.getVisibleOptions();
|
||||
|
||||
if (visibleOptions.length === 0) return;
|
||||
|
||||
switch (event.key) {
|
||||
case 'ArrowDown':
|
||||
event.preventDefault();
|
||||
this.moveSelection(1, visibleOptions);
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
event.preventDefault();
|
||||
this.moveSelection(-1, visibleOptions);
|
||||
break;
|
||||
case 'Enter':
|
||||
event.preventDefault();
|
||||
if (this.selectedIndex >= 0) {
|
||||
const selectedOption = this.folderOptions[this.selectedIndex];
|
||||
if (selectedOption && selectedOption.style.display !== 'none') {
|
||||
selectedOption.click();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'Escape':
|
||||
this.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 移動選擇
|
||||
moveSelection(direction: number, visibleOptions: HTMLElement[]) {
|
||||
// 如果沒有選中項或當前選中項不可見,則從頭開始
|
||||
let currentVisibleIndex = -1;
|
||||
|
||||
if (this.selectedIndex >= 0) {
|
||||
const selectedOption = this.folderOptions[this.selectedIndex];
|
||||
currentVisibleIndex = visibleOptions.indexOf(selectedOption);
|
||||
}
|
||||
|
||||
// 計算新的可見索引
|
||||
let newVisibleIndex = currentVisibleIndex + direction;
|
||||
|
||||
// 循環選擇
|
||||
if (newVisibleIndex < 0) {
|
||||
newVisibleIndex = visibleOptions.length - 1;
|
||||
} else if (newVisibleIndex >= visibleOptions.length) {
|
||||
newVisibleIndex = 0;
|
||||
}
|
||||
|
||||
// 轉換為實際的選項索引
|
||||
if (newVisibleIndex >= 0 && newVisibleIndex < visibleOptions.length) {
|
||||
const newSelectedOption = visibleOptions[newVisibleIndex];
|
||||
const newIndex = this.folderOptions.indexOf(newSelectedOption);
|
||||
this.updateSelection(newIndex);
|
||||
|
||||
// 確保選中項在視圖中可見
|
||||
newSelectedOption.scrollIntoView({ block: 'nearest' });
|
||||
}
|
||||
}
|
||||
|
||||
// 更新選擇
|
||||
updateSelection(index: number) {
|
||||
// 清除之前的選擇
|
||||
if (this.selectedIndex >= 0 && this.selectedIndex < this.folderOptions.length) {
|
||||
this.folderOptions[this.selectedIndex].removeClass('ge-selected-option');
|
||||
}
|
||||
|
||||
this.selectedIndex = index;
|
||||
|
||||
// 設置新的選擇
|
||||
if (this.selectedIndex >= 0 && this.selectedIndex < this.folderOptions.length) {
|
||||
this.folderOptions[this.selectedIndex].addClass('ge-selected-option');
|
||||
}
|
||||
}
|
||||
|
||||
// 獲取當前可見的選項
|
||||
getVisibleOptions(): HTMLElement[] {
|
||||
return this.folderOptions.filter(option =>
|
||||
option.style.display !== 'none'
|
||||
);
|
||||
}
|
||||
|
||||
// 篩選資料夾選項
|
||||
filterFolderOptions(searchTerm: string) {
|
||||
let hasVisibleOptions = false;
|
||||
|
||||
this.folderOptions.forEach(option => {
|
||||
const text = option.textContent?.toLowerCase() || '';
|
||||
if (searchTerm === '' || text.includes(searchTerm)) {
|
||||
option.style.display = 'block';
|
||||
hasVisibleOptions = true;
|
||||
} else {
|
||||
option.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// 重置選擇,並選中第一個可見選項(如果有)
|
||||
this.updateSelection(-1);
|
||||
|
||||
if (hasVisibleOptions) {
|
||||
const visibleOptions = this.getVisibleOptions();
|
||||
if (visibleOptions.length > 0) {
|
||||
const firstVisibleIndex = this.folderOptions.indexOf(visibleOptions[0]);
|
||||
this.updateSelection(firstVisibleIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClose() {
|
||||
|
|
|
|||
100
src/settings.ts
100
src/settings.ts
|
|
@ -32,22 +32,6 @@ export class GridExplorerSettingTab extends PluginSettingTab {
|
|||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
|
||||
// 忽略的資料夾設定
|
||||
new Setting(containerEl)
|
||||
.setName(t('ignored_folders'))
|
||||
.setDesc(t('ignored_folders_desc'))
|
||||
.addTextArea(text => text
|
||||
.setPlaceholder(t('ignored_folders_placeholder'))
|
||||
.setValue(this.plugin.settings.ignoredFolders.join('\n'))
|
||||
.onChange(async (value) => {
|
||||
// 將文字區域的內容轉換為陣列,並過濾掉空行
|
||||
this.plugin.settings.ignoredFolders = value
|
||||
.split('\n')
|
||||
.map(folder => folder.trim())
|
||||
.filter(folder => folder.length > 0);
|
||||
await this.plugin.saveSettings();
|
||||
}).inputEl.rows = 8);
|
||||
|
||||
// 預設排序模式設定
|
||||
new Setting(containerEl)
|
||||
.setName(t('default_sort_type'))
|
||||
|
|
@ -112,5 +96,89 @@ export class GridExplorerSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
// 忽略的資料夾設定
|
||||
const ignoredFoldersContainer = containerEl.createDiv('ignored-folders-container');
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t('ignored_folders'))
|
||||
.setDesc(t('ignored_folders_desc'))
|
||||
.setHeading();
|
||||
|
||||
// 新增資料夾選擇器
|
||||
new Setting(ignoredFoldersContainer)
|
||||
.setName(t('add_ignored_folder'))
|
||||
.addDropdown(dropdown => {
|
||||
// 獲取所有資料夾
|
||||
const folders = this.app.vault.getAllFolders()
|
||||
.filter(folder => folder.path !== '/') // 排除根目錄
|
||||
.sort((a, b) => a.path.localeCompare(b.path));
|
||||
|
||||
// 新增空選項作為預設值
|
||||
dropdown.addOption('', t('select_folders'));
|
||||
|
||||
// 新增所有資料夾作為選項
|
||||
folders.forEach(folder => {
|
||||
// 只顯示尚未被忽略的資料夾
|
||||
if (!this.plugin.settings.ignoredFolders.includes(folder.path)) {
|
||||
dropdown.addOption(folder.path, folder.path);
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.onChange(async (value) => {
|
||||
if (value) {
|
||||
// 新增到忽略列表
|
||||
this.plugin.settings.ignoredFolders.push(value);
|
||||
await this.plugin.saveSettings();
|
||||
|
||||
// 重新渲染列表
|
||||
this.renderIgnoredFoldersList(ignoredFoldersList);
|
||||
|
||||
// 重設下拉選單
|
||||
dropdown.setValue('');
|
||||
this.display();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 顯示目前已忽略的資料夾列表
|
||||
const ignoredFoldersList = ignoredFoldersContainer.createDiv('ge-ignored-folders-list');
|
||||
this.renderIgnoredFoldersList(ignoredFoldersList);
|
||||
|
||||
containerEl.appendChild(ignoredFoldersContainer);
|
||||
}
|
||||
|
||||
// 渲染已忽略的資料夾列表
|
||||
renderIgnoredFoldersList(containerEl: HTMLElement) {
|
||||
containerEl.empty();
|
||||
|
||||
if (this.plugin.settings.ignoredFolders.length === 0) {
|
||||
containerEl.createEl('p', { text: t('no_ignored_folders') });
|
||||
return;
|
||||
}
|
||||
|
||||
const list = containerEl.createEl('ul', { cls: 'ge-ignored-folders-list' });
|
||||
|
||||
this.plugin.settings.ignoredFolders.forEach(folder => {
|
||||
const item = list.createEl('li', { cls: 'ge-ignored-folder-item' });
|
||||
|
||||
item.createSpan({ text: folder, cls: 'ge-ignored-folder-path' });
|
||||
|
||||
const removeButton = item.createEl('button', {
|
||||
cls: 'ge-ignored-folder-remove',
|
||||
text: t('remove')
|
||||
});
|
||||
|
||||
removeButton.addEventListener('click', async () => {
|
||||
// 從忽略列表中移除
|
||||
this.plugin.settings.ignoredFolders = this.plugin.settings.ignoredFolders
|
||||
.filter(f => f !== folder);
|
||||
await this.plugin.saveSettings();
|
||||
|
||||
// 重新渲染列表
|
||||
this.renderIgnoredFoldersList(containerEl);
|
||||
this.display();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,8 @@ type LanguageKey = keyof Translations;
|
|||
|
||||
// 全域翻譯函式
|
||||
export function t(key: string): string {
|
||||
const lang: LanguageKey = getLanguage() as LanguageKey;
|
||||
const lang = window.localStorage.getItem('language') as LanguageKey;
|
||||
//const lang: LanguageKey = getLanguage() as LanguageKey;
|
||||
const translations = TRANSLATIONS[lang] || TRANSLATIONS['en'];
|
||||
return translations[key] || key;
|
||||
}
|
||||
|
|
@ -76,6 +77,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'open_in_new_tab': '在新分頁開啟',
|
||||
'searching': '搜尋中...',
|
||||
'no_files': '沒有找到任何筆記',
|
||||
'filter_folders': '篩選資料夾...',
|
||||
},
|
||||
'en': {
|
||||
// Notifications
|
||||
|
|
@ -135,6 +137,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'open_in_new_tab': 'Open in new tab',
|
||||
'searching': 'Searching...',
|
||||
'no_files': 'No notes found',
|
||||
'filter_folders': 'Filter folders...',
|
||||
},
|
||||
'zh': {
|
||||
// 通知信息
|
||||
|
|
@ -191,9 +194,10 @@ export const TRANSLATIONS: Translations = {
|
|||
'open_grid_view': '开启网格视图',
|
||||
'open_in_grid_view': '在网格视图中开启',
|
||||
'delete_note': '删除笔记',
|
||||
'open_in_new_tab': '在新分頁開啟',
|
||||
'open_in_new_tab': '在新标签页打开',
|
||||
'searching': '搜索中...',
|
||||
'no_files': '没有找到任何笔记',
|
||||
'filter_folders': '筛选文件夹...',
|
||||
},
|
||||
'ja': {
|
||||
// 通知メッジ
|
||||
|
|
@ -253,5 +257,6 @@ export const TRANSLATIONS: Translations = {
|
|||
'open_in_new_tab': '新しいタブで開く',
|
||||
'searching': '検索中...',
|
||||
'no_files': 'ノートが見つかりません',
|
||||
'filter_folders': 'フォルダをフィルタリング...',
|
||||
},
|
||||
};
|
||||
Loading…
Reference in a new issue