mirror of
https://github.com/devon22/obsidian-gridexplorer.git
synced 2026-07-22 05:38:16 +00:00
3.4.9
This commit is contained in:
parent
ec9f6e731d
commit
87549960d7
20 changed files with 764 additions and 182 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -32,4 +32,7 @@ AGENTS.md
|
|||
Changelog.md
|
||||
|
||||
# Exclude snippets directory
|
||||
/snippets
|
||||
/snippets
|
||||
|
||||
# Exclude docs directory
|
||||
/docs
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "gridexplorer",
|
||||
"name": "GridExplorer",
|
||||
"version": "3.4.8",
|
||||
"version": "3.4.9",
|
||||
"minAppVersion": "1.8.7",
|
||||
"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.4.8",
|
||||
"version": "3.4.9",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gridexplorer",
|
||||
"version": "3.4.8",
|
||||
"version": "3.4.9",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jszip": "^3.10.1"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "gridexplorer",
|
||||
"version": "3.4.8",
|
||||
"version": "3.4.9",
|
||||
"description": "Browse note files in a grid view.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -227,17 +227,6 @@ export class ExplorerView extends ItemView {
|
|||
if (newMode !== this.lastMode || newPath !== this.lastPath) {
|
||||
this.lastMode = newMode;
|
||||
this.lastPath = newPath;
|
||||
|
||||
// 當模式切換時,清理搜尋狀態以避免資料夾被強制展開
|
||||
if (this.searchQuery.trim()) {
|
||||
this.searchQuery = '';
|
||||
if (this.searchInputEl) {
|
||||
this.searchInputEl.value = '';
|
||||
}
|
||||
// 同步搜尋輸入框狀態
|
||||
this.syncSearchInput();
|
||||
}
|
||||
|
||||
schedule();
|
||||
}
|
||||
});
|
||||
|
|
@ -1031,7 +1020,7 @@ export class ExplorerView extends ItemView {
|
|||
const name = header.createSpan({ cls: 'ge-explorer-folder-name' });
|
||||
name.textContent = folder.name || '/';
|
||||
|
||||
this.setupFolderIcon(folder, name, toggle, expanded);
|
||||
this.setupFolderIcon(folder, name, toggle, expanded, icon);
|
||||
this.highlightActiveFolder(folder, header);
|
||||
this.attachDropTarget(header, folder.path);
|
||||
|
||||
|
|
@ -1044,7 +1033,7 @@ export class ExplorerView extends ItemView {
|
|||
}
|
||||
|
||||
// 設置資料夾圖示
|
||||
private setupFolderIcon(folder: TFolder, name: HTMLElement, toggle: HTMLElement, expanded: boolean) {
|
||||
private setupFolderIcon(folder: TFolder, name: HTMLElement, toggle: HTMLElement, expanded: boolean, iconEl: HTMLElement) {
|
||||
// 根據同名筆記設置背景色與圖示
|
||||
const iconFromFrontmatter = this.getFolderIconFromFrontmatter(folder, name);
|
||||
|
||||
|
|
@ -1053,7 +1042,16 @@ export class ExplorerView extends ItemView {
|
|||
const customFolderIcon = this.plugin.settings?.customFolderIcon ?? '';
|
||||
if (customFolderIcon && name) {
|
||||
name.textContent = `${customFolderIcon} ${folder.name || '/'}`.trim();
|
||||
if (customFolderIcon.trim()) {
|
||||
iconEl.setCssProps({ display: 'none' });
|
||||
} else {
|
||||
iconEl.setCssProps({ display: '' });
|
||||
}
|
||||
} else {
|
||||
iconEl.setCssProps({ display: '' });
|
||||
}
|
||||
} else {
|
||||
iconEl.setCssProps({ display: 'none' });
|
||||
}
|
||||
|
||||
// 設置切換圖示
|
||||
|
|
|
|||
|
|
@ -77,6 +77,18 @@ export class FileWatcher {
|
|||
if (file instanceof TFile) {
|
||||
// 如果有 GridView 實例
|
||||
if (this.gridView) {
|
||||
// 如果刪除的檔案剛好是目前正在預覽的檔案,應隱藏預覽
|
||||
if (this.gridView.isShowingNote || this.gridView.isShowingZip) {
|
||||
const currentFile = this.gridView.previewManager.getCurrentFile();
|
||||
if (currentFile && file.path === currentFile.path) {
|
||||
if (this.gridView.isShowingNote) {
|
||||
this.gridView.hideNoteInGrid();
|
||||
} else {
|
||||
this.gridView.hideZipInGrid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 找到當前檔案在 GridView 中的索引
|
||||
const gridItemIndex = this.gridView.gridItems.findIndex((item: HTMLElement) =>
|
||||
item.dataset.filePath === file.path
|
||||
|
|
@ -98,6 +110,28 @@ export class FileWatcher {
|
|||
this.plugin.registerEvent(
|
||||
this.app.vault.on('rename', (file, oldPath) => {
|
||||
if (file instanceof TFile) {
|
||||
// 如果重命名的檔案是目前正在預覽的檔案,需要更新預覽標題與內容
|
||||
if (this.gridView.isShowingNote || this.gridView.isShowingZip) {
|
||||
const currentFile = this.gridView.previewManager.getCurrentFile();
|
||||
if (currentFile && (file === currentFile || currentFile.path === oldPath || currentFile.path === file.path)) {
|
||||
if (this.gridView.isShowingNote) {
|
||||
// 更新頂部標題文字
|
||||
const titleEl = this.gridView.noteViewContainer?.querySelector('.ge-note-title');
|
||||
if (titleEl) {
|
||||
titleEl.textContent = file.basename;
|
||||
}
|
||||
// 更新預覽內容(這會重新讀取並渲染,順便更新內部的第一行標題與 backlinks)
|
||||
void this.gridView.previewManager.updateCurrentPreview();
|
||||
} else if (this.gridView.isShowingZip) {
|
||||
// ZIP 預覽:更新頂部標題文字
|
||||
const titleEl = this.gridView.zipViewContainer?.querySelector('.ge-zip-title');
|
||||
if (titleEl) {
|
||||
titleEl.textContent = file.basename;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fileDirPath = file.path.split('/').slice(0, -1).join('/') || '/';
|
||||
const oldDirPath = oldPath.split('/').slice(0, -1).join('/') || '/';
|
||||
// 來源與目標路徑不同,表示移動檔案
|
||||
|
|
|
|||
|
|
@ -25,20 +25,52 @@ interface AppWithInternalPlugins {
|
|||
|
||||
export class GridPreviewManager {
|
||||
private view: GridView;
|
||||
private previewHistory: TFile[] = [];
|
||||
private previewHistoryIndex: number = -1;
|
||||
|
||||
constructor(view: GridView) {
|
||||
this.view = view;
|
||||
|
||||
// 監聽檔案修改事件以即時更新預覽
|
||||
this.view.registerEvent(
|
||||
this.view.app.vault.on('modify', (file) => {
|
||||
if (file instanceof TFile && this.view.isShowingNote) {
|
||||
const currentFile = this.getCurrentFile();
|
||||
if (currentFile && file.path === currentFile.path) {
|
||||
void this.updateCurrentPreview();
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 在網格視圖中直接顯示筆記
|
||||
async showNoteInGrid(file: TFile) {
|
||||
async showNoteInGrid(file: TFile, isHistoryNavigation = false) {
|
||||
if (file.extension === 'zip') {
|
||||
return this.showZipInGrid(file, isHistoryNavigation);
|
||||
}
|
||||
|
||||
// 更新歷史紀錄
|
||||
if (!this.view.isShowingNote) {
|
||||
// 從外部全新開啟
|
||||
this.previewHistory = [file];
|
||||
this.previewHistoryIndex = 0;
|
||||
} else if (!isHistoryNavigation) {
|
||||
// 在內部點擊連結跳轉
|
||||
this.previewHistory = this.previewHistory.slice(0, this.previewHistoryIndex + 1);
|
||||
this.previewHistory.push(file);
|
||||
this.previewHistoryIndex = this.previewHistory.length - 1;
|
||||
}
|
||||
|
||||
// 關閉之前的筆記顯示
|
||||
if (this.view.isShowingNote) {
|
||||
this.hideNoteInGrid();
|
||||
this.hideNoteInGrid(false); // 傳入 false 避免清空我們剛更新的歷史
|
||||
}
|
||||
// 關閉之前的 ZIP 顯示
|
||||
if (this.view.isShowingZip) {
|
||||
this.hideZipInGrid();
|
||||
this.hideZipInGrid(false);
|
||||
}
|
||||
|
||||
const gridContainer = this.view.containerEl.querySelector('.ge-grid-container');
|
||||
|
|
@ -51,28 +83,55 @@ export class GridPreviewManager {
|
|||
// 頂部列 (左右區塊)
|
||||
const topBar = noteViewContainer.createDiv('ge-note-top-bar');
|
||||
const leftBar = topBar.createDiv('ge-note-top-left');
|
||||
const rightBar = topBar.createDiv('ge-note-top-right');
|
||||
|
||||
// 筆記標題
|
||||
const noteTitle = leftBar.createDiv('ge-note-title');
|
||||
// 返回與前進按鈕
|
||||
const backButton = leftBar.createEl('button', { cls: 'clickable-icon ge-note-nav-button ge-note-back-button' });
|
||||
setIcon(backButton, 'arrow-left');
|
||||
backButton.disabled = this.previewHistoryIndex <= 0;
|
||||
backButton.addEventListener('click', () => {
|
||||
if (this.previewHistoryIndex > 0) {
|
||||
this.previewHistoryIndex--;
|
||||
const prevFile = this.previewHistory[this.previewHistoryIndex];
|
||||
void this.showNoteInGrid(prevFile, true);
|
||||
}
|
||||
});
|
||||
|
||||
const forwardButton = leftBar.createEl('button', { cls: 'clickable-icon ge-note-nav-button ge-note-forward-button' });
|
||||
setIcon(forwardButton, 'arrow-right');
|
||||
forwardButton.disabled = this.previewHistoryIndex >= this.previewHistory.length - 1;
|
||||
forwardButton.addEventListener('click', () => {
|
||||
if (this.previewHistoryIndex < this.previewHistory.length - 1) {
|
||||
this.previewHistoryIndex++;
|
||||
const nextFile = this.previewHistory[this.previewHistoryIndex];
|
||||
void this.showNoteInGrid(nextFile, true);
|
||||
}
|
||||
});
|
||||
|
||||
// 筆記標題 (置中)
|
||||
const noteTitle = topBar.createDiv('ge-note-title');
|
||||
noteTitle.textContent = file.basename;
|
||||
if (Platform.isDesktop) {
|
||||
setTooltip(noteTitle, file.basename);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const rightBar = topBar.createDiv('ge-note-top-right');
|
||||
|
||||
// 編輯按鈕
|
||||
const editButton = rightBar.createEl('button', { cls: 'ge-note-edit-button' });
|
||||
const editButton = rightBar.createEl('button', { cls: 'clickable-icon ge-note-edit-button' });
|
||||
setIcon(editButton, 'pencil');
|
||||
editButton.addEventListener('click', () => {
|
||||
void this.view.getLeafByMode(file).openFile(file);
|
||||
});
|
||||
|
||||
|
||||
// Metadata 切換按鈕
|
||||
const infoButton = rightBar.createEl('button', { cls: 'ge-note-info-button' });
|
||||
const infoButton = rightBar.createEl('button', { cls: 'clickable-icon ge-note-info-button' });
|
||||
setIcon(infoButton, 'info');
|
||||
|
||||
// 關閉按鈕
|
||||
const closeButton = rightBar.createEl('button', { cls: 'ge-note-close-button' });
|
||||
const closeButton = rightBar.createEl('button', { cls: 'clickable-icon ge-note-close-button' });
|
||||
setIcon(closeButton, 'x');
|
||||
closeButton.addEventListener('click', () => {
|
||||
this.hideNoteInGrid();
|
||||
|
|
@ -213,7 +272,11 @@ export class GridPreviewManager {
|
|||
e.preventDefault();
|
||||
const linkedFile = this.view.app.metadataCache.getFirstLinkpathDest(linkPath, file.path);
|
||||
if (linkedFile) {
|
||||
void this.view.getLeafByMode(linkedFile).openFile(linkedFile);
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
void this.view.getLeafByMode(linkedFile).openFile(linkedFile);
|
||||
} else {
|
||||
void this.showNoteInGrid(linkedFile);
|
||||
}
|
||||
}
|
||||
});
|
||||
lastIndex = wikilinkRegex.lastIndex;
|
||||
|
|
@ -291,6 +354,18 @@ export class GridPreviewManager {
|
|||
// 創建筆記內容區域
|
||||
const noteContentArea = noteContent.createDiv('ge-note-content');
|
||||
|
||||
// 建立筆記內第一行標題
|
||||
const vaultWithConfig = this.view.app.vault as unknown as { config?: { showInlineTitle?: boolean } };
|
||||
const showInlineTitle = vaultWithConfig.config?.showInlineTitle ?? true;
|
||||
if (showInlineTitle) {
|
||||
noteContentArea.createEl('h1', {
|
||||
cls: 'ge-note-internal-title',
|
||||
text: file.basename
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
// 讀取筆記內容
|
||||
const content = await this.view.app.vault.read(file);
|
||||
|
|
@ -322,7 +397,11 @@ export class GridPreviewManager {
|
|||
const linkText = link.getAttribute('data-href') || href;
|
||||
const linkedFile = this.view.app.metadataCache.getFirstLinkpathDest(linkText, file.path);
|
||||
if (linkedFile) {
|
||||
void this.view.getLeafByMode(linkedFile).openFile(linkedFile);
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
void this.view.getLeafByMode(linkedFile).openFile(linkedFile);
|
||||
} else {
|
||||
void this.showNoteInGrid(linkedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -335,6 +414,10 @@ export class GridPreviewManager {
|
|||
console.error('Error loading note content:', error);
|
||||
}
|
||||
|
||||
// 渲染反向連結與出站連結區塊
|
||||
await this.renderLinksSection(file, noteContent);
|
||||
|
||||
|
||||
// 行動裝置下拉或上拉關閉筆記
|
||||
if (Platform.isMobile && noteViewContainer) {
|
||||
let startY = 0;
|
||||
|
|
@ -456,23 +539,10 @@ export class GridPreviewManager {
|
|||
|
||||
// 設定狀態
|
||||
this.view.isShowingNote = true;
|
||||
|
||||
// 註冊鍵盤事件監聽器
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.hideNoteInGrid();
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
activeDocument.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
// 儲存事件監聽器以便後續移除
|
||||
(noteViewContainer as NoteViewContainerWithKeydownHandler).keydownHandler = handleKeyDown;
|
||||
}
|
||||
|
||||
// 隱藏筆記顯示
|
||||
hideNoteInGrid() {
|
||||
hideNoteInGrid(clearHistory = true) {
|
||||
if (!this.view.isShowingNote) return;
|
||||
|
||||
// 顯示移動端導航欄 (僅在行動裝置上)
|
||||
|
|
@ -487,28 +557,40 @@ export class GridPreviewManager {
|
|||
}
|
||||
|
||||
if (this.view.noteViewContainer) {
|
||||
// 移除鍵盤事件監聽器
|
||||
const keydownHandler = (this.view.noteViewContainer as NoteViewContainerWithKeydownHandler).keydownHandler;
|
||||
if (keydownHandler) {
|
||||
activeDocument.removeEventListener('keydown', keydownHandler);
|
||||
}
|
||||
|
||||
this.view.noteViewContainer.remove();
|
||||
this.view.noteViewContainer = null;
|
||||
}
|
||||
|
||||
this.view.isShowingNote = false;
|
||||
|
||||
if (clearHistory) {
|
||||
this.previewHistory = [];
|
||||
this.previewHistoryIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 在網格視圖中直接顯示 ZIP 圖片網格
|
||||
async showZipInGrid(file: TFile) {
|
||||
async showZipInGrid(file: TFile, isHistoryNavigation = false) {
|
||||
// 更新歷史紀錄
|
||||
if (!this.view.isShowingNote && !this.view.isShowingZip) {
|
||||
// 從外部全新開啟
|
||||
this.previewHistory = [file];
|
||||
this.previewHistoryIndex = 0;
|
||||
} else if (!isHistoryNavigation) {
|
||||
// 在內部點擊連結跳轉
|
||||
this.previewHistory = this.previewHistory.slice(0, this.previewHistoryIndex + 1);
|
||||
this.previewHistory.push(file);
|
||||
this.previewHistoryIndex = this.previewHistory.length - 1;
|
||||
}
|
||||
|
||||
// 關閉之前的 ZIP 顯示
|
||||
if (this.view.isShowingZip) {
|
||||
this.hideZipInGrid();
|
||||
this.hideZipInGrid(false);
|
||||
}
|
||||
// 關閉之前的筆記顯示
|
||||
if (this.view.isShowingNote) {
|
||||
this.hideNoteInGrid();
|
||||
this.hideNoteInGrid(false);
|
||||
}
|
||||
|
||||
const gridContainer = this.view.containerEl.querySelector('.ge-grid-container');
|
||||
|
|
@ -521,17 +603,41 @@ export class GridPreviewManager {
|
|||
// 頂部列 (左右區塊)
|
||||
const topBar = zipViewContainer.createDiv('ge-zip-top-bar');
|
||||
const leftBar = topBar.createDiv('ge-zip-top-left');
|
||||
const rightBar = topBar.createDiv('ge-zip-top-right');
|
||||
|
||||
// 返回與前進按鈕
|
||||
const backButton = leftBar.createEl('button', { cls: 'clickable-icon ge-note-nav-button ge-note-back-button' });
|
||||
setIcon(backButton, 'arrow-left');
|
||||
backButton.disabled = this.previewHistoryIndex <= 0;
|
||||
backButton.addEventListener('click', () => {
|
||||
if (this.previewHistoryIndex > 0) {
|
||||
this.previewHistoryIndex--;
|
||||
const prevFile = this.previewHistory[this.previewHistoryIndex];
|
||||
void this.showNoteInGrid(prevFile, true);
|
||||
}
|
||||
});
|
||||
|
||||
const forwardButton = leftBar.createEl('button', { cls: 'clickable-icon ge-note-nav-button ge-note-forward-button' });
|
||||
setIcon(forwardButton, 'arrow-right');
|
||||
forwardButton.disabled = this.previewHistoryIndex >= this.previewHistory.length - 1;
|
||||
forwardButton.addEventListener('click', () => {
|
||||
if (this.previewHistoryIndex < this.previewHistory.length - 1) {
|
||||
this.previewHistoryIndex++;
|
||||
const nextFile = this.previewHistory[this.previewHistoryIndex];
|
||||
void this.showNoteInGrid(nextFile, true);
|
||||
}
|
||||
});
|
||||
|
||||
// ZIP 標題
|
||||
const zipTitle = leftBar.createDiv('ge-zip-title');
|
||||
const zipTitle = topBar.createDiv('ge-zip-title');
|
||||
zipTitle.textContent = file.basename;
|
||||
if (Platform.isDesktop) {
|
||||
setTooltip(zipTitle, file.basename);
|
||||
}
|
||||
|
||||
const rightBar = topBar.createDiv('ge-zip-top-right');
|
||||
|
||||
// 開啟按鈕 (在分頁中開啟 ZIP 檔案)
|
||||
const openButton = rightBar.createEl('button', { cls: 'ge-zip-open-button' });
|
||||
const openButton = rightBar.createEl('button', { cls: 'clickable-icon ge-zip-open-button' });
|
||||
setIcon(openButton, 'folder-archive');
|
||||
openButton.setAttribute('aria-label', t('zip_open_file'));
|
||||
if (Platform.isDesktop) {
|
||||
|
|
@ -542,7 +648,7 @@ export class GridPreviewManager {
|
|||
});
|
||||
|
||||
// 關閉按鈕
|
||||
const closeButton = rightBar.createEl('button', { cls: 'ge-zip-close-button' });
|
||||
const closeButton = rightBar.createEl('button', { cls: 'clickable-icon ge-zip-close-button' });
|
||||
setIcon(closeButton, 'x');
|
||||
closeButton.setAttribute('aria-label', t('zip_close_view'));
|
||||
if (Platform.isDesktop) {
|
||||
|
|
@ -1036,7 +1142,7 @@ export class GridPreviewManager {
|
|||
}
|
||||
|
||||
// 隱藏 ZIP 顯示
|
||||
hideZipInGrid() {
|
||||
hideZipInGrid(clearHistory = true) {
|
||||
if (!this.view.isShowingZip) return;
|
||||
|
||||
// 顯示移動端導航欄 (僅在行動裝置上)
|
||||
|
|
@ -1074,6 +1180,11 @@ export class GridPreviewManager {
|
|||
}
|
||||
|
||||
this.view.isShowingZip = false;
|
||||
|
||||
if (clearHistory) {
|
||||
this.previewHistory = [];
|
||||
this.previewHistoryIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
selectZipItem(idx: number, gridEl: HTMLElement) {
|
||||
|
|
@ -1089,4 +1200,106 @@ export class GridPreviewManager {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async renderLinksSection(file: TFile, parentEl: HTMLElement) {
|
||||
const app = this.view.app;
|
||||
const resolvedLinks = app.metadataCache.resolvedLinks;
|
||||
|
||||
// 1. 獲取反向連結 (Backlinks)
|
||||
const backlinks = new Set<TFile>();
|
||||
for (const [sourcePath, links] of Object.entries(resolvedLinks)) {
|
||||
if (Object.keys(links).includes(file.path)) {
|
||||
const sourceFile = app.vault.getAbstractFileByPath(sourcePath);
|
||||
if (sourceFile instanceof TFile) {
|
||||
backlinks.add(sourceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果沒有反向連結,就不需要渲染此區塊
|
||||
if (backlinks.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const linksContainer = parentEl.createDiv('ge-note-links-section');
|
||||
|
||||
// 渲染反向連結
|
||||
if (backlinks.size > 0) {
|
||||
const backlinkHeader = linksContainer.createDiv('ge-note-links-header');
|
||||
backlinkHeader.createEl('span', { text: `🔗 ${t('backlinks')} (${backlinks.size})` });
|
||||
const backlinkList = linksContainer.createDiv('ge-note-links-list');
|
||||
|
||||
Array.from(backlinks).forEach((linkFile) => {
|
||||
const item = backlinkList.createEl('a', {
|
||||
cls: 'ge-note-link-item',
|
||||
text: linkFile.basename,
|
||||
});
|
||||
item.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
void this.showNoteInGrid(linkFile);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public getCurrentFile(): TFile | null {
|
||||
if (this.previewHistoryIndex >= 0 && this.previewHistoryIndex < this.previewHistory.length) {
|
||||
return this.previewHistory[this.previewHistoryIndex];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async updateCurrentPreview() {
|
||||
const file = this.getCurrentFile();
|
||||
if (!file || !this.view.noteViewContainer) return;
|
||||
|
||||
const scrollContainer = this.view.noteViewContainer.querySelector('.ge-note-scroll-container');
|
||||
const noteContent = this.view.noteViewContainer.querySelector('.ge-note-content-container');
|
||||
const noteContentArea = this.view.noteViewContainer.querySelector('.ge-note-content');
|
||||
|
||||
if (!scrollContainer || !noteContent || !noteContentArea) return;
|
||||
|
||||
const savedScrollTop = scrollContainer.scrollTop;
|
||||
|
||||
try {
|
||||
// 1. 清空舊的內容區域
|
||||
noteContentArea.empty();
|
||||
|
||||
// 2. 重新建立筆記內第一行標題
|
||||
noteContentArea.createEl('h1', {
|
||||
cls: 'ge-note-internal-title',
|
||||
text: file.basename
|
||||
});
|
||||
|
||||
// 3. 讀取與渲染
|
||||
const content = await this.view.app.vault.read(file);
|
||||
await MarkdownRenderer.render(
|
||||
this.view.app,
|
||||
content,
|
||||
noteContentArea as HTMLElement,
|
||||
file.path,
|
||||
this.view
|
||||
);
|
||||
|
||||
// 4. 加上圖片的 data-source-path
|
||||
noteContentArea
|
||||
.querySelectorAll<HTMLImageElement>('img')
|
||||
.forEach((img) => (img.dataset.sourcePath = file.path));
|
||||
|
||||
// 5. 重新渲染 backlinks
|
||||
const oldLinks = noteContent.querySelector('.ge-note-links-section');
|
||||
if (oldLinks) {
|
||||
oldLinks.remove();
|
||||
}
|
||||
await this.renderLinksSection(file, noteContent as HTMLElement);
|
||||
|
||||
// 6. 還原滾動位置
|
||||
scrollContainer.scrollTop = savedScrollTop;
|
||||
} catch (error) {
|
||||
console.error('Error updating current preview note:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
141
src/GridView.ts
141
src/GridView.ts
|
|
@ -96,12 +96,14 @@ interface GridViewStateData {
|
|||
searchMediaFiles?: boolean;
|
||||
fileNameFilterQuery?: string;
|
||||
includeMedia?: boolean | 'media-only';
|
||||
baseMinMode?: boolean;
|
||||
minMode?: boolean;
|
||||
showIgnoredItems?: boolean;
|
||||
baseCardLayout?: 'horizontal' | 'vertical';
|
||||
cardLayout?: 'horizontal' | 'vertical';
|
||||
hideHeaderElements?: boolean;
|
||||
showFileNameFilter?: boolean;
|
||||
baseShowDateDividers?: boolean;
|
||||
showDateDividers?: boolean;
|
||||
showNoteTags?: boolean;
|
||||
recentSources?: string[];
|
||||
|
|
@ -163,9 +165,11 @@ export class GridView extends ItemView {
|
|||
fileWatcher: FileWatcher | null = null; // 檔案監聽器
|
||||
recentSources: string[] = []; // 歷史記錄
|
||||
futureSources: string[] = []; // 未來紀錄(前進堆疊)
|
||||
minMode: boolean = false; // 最小模式
|
||||
baseMinMode: boolean = false; // 基礎最小模式(不受資料夾臨時覆蓋影響)
|
||||
minMode: boolean = false; // 目前實際使用的最小模式(可能被資料夾 metadata 臨時覆蓋)
|
||||
showIgnoredItems: boolean = false; // 顯示忽略的資料夾及檔案
|
||||
showDateDividers: boolean = false; // 顯示日期分隔器
|
||||
baseShowDateDividers: boolean = false; // 基礎顯示日期分隔器狀態(不受資料夾臨時覆蓋影響)
|
||||
showDateDividers: boolean = false; // 目前實際使用的顯示日期分隔器狀態(可能被資料夾 metadata 臨時覆蓋)
|
||||
showNoteTags: boolean = false; // 顯示筆記標籤
|
||||
showFileNameFilter: boolean = true; // 顯示檔名篩選輸入框
|
||||
pinnedList: string[] = []; // 置頂清單
|
||||
|
|
@ -198,7 +202,10 @@ export class GridView extends ItemView {
|
|||
this.sortType = this.baseSortType;
|
||||
this.baseCardLayout = this.plugin.settings.cardLayout;
|
||||
this.cardLayout = this.baseCardLayout;
|
||||
this.showDateDividers = this.plugin.settings.dateDividerMode !== 'none';
|
||||
this.baseMinMode = false;
|
||||
this.minMode = this.baseMinMode;
|
||||
this.baseShowDateDividers = this.plugin.settings.dateDividerMode !== 'none';
|
||||
this.showDateDividers = this.baseShowDateDividers;
|
||||
this.showNoteTags = this.plugin.settings.showNoteTags;
|
||||
this.showFileNameFilter = this.plugin.settings.showFileNameFilter;
|
||||
this.searchCurrentLocationOnly = this.plugin.settings.searchCurrentLocationOnly;
|
||||
|
|
@ -401,6 +408,14 @@ export class GridView extends ItemView {
|
|||
return;
|
||||
}
|
||||
|
||||
// 當切換來源路徑或模式時,應先隱藏當前筆記/ZIP預覽,並清空預覽歷史記錄
|
||||
if (this.isShowingNote) {
|
||||
this.hideNoteInGrid();
|
||||
}
|
||||
if (this.isShowingZip) {
|
||||
this.hideZipInGrid();
|
||||
}
|
||||
|
||||
// 記錄之前的狀態到歷史記錄中(如果有)
|
||||
if (this.sourceMode && recordHistory) {
|
||||
this.pushHistory(
|
||||
|
|
@ -433,14 +448,30 @@ export class GridView extends ItemView {
|
|||
const mdFile = this.app.vault.getAbstractFileByPath(mdFilePath);
|
||||
let tempLayout: 'horizontal' | 'vertical' = this.baseCardLayout;
|
||||
let folderSort: string | undefined;
|
||||
let tempMinMode: boolean = this.baseMinMode;
|
||||
let tempShowDateDividers: boolean = this.baseShowDateDividers;
|
||||
|
||||
if (mdFile instanceof TFile) {
|
||||
const metadata = this.app.metadataCache.getFileCache(mdFile)?.frontmatter;
|
||||
folderSort = typeof metadata?.sort === 'string' ? metadata.sort : undefined;
|
||||
if (metadata?.cardLayout === 'horizontal' || metadata?.cardLayout === 'vertical') {
|
||||
tempLayout = metadata.cardLayout as 'horizontal' | 'vertical';
|
||||
}
|
||||
if (metadata?.minMode === true || metadata?.minMode === 'true') {
|
||||
tempMinMode = true;
|
||||
} else if (metadata?.minMode === false || metadata?.minMode === 'false') {
|
||||
tempMinMode = false;
|
||||
}
|
||||
if (metadata?.showDateDividers === true || metadata?.showDateDividers === 'true') {
|
||||
tempShowDateDividers = true;
|
||||
} else if (metadata?.showDateDividers === false || metadata?.showDateDividers === 'false') {
|
||||
tempShowDateDividers = false;
|
||||
}
|
||||
}
|
||||
this.cardLayout = tempLayout;
|
||||
this.minMode = tempMinMode;
|
||||
this.showDateDividers = tempShowDateDividers;
|
||||
|
||||
// 根據資料夾 frontmatter 的 sort 覆蓋實際排序,否則使用 baseSortType
|
||||
this.sortType = folderSort && typeof folderSort === 'string' && folderSort.trim() !== ''
|
||||
? folderSort
|
||||
|
|
@ -448,6 +479,8 @@ export class GridView extends ItemView {
|
|||
} else {
|
||||
// 非資料夾模式時
|
||||
this.cardLayout = this.baseCardLayout; // 回復基礎卡片排列
|
||||
this.minMode = this.baseMinMode; // 回復基礎最小化模式
|
||||
this.showDateDividers = this.baseShowDateDividers; // 回復基礎日期分隔器模式
|
||||
this.sourcePath = '/'; // 強制設定路徑為根目錄 (創建筆記用)
|
||||
|
||||
// 切換到自訂模式時:重設選項索引,並將排序設為 'none'
|
||||
|
|
@ -1136,7 +1169,34 @@ export class GridView extends ItemView {
|
|||
} else {
|
||||
// 其他檔案顯示副檔名
|
||||
if (!this.minMode) {
|
||||
contentArea.createEl('p', { text: file.extension.toUpperCase() });
|
||||
const extension = file.extension.toLowerCase();
|
||||
const pEl = contentArea.createEl('p', { cls: 'ge-non-doc-preview' });
|
||||
const iconSpan = pEl.createSpan({ cls: 'ge-non-doc-icon' });
|
||||
let iconName = 'file';
|
||||
if (isImageFile(file)) {
|
||||
iconName = 'image';
|
||||
iconSpan.addClass('ge-img');
|
||||
} else if (isVideoFile(file)) {
|
||||
iconName = 'play-circle';
|
||||
iconSpan.addClass('ge-video');
|
||||
} else if (isAudioFile(file)) {
|
||||
iconName = 'music';
|
||||
iconSpan.addClass('ge-audio');
|
||||
} else if (extension === 'pdf') {
|
||||
iconName = 'paperclip';
|
||||
iconSpan.addClass('ge-pdf');
|
||||
} else if (extension === 'canvas') {
|
||||
iconName = 'layout-dashboard';
|
||||
iconSpan.addClass('ge-canvas');
|
||||
} else if (extension === 'base') {
|
||||
iconName = 'layout-list';
|
||||
iconSpan.addClass('ge-base');
|
||||
} else if (extension === 'zip') {
|
||||
iconName = 'folder-archive';
|
||||
iconSpan.addClass('ge-zip');
|
||||
}
|
||||
setIcon(iconSpan, iconName);
|
||||
pEl.createSpan({ text: file.extension.toUpperCase() });
|
||||
}
|
||||
|
||||
setTooltip(fileEl, `${file.name}`, { delay: 2000 })
|
||||
|
|
@ -1565,36 +1625,6 @@ export class GridView extends ItemView {
|
|||
fileEl.addClass('ge-media-card');
|
||||
}
|
||||
|
||||
// 添加檔案類型圖示
|
||||
if (isImageFile(file)) {
|
||||
const iconContainer = titleContainer.createDiv('ge-icon-container ge-img');
|
||||
setIcon(iconContainer, 'image');
|
||||
} else if (isVideoFile(file)) {
|
||||
const iconContainer = titleContainer.createDiv('ge-icon-container ge-video');
|
||||
setIcon(iconContainer, 'play-circle');
|
||||
} else if (isAudioFile(file)) {
|
||||
const iconContainer = titleContainer.createDiv('ge-icon-container ge-audio');
|
||||
setIcon(iconContainer, 'music');
|
||||
} else if (extension === 'pdf') {
|
||||
const iconContainer = titleContainer.createDiv('ge-icon-container ge-pdf');
|
||||
setIcon(iconContainer, 'paperclip');
|
||||
} else if (extension === 'canvas') {
|
||||
const iconContainer = titleContainer.createDiv('ge-icon-container ge-canvas');
|
||||
setIcon(iconContainer, 'layout-dashboard');
|
||||
} else if (extension === 'base') {
|
||||
const iconContainer = titleContainer.createDiv('ge-icon-container ge-base');
|
||||
setIcon(iconContainer, 'layout-list');
|
||||
} else if (extension === 'zip') {
|
||||
const iconContainer = titleContainer.createDiv('ge-icon-container ge-zip');
|
||||
setIcon(iconContainer, 'folder-archive');
|
||||
} else if (extension === 'md' || extension === 'txt') {
|
||||
const iconContainer = titleContainer.createDiv('ge-icon-container');
|
||||
setIcon(iconContainer, 'file-text');
|
||||
} else {
|
||||
const iconContainer = titleContainer.createDiv('ge-icon-container');
|
||||
setIcon(iconContainer, 'file');
|
||||
}
|
||||
|
||||
// 創建標題(立即載入)
|
||||
const shouldShowExtension = this.minMode && extension !== 'md';
|
||||
const displayText = shouldShowExtension ? `${file.basename}.${file.extension}` : file.basename;
|
||||
|
|
@ -2006,6 +2036,41 @@ export class GridView extends ItemView {
|
|||
});
|
||||
}
|
||||
|
||||
// 複製選項
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t("make_a_copy"))
|
||||
.setIcon("copy")
|
||||
.setSection?.("action")
|
||||
.onClick(async () => {
|
||||
for (const f of selectedFiles) {
|
||||
const parentPath = f.parent ? f.parent.path : "";
|
||||
let copyPath = "";
|
||||
if (parentPath && parentPath !== "/") {
|
||||
copyPath = `${parentPath}/${f.basename} 1.${f.extension}`;
|
||||
} else {
|
||||
copyPath = `${f.basename} 1.${f.extension}`;
|
||||
}
|
||||
|
||||
let counter = 1;
|
||||
while (this.app.vault.getAbstractFileByPath(copyPath)) {
|
||||
counter++;
|
||||
if (parentPath && parentPath !== "/") {
|
||||
copyPath = `${parentPath}/${f.basename} ${counter}.${f.extension}`;
|
||||
} else {
|
||||
copyPath = `${f.basename} ${counter}.${f.extension}`;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this.app.vault.copy(f, copyPath);
|
||||
} catch (err) {
|
||||
console.error("Failed to copy file:", err);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 刪除選項
|
||||
menu.addItem((item) => {
|
||||
(item as MenuItemWithWarning).setWarning(true);
|
||||
|
|
@ -2390,12 +2455,14 @@ export class GridView extends ItemView {
|
|||
searchMediaFiles: this.searchMediaFiles,
|
||||
fileNameFilterQuery: this.fileNameFilterQuery,
|
||||
includeMedia: this.includeMedia,
|
||||
baseMinMode: this.baseMinMode,
|
||||
minMode: this.minMode,
|
||||
showIgnoredItems: this.showIgnoredItems,
|
||||
baseCardLayout: this.baseCardLayout,
|
||||
cardLayout: this.cardLayout,
|
||||
hideHeaderElements: this.hideHeaderElements,
|
||||
showFileNameFilter: this.showFileNameFilter,
|
||||
baseShowDateDividers: this.baseShowDateDividers,
|
||||
showDateDividers: this.showDateDividers,
|
||||
showNoteTags: this.showNoteTags,
|
||||
recentSources: this.recentSources,
|
||||
|
|
@ -2418,13 +2485,15 @@ export class GridView extends ItemView {
|
|||
this.searchMediaFiles = state.state.searchMediaFiles ?? false;
|
||||
this.fileNameFilterQuery = state.state.fileNameFilterQuery ?? '';
|
||||
this.includeMedia = state.state.includeMedia ?? false;
|
||||
this.minMode = state.state.minMode ?? false;
|
||||
this.baseMinMode = state.state.baseMinMode ?? state.state.minMode ?? false;
|
||||
this.minMode = state.state.minMode ?? this.baseMinMode;
|
||||
this.showIgnoredItems = state.state.showIgnoredItems ?? false;
|
||||
this.baseCardLayout = state.state.baseCardLayout ?? 'horizontal';
|
||||
this.cardLayout = state.state.cardLayout ?? this.baseCardLayout;
|
||||
this.hideHeaderElements = state.state.hideHeaderElements ?? false;
|
||||
this.showFileNameFilter = state.state.showFileNameFilter ?? this.plugin.settings.showFileNameFilter;
|
||||
this.showDateDividers = state.state.showDateDividers ?? this.plugin.settings.dateDividerMode !== 'none';
|
||||
this.baseShowDateDividers = state.state.baseShowDateDividers ?? state.state.showDateDividers ?? (this.plugin.settings.dateDividerMode !== 'none');
|
||||
this.showDateDividers = state.state.showDateDividers ?? this.baseShowDateDividers;
|
||||
this.showNoteTags = state.state.showNoteTags ?? this.plugin.settings.showNoteTags;
|
||||
this.recentSources = state.state.recentSources ?? [];
|
||||
this.futureSources = state.state.futureSources ?? [];
|
||||
|
|
|
|||
53
src/main.ts
53
src/main.ts
|
|
@ -12,6 +12,16 @@ interface MenuItemWithSubmenu extends MenuItem {
|
|||
setSubmenu(): Menu;
|
||||
}
|
||||
|
||||
interface CustomWorkspace {
|
||||
on(name: 'grid-explorer:preview-file', callback: (fileOrPath: string | TFile) => void): EventRef;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
GridExplorer?: GridExplorerPlugin;
|
||||
}
|
||||
}
|
||||
|
||||
type WorkspaceEventHandler = (name: string, callback: (...data: unknown[]) => unknown) => EventRef;
|
||||
|
||||
interface CanvasPosition {
|
||||
|
|
@ -548,8 +558,18 @@ export default class GridExplorerPlugin extends Plugin {
|
|||
// console.log('GridExplorer: Starting cache warming process.');
|
||||
// this.startWarmingCache();
|
||||
});
|
||||
|
||||
// 註冊全域事件與掛載 window API 供其他外掛呼叫
|
||||
this.registerEvent(
|
||||
(this.app.workspace as unknown as CustomWorkspace).on('grid-explorer:preview-file', (fileOrPath: string | TFile) => {
|
||||
void this.previewFile(fileOrPath);
|
||||
})
|
||||
);
|
||||
window.GridExplorer = this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// startWarmingCache() {
|
||||
// // 1. 取得所有 Markdown 檔案的列表
|
||||
// const filesToWarm = this.app.vault.getMarkdownFiles();
|
||||
|
|
@ -844,8 +864,41 @@ export default class GridExplorerPlugin extends Plugin {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
async previewFile(fileOrPath: TFile | string) {
|
||||
let file: TFile | null = null;
|
||||
if (typeof fileOrPath === 'string') {
|
||||
const abstractFile = this.app.vault.getAbstractFileByPath(fileOrPath);
|
||||
if (abstractFile instanceof TFile) {
|
||||
file = abstractFile;
|
||||
}
|
||||
} else if (fileOrPath instanceof TFile) {
|
||||
file = fileOrPath;
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
console.warn('Grid Explorer: Invalid file or path provided for preview.', fileOrPath);
|
||||
return;
|
||||
}
|
||||
|
||||
// 取得或啟用 GridView
|
||||
const activeView = this.app.workspace.getActiveViewOfType(GridView);
|
||||
const view = activeView ?? await this.activateView();
|
||||
if (view instanceof GridView) {
|
||||
await view.showNoteInGrid(file);
|
||||
}
|
||||
}
|
||||
|
||||
onunload() {
|
||||
if (window.GridExplorer === this) {
|
||||
delete window.GridExplorer;
|
||||
}
|
||||
super.onunload();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function migrateDataviewCodeToQuery(settings: GallerySettings): void {
|
||||
if (!settings.customModes) return;
|
||||
for (const mode of settings.customModes) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ export interface FolderNoteSettings {
|
|||
icon: string;
|
||||
isPinned: boolean;
|
||||
cardLayout: '' | 'horizontal' | 'vertical';
|
||||
minMode: '' | 'true' | 'false';
|
||||
showDateDividers: '' | 'true' | 'false';
|
||||
}
|
||||
|
||||
interface FolderNoteFrontmatter {
|
||||
|
|
@ -17,6 +19,8 @@ interface FolderNoteFrontmatter {
|
|||
icon?: unknown;
|
||||
cardLayout?: unknown;
|
||||
pinned?: unknown;
|
||||
minMode?: unknown;
|
||||
showDateDividers?: unknown;
|
||||
}
|
||||
|
||||
function getStringValue(value: unknown, fallback = ''): string {
|
||||
|
|
@ -43,7 +47,9 @@ export class FolderNoteSettingsModal extends Modal {
|
|||
color: '',
|
||||
icon: '📁',
|
||||
isPinned: false,
|
||||
cardLayout: ''
|
||||
cardLayout: '',
|
||||
minMode: '',
|
||||
showDateDividers: ''
|
||||
};
|
||||
existingFile: TFile | null = null;
|
||||
|
||||
|
|
@ -180,6 +186,34 @@ export class FolderNoteSettingsModal extends Modal {
|
|||
});
|
||||
});
|
||||
|
||||
// 最小化模式選項
|
||||
new Setting(contentEl)
|
||||
.setName(t('min_mode'))
|
||||
.setDesc(t('display_minimized_desc'))
|
||||
.addDropdown(drop => {
|
||||
drop.addOption('', t('default'));
|
||||
drop.addOption('true', t('enable'));
|
||||
drop.addOption('false', t('disable'));
|
||||
drop.setValue(this.settings.minMode);
|
||||
drop.onChange(async (value) => {
|
||||
this.settings.minMode = value as '' | 'true' | 'false';
|
||||
});
|
||||
});
|
||||
|
||||
// 顯示日期分隔器選項
|
||||
new Setting(contentEl)
|
||||
.setName(t('show_date_dividers'))
|
||||
.setDesc(t('show_date_dividers_desc'))
|
||||
.addDropdown(drop => {
|
||||
drop.addOption('', t('default'));
|
||||
drop.addOption('true', t('enable'));
|
||||
drop.addOption('false', t('disable'));
|
||||
drop.setValue(this.settings.showDateDividers);
|
||||
drop.onChange(async (value) => {
|
||||
this.settings.showDateDividers = value as '' | 'true' | 'false';
|
||||
});
|
||||
});
|
||||
|
||||
// 置頂勾選框
|
||||
new Setting(contentEl)
|
||||
.setName(t('foldernote_pinned'))
|
||||
|
|
@ -226,6 +260,24 @@ export class FolderNoteSettingsModal extends Modal {
|
|||
this.settings.cardLayout =
|
||||
cardLayout === 'horizontal' || cardLayout === 'vertical' ? cardLayout : '';
|
||||
|
||||
const minMode = frontmatter.minMode;
|
||||
if (minMode === true || minMode === 'true') {
|
||||
this.settings.minMode = 'true';
|
||||
} else if (minMode === false || minMode === 'false') {
|
||||
this.settings.minMode = 'false';
|
||||
} else {
|
||||
this.settings.minMode = '';
|
||||
}
|
||||
|
||||
const showDateDividers = frontmatter.showDateDividers;
|
||||
if (showDateDividers === true || showDateDividers === 'true') {
|
||||
this.settings.showDateDividers = 'true';
|
||||
} else if (showDateDividers === false || showDateDividers === 'false') {
|
||||
this.settings.showDateDividers = 'false';
|
||||
} else {
|
||||
this.settings.showDateDividers = '';
|
||||
}
|
||||
|
||||
if (Array.isArray(frontmatter.pinned)) {
|
||||
this.settings.isPinned = frontmatter.pinned.some((item: unknown) => {
|
||||
const pinnedName = getPinnedName(item);
|
||||
|
|
@ -284,6 +336,22 @@ export class FolderNoteSettingsModal extends Modal {
|
|||
} else {
|
||||
delete frontmatter.cardLayout;
|
||||
}
|
||||
|
||||
if (this.settings.minMode === 'true') {
|
||||
frontmatter.minMode = true;
|
||||
} else if (this.settings.minMode === 'false') {
|
||||
frontmatter.minMode = false;
|
||||
} else {
|
||||
delete frontmatter.minMode;
|
||||
}
|
||||
|
||||
if (this.settings.showDateDividers === 'true') {
|
||||
frontmatter.showDateDividers = true;
|
||||
} else if (this.settings.showDateDividers === 'false') {
|
||||
frontmatter.showDateDividers = false;
|
||||
} else {
|
||||
delete frontmatter.showDateDividers;
|
||||
}
|
||||
|
||||
const folderName = `${this.folder.name}.md`;
|
||||
if (this.settings.isPinned) {
|
||||
|
|
|
|||
|
|
@ -566,7 +566,8 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
.setIcon('minimize-2')
|
||||
.setChecked(gridView.minMode)
|
||||
.onClick(() => {
|
||||
gridView.minMode = !gridView.minMode;
|
||||
gridView.baseMinMode = !gridView.minMode;
|
||||
gridView.minMode = gridView.baseMinMode;
|
||||
gridView.app.workspace.requestSaveLayout();
|
||||
void gridView.render();
|
||||
});
|
||||
|
|
@ -579,7 +580,8 @@ export function renderHeaderButton(gridView: GridView) {
|
|||
.setIcon('calendar')
|
||||
.setChecked(gridView.showDateDividers)
|
||||
.onClick(() => {
|
||||
gridView.showDateDividers = !gridView.showDateDividers;
|
||||
gridView.baseShowDateDividers = !gridView.showDateDividers;
|
||||
gridView.showDateDividers = gridView.baseShowDateDividers;
|
||||
gridView.app.workspace.requestSaveLayout();
|
||||
void gridView.render();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export const DEFAULT_SETTINGS: GallerySettings = {
|
|||
verticalImageAreaHeight: 180, // 直向卡片 - 圖片區域高度
|
||||
verticalCardImagePosition: 'top', // 直向卡片圖片位置
|
||||
titleFontSize: 1.0, // 筆記標題的字型大小,預設 1.0
|
||||
multiLineTitle: false,
|
||||
multiLineTitle: true, // 標題允許兩行顯示
|
||||
summaryLength: 100, // 筆記摘要的字數,預設 100
|
||||
enableFileWatcher: true, // 預設啟用檔案監控
|
||||
folderDisplayStyle: 'show', // 預設直接顯示資料夾
|
||||
|
|
@ -155,7 +155,7 @@ export const DEFAULT_SETTINGS: GallerySettings = {
|
|||
quickAccessCommandPath: '', // Path used by "Open quick access folder" command
|
||||
useQuickAccessAsNewTabMode: 'default',
|
||||
quickAccessModeType: 'all-files', // Default quick access view type
|
||||
showNoteInGrid: false, // 預設不在 grid container 中顯示筆記
|
||||
showNoteInGrid: Platform.isMobile ? true : false, // 行動裝置: 預設在網格中顯示筆記,非行動裝置預設不在網格中顯示筆記
|
||||
closeGridViewOnOpenNote: false, // 預設開啟筆記檔案時不關閉目前的網格視圖
|
||||
openNoteLayout: 'default', // 預設開啟筆記的方式
|
||||
searchCurrentLocationOnly: false, // 預設搜尋所有筆記
|
||||
|
|
@ -307,6 +307,9 @@ export class GridExplorerSettingTab extends PluginSettingTab {
|
|||
const infoEl = itemEl.createDiv({ cls: 'ge-custom-mode-info' });
|
||||
infoEl.createSpan({ text: mode.icon || '🧩', cls: 'ge-custom-mode-icon' });
|
||||
infoEl.createSpan({ text: mode.displayName, cls: 'ge-custom-mode-name' });
|
||||
infoEl.addEventListener('click', () => {
|
||||
checkbox.click();
|
||||
});
|
||||
|
||||
// 操作按鈕
|
||||
const actionsEl = itemEl.createDiv({ cls: 'ge-custom-mode-actions' });
|
||||
|
|
@ -523,6 +526,9 @@ export class GridExplorerSettingTab extends PluginSettingTab {
|
|||
const infoEl = itemEl.createDiv({ cls: 'ge-display-mode-info' });
|
||||
infoEl.createSpan({ text: icon, cls: 'ge-display-mode-icon' });
|
||||
infoEl.createSpan({ text: title, cls: 'ge-display-mode-name' });
|
||||
infoEl.addEventListener('click', () => {
|
||||
checkbox.click();
|
||||
});
|
||||
|
||||
if (extraRenderer) {
|
||||
const extraEl = itemEl.createDiv({ cls: 'ge-display-mode-extra' });
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export default {
|
|||
'sorting': 'Sort by',
|
||||
'refresh': 'Refresh',
|
||||
'reselect': 'Reselect',
|
||||
'backlinks': 'Backlinks',
|
||||
'no_backlinks': 'No backlinks',
|
||||
'back': 'Back',
|
||||
'search': 'Search',
|
||||
|
|
@ -39,6 +40,7 @@ export default {
|
|||
'save': 'Save',
|
||||
'option': 'Option',
|
||||
'add_option': 'Add option',
|
||||
'make_a_copy': 'Make a copy',
|
||||
|
||||
// View Titles
|
||||
'grid_view_title': 'Grid view',
|
||||
|
|
@ -185,6 +187,8 @@ export default {
|
|||
'foldernote_display_settings_desc': 'Set the display mode of folder notes',
|
||||
'all': 'All',
|
||||
'default': 'Default',
|
||||
'enable': 'Enable',
|
||||
'disable': 'Disable',
|
||||
'hidden': 'Hidden',
|
||||
'all_bookmarks': 'All Bookmarks',
|
||||
'ungrouped_bookmarks': 'Ungrouped Bookmarks',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export default {
|
|||
'sorting': '並び替え',
|
||||
'refresh': '更新',
|
||||
'reselect': '再選択',
|
||||
'backlinks': 'バックリンク',
|
||||
'no_backlinks': 'バックリンクなし',
|
||||
'back': '戻る',
|
||||
'search': '検索',
|
||||
|
|
@ -38,6 +39,7 @@ export default {
|
|||
'save': '保存',
|
||||
'option': '選択肢',
|
||||
'add_option': '選択肢を追加',
|
||||
'make_a_copy': '複製を作成',
|
||||
|
||||
// ビュータイトル
|
||||
'grid_view_title': 'グリッドビュー',
|
||||
|
|
@ -184,6 +186,8 @@ export default {
|
|||
'foldernote_display_settings_desc': 'フォルダノートの表示方法を設定します',
|
||||
'all': 'すべて',
|
||||
'default': 'デフォルト',
|
||||
'enable': '有効',
|
||||
'disable': '無効',
|
||||
'hidden': '隠す',
|
||||
'all_bookmarks': 'すべてのブックマーク',
|
||||
'ungrouped_bookmarks': 'グループなし',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export default {
|
|||
'sorting': '정렬 기준',
|
||||
'refresh': '새로고침',
|
||||
'reselect': '다시 선택',
|
||||
'backlinks': '백링크',
|
||||
'no_backlinks': '백링크 없음',
|
||||
'back': '뒤로',
|
||||
'search': '검색',
|
||||
|
|
@ -39,6 +40,7 @@ export default {
|
|||
'save': '저장',
|
||||
'option': '옵션',
|
||||
'add_option': '옵션 추가',
|
||||
'make_a_copy': '복사본 만들기',
|
||||
|
||||
// View Titles
|
||||
'grid_view_title': '그리드 뷰',
|
||||
|
|
@ -185,6 +187,8 @@ export default {
|
|||
'foldernote_display_settings_desc': '폴더 노트의 표시 모드 설정',
|
||||
'all': '전체',
|
||||
'default': '기본값',
|
||||
'enable': '활성화',
|
||||
'disable': '비활성화',
|
||||
'hidden': '숨김',
|
||||
'all_bookmarks': '모든 북마크',
|
||||
'ungrouped_bookmarks': '그룹 해제됨',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export default {
|
|||
'sorting': 'Сортировать по',
|
||||
'refresh': 'Обновить',
|
||||
'reselect': 'Перевыбрать',
|
||||
'backlinks': 'Обратные ссылки',
|
||||
'no_backlinks': 'Нет обратных ссылок',
|
||||
'back': 'Назад',
|
||||
'search': 'Поиск',
|
||||
|
|
@ -38,6 +39,7 @@ export default {
|
|||
'save': 'Сохранить',
|
||||
'option': 'Опция',
|
||||
'add_option': 'Добавить опцию',
|
||||
'make_a_copy': 'Создать копию',
|
||||
|
||||
// View Titles
|
||||
'grid_view_title': 'Сеточный вид',
|
||||
|
|
@ -184,6 +186,8 @@ export default {
|
|||
'foldernote_display_settings_desc': 'Установить режим отображения заметок папок',
|
||||
'all': 'Все',
|
||||
'default': 'По умолчанию',
|
||||
'enable': 'Включить',
|
||||
'disable': 'Выключить',
|
||||
'hidden': 'Скрытые',
|
||||
'all_bookmarks': 'Все закладки',
|
||||
'ungrouped_bookmarks': 'Без группы',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export default {
|
|||
'sorting': 'Сортувати за',
|
||||
'refresh': 'Оновити',
|
||||
'reselect': 'Перевибрати',
|
||||
'backlinks': 'Зворотні посилання',
|
||||
'no_backlinks': 'Немає зворотних посилань',
|
||||
'back': 'Назад',
|
||||
'search': 'Пошук',
|
||||
|
|
@ -38,6 +39,7 @@ export default {
|
|||
'save': 'Зберегти',
|
||||
'option': 'Опція',
|
||||
'add_option': 'Додати опцію',
|
||||
'make_a_copy': 'Створити копію',
|
||||
|
||||
// View Titles
|
||||
'grid_view_title': 'Сітковий вигляд',
|
||||
|
|
@ -184,6 +186,8 @@ export default {
|
|||
'foldernote_display_settings_desc': 'Встановіть режим відображення нотаток папок',
|
||||
'all': 'Усі',
|
||||
'default': 'За замовчуванням',
|
||||
'enable': 'Увімкнути',
|
||||
'disable': 'Вимкнути',
|
||||
'hidden': 'Приховані',
|
||||
'all_bookmarks': 'Усі закладки',
|
||||
'ungrouped_bookmarks': 'Без групи',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export default {
|
|||
'sorting': '排序方式',
|
||||
'refresh': '重新整理',
|
||||
'reselect': '重新選擇位置',
|
||||
'backlinks': '反向連結',
|
||||
'no_backlinks': '沒有反向連結',
|
||||
'back': '返回',
|
||||
'search': '搜尋',
|
||||
|
|
@ -39,6 +40,7 @@ export default {
|
|||
'save': '儲存',
|
||||
'option': '選項',
|
||||
'add_option': '新增選項',
|
||||
'make_a_copy': "建立副本",
|
||||
|
||||
// 視圖標題
|
||||
'grid_view_title': '網格視圖',
|
||||
|
|
@ -185,6 +187,8 @@ export default {
|
|||
'foldernote_display_settings_desc': '設定資料夾筆記的顯示方式',
|
||||
'all': '全部',
|
||||
'default': '預設',
|
||||
'enable': '啟用',
|
||||
'disable': '停用',
|
||||
'hidden': '隱藏',
|
||||
'all_bookmarks': '全部書籤',
|
||||
'ungrouped_bookmarks': '無群組書籤',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export default {
|
|||
'sorting': '排序方式',
|
||||
'refresh': '刷新',
|
||||
'reselect': '重新选择位置',
|
||||
'backlinks': '反向链接',
|
||||
'no_backlinks': '没有反向链接',
|
||||
'back': '返回',
|
||||
'search': '搜索',
|
||||
|
|
@ -38,6 +39,7 @@ export default {
|
|||
'save': '保存',
|
||||
'option': '选项',
|
||||
'add_option': '添加选项',
|
||||
'make_a_copy': '创建副本',
|
||||
|
||||
// 视图标题
|
||||
'grid_view_title': '网格视图',
|
||||
|
|
@ -184,6 +186,8 @@ export default {
|
|||
'foldernote_display_settings_desc': '设置文件夹笔记的显示方式',
|
||||
'all': '全部',
|
||||
'default': '默认',
|
||||
'enable': '启用',
|
||||
'disable': '禁用',
|
||||
'hidden': '隐藏',
|
||||
'all_bookmarks': '全部书签',
|
||||
'ungrouped_bookmarks': '无群组书签',
|
||||
|
|
|
|||
276
styles.css
276
styles.css
|
|
@ -129,39 +129,9 @@
|
|||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* 圖片圖示 Image Icon */
|
||||
.ge-icon-container.ge-img {
|
||||
color: var(--color-blue);
|
||||
}
|
||||
|
||||
/* 影片圖示 Video Icon */
|
||||
.ge-icon-container.ge-video {
|
||||
color: var(--color-red);
|
||||
}
|
||||
|
||||
/* 音樂圖示 Audio Icon */
|
||||
.ge-icon-container.ge-audio {
|
||||
color: var(--color-purple);
|
||||
}
|
||||
|
||||
/* PDF圖示 PDF Icon */
|
||||
.ge-icon-container.ge-pdf {
|
||||
color: var(--color-orange);
|
||||
}
|
||||
|
||||
/* Canvas圖示 Canvas Icon */
|
||||
.ge-icon-container.ge-canvas {
|
||||
color: var(--color-green);
|
||||
}
|
||||
|
||||
/* 基礎圖示 Base Icon */
|
||||
.ge-icon-container.ge-base {
|
||||
color: var(--color-cyan);
|
||||
}
|
||||
|
||||
/* 標題 Title */
|
||||
.ge-title {
|
||||
margin: 0 0 0 3px;
|
||||
margin: 0;
|
||||
font-size: var(--title-font-size);
|
||||
color: var(--text-normal);
|
||||
overflow: hidden;
|
||||
|
|
@ -176,22 +146,11 @@
|
|||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.ge-title-container.has-multiline-title .ge-icon-container {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.ge-title-container.has-multiline-title .ge-icon-container svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.ge-title.ge-multiline-title {
|
||||
white-space: normal;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-line-clamp: 3;
|
||||
line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 1.3;
|
||||
overflow: hidden;
|
||||
|
|
@ -225,6 +184,53 @@
|
|||
height: auto;
|
||||
}
|
||||
|
||||
/* 非文件檔預覽樣式 */
|
||||
.ge-content-area p.ge-non-doc-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.ge-non-doc-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.ge-non-doc-icon.ge-img {
|
||||
color: var(--color-blue);
|
||||
}
|
||||
|
||||
.ge-non-doc-icon.ge-video {
|
||||
color: var(--color-red);
|
||||
}
|
||||
|
||||
.ge-non-doc-icon.ge-audio {
|
||||
color: var(--color-purple);
|
||||
}
|
||||
|
||||
.ge-non-doc-icon.ge-pdf {
|
||||
color: var(--color-orange);
|
||||
}
|
||||
|
||||
.ge-non-doc-icon.ge-canvas {
|
||||
color: var(--color-green);
|
||||
}
|
||||
|
||||
.ge-non-doc-icon.ge-base {
|
||||
color: var(--color-cyan);
|
||||
}
|
||||
|
||||
.ge-non-doc-icon.ge-zip {
|
||||
color: var(--color-folder); /* obsidian color or fallback */
|
||||
}
|
||||
|
||||
|
||||
/* 圖片區域 Image Area */
|
||||
.ge-image-area {
|
||||
width: var(--image-area-width);
|
||||
|
|
@ -1058,6 +1064,7 @@ span.ge-mode-title {
|
|||
gap: 8px;
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ge-custom-mode-icon {
|
||||
|
|
@ -1151,6 +1158,7 @@ span.ge-mode-title {
|
|||
gap: 8px;
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ge-display-mode-icon {
|
||||
|
|
@ -2296,11 +2304,10 @@ a.ge-current-folder:hover {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding-left: 20px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
|
||||
.ge-note-top-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -2330,50 +2337,47 @@ a.ge-current-folder:hover {
|
|||
.ge-note-info-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 12px;
|
||||
background-color: var(--interactive-normal);
|
||||
border-radius: var(--button-radius);
|
||||
color: var(--text-normal);
|
||||
font-size: 14px;
|
||||
justify-content: center;
|
||||
padding: 6px;
|
||||
background-color: transparent;
|
||||
border-radius: var(--clickable-icon-radius, 4px);
|
||||
color: var(--icon-color);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, transform 0.1s;
|
||||
}
|
||||
|
||||
.is-tablet .ge-note-close-button:not(.clickable-icon),
|
||||
.is-tablet .ge-note-edit-button:not(.clickable-icon),
|
||||
.is-tablet .ge-note-info-button:not(.clickable-icon) {
|
||||
padding: 6px 12px;
|
||||
transition: background-color 0.2s;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ge-note-close-button:hover,
|
||||
.ge-note-edit-button:hover,
|
||||
.ge-note-info-button:hover {
|
||||
background-color: var(--interactive-hover);
|
||||
transform: translateY(-1px);
|
||||
opacity: 1;
|
||||
background-color: var(--background-modifier-hover);
|
||||
color: var(--icon-color-focused);
|
||||
}
|
||||
|
||||
.ge-note-close-button:active,
|
||||
.ge-note-edit-button:active,
|
||||
.ge-note-info-button:active {
|
||||
transform: translateY(0);
|
||||
background-color: var(--background-modifier-active);
|
||||
}
|
||||
|
||||
.is-mobile .ge-note-info-button:focus,
|
||||
.is-mobile .ge-note-info-button:focus-visible {
|
||||
outline: none;
|
||||
background-color: var(--interactive-normal);
|
||||
transform: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.ge-note-content-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
padding: var(--file-margins);
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.is-mobile .ge-note-content-container {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.ge-note-title {
|
||||
font-size: 1em;
|
||||
font-weight: var(--inline-title-weight);
|
||||
|
|
@ -3295,9 +3299,7 @@ a.ge-current-folder:hover {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding-left: 20px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.ge-zip-top-right {
|
||||
|
|
@ -3308,33 +3310,37 @@ a.ge-current-folder:hover {
|
|||
}
|
||||
|
||||
.ge-zip-title {
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
color: var(--text-normal);
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
font-size: 0.95em;
|
||||
color: var(--text-muted);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.ge-zip-close-button,
|
||||
.ge-zip-open-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 12px;
|
||||
background-color: var(--interactive-normal);
|
||||
border-radius: var(--button-radius);
|
||||
color: var(--text-normal);
|
||||
font-size: 14px;
|
||||
justify-content: center;
|
||||
padding: 6px;
|
||||
background-color: transparent;
|
||||
border-radius: var(--clickable-icon-radius, 4px);
|
||||
color: var(--icon-color);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, transform 0.1s;
|
||||
transition: background-color 0.2s;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ge-zip-close-button:hover,
|
||||
.ge-zip-open-button:hover {
|
||||
background-color: var(--interactive-hover);
|
||||
transform: translateY(-1px);
|
||||
background-color: var(--background-modifier-hover);
|
||||
color: var(--icon-color-focused);
|
||||
}
|
||||
|
||||
.ge-zip-scroll-container {
|
||||
|
|
@ -3422,7 +3428,7 @@ a.ge-current-folder:hover {
|
|||
|
||||
@media (hover: hover) {
|
||||
.ge-folder-button:hover {
|
||||
background-color: var(--background-modifier-hover);
|
||||
background-color: var(--text-selection);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
|
@ -3502,4 +3508,106 @@ a.ge-current-folder:hover {
|
|||
.ge-folder-button.ge-folder-color-custom {
|
||||
background-color: var(--ge-folder-color-bg);
|
||||
border-color: var(--ge-folder-color-border);
|
||||
}
|
||||
|
||||
/* 筆記預覽內部關聯連結區塊 */
|
||||
.ge-note-links-section {
|
||||
margin-top: 40px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid var(--background-modifier-border);
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.ge-note-links-header {
|
||||
font-size: 0.9em;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 12px;
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ge-note-links-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.ge-note-link-item {
|
||||
font-size: 0.85em;
|
||||
padding: 4px 10px;
|
||||
background-color: var(--background-secondary-alt);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 12px;
|
||||
color: var(--text-normal);
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ge-note-link-item:hover {
|
||||
background-color: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
border-color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
/* 歷史導航按鈕 */
|
||||
.ge-note-nav-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 6px;
|
||||
background-color: transparent;
|
||||
border-radius: var(--clickable-icon-radius, 4px);
|
||||
color: var(--icon-color);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ge-note-nav-button:hover:not(:disabled) {
|
||||
background-color: var(--background-modifier-hover);
|
||||
color: var(--icon-color-focused);
|
||||
}
|
||||
|
||||
.ge-note-nav-button:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.ge-note-nav-button svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
|
||||
/* 頂部列與標題置中 */
|
||||
.ge-note-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
font-size: 0.95em;
|
||||
color: var(--text-muted);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 筆記內第一行標題 (預設顯示) */
|
||||
.ge-note-internal-title {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
padding-bottom: 12px;
|
||||
font-size: var(--inline-title-size);
|
||||
font-weight: var(--inline-title-weight);
|
||||
line-height: var(--inline-title-line-height);
|
||||
font-style: var(--inline-title-style);
|
||||
font-variant: var(--inline-title-variant);
|
||||
font-family: var(--inline-title-font);
|
||||
letter-spacing: -0.015em;
|
||||
}
|
||||
Loading…
Reference in a new issue