mirror of
https://github.com/devon22/obsidian-gridexplorer.git
synced 2026-07-22 05:38:16 +00:00
3.1.0
This commit is contained in:
parent
1377a052c7
commit
5003d6d7a8
15 changed files with 232 additions and 150 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "gridexplorer",
|
||||
"name": "GridExplorer",
|
||||
"version": "3.0.9",
|
||||
"version": "3.1.0",
|
||||
"minAppVersion": "1.1.0",
|
||||
"description": "Browse note files in a grid view.",
|
||||
"author": "Devon22",
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "gridexplorer",
|
||||
"version": "3.0.9",
|
||||
"version": "3.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gridexplorer",
|
||||
"version": "3.0.9",
|
||||
"version": "3.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@esbuild/linux-x64": "0.17.3",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "gridexplorer",
|
||||
"version": "3.0.9",
|
||||
"version": "3.1.0",
|
||||
"description": "Browse note files in a grid view.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ export class GridView extends ItemView {
|
|||
pinnedList: string[] = []; // 置頂清單
|
||||
taskFilter: string = 'uncompleted'; // 任務分類
|
||||
hideHeaderElements: boolean = false; // 是否隱藏標題列元素(模式名稱和按鈕)
|
||||
bookmarkGroupId: string = 'all'; // 書籤群組 ID
|
||||
customOptionIndex: number = -1; // 自訂模式選項索引
|
||||
baseCardLayout: 'horizontal' | 'vertical' = 'horizontal'; // 使用者在設定或 UI 中選擇的基礎卡片樣式(不受資料夾臨時覆蓋影響)
|
||||
cardLayout: 'horizontal' | 'vertical' = 'horizontal'; // 目前實際使用的卡片樣式(可能被資料夾 metadata 臨時覆蓋)
|
||||
|
|
@ -252,7 +253,8 @@ export class GridView extends ItemView {
|
|||
searchQuery?: string,
|
||||
searchCurrentLocationOnly?: boolean,
|
||||
searchFilesNameOnly?: boolean,
|
||||
searchMediaFiles?: boolean
|
||||
searchMediaFiles?: boolean,
|
||||
bookmarkGroupId?: string
|
||||
) {
|
||||
|
||||
// 如果新的狀態與當前狀態相同,則不進行任何操作
|
||||
|
|
@ -261,7 +263,8 @@ export class GridView extends ItemView {
|
|||
this.searchQuery === searchQuery &&
|
||||
this.searchCurrentLocationOnly === searchCurrentLocationOnly &&
|
||||
this.searchFilesNameOnly === searchFilesNameOnly &&
|
||||
this.searchMediaFiles === searchMediaFiles) {
|
||||
this.searchMediaFiles === searchMediaFiles &&
|
||||
(bookmarkGroupId === undefined || this.bookmarkGroupId === bookmarkGroupId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -337,6 +340,9 @@ export class GridView extends ItemView {
|
|||
if (searchMediaFiles !== undefined) {
|
||||
this.searchMediaFiles = searchMediaFiles;
|
||||
}
|
||||
if (bookmarkGroupId !== undefined) {
|
||||
this.bookmarkGroupId = bookmarkGroupId;
|
||||
}
|
||||
|
||||
// 通知 Obsidian 保存視圖狀態
|
||||
this.app.workspace.requestSaveLayout();
|
||||
|
|
@ -1991,19 +1997,6 @@ export class GridView extends ItemView {
|
|||
|
||||
// 在網格視圖中直接顯示筆記
|
||||
async showNoteInGrid(file: TFile) {
|
||||
// 隱藏移動端導航欄
|
||||
if (Platform.isPhone) {
|
||||
const mobileNavbar = document.querySelector('.mobile-navbar') as HTMLElement;
|
||||
if (mobileNavbar) {
|
||||
if (!document.body.classList.contains('is-floating-nav')) {
|
||||
mobileNavbar.style.transform = 'translateY(100%)';
|
||||
} else {
|
||||
mobileNavbar.style.transform = 'translateY(200%)';
|
||||
}
|
||||
mobileNavbar.style.transition = 'transform 0.3s ease-out';
|
||||
}
|
||||
}
|
||||
|
||||
// 關閉之前的筆記顯示
|
||||
if (this.isShowingNote) {
|
||||
this.hideNoteInGrid();
|
||||
|
|
@ -2062,6 +2055,59 @@ export class GridView extends ItemView {
|
|||
noteContent.style.padding = '15px';
|
||||
}
|
||||
|
||||
// 在移動端添加滾動監聽,根據滾動方向控制導航欄顯示/隱藏
|
||||
if (Platform.isPhone) {
|
||||
let lastScrollTop = 0;
|
||||
const handleScroll = () => {
|
||||
const mobileNavbar = document.querySelector('.mobile-navbar') as HTMLElement;
|
||||
if (!mobileNavbar) return;
|
||||
|
||||
const currentScrollTop = scrollContainer.scrollTop;
|
||||
|
||||
// 往上捲(滾動位置增加)時隱藏導航欄
|
||||
if (currentScrollTop > lastScrollTop && currentScrollTop > 50) {
|
||||
if (!document.body.classList.contains('is-floating-nav')) {
|
||||
mobileNavbar.style.transform = 'translateY(100%)';
|
||||
} else {
|
||||
mobileNavbar.style.transform = 'translateY(200%)';
|
||||
}
|
||||
mobileNavbar.style.transition = 'transform 0.3s ease-out';
|
||||
}
|
||||
// 往下捲(滾動位置減少)時顯示導航欄
|
||||
else if (currentScrollTop < lastScrollTop) {
|
||||
mobileNavbar.style.transform = 'translateY(0)';
|
||||
mobileNavbar.style.transition = 'transform 0.3s ease-in';
|
||||
}
|
||||
|
||||
lastScrollTop = currentScrollTop;
|
||||
};
|
||||
|
||||
scrollContainer.addEventListener('scroll', handleScroll);
|
||||
|
||||
// 監聽分頁切換事件,當離開當前視圖時恢復導航欄
|
||||
const handleActiveLeafChange = () => {
|
||||
const activeView = this.app.workspace.getActiveViewOfType(GridView);
|
||||
// 如果當前活動視圖不是這個 GridView 實例,或者不在顯示筆記狀態
|
||||
if (activeView !== this || !this.isShowingNote) {
|
||||
const navbar = document.querySelector('.mobile-navbar') as HTMLElement;
|
||||
if (navbar) {
|
||||
navbar.style.transform = 'translateY(0)';
|
||||
navbar.style.transition = 'transform 0.3s ease-in';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 註冊事件監聽器
|
||||
this.registerEvent(
|
||||
this.app.workspace.on('active-leaf-change', handleActiveLeafChange)
|
||||
);
|
||||
|
||||
// 儲存滾動事件清理函數
|
||||
this.eventCleanupFunctions.push(() => {
|
||||
scrollContainer.removeEventListener('scroll', handleScroll);
|
||||
});
|
||||
}
|
||||
|
||||
// 取得 Metadata (Frontmatter)
|
||||
const fileCache = this.app.metadataCache.getFileCache(file);
|
||||
const frontmatter = fileCache?.frontmatter;
|
||||
|
|
@ -2304,6 +2350,7 @@ export class GridView extends ItemView {
|
|||
showNoteTags: this.showNoteTags,
|
||||
recentSources: this.recentSources,
|
||||
futureSources: this.futureSources,
|
||||
bookmarkGroupId: this.bookmarkGroupId,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -2329,6 +2376,7 @@ export class GridView extends ItemView {
|
|||
this.showNoteTags = state.state.showNoteTags ?? this.plugin.settings.showNoteTags;
|
||||
this.recentSources = state.state.recentSources ?? [];
|
||||
this.futureSources = state.state.futureSources ?? [];
|
||||
this.bookmarkGroupId = state.state.bookmarkGroupId ?? 'all';
|
||||
await this.render();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
backButton.addEventListener('click', async (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
|
||||
// 如果有歷史記錄
|
||||
if (gridView.recentSources.length > 0) {
|
||||
// 將當前狀態推入 futureSources 以便前進
|
||||
|
|
@ -54,7 +54,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
// 取得最近一筆歷史記錄
|
||||
const lastSource = JSON.parse(gridView.recentSources[0]);
|
||||
gridView.recentSources.shift(); // 從歷史記錄中移除
|
||||
|
||||
|
||||
// 設定來源及搜尋狀態(不記錄到歷史)
|
||||
await gridView.setSource(
|
||||
lastSource.mode,
|
||||
|
|
@ -119,7 +119,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
// 只有在有歷史記錄時才顯示右鍵選單
|
||||
if (gridView.recentSources.length > 0) {
|
||||
event.preventDefault();
|
||||
|
||||
|
||||
const menu = new Menu();
|
||||
|
||||
// 添加歷史記錄
|
||||
|
|
@ -127,11 +127,11 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
try {
|
||||
const sourceInfo = JSON.parse(sourceInfoStr);
|
||||
const { mode, path } = sourceInfo;
|
||||
|
||||
|
||||
// 根據模式顯示圖示和文字
|
||||
let displayText = '';
|
||||
let icon = '';
|
||||
|
||||
|
||||
switch (mode) {
|
||||
case 'folder':
|
||||
displayText = path || '/';
|
||||
|
|
@ -190,7 +190,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
displayText += `: "${sourceInfo.searchQuery}"`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 添加歷史記錄到選單
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
|
|
@ -213,7 +213,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
if (clickedIndex !== -1) {
|
||||
const newerHistory = gridView.recentSources.slice(0, clickedIndex);
|
||||
const forwardStack = [...newerHistory].reverse();
|
||||
gridView.futureSources = [...forwardStack, currentKey, ...gridView.futureSources];
|
||||
gridView.futureSources = [...forwardStack, currentKey, ...gridView.futureSources];
|
||||
if (gridView.futureSources.length > 10) {
|
||||
gridView.futureSources.length = 10;
|
||||
}
|
||||
|
|
@ -242,7 +242,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
menu.showAtMouseEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 添加右鍵選單支援
|
||||
forwardButton.addEventListener('contextmenu', (event) => {
|
||||
// 只有在有歷史記錄或未來記錄時才顯示右鍵選單
|
||||
|
|
@ -250,7 +250,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
event.preventDefault();
|
||||
|
||||
const menu = new Menu();
|
||||
|
||||
|
||||
// 添加未來記錄
|
||||
gridView.futureSources.forEach((sourceInfoStr, index) => {
|
||||
try {
|
||||
|
|
@ -381,7 +381,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
// 添加新增筆記按鈕
|
||||
const newNoteButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('new_note') } });
|
||||
setIcon(newNoteButton, 'square-pen');
|
||||
newNoteButton.addEventListener('click', (event) => {
|
||||
newNoteButton.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
const menu = new Menu();
|
||||
// 新增筆記
|
||||
|
|
@ -396,54 +396,54 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
// 新增資料夾
|
||||
menu.addItem((item) => {
|
||||
item.setTitle(t('new_folder'))
|
||||
.setIcon('folder')
|
||||
.onClick(async () => {
|
||||
await createNewFolder(gridView.app, gridView.sourcePath, () => {
|
||||
requestAnimationFrame(() => {
|
||||
gridView.render();
|
||||
.setIcon('folder')
|
||||
.onClick(async () => {
|
||||
await createNewFolder(gridView.app, gridView.sourcePath, () => {
|
||||
requestAnimationFrame(() => {
|
||||
gridView.render();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
// 新增畫布
|
||||
menu.addItem((item) => {
|
||||
item.setTitle(t('new_canvas'))
|
||||
.setIcon('layout-dashboard')
|
||||
.onClick(async () => {
|
||||
await createNewCanvas(gridView.app, gridView.sourcePath);
|
||||
});
|
||||
.setIcon('layout-dashboard')
|
||||
.onClick(async () => {
|
||||
await createNewCanvas(gridView.app, gridView.sourcePath);
|
||||
});
|
||||
});
|
||||
// 新增 base
|
||||
menu.addItem((item) => {
|
||||
item.setTitle(t('new_base'))
|
||||
.setIcon('layout-dashboard')
|
||||
.onClick(async () => {
|
||||
await createNewBase(gridView.app, gridView.sourcePath);
|
||||
});
|
||||
.setIcon('layout-dashboard')
|
||||
.onClick(async () => {
|
||||
await createNewBase(gridView.app, gridView.sourcePath);
|
||||
});
|
||||
});
|
||||
// 新增捷徑
|
||||
menu.addItem((item) => {
|
||||
item.setTitle(t('new_shortcut'))
|
||||
.setIcon('shuffle')
|
||||
.onClick(async () => {
|
||||
const modal = new ShortcutSelectionModal(gridView.app, gridView.plugin, async (option) => {
|
||||
await createShortcutUtil(gridView.app, gridView.sourcePath, option);
|
||||
.setIcon('shuffle')
|
||||
.onClick(async () => {
|
||||
const modal = new ShortcutSelectionModal(gridView.app, gridView.plugin, async (option) => {
|
||||
await createShortcutUtil(gridView.app, gridView.sourcePath, option);
|
||||
});
|
||||
modal.open();
|
||||
});
|
||||
modal.open();
|
||||
});
|
||||
});
|
||||
menu.showAtMouseEvent(event);
|
||||
});
|
||||
|
||||
// 添加重新選擇資料夾按鈕
|
||||
const reselectButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('reselect') } });
|
||||
const reselectButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('reselect') } });
|
||||
reselectButton.addEventListener('click', () => {
|
||||
showFolderSelectionModal(gridView.app, gridView.plugin, gridView, reselectButton);
|
||||
});
|
||||
setIcon(reselectButton, "grid");
|
||||
|
||||
// 添加重新整理按鈕
|
||||
const refreshButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('refresh') } });
|
||||
const refreshButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('refresh') } });
|
||||
refreshButton.addEventListener('click', () => {
|
||||
if (gridView.sortType === 'random') {
|
||||
gridView.clearSelection();
|
||||
|
|
@ -462,51 +462,10 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
searchButton.addEventListener('click', () => {
|
||||
showSearchModal(gridView.app, gridView, gridView.searchQuery, searchButton);
|
||||
});
|
||||
|
||||
|
||||
// 如果有搜尋關鍵字,顯示搜尋文字和取消按鈕
|
||||
// if (gridView.searchQuery) {
|
||||
// searchButton.style.display = 'none';
|
||||
// const searchTextContainer = searchButtonContainer.createDiv('ge-search-text-container');
|
||||
// searchTextContainer.setAttribute('aria-label', gridView.searchQuery);
|
||||
|
||||
// // 創建搜尋文字
|
||||
// const searchText = searchTextContainer.createEl('span', { cls: 'ge-search-text', text: gridView.searchQuery });
|
||||
// // 讓搜尋文字可點選
|
||||
// searchText.style.cursor = 'pointer';
|
||||
// searchText.addEventListener('click', () => {
|
||||
// showSearchModal(gridView.app, gridView, gridView.searchQuery, searchText);
|
||||
// });
|
||||
|
||||
// // 先保存開啟 Modal 時的原始狀態
|
||||
// const originalSearchQuery = gridView.searchQuery;
|
||||
// const originalsearchCurrentLocationOnly = gridView.searchCurrentLocationOnly;
|
||||
// const originalSearchFilesNameOnly = gridView.searchFilesNameOnly;
|
||||
// const originalSearchMediaFiles = gridView.searchMediaFiles;
|
||||
|
||||
// // 創建取消按鈕
|
||||
// const clearButton = searchTextContainer.createDiv('ge-clear-button');
|
||||
// setIcon(clearButton, 'x');
|
||||
// clearButton.addEventListener('click', (e) => {
|
||||
// e.stopPropagation(); // 防止觸發搜尋文字的點擊事件
|
||||
// gridView.pushHistory(
|
||||
// gridView.sourceMode,
|
||||
// gridView.sourcePath,
|
||||
// originalSearchQuery,
|
||||
// originalsearchCurrentLocationOnly,
|
||||
// originalSearchFilesNameOnly,
|
||||
// originalSearchMediaFiles,
|
||||
// );
|
||||
// gridView.searchQuery = '';
|
||||
// gridView.clearSelection();
|
||||
// gridView.app.workspace.requestSaveLayout();
|
||||
// gridView.render();
|
||||
// });
|
||||
// }
|
||||
|
||||
// 更多選項按鈕
|
||||
const menu = new Menu();
|
||||
menu.addItem((item) => {
|
||||
const moreMenu = new Menu();
|
||||
moreMenu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_new_grid_view'))
|
||||
.setIcon('grid')
|
||||
|
|
@ -539,10 +498,10 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
workspace.revealLeaf(leaf);
|
||||
});
|
||||
});
|
||||
menu.addSeparator();
|
||||
moreMenu.addSeparator();
|
||||
|
||||
// 直向卡片切換
|
||||
menu.addItem((item) => {
|
||||
moreMenu.addItem((item) => {
|
||||
item.setTitle(t('vertical_card'))
|
||||
.setIcon('layout')
|
||||
.setChecked(gridView.baseCardLayout === 'vertical')
|
||||
|
|
@ -554,7 +513,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
});
|
||||
});
|
||||
// 最小化模式選項
|
||||
menu.addItem((item) => {
|
||||
moreMenu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('min_mode'))
|
||||
.setIcon('minimize-2')
|
||||
|
|
@ -567,7 +526,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
});
|
||||
// 顯示日期分隔器
|
||||
if (gridView.plugin.settings.dateDividerMode !== 'none') {
|
||||
menu.addItem((item) => {
|
||||
moreMenu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('show_date_dividers'))
|
||||
.setIcon('calendar')
|
||||
|
|
@ -580,7 +539,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
});
|
||||
}
|
||||
// 顯示筆記標籤
|
||||
menu.addItem((item) => {
|
||||
moreMenu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('show_note_tags'))
|
||||
.setIcon('tag')
|
||||
|
|
@ -592,7 +551,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
});
|
||||
});
|
||||
// 顯示忽略的資料夾及檔案選項
|
||||
menu.addItem((item) => {
|
||||
moreMenu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('show_ignored_items'))
|
||||
.setIcon('folder-open-dot')
|
||||
|
|
@ -603,11 +562,11 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
gridView.render();
|
||||
});
|
||||
});
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
moreMenu.addSeparator();
|
||||
|
||||
// 開啟瀏覽器
|
||||
menu.addItem((item) => {
|
||||
moreMenu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_explorer'))
|
||||
.setIcon('folder-tree')
|
||||
|
|
@ -626,7 +585,7 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
});
|
||||
|
||||
// 顯示設定選項
|
||||
menu.addItem((item) => {
|
||||
moreMenu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_settings'))
|
||||
.setIcon('settings')
|
||||
|
|
@ -636,17 +595,17 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
(gridView.app as any).setting.openTabById(gridView.plugin.manifest.id);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
const moreOptionsButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('more_options') } });
|
||||
setIcon(moreOptionsButton, 'ellipsis-vertical');
|
||||
moreOptionsButton.addEventListener('click', (event) => {
|
||||
menu.showAtMouseEvent(event);
|
||||
moreMenu.showAtMouseEvent(event);
|
||||
});
|
||||
|
||||
headerButtonsDiv.addEventListener('contextmenu', (event) => {
|
||||
if (event.target === headerButtonsDiv) {
|
||||
event.preventDefault();
|
||||
menu.showAtMouseEvent(event);
|
||||
moreMenu.showAtMouseEvent(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,20 +13,20 @@ export function renderModePath(gridView: GridView) {
|
|||
|
||||
// 創建模式名稱和排序按鈕的容器
|
||||
const modeHeaderContainer = gridView.containerEl.createDiv('ge-mode-header-container');
|
||||
|
||||
|
||||
// 左側:模式名稱
|
||||
const modenameContainer = modeHeaderContainer.createDiv('ge-modename-content');
|
||||
|
||||
|
||||
// 右側:排序按鈕
|
||||
const rightActions = modeHeaderContainer.createDiv('ge-right-actions');
|
||||
|
||||
|
||||
// 添加排序按鈕
|
||||
if (gridView.sourceMode !== 'bookmarks' &&
|
||||
gridView.sourceMode !== 'recent-files' &&
|
||||
if (gridView.sourceMode !== 'bookmarks' &&
|
||||
gridView.sourceMode !== 'recent-files' &&
|
||||
gridView.sourceMode !== 'random-note') {
|
||||
const sortButton = rightActions.createEl('a', {
|
||||
const sortButton = rightActions.createEl('a', {
|
||||
cls: 'ge-sort-button',
|
||||
attr: {
|
||||
attr: {
|
||||
'aria-label': t('sorting'),
|
||||
'href': '#'
|
||||
}
|
||||
|
|
@ -648,6 +648,53 @@ export function renderModePath(gridView: GridView) {
|
|||
}
|
||||
|
||||
switch (gridView.sourceMode) {
|
||||
case 'bookmarks':
|
||||
const bookmarkGroupName = gridView.bookmarkGroupId === 'all' ? t('all_bookmarks') : gridView.bookmarkGroupId;
|
||||
const bookmarkGroupSpan = modenameContainer.createEl('a', { text: bookmarkGroupName, cls: 'ge-sub-option' });
|
||||
bookmarkGroupSpan.addEventListener('click', (evt) => {
|
||||
const menu = new Menu();
|
||||
|
||||
// "全部" 選項
|
||||
menu.addItem((item) => {
|
||||
item.setTitle(t('all_bookmarks'))
|
||||
.setIcon('layers')
|
||||
.setChecked(gridView.bookmarkGroupId === 'all')
|
||||
.onClick(() => {
|
||||
gridView.setSource('bookmarks', '', false, undefined, undefined, undefined, undefined, 'all');
|
||||
});
|
||||
});
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
// 取得所有書籤群組
|
||||
const bookmarksPlugin = (gridView.app as any).internalPlugins.plugins.bookmarks;
|
||||
if (bookmarksPlugin?.enabled) {
|
||||
const bookmarks = bookmarksPlugin.instance.items;
|
||||
const groups: string[] = [];
|
||||
const findGroups = (items: any[]) => {
|
||||
items.forEach(item => {
|
||||
if (item.type === 'group') {
|
||||
groups.push(item.title);
|
||||
if (item.items) findGroups(item.items);
|
||||
}
|
||||
});
|
||||
};
|
||||
findGroups(bookmarks);
|
||||
|
||||
groups.forEach(groupTitle => {
|
||||
menu.addItem((item) => {
|
||||
item.setTitle(groupTitle)
|
||||
.setIcon('folder')
|
||||
.setChecked(gridView.bookmarkGroupId === groupTitle)
|
||||
.onClick(() => {
|
||||
gridView.setSource('bookmarks', '', false, undefined, undefined, undefined, undefined, groupTitle);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
menu.showAtMouseEvent(evt);
|
||||
});
|
||||
break;
|
||||
case 'random-note':
|
||||
case 'recent-files':
|
||||
case 'all-files':
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ export default {
|
|||
'all': 'All',
|
||||
'default': 'Default',
|
||||
'hidden': 'Hidden',
|
||||
'all_bookmarks': 'All Bookmarks',
|
||||
|
||||
// Hide header elements setting
|
||||
'hide_header_elements': 'Hide header elements',
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ export default {
|
|||
'all': 'すべて',
|
||||
'default': 'デフォルト',
|
||||
'hidden': '隠す',
|
||||
'bookmark_groups': 'ブックマーク群組',
|
||||
|
||||
// 隠すヘッダー要素
|
||||
'hide_header_elements': 'ヘッダー要素を隠す',
|
||||
|
|
@ -301,7 +302,7 @@ export default {
|
|||
'use_quick_access_mode': 'クイックアクセスモードを使用する',
|
||||
'open_quick_access_folder': 'クイックアクセス フォルダーを開く',
|
||||
'open_quick_access_mode': 'クイックアクセスモードを開く',
|
||||
|
||||
|
||||
// Explorer Stash
|
||||
'stash': '一時保存',
|
||||
'drop_files_here': 'ここにドラッグして一時保存',
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ export default {
|
|||
'all': '전체',
|
||||
'default': '기본값',
|
||||
'hidden': '숨김',
|
||||
'bookmark_groups': '북마크群組',
|
||||
|
||||
// Hide header elements setting
|
||||
'hide_header_elements': '헤더 요소 숨기기',
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ export default {
|
|||
'all': 'Все',
|
||||
'default': 'По умолчанию',
|
||||
'hidden': 'Скрытые',
|
||||
'bookmark_groups': 'Букмарк группы',
|
||||
|
||||
// Hide header elements setting
|
||||
'hide_header_elements': 'Скрыть элементы заголовка',
|
||||
|
|
@ -301,7 +302,7 @@ export default {
|
|||
'use_quick_access_mode': 'Использовать режим быстрого доступа',
|
||||
'open_quick_access_folder': 'Открыть папку быстрого доступа',
|
||||
'open_quick_access_mode': 'Открыть быстрый доступ по режиму',
|
||||
|
||||
|
||||
// Explorer Stash
|
||||
'stash': 'Хранилище',
|
||||
'drop_files_here': 'Перетащите файлы сюда, чтобы сохранить',
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ export default {
|
|||
'all': 'Усі',
|
||||
'default': 'За замовчуванням',
|
||||
'hidden': 'Приховані',
|
||||
'bookmark_groups': 'Групи закладок',
|
||||
|
||||
// Hide header elements setting
|
||||
'hide_header_elements': 'Приховати елементи заголовка',
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ export default {
|
|||
'all': '全部',
|
||||
'default': '預設',
|
||||
'hidden': '隱藏',
|
||||
'all_bookmarks': '全部書籤',
|
||||
|
||||
// 隱藏頂部元素
|
||||
'hide_header_elements': '隱藏頂部元素',
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ export default {
|
|||
'all': '全部',
|
||||
'default': '默认',
|
||||
'hidden': '隐藏',
|
||||
'all_bookmarks': '全部书签',
|
||||
|
||||
// 隐藏頂部元素
|
||||
'hide_header_elements': '隱藏頂部元素',
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export function sortFiles(files: TFile[], gridView: GridView, overrideSortType?:
|
|||
const hasModifiedField = !!settings.modifiedDateField;
|
||||
const hasCreatedField = !!settings.createdDateField;
|
||||
const hasAnyDateField = hasModifiedField || hasCreatedField;
|
||||
|
||||
|
||||
// 符合以下任一條件就使用簡單排序:
|
||||
// 1. 非日期排序類型 (name-asc, name-desc, random)
|
||||
// 2. 沒有設定任何日期欄位
|
||||
|
|
@ -106,7 +106,7 @@ export function sortFiles(files: TFile[], gridView: GridView, overrideSortType?:
|
|||
// 只對 .md 檔案讀取 metadata
|
||||
const shouldReadMetadata = file.extension === 'md';
|
||||
const metadata = shouldReadMetadata ? app.metadataCache.getFileCache(file) : null;
|
||||
|
||||
|
||||
return {
|
||||
file,
|
||||
mDate: (() => {
|
||||
|
|
@ -167,12 +167,12 @@ export function isFolderIgnored(folder: TFolder, ignoredFolders: string[], ignor
|
|||
if (showIgnoredFolders) return false;
|
||||
|
||||
// 檢查資料夾是否在忽略清單中
|
||||
const isInIgnoredFolders = ignoredFolders.some(ignored =>
|
||||
const isInIgnoredFolders = ignoredFolders.some(ignored =>
|
||||
folder.path === ignored || folder.path.startsWith(ignored + '/')
|
||||
);
|
||||
|
||||
|
||||
if (isInIgnoredFolders) return true;
|
||||
|
||||
|
||||
// 檢查資料夾是否符合忽略的模式
|
||||
if (ignoredFolderPatterns && ignoredFolderPatterns.length > 0) {
|
||||
const matchesIgnoredPattern = ignoredFolderPatterns.some(pattern => {
|
||||
|
|
@ -180,7 +180,7 @@ export function isFolderIgnored(folder: TFolder, ignoredFolders: string[], ignor
|
|||
// 嘗試將模式作為正則表達式處理
|
||||
// 如果模式包含特殊字符,使用正則表達式處理
|
||||
if (/[\^\$\*\+\?\(\)\[\]\{\}\|\\]/.test(pattern)) {
|
||||
const regex = new RegExp(pattern);
|
||||
const regex = new RegExp(pattern);
|
||||
return regex.test(folder.path);
|
||||
} else {
|
||||
// 檢查資料夾名稱是否包含模式字串(不區分大小寫)
|
||||
|
|
@ -191,7 +191,7 @@ export function isFolderIgnored(folder: TFolder, ignoredFolders: string[], ignor
|
|||
return folder.name.toLowerCase().includes(pattern.toLowerCase());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (matchesIgnoredPattern) return true;
|
||||
}
|
||||
|
||||
|
|
@ -201,15 +201,15 @@ export function isFolderIgnored(folder: TFolder, ignoredFolders: string[], ignor
|
|||
// 檢查檔案是否應該被忽略
|
||||
export function ignoredFiles(files: TFile[], gridView: GridView): TFile[] {
|
||||
const settings = gridView.plugin.settings;
|
||||
|
||||
|
||||
// 如果開啟顯示忽略項目模式,則顯示所有檔案
|
||||
if (gridView.showIgnoredItems) {
|
||||
return files;
|
||||
}
|
||||
|
||||
|
||||
// 建立一個快取來存儲已經檢查過的資料夾路徑
|
||||
const folderCache: {[path: string]: boolean} = {};
|
||||
|
||||
const folderCache: { [path: string]: boolean } = {};
|
||||
|
||||
return files.filter(file => {
|
||||
// 檢查檔案的 metadata 是否有 hidden: true
|
||||
if (file.extension === 'md') {
|
||||
|
|
@ -222,13 +222,13 @@ export function ignoredFiles(files: TFile[], gridView: GridView): TFile[] {
|
|||
|
||||
// 獲取檔案所在的資料夾路徑
|
||||
const folderPath = file.parent?.path || '/';
|
||||
|
||||
|
||||
|
||||
|
||||
// 如果快取中沒有這個資料夾的檢查結果,則進行檢查
|
||||
if (folderCache[folderPath] === undefined) {
|
||||
// 獲取資料夾對象
|
||||
const folder = gridView.app.vault.getAbstractFileByPath(folderPath);
|
||||
|
||||
|
||||
if (folder instanceof TFolder) {
|
||||
// 使用 isFolderIgnored 檢查資料夾是否應該被忽略
|
||||
folderCache[folderPath] = isFolderIgnored(
|
||||
|
|
@ -242,7 +242,7 @@ export function ignoredFiles(files: TFile[], gridView: GridView): TFile[] {
|
|||
folderCache[folderPath] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 如果資料夾被忽略,則過濾掉該檔案
|
||||
return !folderCache[folderPath];
|
||||
});
|
||||
|
|
@ -262,11 +262,11 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
// 只取得當前資料夾中的支援檔案,不包含子資料夾
|
||||
const files = folder.children.filter((file): file is TFile => {
|
||||
if (!(file instanceof TFile)) return false;
|
||||
|
||||
|
||||
// 當存在搜尋關鍵字時,是否包含媒體檔案取決於 includeMediaFiles
|
||||
// 不存在搜尋關鍵字時,是否包含媒體檔案取決於 settings.showMediaFiles
|
||||
const allowMedia = settings.showMediaFiles && (!gridView.searchQuery || includeMediaFiles);
|
||||
|
||||
|
||||
// 如果是文件檔案,直接包含;若為媒體檔案則依 allowMedia 判斷
|
||||
if (isDocumentFile(file) || (allowMedia && isMediaFile(file))) {
|
||||
return true;
|
||||
|
|
@ -285,13 +285,13 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
const resultDomLookup = searchLeaf.view.dom.resultDomLookup;
|
||||
if (resultDomLookup) {
|
||||
const files = Array.from(resultDomLookup.keys())
|
||||
.filter((file): file is TFile => file instanceof TFile);
|
||||
.filter((file): file is TFile => file instanceof TFile);
|
||||
return sortFiles(files, gridView);
|
||||
}
|
||||
}
|
||||
}
|
||||
return [];
|
||||
} else if (sourceMode === 'backlinks') {
|
||||
} else if (sourceMode === 'backlinks') {
|
||||
// 反向連結模式:找出所有引用當前筆記的檔案
|
||||
const activeFile = app.workspace.getActiveFile();
|
||||
if (!activeFile) {
|
||||
|
|
@ -305,10 +305,10 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
if (Object.keys(links).includes(activeFile.path)) {
|
||||
const sourceFile = app.vault.getAbstractFileByPath(sourcePath) as TFile;
|
||||
if (sourceFile) {
|
||||
backlinks.add(sourceFile);
|
||||
}
|
||||
backlinks.add(sourceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sortFiles(Array.from(backlinks) as TFile[], gridView);
|
||||
} else if (sourceMode === 'outgoinglinks') {
|
||||
|
|
@ -322,11 +322,11 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
// 使用 resolvedLinks 來找出外部連結
|
||||
const resolvedLinks = app.metadataCache.resolvedLinks;
|
||||
const fileLinks = resolvedLinks[activeFile.path];
|
||||
|
||||
|
||||
if (fileLinks) {
|
||||
for (const targetPath of Object.keys(fileLinks)) {
|
||||
const targetFile = app.vault.getAbstractFileByPath(targetPath) as TFile;
|
||||
if (targetFile && (isDocumentFile(targetFile) ||
|
||||
if (targetFile && (isDocumentFile(targetFile) ||
|
||||
(settings.showMediaFiles && isMediaFile(targetFile)))) {
|
||||
outgoingLinks.add(targetFile);
|
||||
}
|
||||
|
|
@ -362,7 +362,7 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
}
|
||||
|
||||
return sortFiles(Array.from(outgoingLinks), gridView);
|
||||
} else if(sourceMode === 'bookmarks') {
|
||||
} else if (sourceMode === 'bookmarks') {
|
||||
// 書籤模式
|
||||
const bookmarksPlugin = (app as any).internalPlugins.plugins.bookmarks;
|
||||
if (!bookmarksPlugin?.enabled) {
|
||||
|
|
@ -371,7 +371,7 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
|
||||
const bookmarks = bookmarksPlugin.instance.items;
|
||||
const bookmarkedFiles = new Set();
|
||||
|
||||
|
||||
const processBookmarkItem = (item: any) => {
|
||||
if (item.type === 'file') {
|
||||
const file = app.vault.getAbstractFileByPath(item.path);
|
||||
|
|
@ -386,8 +386,29 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
item.items.forEach(processBookmarkItem);
|
||||
}
|
||||
};
|
||||
|
||||
bookmarks.forEach(processBookmarkItem);
|
||||
|
||||
const bookmarkGroupId = gridView.bookmarkGroupId;
|
||||
if (!bookmarkGroupId || bookmarkGroupId === 'all') {
|
||||
bookmarks.forEach(processBookmarkItem);
|
||||
} else {
|
||||
// 遞迴尋找指定的群組
|
||||
const findAndProcessGroup = (items: any[]) => {
|
||||
for (const item of items) {
|
||||
if (item.type === 'group') {
|
||||
// 使用 title 作為 ID
|
||||
if (item.title === bookmarkGroupId) {
|
||||
item.items.forEach(processBookmarkItem);
|
||||
return true;
|
||||
}
|
||||
if (item.items && findAndProcessGroup(item.items)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
findAndProcessGroup(bookmarks);
|
||||
}
|
||||
return Array.from(bookmarkedFiles) as TFile[];
|
||||
} else if (sourceMode === 'tasks') {
|
||||
// 任務模式
|
||||
|
|
@ -404,7 +425,7 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
for (const task of allTasks) {
|
||||
const file = app.vault.getAbstractFileByPath(task.path);
|
||||
if (!(file instanceof TFile)) continue;
|
||||
|
||||
|
||||
// 根據過濾條件檢查任務
|
||||
if (gridView.taskFilter === 'uncompleted' && !task.isDone) {
|
||||
filesWithTasks.add(file);
|
||||
|
|
@ -423,7 +444,7 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
try {
|
||||
const tasks = dv.pages().file.tasks;
|
||||
let filteredTasks;
|
||||
|
||||
|
||||
if (gridView.taskFilter === 'uncompleted') {
|
||||
filteredTasks = tasks.where((t: { completed: boolean }) => !t.completed);
|
||||
} else if (gridView.taskFilter === 'completed') {
|
||||
|
|
@ -431,7 +452,7 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
} else { // 'all'
|
||||
filteredTasks = tasks;
|
||||
}
|
||||
|
||||
|
||||
for (const task of filteredTasks.array()) {
|
||||
const file = app.vault.getAbstractFileByPath(task.path);
|
||||
if (file instanceof TFile) {
|
||||
|
|
@ -442,7 +463,7 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
console.error('Error getting tasks from Dataview:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// 使用原生方法
|
||||
const markdownFiles = app.vault.getMarkdownFiles();
|
||||
|
|
@ -465,7 +486,7 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
const hasCompleted = /^[\s]*[-*]\s*\[x\](?![^\[]*\[\s*[^\s\]]+\]).*$/m.test(content);
|
||||
shouldAdd = hasIncomplete || hasCompleted;
|
||||
}
|
||||
|
||||
|
||||
if (shouldAdd) {
|
||||
filesWithTasks.add(file);
|
||||
}
|
||||
|
|
@ -531,7 +552,7 @@ export async function getFiles(gridView: GridView, includeMediaFiles: boolean):
|
|||
dvCode = mode.options[idx].dataviewCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const activeFile = app.workspace.getActiveFile();
|
||||
if (activeFile) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"3.0.9": "1.1.0"
|
||||
"3.1.0": "1.1.0"
|
||||
}
|
||||
Loading…
Reference in a new issue