From 8677eee105987921171df669c0231ba730619cc1 Mon Sep 17 00:00:00 2001 From: Devon22 Date: Fri, 11 Jul 2025 17:39:33 +0800 Subject: [PATCH] 2.6.2 --- manifest.json | 2 +- package-lock.json | 4 +- package.json | 2 +- src/GridView.ts | 173 +++++++++++++++++++++++++++++------ src/modal/customModeModal.ts | 48 +++++++--- src/settings.ts | 2 + src/translations.ts | 18 ++-- styles.css | 93 +++++++++++++------ versions.json | 5 +- 9 files changed, 256 insertions(+), 91 deletions(-) diff --git a/manifest.json b/manifest.json index 1f2d63f..5046f51 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "gridexplorer", "name": "GridExplorer", - "version": "2.6.1", + "version": "2.6.2", "minAppVersion": "1.1.0", "description": "Browse note files in a grid view.", "author": "Devon22", diff --git a/package-lock.json b/package-lock.json index a7da3d3..137611c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gridexplorer", - "version": "2.6.1", + "version": "2.6.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gridexplorer", - "version": "2.6.1", + "version": "2.6.2", "license": "MIT", "devDependencies": { "@types/node": "^16.11.6", diff --git a/package.json b/package.json index c53ee58..f593216 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gridexplorer", - "version": "2.6.1", + "version": "2.6.2", "description": "Browse note files in a grid view.", "main": "main.js", "scripts": { diff --git a/src/GridView.ts b/src/GridView.ts index 1c37284..03fdddd 100644 --- a/src/GridView.ts +++ b/src/GridView.ts @@ -1,4 +1,4 @@ -import { WorkspaceLeaf, ItemView, TFolder, TFile, Menu, Notice, Platform, setIcon, getFrontMatterInfo, FrontMatterCache, normalizePath } from 'obsidian'; +import { WorkspaceLeaf, ItemView, TFolder, TFile, Menu, Notice, Platform, setIcon, getFrontMatterInfo, FrontMatterCache, normalizePath, setTooltip } from 'obsidian'; import GridExplorerPlugin from '../main'; import { handleKeyDown as handleKeyDownHelper } from './handleKeyDown'; import { isDocumentFile, isMediaFile, isImageFile, isVideoFile, isAudioFile, sortFiles, ignoredFiles, getFiles, IMAGE_EXTENSIONS, VIDEO_EXTENSIONS } from './fileUtils'; @@ -197,6 +197,11 @@ export class GridView extends ItemView { if(this.sourceMode === '') this.sourceMode = 'folder'; if(this.sourcePath === '') this.sourcePath = '/'; + // 非資料夾模式時,強制路徑為根目錄 + if(this.sourceMode !== 'folder') { + this.sourcePath = '/'; + } + this.render(resetScroll); // 通知 Obsidian 保存視圖狀態 this.app.workspace.requestSaveLayout(); @@ -696,12 +701,12 @@ export class GridView extends ItemView { parentFolderName = t('root'); } - const folderNameContainer = this.containerEl.createDiv('ge-foldername-content'); + const modenameContainer = this.containerEl.createDiv('ge-modename-content'); // 為區域添加點擊事件,點擊後網格容器捲動到最頂部 - folderNameContainer.addEventListener('click', (event: MouseEvent) => { + modenameContainer.addEventListener('click', (event: MouseEvent) => { // 只有當點擊的是頂部按鈕區域本身(而不是其中的按鈕)時才觸發捲動 - if (event.target === folderNameContainer) { + if (event.target === modenameContainer) { event.preventDefault(); // 取得網格容器 const gridContainer = this.containerEl.querySelector('.ge-grid-container'); @@ -716,7 +721,7 @@ export class GridView extends ItemView { // 建立可點擊的上層資料夾名稱 const customFolderIcon = this.plugin.settings.customFolderIcon; - const parentFolderLink = folderNameContainer.createEl('a', { + const parentFolderLink = modenameContainer.createEl('a', { text: `${customFolderIcon} ${parentFolderName}`.trim(), cls: 'ge-parent-folder-link' }); @@ -801,10 +806,10 @@ export class GridView extends ItemView { }); // 分隔符號 - folderNameContainer.createEl('span', { text: ' > ' }); + modenameContainer.createEl('span', { text: ' > ' }); // 目前資料夾名稱 - folderNameContainer.createEl('span', { text: currentFolderName }); + modenameContainer.createEl('span', { text: currentFolderName }); if (Platform.isDesktop) { // 為上層按鈕添加拖曳目標功能 @@ -864,12 +869,12 @@ export class GridView extends ItemView { } } else if (!(this.searchQuery !== '' && this.searchAllFiles)) { // 顯示目前模式名稱 - const folderNameContainer = this.containerEl.createDiv('ge-foldername-content'); + const modenameContainer = this.containerEl.createDiv('ge-modename-content'); // 為區域添加點擊事件,點擊後網格容器捲動到最頂部 - folderNameContainer.addEventListener('click', (event: MouseEvent) => { + modenameContainer.addEventListener('click', (event: MouseEvent) => { // 只有當點擊的是頂部按鈕區域本身(而不是其中的按鈕)時才觸發捲動 - if (event.target === folderNameContainer) { + if (event.target === modenameContainer) { event.preventDefault(); // 取得網格容器 const gridContainer = this.containerEl.querySelector('.ge-grid-container'); @@ -953,17 +958,45 @@ export class GridView extends ItemView { } } - // 顯示模式名稱 - folderNameContainer.createEl('span', { - text: `${modeIcon} ${modeName}`.trim(), - cls: 'ge-mode-title' - }); + // 顯示模式名稱 (若為自訂模式則提供點擊選單以快速切換) + let modeTitleEl: HTMLElement; + if (this.sourceMode.startsWith('custom-')) { + // 使用可點擊的 元素 + modeTitleEl = modenameContainer.createEl('a', { + text: `${modeIcon} ${modeName}`.trim(), + cls: 'ge-parent-folder-link' + }); + + // 點擊時顯示所有自訂模式選單 + modeTitleEl.addEventListener('click', (evt) => { + const menu = new Menu(); + this.plugin.settings.customModes + .filter(m => m.enabled ?? true) // 僅顯示啟用的自訂模式 + .forEach((m) => { + menu.addItem(item => { + item.setTitle(`${m.icon || '🧩'} ${m.displayName}`) + .setChecked(m.internalName === this.sourceMode) + .onClick(() => { + // 切換至選取的自訂模式並重新渲染 + this.setSource(m.internalName, '', true); + }); + }); + }); + menu.showAtMouseEvent(evt); + }); + } else { + // 其他模式維持原本的 span + modeTitleEl = modenameContainer.createEl('span', { + text: `${modeIcon} ${modeName}`.trim(), + cls: 'ge-mode-title' + }); + } switch (this.sourceMode) { case 'tasks': - folderNameContainer.createEl('span', { text: ' > ' }); + modenameContainer.createEl('span', { text: ' > ' }); - const taskFilterSpan = folderNameContainer.createEl('a', { text: t(`${this.taskFilter}`), cls: 'ge-task-filter' }); + const taskFilterSpan = modenameContainer.createEl('a', { text: t(`${this.taskFilter}`), cls: 'ge-task-filter' }); taskFilterSpan.addEventListener('click', (evt) => { const menu = new Menu(); menu.addItem((item) => { @@ -999,10 +1032,16 @@ export class GridView extends ItemView { break; default: if (this.sourceMode.startsWith('custom-')) { + // 把 modenameContainer 加上所有自訂模式選項的選單 + // 取得當前自訂模式 const mode = this.plugin.settings.customModes.find(m => m.internalName === this.sourceMode); if (mode && mode.options && mode.options.length > 0) { - folderNameContainer.createEl('span', { text: ' > ' }); + modenameContainer.createEl('span', { text: ' > ' }); + + if (this.customOptionIndex >= mode.options.length || this.customOptionIndex < -1) { + this.customOptionIndex = -1; + } let subName: string | undefined; if (this.customOptionIndex === -1) { @@ -1012,7 +1051,7 @@ export class GridView extends ItemView { subName = opt.name?.trim() || `${t('option')} ${this.customOptionIndex + 1}`; } - const subSpan = folderNameContainer.createEl('a', { text: subName ?? '-', cls: 'ge-sub-option' }); + const subSpan = modenameContainer.createEl('a', { text: subName ?? '-', cls: 'ge-sub-option' }); subSpan.addEventListener('click', (evt) => { const menu = new Menu(); // 預設選項 @@ -1045,8 +1084,8 @@ export class GridView extends ItemView { } } else if (this.searchQuery !== '' && this.searchAllFiles) { // 顯示全域搜尋名稱 - const folderNameContainer = this.containerEl.createDiv('ge-foldername-content'); - folderNameContainer.createEl('span', { + const modenameContainer = this.containerEl.createDiv('ge-modename-content'); + modenameContainer.createEl('span', { text: `🔍 ${t('global_search')}`, cls: 'ge-mode-title' }); @@ -1226,7 +1265,7 @@ export class GridView extends ItemView { const titleContainer = contentArea.createDiv('ge-title-container'); const customFolderIcon = this.plugin.settings.customFolderIcon; titleContainer.createEl('span', { cls: 'ge-title', text: `${customFolderIcon} ${folder.name}`.trim() }); - titleContainer.setAttribute('title', folder.name); + setTooltip(folderEl, folder.name,{ placement: this.cardLayout === 'vertical' ? 'bottom' : 'right' }); // 檢查同名筆記是否存在 const notePath = `${folder.path}/${folder.name}.md`; @@ -1681,11 +1720,59 @@ export class GridView extends ItemView { let pEl: HTMLElement | null = null; if (!this.minMode) { - const summaryField = this.plugin.settings.noteSummaryField || 'summary'; - const summaryValue = metadata?.[summaryField]; + let summaryField = this.plugin.settings.noteSummaryField || 'summary'; + let summaryValue = metadata?.[summaryField]; + if (this.sourceMode.startsWith('custom-')) { + // 自訂模式下,使用自訂的 fields 來顯示摘要 + const mode = this.plugin.settings.customModes.find(m => m.internalName === this.sourceMode); + if (mode) { + let fields = mode?.fields || ''; + // 當有選到子選項 (index >= 0) 而且 options 陣列確實存在 + if (this.customOptionIndex >= 0 && + mode.options && + this.customOptionIndex < mode.options.length) { + const option = mode.options[this.customOptionIndex]; + fields = option.fields || ''; + } + + // 如果 fields 不為空,則使用它來顯示摘要 + if (fields) { + // 將 fields 以逗號分隔成陣列,並過濾掉空值 + const fieldList = fields.split(',').map(f => f.trim()).filter(Boolean); + const fieldValues: string[] = []; + + // 收集所有欄位值 + fieldList.forEach(field => { + if (metadata?.[field] !== undefined && metadata?.[field] !== '' && metadata?.[field] !== null) { + // 如果是數字,則加入千位分隔符號 + if (typeof metadata[field] === 'number') { + metadata[field] = metadata[field].toLocaleString(); + } + // 如果是陣列,則轉換為字串 + if (Array.isArray(metadata[field])) { + metadata[field] = metadata[field].join(', '); + } + fieldValues.push(`${field}: ${metadata[field]}`); + } + }); + + // 如果有找到任何欄位值,則組合起來 + if (fieldValues.length > 0) { + summaryValue = fieldValues.join('\n'); // 使用 | 分隔不同欄位 + } + } + } + } if (summaryValue) { - pEl = contentArea.createEl('p', { text: summaryValue.trim() }); + if (!this.sourceMode.startsWith('custom-')) { + // Frontmatter 有設定摘要值 + pEl = contentArea.createEl('p', { text: summaryValue.trim() }); + } else { + // custom mode 有設定顯示欄位值 + pEl = contentArea.createEl('p', { text: summaryValue.trim() , cls: 'ge-content-area-p-field' }); + } } else { + // Frontmatter 沒有設定摘要值,則使用內文 let contentWithoutFrontmatter = ''; if (summaryLength < 500) { contentWithoutFrontmatter = content.substring(frontMatterInfo.contentStart).slice(0, 500); @@ -1737,7 +1824,8 @@ export class GridView extends ItemView { //將預覽文字設定到標題的 title 屬性中 const titleEl = fileEl.querySelector('.ge-title'); if (titleEl && pEl) { - titleEl.setAttribute('title', `${titleEl.textContent}\n${pEl.textContent}` || ''); + // titleEl.setAttribute('title', `${titleEl.textContent}\n${pEl.textContent}` || ''); + setTooltip(contentArea as HTMLElement, `${titleEl.textContent}`, { placement: this.cardLayout === 'vertical' ? 'bottom' : 'right' }) } if (frontMatterInfo.exists) { @@ -1783,6 +1871,8 @@ export class GridView extends ItemView { if (!this.minMode) { contentArea.createEl('p', { text: file.extension.toUpperCase() }); } + + setTooltip(fileEl as HTMLElement, `${file.name}`, { placement: this.cardLayout === 'vertical' ? 'bottom' : 'right' }) } // 顯示標籤(僅限 Markdown 檔案) @@ -2208,6 +2298,11 @@ export class GridView extends ItemView { fileEl.addClass('ge-foldernote'); } + //如果檔案是否處於置頂範圍,添加 ge-pinned 類別 + if (this.pinnedList.includes(file.name)) { + fileEl.addClass('ge-pinned'); + } + // 創建左側內容區,包含圖示和標題 const contentArea = fileEl.createDiv('ge-content-area'); @@ -2216,7 +2311,9 @@ export class GridView extends ItemView { const extension = file.extension.toLowerCase(); // 檢查是否為媒體檔案,如果是則添加 ge-media-card 類別 - if (this.cardLayout === 'vertical' && (isImageFile(file) || isVideoFile(file))) { + if (this.cardLayout === 'vertical' && + (isImageFile(file) || isVideoFile(file)) && + !this.minMode) { fileEl.addClass('ge-media-card'); } @@ -2252,7 +2349,7 @@ export class GridView extends ItemView { const displayText = shouldShowExtension ? `${file.basename}.${file.extension}` : file.basename; const titleEl = titleContainer.createEl('span', { cls: 'ge-title', text: displayText }); if (this.plugin.settings.multiLineTitle) titleEl.addClass('ge-multiline-title'); - titleEl.setAttribute('title', displayText); + //titleEl.setAttribute('title', displayText); // 創建圖片區域,但先不載入圖片 if (!this.minMode) { @@ -2347,6 +2444,7 @@ export class GridView extends ItemView { // 獲取選中的檔案 const selectedFiles = this.getSelectedFiles(); + let drag_filename = ''; // 添加拖曳資料 if (selectedFiles.length > 1) { @@ -2360,6 +2458,8 @@ export class GridView extends ItemView { // 添加檔案路徑列表 event.dataTransfer?.setData('application/obsidian-grid-explorer-files', JSON.stringify(selectedFiles.map(f => f.path))); + + drag_filename = `${selectedFiles.length} ${t('files')}`; } else { // 如果只有單個檔案被選中,使用檔案路徑 const isMedia = isMediaFile(file); @@ -2373,8 +2473,25 @@ export class GridView extends ItemView { // 添加檔案路徑列表 event.dataTransfer?.setData('application/obsidian-grid-explorer-files', JSON.stringify([file.path])); + + drag_filename = file.basename; } + const dragImage = document.createElement('div'); + dragImage.className = 'ge-custom-drag-preview'; + dragImage.textContent = drag_filename; + + // 將元素暫時加入 DOM + document.body.appendChild(dragImage); + + // 設定拖曳圖示 + event.dataTransfer!.setDragImage(dragImage, 20, 20); + + // 延遲移除元素(讓拖曳圖示正常顯示) + setTimeout(() => { + document.body.removeChild(dragImage); + }, 0); + // 設定拖曳效果 event.dataTransfer!.effectAllowed = 'all'; // 添加拖曳中的視覺效果 diff --git a/src/modal/customModeModal.ts b/src/modal/customModeModal.ts index 5d21060..3b085b4 100644 --- a/src/modal/customModeModal.ts +++ b/src/modal/customModeModal.ts @@ -30,25 +30,25 @@ export class CustomModeModal extends Modal { // 向下相容:使用第一個選項作為主要 dataviewCode let dataviewCode = this.mode ? this.mode.dataviewCode : ''; let enabled = this.mode ? (this.mode.enabled ?? true) : true; + let fields = this.mode ? this.mode.fields : ''; new Setting(contentEl) - .setName(t('custom_mode_display_name')) - .setDesc(t('custom_mode_display_name_desc')) - .addText(text => { - text.setValue(displayName) - .onChange(value => { - displayName = value; - }); - }); - - new Setting(contentEl) - .setName(t('custom_mode_icon')) - .setDesc(t('custom_mode_icon_desc')) + .setName(t('custom_mode_display_name')) + .setDesc(t('custom_mode_display_name_desc')) .addText(text => { text.setValue(icon) .onChange(value => { icon = value || '🧩'; }); + // 設置固定寬度,適合單個圖示 + text.inputEl.style.width = '3em'; + text.inputEl.style.minWidth = '3em'; + }) + .addText(text => { + text.setValue(displayName) + .onChange(value => { + displayName = value; + }); }); const dvSetting = new Setting(contentEl) @@ -61,9 +61,11 @@ export class CustomModeModal extends Modal { dvSetting.settingEl.style.gap = '0.5rem'; dvSetting.addText(text => { - text.setValue(name).onChange(v => name = v); + text.setValue(name) + .setPlaceholder(t('default')) + .onChange(v => name = v); }); - + dvSetting.addTextArea(text => { text.setValue(dataviewCode) .onChange(value => { @@ -75,6 +77,14 @@ export class CustomModeModal extends Modal { text.inputEl.style.width = '100%'; }); + dvSetting.addText(text => { + text.setValue(fields || '') + .setPlaceholder(t('custom_mode_fields_placeholder')) + .onChange(value => { + fields = value; + }); + }); + // 讓 Text 與 TextArea 在 control 區域各佔一行 dvSetting.controlEl.style.display = 'flex'; dvSetting.controlEl.style.flexDirection = 'column'; @@ -115,6 +125,13 @@ export class CustomModeModal extends Modal { }); text.inputEl.setAttr('rows', 6); text.inputEl.style.width = '100%'; + }) + .addText(text => { + text.setPlaceholder(t('custom_mode_fields_placeholder')) + .setValue(opt.fields || '') + .onChange(val => { + opt.fields = val; + }); }); // 移除按鈕(至少保留一個) @@ -160,7 +177,8 @@ export class CustomModeModal extends Modal { name, dataviewCode, options: options, - enabled + enabled, + fields }); this.close(); }); diff --git a/src/settings.ts b/src/settings.ts index 7f7ac77..b1ea55c 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -6,6 +6,7 @@ import { t } from './translations'; export interface CustomModeOption { name: string; dataviewCode: string; + fields?: string; } export interface CustomMode { @@ -16,6 +17,7 @@ export interface CustomMode { dataviewCode: string; options?: CustomModeOption[]; enabled?: boolean; // 是否顯示此自訂模式,預設為 true + fields?: string; } export interface GallerySettings { diff --git a/src/translations.ts b/src/translations.ts index a1f925a..6c414b5 100644 --- a/src/translations.ts +++ b/src/translations.ts @@ -148,13 +148,12 @@ export const TRANSLATIONS: Translations = { 'import_error': '匯入失敗:無效的檔案格式', 'edit_custom_mode': '編輯自訂模式', 'custom_mode': '自訂模式', - 'custom_mode_icon': '圖示', - 'custom_mode_icon_desc': '在模式選單中顯示的圖示', 'custom_mode_display_name': '顯示名稱', 'custom_mode_display_name_desc': '在模式選單中顯示的名稱', 'custom_mode_dataview_code': 'Dataviewjs 代碼', 'custom_mode_dataview_code_desc': '輸入 Dataviewjs 代碼以取得檔案列表', 'custom_mode_sub_options': '自訂模式子選項', + 'custom_mode_fields_placeholder': '輸入 frontmatter 欄位名稱,用逗號分隔 (如: date,category,status) (可選)', 'show_bookmarks_mode': '顯示書籤模式', 'show_search_mode': '顯示搜尋結果模式', 'show_backlinks_mode': '顯示反向連結模式', @@ -409,13 +408,12 @@ export const TRANSLATIONS: Translations = { 'import_error': 'Import failed: Invalid file format', 'edit_custom_mode': 'Edit Custom Mode', 'custom_mode': 'Custom Mode', - 'custom_mode_icon': 'Icon', - 'custom_mode_icon_desc': 'The icon displayed in the mode menu', 'custom_mode_display_name': 'Display Name', 'custom_mode_display_name_desc': 'The name displayed in the mode menu', 'custom_mode_dataview_code': 'Dataview Query', 'custom_mode_dataview_code_desc': 'Enter a Dataview query to get the list of files', 'custom_mode_sub_options': 'Custom Mode Sub Options', + 'custom_mode_fields_placeholder': 'Enter frontmatter field names, separated by commas (e.g. date,category,status) (optional)', 'show_bookmarks_mode': 'Show bookmarks mode', 'show_search_mode': 'Show search results mode', 'show_backlinks_mode': 'Show backlinks mode', @@ -670,13 +668,12 @@ export const TRANSLATIONS: Translations = { 'import_error': '导入失败:无效的文件格式', 'edit_custom_mode': '编辑自定义模式', 'custom_mode': '自定义模式', - 'custom_mode_icon': '图标', - 'custom_mode_icon_desc': '在模式菜单中显示的图标', 'custom_mode_display_name': '显示名称', 'custom_mode_display_name_desc': '在模式菜单中显示的名称', 'custom_mode_dataview_code': 'Dataviewjs 代码', 'custom_mode_dataview_code_desc': '输入 Dataviewjs 代码以获取文件列表', 'custom_mode_sub_options': '自定义模式子选项', + 'custom_mode_fields_placeholder': '输入 frontmatter 栏位名称,用逗号分隔 (如: date,category,status) (可选)', 'show_bookmarks_mode': '显示书签模式', 'show_search_mode': '显示搜索结果模式', 'show_backlinks_mode': '显示反向链接模式', @@ -931,13 +928,12 @@ export const TRANSLATIONS: Translations = { 'import_error': 'インポート失敗:無効なファイル形式', 'edit_custom_mode': 'カスタムモードを編集', 'custom_mode': 'カスタムモード', - 'custom_mode_icon': 'アイコン', - 'custom_mode_icon_desc': 'モードメニューで表示するアイコン', 'custom_mode_display_name': '表示名', 'custom_mode_display_name_desc': 'モードメニューで表示する名前', 'custom_mode_dataview_code': 'Dataviewjs コード', 'custom_mode_dataview_code_desc': 'ファイルリストを取得する Dataviewjs コードを入力', 'custom_mode_sub_options': 'カスタムモード子選択肢', + 'custom_mode_fields_placeholder': 'frontmatterのフィールド名をカンマ区切りで入力 (例: date,category,status) (任意)', 'show_bookmarks_mode': 'ブックマークモードを表示', 'show_search_mode': '検索結果モードを表示', 'show_backlinks_mode': 'バックリンクモードを表示', @@ -1193,13 +1189,12 @@ export const TRANSLATIONS: Translations = { 'import_error': 'Ошибка импорта: недопустимый формат файла', 'edit_custom_mode': 'Редактировать режим отображения', 'custom_mode': 'Режим отображения', - 'custom_mode_icon': 'Иконка', - 'custom_mode_icon_desc': 'Иконка, отображаемая в меню режимов', 'custom_mode_display_name': 'Отображаемое имя', 'custom_mode_display_name_desc': 'Отображаемое имя в меню режимов', 'custom_mode_dataview_code': 'Код Dataview', 'custom_mode_dataview_code_desc': 'Введите код Dataview для получения списка файлов', 'custom_mode_sub_options': 'Подопции пользовательского режима', + 'custom_mode_fields_placeholder': 'Введите названия полей frontmatter через запятую (напр.: date,category,status) (необязательно)', 'show_bookmarks_mode': 'Показывать режим закладок', 'show_search_mode': 'Показывать режим результатов поиска', 'show_backlinks_mode': 'Показывать режим обратных ссылок', @@ -1454,13 +1449,12 @@ export const TRANSLATIONS: Translations = { 'import_error': 'Помилка імпорту: недопустимий формат файлу', 'edit_custom_mode': 'Редагувати режим відображення', 'custom_mode': 'Режим відображення', - 'custom_mode_icon': 'Іконка', - 'custom_mode_icon_desc': 'Іконка, відображається в меню режимів', 'custom_mode_display_name': 'Відображається ім`я', 'custom_mode_display_name_desc': 'Відображається ім`я в меню режимів', 'custom_mode_dataview_code': 'Код Dataview', 'custom_mode_dataview_code_desc': 'Введіть код Dataview для отримання списку файлів', 'custom_mode_sub_options': 'Підпараметри користувацького режиму', + 'custom_mode_fields_placeholder': 'Введіть назви полів frontmatter через кому (напр.: date,category,status) (необязательно)', 'show_bookmarks_mode': 'Показувати режим закладок', 'show_search_mode': 'Показувати режим результатів пошуку', 'show_backlinks_mode': 'Показувати режим зворотних посилань', diff --git a/styles.css b/styles.css index 7646b1f..7f2f401 100644 --- a/styles.css +++ b/styles.css @@ -4,8 +4,6 @@ height: 100%; } - - /* --------------------------------------------------------------------------- */ /* 網格容器 Grid Container */ @@ -46,6 +44,10 @@ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } +.ge-grid-item:hover p { + color: var(--text-muted); +} + /* 摘要區域 Content Area */ .ge-content-area { flex: 1; @@ -134,20 +136,27 @@ line-height: 1.4; overflow: hidden; display: -webkit-box; + height: 100%; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; - height: 100%; -} - -.ge-grid-item:hover p { - color: var(--text-muted); } .ge-content-area p:empty { margin: 0; } +.ge-content-area-p-field, +.ge-content-area .ge-content-area-p-field { + display: block; + -webkit-line-clamp: unset !important; + line-clamp: unset !important; + -webkit-box-orient: unset !important; + white-space: pre-wrap; + overflow: visible; + height: auto; +} + /* 圖片區域 Image Area */ .ge-image-area { width: var(--image-area-width); @@ -182,7 +191,8 @@ flex-direction: column; align-items: stretch; height: var(--grid-item-height); /* 與一般網格一致,保持同排等高 */ - gap: 12px; + gap: 0px; + padding: 0px !important; } /* 摘要文字 Content Area */ @@ -190,18 +200,14 @@ order: 1; flex: 1 1 auto; /* 使摘要區撐開,標籤可貼底 */ flex-grow: 1; /* Add this line */ + padding: 10px !important; } /* 圖片置中,滿版顯示 Image Area */ .ge-vertical-card .ge-image-area { order: 3; width: 100%; - height: var(--image-area-height); -} - -.ge-vertical-card .ge-image-area img, -.ge-vertical-card .ge-image-area video { - border-radius: 6px; + height: var(--image-area-height); } /* 標籤列置底 Tags Container */ @@ -219,6 +225,11 @@ order: 3; } +.ge-vertical-card.ge-image-top .ge-image-area img, +.ge-vertical-card.ge-image-top .ge-image-area video { + border-radius: calc(var(--button-radius) - var(--border-width)) calc(var(--button-radius) - var(--border-width)) 0px 0px !important; +} + /* 預設 bottom 可維持原有順序,以下為明確設置 */ .ge-vertical-card.ge-image-bottom .ge-image-area { order: 3; @@ -228,6 +239,11 @@ order: 1; } +.ge-vertical-card.ge-image-bottom .ge-image-area img, +.ge-vertical-card.ge-image-bottom .ge-image-area video { + border-radius: 0px 0px calc(var(--button-radius) - var(--border-width)) calc(var(--button-radius) - var(--border-width)) !important; +} + /* 鼠標懸停效果:整張卡片微抬升 */ .ge-vertical-card .ge-grid-item:hover { transform: translateY(-2px); @@ -292,6 +308,7 @@ justify-content: center; background-color: var(--background-secondary); border-radius: 4px; + border: 1px solid var(--background-modifier-border); } .ge-video-thumbnail svg { @@ -535,8 +552,8 @@ /* --------------------------------------------------------------------------- */ -/* 資料夾名稱區域樣式 Folder Name Content */ -.ge-foldername-content { +/* Mode名稱區域樣式 Mode Name Content */ +.ge-modename-content { justify-content: center; padding: 10px 8px 9px 8px; background-color: var(--background-secondary); @@ -544,24 +561,23 @@ font-size: var(--font-ui-medium); } -.ge-foldername-content span { +.ge-modename-content span { display: inline-flex; align-items: center; - } -.ge-foldername-content span.ge-mode-title { +.ge-modename-content span.ge-mode-title { padding-left: 5px; padding-right: 3px; } /* 為資料夾名稱、分隔符等元素添加間距 */ -.ge-foldername-content > *:nth-child(1) { +.ge-modename-content > *:nth-child(1) { margin-left: 11px; margin-right: 3px; } -.ge-foldername-content > *:nth-child(2) { +.ge-modename-content > *:nth-child(2) { margin-right: 6px; } @@ -1193,18 +1209,18 @@ width: 60px; } -/* 忽略資料夾設定 */ +/* 忽略資料夾設定 Ignored Folders Setting */ .ge-ignored-folders-container { margin-bottom: 16px; } -/* 忽略資料夾列表 */ +/* 忽略資料夾列表 Ignored Folders List */ .ge-ignored-folders-list { list-style: none; padding: 0; } -/* 忽略資料夾項目 */ +/* 忽略資料夾項目 Ignored Folder Item */ .ge-ignored-folder-item { display: flex; align-items: center; @@ -1216,7 +1232,7 @@ background-color: var(--background-primary); } -/* 忽略資料夾路徑 */ +/* 忽略資料夾路徑 Ignored Folder Path */ .ge-ignored-folder-path { flex-grow: 1; margin-right: 8px; @@ -1225,7 +1241,7 @@ white-space: nowrap; } -/* 忽略資料夾刪除按鈕 */ +/* 忽略資料夾刪除按鈕 Ignored Folder Remove */ .ge-ignored-folder-remove { background-color: var(--interactive-normal); color: var(--text-normal); @@ -1240,13 +1256,34 @@ background-color: var(--interactive-hover); } -/* 忽略資料夾模式的容器 */ +/* 忽略資料夾模式的容器 Ignored Folder Patterns Container */ .ignored-folder-patterns-container { margin-bottom: 16px; } -/* 忽略資料夾模式列表 */ +/* 忽略資料夾模式列表 Ignored Folder Patterns List */ .ge-ignored-folder-patterns-list { list-style: none; padding: 0; } + +/* 拖曳預覽 Drag Preview */ +.ge-custom-drag-preview { + position: absolute; + top: -1000px; /* 隱藏在視窗外 */ + left: -1000px; + font-size: var(--font-ui-small); + white-space: nowrap; + color: rgba(var(--mono-rgb-0), 0.9); + background: rgba(var(--mono-rgb-100), 0.9); + border: 1px solid var(--border-color); + border-radius: 4px; + padding: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + pointer-events: none; + z-index: 1000; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; +} + diff --git a/versions.json b/versions.json index 75683bf..689a76e 100644 --- a/versions.json +++ b/versions.json @@ -1,6 +1,3 @@ { - "2.5.6": "1.1.0", - "2.5.7": "1.1.0", - "2.6.0": "1.1.0", - "2.6.1": "1.1.0" + "2.6.2": "1.1.0" } \ No newline at end of file