mirror of
https://github.com/devon22/obsidian-gridexplorer.git
synced 2026-07-22 05:38:16 +00:00
1.9.12
This commit is contained in:
parent
0d78177e79
commit
9941dad5fc
10 changed files with 614 additions and 306 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "gridexplorer",
|
||||
"name": "GridExplorer",
|
||||
"version": "1.9.11",
|
||||
"version": "1.9.12",
|
||||
"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": "1.9.11",
|
||||
"version": "1.9.12",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gridexplorer",
|
||||
"version": "1.9.11",
|
||||
"version": "1.9.12",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "gridexplorer",
|
||||
"version": "1.9.10",
|
||||
"version": "1.9.12",
|
||||
"description": "Browse note files in a grid view.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
744
src/GridView.ts
744
src/GridView.ts
|
|
@ -532,43 +532,41 @@ export class GridView extends ItemView {
|
|||
setIcon(sortButton, 'arrow-up-narrow-wide');
|
||||
}
|
||||
|
||||
if (this.sourceMode !== 'random-note') {
|
||||
// 添加搜尋按鈕
|
||||
const searchButtonContainer = headerButtonsDiv.createDiv('ge-search-button-container');
|
||||
const searchButton = searchButtonContainer.createEl('button', {
|
||||
cls: 'search-button',
|
||||
attr: { 'aria-label': t('search') }
|
||||
});
|
||||
setIcon(searchButton, 'search');
|
||||
searchButton.addEventListener('click', () => {
|
||||
showSearchModal(this.app, this, '');
|
||||
// 添加搜尋按鈕
|
||||
const searchButtonContainer = headerButtonsDiv.createDiv('ge-search-button-container');
|
||||
const searchButton = searchButtonContainer.createEl('button', {
|
||||
cls: 'search-button',
|
||||
attr: { 'aria-label': t('search') }
|
||||
});
|
||||
setIcon(searchButton, 'search');
|
||||
searchButton.addEventListener('click', () => {
|
||||
showSearchModal(this.app, this, '');
|
||||
});
|
||||
|
||||
// 如果有搜尋關鍵字,顯示搜尋文字和取消按鈕
|
||||
if (this.searchQuery) {
|
||||
searchButton.style.display = 'none';
|
||||
const searchTextContainer = searchButtonContainer.createDiv('ge-search-text-container');
|
||||
|
||||
// 創建搜尋文字
|
||||
const searchText = searchTextContainer.createEl('span', { cls: 'ge-search-text', text: this.searchQuery });
|
||||
// 讓搜尋文字可點選
|
||||
searchText.style.cursor = 'pointer';
|
||||
searchText.addEventListener('click', () => {
|
||||
showSearchModal(this.app, this, this.searchQuery);
|
||||
});
|
||||
|
||||
// 如果有搜尋關鍵字,顯示搜尋文字和取消按鈕
|
||||
if (this.searchQuery) {
|
||||
searchButton.style.display = 'none';
|
||||
const searchTextContainer = searchButtonContainer.createDiv('ge-search-text-container');
|
||||
|
||||
// 創建搜尋文字
|
||||
const searchText = searchTextContainer.createEl('span', { cls: 'ge-search-text', text: this.searchQuery });
|
||||
// 讓搜尋文字可點選
|
||||
searchText.style.cursor = 'pointer';
|
||||
searchText.addEventListener('click', () => {
|
||||
showSearchModal(this.app, this, this.searchQuery);
|
||||
});
|
||||
|
||||
// 創建取消按鈕
|
||||
const clearButton = searchTextContainer.createDiv('ge-clear-button');
|
||||
setIcon(clearButton, 'x');
|
||||
clearButton.addEventListener('click', (e) => {
|
||||
e.stopPropagation(); // 防止觸發搜尋文字的點擊事件
|
||||
this.searchQuery = '';
|
||||
this.clearSelection();
|
||||
this.render();
|
||||
// 通知 Obsidian 保存視圖狀態
|
||||
this.app.workspace.requestSaveLayout();
|
||||
});
|
||||
}
|
||||
// 創建取消按鈕
|
||||
const clearButton = searchTextContainer.createDiv('ge-clear-button');
|
||||
setIcon(clearButton, 'x');
|
||||
clearButton.addEventListener('click', (e) => {
|
||||
e.stopPropagation(); // 防止觸發搜尋文字的點擊事件
|
||||
this.searchQuery = '';
|
||||
this.clearSelection();
|
||||
this.render();
|
||||
// 通知 Obsidian 保存視圖狀態
|
||||
this.app.workspace.requestSaveLayout();
|
||||
});
|
||||
}
|
||||
|
||||
if ((this.sourceMode === 'all-files' || this.sourceMode === 'recent-files' || this.sourceMode === 'random-note') &&
|
||||
|
|
@ -901,7 +899,9 @@ export class GridView extends ItemView {
|
|||
}
|
||||
|
||||
let files: TFile[] = [];
|
||||
if (this.searchQuery && this.sourceMode !== 'random-note') {
|
||||
// 使用 Map 來記錄原始順序
|
||||
let fileIndexMap = new Map<TFile, number>();
|
||||
if (this.searchQuery) {
|
||||
// 顯示搜尋中的提示
|
||||
const loadingDiv = container.createDiv('ge-loading-indicator');
|
||||
loadingDiv.setText(t('searching'));
|
||||
|
|
@ -909,63 +909,101 @@ export class GridView extends ItemView {
|
|||
// 取得 vault 中所有支援的檔案
|
||||
let allFiles: TFile[] = [];
|
||||
if (this.searchAllFiles) {
|
||||
allFiles = this.app.vault.getFiles();
|
||||
// 全部檔案
|
||||
allFiles = this.app.vault.getFiles().filter(file =>
|
||||
isDocumentFile(file) || (isMediaFile(file) && this.searchMediaFiles)
|
||||
);
|
||||
} else {
|
||||
// 當前位置檔案
|
||||
const randomNoteIncludeMedia = this.randomNoteIncludeMedia;
|
||||
this.randomNoteIncludeMedia = this.searchMediaFiles;
|
||||
allFiles = await getFiles(this);
|
||||
this.randomNoteIncludeMedia = randomNoteIncludeMedia;
|
||||
|
||||
if (this.sourceMode === 'recent-files') {
|
||||
// 搜尋"最近檔案"的當前位置時,先作忽略檔案和只取前n筆
|
||||
allFiles = ignoredFiles(allFiles, this).slice(0, this.plugin.settings.recentFilesCount);
|
||||
} else if (this.sourceMode === 'bookmarks') {
|
||||
allFiles = allFiles.filter(file =>
|
||||
isDocumentFile(file) || (isMediaFile(file) && this.searchMediaFiles)
|
||||
);
|
||||
// 使用 Map 來記錄原始順序
|
||||
allFiles.forEach((file, index) => {
|
||||
fileIndexMap.set(file, index);
|
||||
});
|
||||
} else if (this.sourceMode === 'search') {
|
||||
allFiles = allFiles.filter(file =>
|
||||
isDocumentFile(file) || (isMediaFile(file) && this.searchMediaFiles)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 根據設定過濾檔案
|
||||
const filteredFiles = allFiles.filter(file => {
|
||||
// 文件檔案始終包含
|
||||
if (isDocumentFile(file)) {
|
||||
return true;
|
||||
}
|
||||
// 媒體檔案根據 searchMediaFiles 設定決定是否包含
|
||||
if (isMediaFile(file)) {
|
||||
return this.searchMediaFiles;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// 根據搜尋關鍵字進行過濾(不分大小寫)
|
||||
const lowerCaseSearchQuery = this.searchQuery.toLowerCase();
|
||||
const searchTerms = this.searchQuery.toLowerCase().split(/\s+/).filter(term => term.trim() !== '');
|
||||
// 使用 Promise.all 來非同步地讀取所有檔案內容
|
||||
await Promise.all(
|
||||
filteredFiles.map(async file => {
|
||||
allFiles.map(async file => {
|
||||
const fileName = file.name.toLowerCase();
|
||||
if (fileName.includes(lowerCaseSearchQuery)) {
|
||||
// 檢查檔案名稱是否包含所有搜尋字串
|
||||
const matchesFileName = searchTerms.every(term => fileName.includes(term));
|
||||
if (matchesFileName) {
|
||||
files.push(file);
|
||||
} else if (file.extension === 'md') {
|
||||
// 只對 Markdown 檔案進行內容搜尋
|
||||
const content = (await this.app.vault.cachedRead(file)).toLowerCase();
|
||||
if (content.includes(lowerCaseSearchQuery)) {
|
||||
// 檢查檔案內容是否包含所有搜尋字串
|
||||
const matchesContent = searchTerms.every(term => content.includes(term));
|
||||
if (matchesContent) {
|
||||
files.push(file);
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// 根據設定的排序方式排序檔案
|
||||
files = sortFiles(files, this);
|
||||
|
||||
// 排序檔案
|
||||
if (this.sourceMode === 'recent-files') {
|
||||
// 臨時的排序類型
|
||||
const sortType = this.sortType;
|
||||
this.sortType = 'mtime-desc';
|
||||
files = sortFiles(files, this);
|
||||
this.sortType = sortType;
|
||||
} else if (this.sourceMode === 'bookmarks') {
|
||||
// 保持原始順序
|
||||
files.sort((a, b) => {
|
||||
const indexA = fileIndexMap.get(a) ?? Number.MAX_SAFE_INTEGER;
|
||||
const indexB = fileIndexMap.get(b) ?? Number.MAX_SAFE_INTEGER;
|
||||
return indexA - indexB;
|
||||
});
|
||||
} else if (this.sourceMode === 'random-note') {
|
||||
const sortType = this.sortType;
|
||||
this.sortType = 'random';
|
||||
files = sortFiles(files, this);
|
||||
this.sortType = sortType;
|
||||
} else {
|
||||
files = sortFiles(files, this);
|
||||
}
|
||||
|
||||
// 忽略檔案
|
||||
files = ignoredFiles(files, this);
|
||||
|
||||
// 移除搜尋中的提示
|
||||
loadingDiv.remove();
|
||||
} else {
|
||||
// 獲取檔案列表並根據搜尋關鍵字過濾
|
||||
// 無搜尋關鍵字的情況
|
||||
files = await getFiles(this);
|
||||
}
|
||||
|
||||
//忽略檔案
|
||||
files = ignoredFiles(files, this)
|
||||
// 忽略檔案
|
||||
files = ignoredFiles(files, this)
|
||||
|
||||
//最近檔案模式,只取前30筆
|
||||
if (this.sourceMode === 'recent-files') {
|
||||
files = files.slice(0, this.plugin.settings.recentFilesCount);
|
||||
}
|
||||
// 最近檔案模式,只取前n筆
|
||||
if (this.sourceMode === 'recent-files') {
|
||||
files = files.slice(0, this.plugin.settings.recentFilesCount);
|
||||
}
|
||||
|
||||
// 隨機筆記模式,只取前10筆
|
||||
if (this.sourceMode === 'random-note') {
|
||||
files = files.slice(0, this.plugin.settings.randomNoteCount);
|
||||
// 隨機筆記模式,只取前n筆
|
||||
if (this.sourceMode === 'random-note') {
|
||||
files = files.slice(0, this.plugin.settings.randomNoteCount);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果沒有檔案,顯示提示訊息
|
||||
|
|
@ -1048,6 +1086,78 @@ export class GridView extends ItemView {
|
|||
// 其他檔案顯示副檔名
|
||||
contentArea.createEl('p', { text: file.extension.toUpperCase() });
|
||||
}
|
||||
|
||||
// 顯示標籤(僅限 Markdown 檔案)
|
||||
if (file.extension === 'md' && this.plugin.settings.showNoteTags) {
|
||||
const fileCache = this.app.metadataCache.getFileCache(file);
|
||||
const allTags = new Set<string>();
|
||||
|
||||
// 從 frontmatter 獲取標籤
|
||||
let frontmatterTags = fileCache?.frontmatter?.tags || [];
|
||||
|
||||
// 處理不同的標籤格式
|
||||
if (typeof frontmatterTags === 'string') {
|
||||
// 如果是字符串,按逗號或空格分割
|
||||
frontmatterTags.split(/[,\s]+/).filter(tag => tag.trim() !== '')
|
||||
.forEach(tag => allTags.add(tag));
|
||||
} else if (Array.isArray(frontmatterTags)) {
|
||||
frontmatterTags.forEach(tag => {
|
||||
// 處理陣列中的每個標籤,可能是字符串或包含空格的字符串
|
||||
if (typeof tag === 'string') {
|
||||
// 檢查標籤是否包含空格(可能是未被正確分割的多個標籤)
|
||||
if (tag.includes(' ')) {
|
||||
// 按空格分割並添加每個子標籤
|
||||
tag.split(/\s+/).filter(subTag => subTag.trim() !== '')
|
||||
.forEach(subTag => allTags.add(subTag));
|
||||
} else {
|
||||
allTags.add(tag);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 從檔案 cache 中獲取內文標籤
|
||||
const cacheTags = fileCache?.tags || [];
|
||||
cacheTags.forEach(tagObj => {
|
||||
const tag = tagObj.tag.startsWith('#') ? tagObj.tag.substring(1) : tagObj.tag;
|
||||
allTags.add(tag);
|
||||
});
|
||||
|
||||
if (allTags.size > 0) {
|
||||
// 創建標籤容器
|
||||
const tagsContainer = contentArea.createDiv('ge-tags-container');
|
||||
|
||||
// 根據區塊寬度動態計算可顯示的標籤數量
|
||||
const containerWidth = tagsContainer.getBoundingClientRect().width;
|
||||
const tagWidth = 70;
|
||||
const maxTags = Math.floor(containerWidth / tagWidth);
|
||||
|
||||
// 取得要顯示的標籤
|
||||
const displayTags = Array.from(allTags).slice(0, maxTags);
|
||||
|
||||
displayTags.forEach(tag => {
|
||||
const tagEl = tagsContainer.createEl('span', {
|
||||
cls: 'ge-tag',
|
||||
text: tag.startsWith('#') ? tag : `#${tag}`
|
||||
});
|
||||
|
||||
// 添加點擊事件,點擊後設置搜尋關鍵字並重新渲染
|
||||
tagEl.addEventListener('click', (e) => {
|
||||
e.stopPropagation(); // 防止事件冒泡到卡片
|
||||
const tagText = tag.startsWith('#') ? tag.substring(1) : tag;
|
||||
if (this.searchQuery === tagText) {
|
||||
return;
|
||||
}
|
||||
this.searchQuery = tagText;
|
||||
this.searchAllFiles = true;
|
||||
this.searchMediaFiles = false;
|
||||
this.render(true);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
contentArea.setAttribute('data-loaded', 'true');
|
||||
}
|
||||
|
||||
|
|
@ -1099,66 +1209,167 @@ export class GridView extends ItemView {
|
|||
});
|
||||
|
||||
// 顯示檔案
|
||||
for (const file of files) {
|
||||
const fileEl = container.createDiv('ge-grid-item');
|
||||
this.gridItems.push(fileEl); // 添加到網格項目數組
|
||||
fileEl.dataset.filePath = file.path;
|
||||
|
||||
// 創建左側內容區,包含圖示和標題
|
||||
const contentArea = fileEl.createDiv('ge-content-area');
|
||||
|
||||
// 創建標題容器
|
||||
const titleContainer = contentArea.createDiv('ge-title-container');
|
||||
const extension = file.extension.toLowerCase();
|
||||
if (files.length > 0) {
|
||||
// 檢查是否應該顯示日期分隔器
|
||||
const dateDividerMode = this.plugin.settings.dateDividerMode || 'none';
|
||||
const sortType = this.folderSortType ? this.folderSortType : this.sortType;
|
||||
const shouldShowDateDividers = dateDividerMode !== 'none' &&
|
||||
(sortType.startsWith('mtime-') || sortType.startsWith('ctime-')) &&
|
||||
this.sourceMode !== 'random-note' &&
|
||||
this.sourceMode !== 'bookmarks';
|
||||
|
||||
// 添加檔案類型圖示
|
||||
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 === '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');
|
||||
}
|
||||
let lastDateString = '';
|
||||
|
||||
// 創建標題(立即載入)
|
||||
const titleEl = titleContainer.createEl('span', { cls: 'ge-title', text: file.basename });
|
||||
titleEl.setAttribute('title', file.basename);
|
||||
|
||||
// 創建圖片區域,但先不載入圖片
|
||||
fileEl.createDiv('ge-image-area');
|
||||
|
||||
// 開始觀察這個元素
|
||||
observer.observe(fileEl);
|
||||
|
||||
// 點擊時開啟檔案
|
||||
fileEl.addEventListener('click', (event) => {
|
||||
// 獲取項目索引
|
||||
const index = this.gridItems.indexOf(fileEl);
|
||||
if (index < 0) return;
|
||||
|
||||
// 處理多選邏輯
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
if (this.selectedItemIndex !== -1) {
|
||||
// 如果已有選中狀態,則繼續選中
|
||||
this.selectItem(index, true);
|
||||
this.hasKeyboardFocus = true;
|
||||
for (const file of files) {
|
||||
// 如果啟用日期分隔器,檢查是否需要添加新的日期分隔器
|
||||
if (shouldShowDateDividers) {
|
||||
let timestamp = 0;
|
||||
|
||||
// 根據排序類型獲取日期時間戳
|
||||
if (sortType.startsWith('mtime-') || sortType.startsWith('ctime-')) {
|
||||
const isModifiedTime = sortType.startsWith('mtime-');
|
||||
|
||||
// 檢查是否是 Markdown 文件,且有設定對應的 frontmatter 字段
|
||||
let frontMatterDate = null;
|
||||
if (file.extension === 'md') {
|
||||
const metadata = this.app.metadataCache.getFileCache(file);
|
||||
if (metadata?.frontmatter) {
|
||||
const fieldName = isModifiedTime
|
||||
? this.plugin.settings.modifiedDateField
|
||||
: this.plugin.settings.createdDateField;
|
||||
|
||||
if (fieldName && metadata.frontmatter[fieldName]) {
|
||||
const dateStr = metadata.frontmatter[fieldName];
|
||||
const date = new Date(dateStr);
|
||||
if (!isNaN(date.getTime())) {
|
||||
frontMatterDate = date;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 frontmatter 中的日期或檔案的狀態日期
|
||||
if (frontMatterDate) {
|
||||
timestamp = frontMatterDate.getTime();
|
||||
} else {
|
||||
timestamp = isModifiedTime ? file.stat.mtime : file.stat.ctime;
|
||||
}
|
||||
}
|
||||
|
||||
// 創建日期物件並格式化
|
||||
const fileDate = new Date(timestamp);
|
||||
|
||||
// 根據日期分隔器模式設定格式化
|
||||
let currentDateString = '';
|
||||
|
||||
if (dateDividerMode === 'year') {
|
||||
// 年分隔器:只顯示年份
|
||||
currentDateString = fileDate.getFullYear().toString();
|
||||
} else if (dateDividerMode === 'month') {
|
||||
// 月分隔器:顯示年-月
|
||||
const year = fileDate.getFullYear();
|
||||
const month = fileDate.getMonth() + 1; // getMonth() 回傳 0-11
|
||||
currentDateString = `${year}-${month.toString().padStart(2, '0')}`;
|
||||
} else {
|
||||
// 沒有選中狀態則開啟新分頁
|
||||
// 日分隔器:顯示完整日期(預設行為)
|
||||
currentDateString = fileDate.toLocaleDateString();
|
||||
}
|
||||
|
||||
// 如果日期不同於上一個檔案的日期,添加分隔器
|
||||
if (currentDateString !== lastDateString) {
|
||||
lastDateString = currentDateString;
|
||||
|
||||
// 創建日期分隔器
|
||||
const dateDivider = container.createDiv('ge-date-divider');
|
||||
dateDivider.textContent = currentDateString;
|
||||
}
|
||||
}
|
||||
|
||||
const fileEl = container.createDiv('ge-grid-item');
|
||||
this.gridItems.push(fileEl); // 添加到網格項目數組
|
||||
fileEl.dataset.filePath = file.path;
|
||||
|
||||
// 創建左側內容區,包含圖示和標題
|
||||
const contentArea = fileEl.createDiv('ge-content-area');
|
||||
|
||||
// 創建標題容器
|
||||
const titleContainer = contentArea.createDiv('ge-title-container');
|
||||
const extension = file.extension.toLowerCase();
|
||||
|
||||
// 添加檔案類型圖示
|
||||
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 === '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 titleEl = titleContainer.createEl('span', { cls: 'ge-title', text: file.basename });
|
||||
titleEl.setAttribute('title', file.basename);
|
||||
|
||||
// 創建圖片區域,但先不載入圖片
|
||||
fileEl.createDiv('ge-image-area');
|
||||
|
||||
// 開始觀察這個元素
|
||||
observer.observe(fileEl);
|
||||
|
||||
// 點擊時開啟檔案
|
||||
fileEl.addEventListener('click', (event) => {
|
||||
// 獲取項目索引
|
||||
const index = this.gridItems.indexOf(fileEl);
|
||||
if (index < 0) return;
|
||||
|
||||
// 處理多選邏輯
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
if (this.selectedItemIndex !== -1) {
|
||||
// 如果已有選中狀態,則繼續選中
|
||||
this.selectItem(index, true);
|
||||
this.hasKeyboardFocus = true;
|
||||
} else {
|
||||
// 沒有選中狀態則開啟新分頁
|
||||
if (isMediaFile(file)) {
|
||||
// 開啟媒體檔案
|
||||
if (isAudioFile(file)) {
|
||||
FloatingAudioPlayer.open(this.app, file);
|
||||
} else {
|
||||
this.openMediaFile(file, files);
|
||||
}
|
||||
} else {
|
||||
// 開啟文件檔案
|
||||
this.app.workspace.getLeaf().openFile(file);
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
return;
|
||||
} else if (event.shiftKey) {
|
||||
// Shift 鍵:範圍選擇
|
||||
this.handleRangeSelection(index);
|
||||
this.hasKeyboardFocus = true;
|
||||
event.preventDefault();
|
||||
return;
|
||||
} else {
|
||||
// 一般點擊:選中單個項目並開啟
|
||||
this.selectItem(index);
|
||||
this.hasKeyboardFocus = true;
|
||||
|
||||
// 根據檔案類型處理點擊事件
|
||||
if (isMediaFile(file)) {
|
||||
// 開啟媒體檔案
|
||||
if (isAudioFile(file)) {
|
||||
|
|
@ -1168,57 +1379,87 @@ export class GridView extends ItemView {
|
|||
}
|
||||
} else {
|
||||
// 開啟文件檔案
|
||||
this.app.workspace.getLeaf().openFile(file);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 處理滑鼠中鍵點擊
|
||||
fileEl.addEventListener('mousedown', (event) => {
|
||||
if (event.button === 1) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
fileEl.addEventListener('mouseup', (event) => {
|
||||
if (event.button === 1) {
|
||||
event.preventDefault();
|
||||
if (!isMediaFile(file)) {
|
||||
this.app.workspace.getLeaf(true).openFile(file);
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
return;
|
||||
} else if (event.shiftKey) {
|
||||
// Shift 鍵:範圍選擇
|
||||
this.handleRangeSelection(index);
|
||||
this.hasKeyboardFocus = true;
|
||||
event.preventDefault();
|
||||
return;
|
||||
} else {
|
||||
// 一般點擊:選中單個項目並開啟
|
||||
this.selectItem(index);
|
||||
this.hasKeyboardFocus = true;
|
||||
});
|
||||
|
||||
// 根據檔案類型處理點擊事件
|
||||
if (isMediaFile(file)) {
|
||||
// 開啟媒體檔案
|
||||
if (isAudioFile(file)) {
|
||||
FloatingAudioPlayer.open(this.app, file);
|
||||
} else {
|
||||
this.openMediaFile(file, files);
|
||||
if(Platform.isDesktop) {
|
||||
// 添加拖曳功能
|
||||
fileEl.setAttribute('draggable', 'true');
|
||||
fileEl.addEventListener('dragstart', (event) => {
|
||||
// 獲取項目索引
|
||||
const index = this.gridItems.indexOf(fileEl);
|
||||
if (index >= 0) {
|
||||
// 如果項目未被選中,則選中它
|
||||
if (!this.selectedItems.has(index)) {
|
||||
this.selectItem(index);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 開啟文件檔案
|
||||
this.app.workspace.getLeaf().openFile(file);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 處理滑鼠中鍵點擊
|
||||
fileEl.addEventListener('mousedown', (event) => {
|
||||
if (event.button === 1) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
fileEl.addEventListener('mouseup', (event) => {
|
||||
if (event.button === 1) {
|
||||
event.preventDefault();
|
||||
if (!isMediaFile(file)) {
|
||||
this.app.workspace.getLeaf(true).openFile(file);
|
||||
}
|
||||
}
|
||||
});
|
||||
// 獲取選中的檔案
|
||||
const selectedFiles = this.getSelectedFiles();
|
||||
|
||||
// 添加拖曳資料
|
||||
if (selectedFiles.length > 1) {
|
||||
// 如果多個檔案被選中,使用 files-menu
|
||||
const fileList = selectedFiles.map(f => {
|
||||
const isMedia = isMediaFile(f);
|
||||
return isMedia ? `![[${f.path}]]` : `[[${f.path}]]`;
|
||||
}).join('\n');
|
||||
event.dataTransfer?.setData('text/plain', fileList);
|
||||
|
||||
// 添加檔案路徑列表
|
||||
event.dataTransfer?.setData('application/obsidian-grid-explorer-files',
|
||||
JSON.stringify(selectedFiles.map(f => f.path)));
|
||||
} else {
|
||||
// 如果只有單個檔案被選中,使用檔案路徑
|
||||
const isMedia = isMediaFile(file);
|
||||
const mdLink = isMedia
|
||||
? `![[${file.path}]]` // 媒體檔案使用 ![[]] 格式
|
||||
: `[[${file.path}]]`; // 一般檔案使用 [[]] 格式
|
||||
|
||||
if(Platform.isDesktop) {
|
||||
// 添加拖曳功能
|
||||
fileEl.setAttribute('draggable', 'true');
|
||||
fileEl.addEventListener('dragstart', (event) => {
|
||||
// 添加拖曳資料
|
||||
event.dataTransfer?.setData('text/plain', mdLink);
|
||||
|
||||
// 添加檔案路徑列表
|
||||
event.dataTransfer?.setData('application/obsidian-grid-explorer-files',
|
||||
JSON.stringify([file.path]));
|
||||
}
|
||||
|
||||
// 設定拖曳效果
|
||||
event.dataTransfer!.effectAllowed = 'all';
|
||||
// 添加拖曳中的視覺效果
|
||||
fileEl.addClass('ge-dragging');
|
||||
});
|
||||
|
||||
fileEl.addEventListener('dragend', () => {
|
||||
// 移除拖曳中的視覺效果
|
||||
fileEl.removeClass('ge-dragging');
|
||||
});
|
||||
}
|
||||
|
||||
// 添加右鍵選單
|
||||
fileEl.addEventListener('contextmenu', (event) => {
|
||||
event.preventDefault();
|
||||
const menu = new Menu();
|
||||
|
||||
// 獲取項目索引
|
||||
const index = this.gridItems.indexOf(fileEl);
|
||||
if (index >= 0) {
|
||||
|
|
@ -1231,122 +1472,67 @@ export class GridView extends ItemView {
|
|||
// 獲取選中的檔案
|
||||
const selectedFiles = this.getSelectedFiles();
|
||||
|
||||
// 添加拖曳資料
|
||||
if (selectedFiles.length > 1) {
|
||||
// 如果多個檔案被選中,使用 files-menu
|
||||
const fileList = selectedFiles.map(f => {
|
||||
const isMedia = isMediaFile(f);
|
||||
return isMedia ? `![[${f.path}]]` : `[[${f.path}]]`;
|
||||
}).join('\n');
|
||||
event.dataTransfer?.setData('text/plain', fileList);
|
||||
// 多個檔案被選中,使用 files-menu
|
||||
this.app.workspace.trigger('files-menu', menu, selectedFiles);
|
||||
|
||||
// 添加檔案路徑列表
|
||||
event.dataTransfer?.setData('application/obsidian-grid-explorer-files',
|
||||
JSON.stringify(selectedFiles.map(f => f.path)));
|
||||
// 檢查是否所有選中的檔案都是 md 檔案
|
||||
const allMdFiles = selectedFiles.every(file => file.extension === 'md');
|
||||
if (allMdFiles) {
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('set_note_color'))
|
||||
.setIcon('palette')
|
||||
.onClick(() => {
|
||||
showNoteColorSettingsModal(this.app, this.plugin, selectedFiles);
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 如果只有單個檔案被選中,使用檔案路徑
|
||||
const isMedia = isMediaFile(file);
|
||||
const mdLink = isMedia
|
||||
? `![[${file.path}]]` // 媒體檔案使用 ![[]] 格式
|
||||
: `[[${file.path}]]`; // 一般檔案使用 [[]] 格式
|
||||
|
||||
// 添加拖曳資料
|
||||
event.dataTransfer?.setData('text/plain', mdLink);
|
||||
|
||||
// 添加檔案路徑列表
|
||||
event.dataTransfer?.setData('application/obsidian-grid-explorer-files',
|
||||
JSON.stringify([file.path]));
|
||||
this.app.workspace.trigger('file-menu', menu, file);
|
||||
}
|
||||
|
||||
// 設定拖曳效果
|
||||
event.dataTransfer!.effectAllowed = 'all';
|
||||
// 添加拖曳中的視覺效果
|
||||
fileEl.addClass('ge-dragging');
|
||||
});
|
||||
|
||||
fileEl.addEventListener('dragend', () => {
|
||||
// 移除拖曳中的視覺效果
|
||||
fileEl.removeClass('ge-dragging');
|
||||
// 新增在新分頁開啟選項
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_in_new_tab'))
|
||||
.setIcon('external-link')
|
||||
.setSection?.("open")
|
||||
.onClick(() => {
|
||||
if (selectedFiles.length > 1) {
|
||||
// 如果多個檔案被選中,開啟所有文件檔案
|
||||
const documentFiles = selectedFiles.filter(f => isDocumentFile(f));
|
||||
for (const docFile of documentFiles) {
|
||||
this.app.workspace.getLeaf(true).openFile(docFile);
|
||||
}
|
||||
} else {
|
||||
this.app.workspace.getLeaf(true).openFile(file);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 刪除選項
|
||||
menu.addItem((item) => {
|
||||
(item as any).setWarning(true);
|
||||
item
|
||||
.setTitle(t('delete_note'))
|
||||
.setIcon('trash')
|
||||
.onClick(async () => {
|
||||
if (selectedFiles.length > 1) {
|
||||
// 刪除多個檔案
|
||||
for (const f of selectedFiles) {
|
||||
await this.app.fileManager.trashFile(f);
|
||||
}
|
||||
// 清除選中狀態
|
||||
this.clearSelection();
|
||||
} else {
|
||||
// 刪除單個檔案
|
||||
await this.app.fileManager.trashFile(file);
|
||||
}
|
||||
});
|
||||
});
|
||||
menu.showAtMouseEvent(event);
|
||||
});
|
||||
}
|
||||
|
||||
// 添加右鍵選單
|
||||
fileEl.addEventListener('contextmenu', (event) => {
|
||||
event.preventDefault();
|
||||
const menu = new Menu();
|
||||
|
||||
// 獲取項目索引
|
||||
const index = this.gridItems.indexOf(fileEl);
|
||||
if (index >= 0) {
|
||||
// 如果項目未被選中,則選中它
|
||||
if (!this.selectedItems.has(index)) {
|
||||
this.selectItem(index);
|
||||
}
|
||||
}
|
||||
|
||||
// 獲取選中的檔案
|
||||
const selectedFiles = this.getSelectedFiles();
|
||||
|
||||
if (selectedFiles.length > 1) {
|
||||
// 多個檔案被選中,使用 files-menu
|
||||
this.app.workspace.trigger('files-menu', menu, selectedFiles);
|
||||
|
||||
// 檢查是否所有選中的檔案都是 md 檔案
|
||||
const allMdFiles = selectedFiles.every(file => file.extension === 'md');
|
||||
if (allMdFiles) {
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('set_note_color'))
|
||||
.setIcon('palette')
|
||||
.onClick(() => {
|
||||
showNoteColorSettingsModal(this.app, this.plugin, selectedFiles);
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.app.workspace.trigger('file-menu', menu, file);
|
||||
}
|
||||
// 新增在新分頁開啟選項
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_in_new_tab'))
|
||||
.setIcon('external-link')
|
||||
.setSection?.("open")
|
||||
.onClick(() => {
|
||||
if (selectedFiles.length > 1) {
|
||||
// 如果多個檔案被選中,開啟所有文件檔案
|
||||
const documentFiles = selectedFiles.filter(f => isDocumentFile(f));
|
||||
for (const docFile of documentFiles) {
|
||||
this.app.workspace.getLeaf(true).openFile(docFile);
|
||||
}
|
||||
} else {
|
||||
this.app.workspace.getLeaf(true).openFile(file);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 刪除選項
|
||||
menu.addItem((item) => {
|
||||
(item as any).setWarning(true);
|
||||
item
|
||||
.setTitle(t('delete_note'))
|
||||
.setIcon('trash')
|
||||
.onClick(async () => {
|
||||
if (selectedFiles.length > 1) {
|
||||
// 刪除多個檔案
|
||||
for (const f of selectedFiles) {
|
||||
await this.app.fileManager.trashFile(f);
|
||||
}
|
||||
// 清除選中狀態
|
||||
this.clearSelection();
|
||||
} else {
|
||||
// 刪除單個檔案
|
||||
await this.app.fileManager.trashFile(file);
|
||||
}
|
||||
});
|
||||
});
|
||||
menu.showAtMouseEvent(event);
|
||||
});
|
||||
}
|
||||
|
||||
if(Platform.isDesktop) {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,11 @@ export class SearchModal extends Modal {
|
|||
text: t('search_current_location_only'),
|
||||
cls: 'ge-search-scope-label'
|
||||
});
|
||||
// 隨機筆記模式下,搜尋範圍設定不顯示
|
||||
if (this.gridView.sourceMode === 'random-note') {
|
||||
searchScopeContainer.style.display = 'none';
|
||||
searchScopeCheckbox.checked = false;
|
||||
}
|
||||
|
||||
// 創建搜尋媒體檔案設定
|
||||
const searchMediaFilesContainer = searchOptionsContainer.createDiv('ge-search-media-files-container');
|
||||
|
|
@ -74,6 +79,12 @@ export class SearchModal extends Modal {
|
|||
text: t('search_media_files'),
|
||||
cls: 'ge-search-media-files-label'
|
||||
});
|
||||
// 如果設定中的顯示媒體檔案為false,或在反向連結模式下,則隱藏搜尋媒體檔案設定
|
||||
if (!this.gridView.plugin.settings.showMediaFiles || this.gridView.sourceMode === 'backlinks') {
|
||||
searchMediaFilesContainer.style.display = 'none';
|
||||
searchMediaFilesCheckbox.checked = false;
|
||||
this.gridView.searchMediaFiles = false;
|
||||
}
|
||||
|
||||
// 點擊容器時切換勾選框狀態
|
||||
searchScopeContainer.addEventListener('click', (e) => {
|
||||
|
|
|
|||
|
|
@ -184,7 +184,6 @@ export async function getFiles(gridView: GridView): Promise<TFile[]> {
|
|||
const settings = gridView.plugin.settings;
|
||||
const sourceMode = gridView.sourceMode;
|
||||
const sourcePath = gridView.sourcePath;
|
||||
const searchQuery = gridView.searchQuery;
|
||||
const randomNoteIncludeMedia = gridView.randomNoteIncludeMedia;
|
||||
|
||||
if (sourceMode === 'folder' && sourcePath) {
|
||||
|
|
@ -200,10 +199,8 @@ export async function getFiles(gridView: GridView): Promise<TFile[]> {
|
|||
(settings.showMediaFiles && isMediaFile(file))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return sortFiles(files, gridView);
|
||||
}
|
||||
return [];
|
||||
|
|
@ -222,11 +219,7 @@ export async function getFiles(gridView: GridView): Promise<TFile[]> {
|
|||
}
|
||||
}
|
||||
return [];
|
||||
} else if (sourceMode === 'backlinks') {
|
||||
if(searchQuery !== '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
} else if (sourceMode === 'backlinks') {
|
||||
// 反向連結模式:找出所有引用當前筆記的檔案
|
||||
const activeFile = app.workspace.getActiveFile();
|
||||
if (!activeFile) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ export interface GallerySettings {
|
|||
createdDateField: string; // 建立時間的欄位名稱
|
||||
recentFilesCount: number; // 最近筆記模式顯示的筆數
|
||||
randomNoteCount: number; // 隨機筆記模式顯示的筆數
|
||||
showNoteTags: boolean; // 是否顯示筆記標籤
|
||||
dateDividerMode: string; // 日期分隔器模式:none, year, month, day
|
||||
}
|
||||
|
||||
// 預設設定
|
||||
|
|
@ -60,7 +62,9 @@ export const DEFAULT_SETTINGS: GallerySettings = {
|
|||
customDocumentExtensions: '', // 自訂文件副檔名(用逗號分隔)
|
||||
recentSources: [], // 預設最近的瀏覽記錄
|
||||
modifiedDateField: '',
|
||||
createdDateField: ''
|
||||
createdDateField: '',
|
||||
showNoteTags: false, // 預設不顯示筆記標籤
|
||||
dateDividerMode: 'none', // 預設不使用日期分隔器
|
||||
};
|
||||
|
||||
// 設定頁面類別
|
||||
|
|
@ -292,6 +296,23 @@ export class GridExplorerSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings(false);
|
||||
}));
|
||||
|
||||
// 日期分隔器模式設定
|
||||
new Setting(containerEl)
|
||||
.setName(t('date_divider_mode'))
|
||||
.setDesc(t('date_divider_mode_desc'))
|
||||
.addDropdown(dropdown => {
|
||||
dropdown
|
||||
.addOption('none', t('date_divider_mode_none'))
|
||||
.addOption('year', t('date_divider_mode_year'))
|
||||
.addOption('month', t('date_divider_mode_month'))
|
||||
.addOption('day', t('date_divider_mode_day'))
|
||||
.setValue(this.plugin.settings.dateDividerMode)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.dateDividerMode = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
// 檔案監控功能設定
|
||||
new Setting(containerEl)
|
||||
.setName(t('enable_file_watcher'))
|
||||
|
|
@ -319,7 +340,7 @@ export class GridExplorerSettingTab extends PluginSettingTab {
|
|||
});
|
||||
});
|
||||
|
||||
// 顯示"返回上级文件夹"選項設定
|
||||
// 顯示"回上層資料夾"選項設定
|
||||
new Setting(containerEl)
|
||||
.setName(t('show_parent_folder_item'))
|
||||
.setDesc(t('show_parent_folder_item_desc'))
|
||||
|
|
@ -332,6 +353,19 @@ export class GridExplorerSettingTab extends PluginSettingTab {
|
|||
});
|
||||
});
|
||||
|
||||
// 顯示筆記標籤設定
|
||||
new Setting(containerEl)
|
||||
.setName(t('show_note_tags'))
|
||||
.setDesc(t('show_note_tags_desc'))
|
||||
.addToggle(toggle => {
|
||||
toggle
|
||||
.setValue(this.plugin.settings.showNoteTags)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.showNoteTags = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
// 網格項目寬度設定
|
||||
new Setting(containerEl)
|
||||
.setName(t('grid_item_width'))
|
||||
|
|
|
|||
|
|
@ -63,10 +63,12 @@ export const TRANSLATIONS: Translations = {
|
|||
// 設定
|
||||
'grid_view_settings': '網格視圖設定',
|
||||
'media_files_settings': '媒體檔案設定',
|
||||
'show_media_files': '顯示圖片和影片',
|
||||
'show_media_files_desc': '在網格視圖中顯示圖片和影片檔案',
|
||||
'show_media_files': '顯示媒體檔案',
|
||||
'show_media_files_desc': '在網格視圖中顯示媒體檔案',
|
||||
'show_video_thumbnails': '顯示影片縮圖',
|
||||
'show_video_thumbnails_desc': '在網格視圖中顯示影片的縮圖,關閉時將顯示播放圖示',
|
||||
'show_note_tags': '顯示筆記標籤',
|
||||
'show_note_tags_desc': '在網格視圖中顯示筆記的標籤',
|
||||
'ignored_folders': '忽略的資料夾',
|
||||
'ignored_folders_desc': '在這裡設定要忽略的資料夾',
|
||||
'add_ignored_folder': '新增忽略資料夾',
|
||||
|
|
@ -111,7 +113,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'show_random_note_mode': '顯示隨機筆記模式',
|
||||
'random_note_count': '隨機筆記模式顯示筆數',
|
||||
'random_note_notes_only': '僅筆記',
|
||||
'random_note_include_media_files': '包含圖片影片',
|
||||
'random_note_include_media_files': '包含媒體檔案',
|
||||
|
||||
// 顯示"返回上層資料夾"選項設定
|
||||
'show_parent_folder_item': '顯示「返回上層資料夾」',
|
||||
|
|
@ -174,6 +176,15 @@ export const TRANSLATIONS: Translations = {
|
|||
'rename_folder': '重新命名資料夾',
|
||||
'enter_new_folder_name': '輸入新資料夾名稱',
|
||||
'search_selection_in_grid_view': '在網格視圖中搜尋...',
|
||||
'show_date_dividers': '顯示日期分隔器',
|
||||
'show_date_dividers_desc': '在日期相關排序時,在不同天的第一筆之前顯示日期分隔器',
|
||||
'date_divider_format': '日期分隔器格式',
|
||||
'date_divider_mode': '日期分隔器',
|
||||
'date_divider_mode_desc': '選擇日期分隔器的顯示模式',
|
||||
'date_divider_mode_none': '不使用',
|
||||
'date_divider_mode_year': '年',
|
||||
'date_divider_mode_month': '月',
|
||||
'date_divider_mode_day': '日',
|
||||
},
|
||||
'en': {
|
||||
// Notifications
|
||||
|
|
@ -219,10 +230,12 @@ export const TRANSLATIONS: Translations = {
|
|||
// Settings
|
||||
'grid_view_settings': 'Grid view settings',
|
||||
'media_files_settings': 'Media files settings',
|
||||
'show_media_files': 'Show images and videos',
|
||||
'show_media_files_desc': 'Display image and video files in the grid view',
|
||||
'show_media_files': 'Show media files',
|
||||
'show_media_files_desc': 'Display media files in the grid view',
|
||||
'show_video_thumbnails': 'Show video thumbnails',
|
||||
'show_video_thumbnails_desc': 'Display thumbnails for videos in the grid view, shows a play icon when disabled',
|
||||
'show_note_tags': 'Show note tags',
|
||||
'show_note_tags_desc': 'Display tags for notes in the grid view',
|
||||
'ignored_folders': 'Ignored folders',
|
||||
'ignored_folders_desc': 'Set folders to ignore here',
|
||||
'add_ignored_folder': 'Add ignored folder',
|
||||
|
|
@ -330,6 +343,15 @@ export const TRANSLATIONS: Translations = {
|
|||
'rename_folder': 'Rename folder',
|
||||
'enter_new_folder_name': 'Enter new folder name',
|
||||
'search_selection_in_grid_view': 'Search ... in grid view',
|
||||
'show_date_dividers': 'Show date dividers',
|
||||
'show_date_dividers_desc': 'Show date dividers before the first item of each different day when using date-related sorting',
|
||||
'date_divider_format': 'Date divider format',
|
||||
'date_divider_mode': 'Date divider',
|
||||
'date_divider_mode_desc': 'Select the display mode for date dividers',
|
||||
'date_divider_mode_none': 'None',
|
||||
'date_divider_mode_year': 'Year',
|
||||
'date_divider_mode_month': 'Month',
|
||||
'date_divider_mode_day': 'Day',
|
||||
},
|
||||
'zh': {
|
||||
// 通知信息
|
||||
|
|
@ -375,10 +397,12 @@ export const TRANSLATIONS: Translations = {
|
|||
// 设置
|
||||
'grid_view_settings': '网格视图设置',
|
||||
'media_files_settings': '媒体文件设置',
|
||||
'show_media_files': '显示图片和视频',
|
||||
'show_media_files_desc': '在网格视图中显示图片和视频文件',
|
||||
'show_media_files': '显示媒体文件',
|
||||
'show_media_files_desc': '在网格视图中显示媒体文件',
|
||||
'show_video_thumbnails': '显示视频缩略图',
|
||||
'show_video_thumbnails_desc': '在网格视图中显示视频的缩略图,关闭时将显示播放图标',
|
||||
'show_note_tags': '显示笔记标签',
|
||||
'show_note_tags_desc': '在网格视图中显示笔记的标签',
|
||||
'ignored_folders': '忽略的文件夹',
|
||||
'ignored_folders_desc': '在这里设置要忽略的文件夹',
|
||||
'add_ignored_folder': '添加忽略文件夹',
|
||||
|
|
@ -423,7 +447,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'show_random_note_mode': '显示随机笔记模式',
|
||||
'random_note_count': '随机笔记模式显示笔数',
|
||||
'random_note_notes_only': '仅笔记',
|
||||
'random_note_include_media_files': '包含图片视频',
|
||||
'random_note_include_media_files': '包含媒体文件',
|
||||
|
||||
// 显示"返回上级文件夹"选项设置
|
||||
'show_parent_folder_item': '显示「返回上级文件夹」',
|
||||
|
|
@ -486,6 +510,15 @@ export const TRANSLATIONS: Translations = {
|
|||
'rename_folder': '重新命名文件夹',
|
||||
'enter_new_folder_name': '输入新文件夹名称',
|
||||
'search_selection_in_grid_view': '在网格视图中搜寻...',
|
||||
'show_date_dividers': '显示日期分隔器',
|
||||
'show_date_dividers_desc': '在日期相关排序时,在不同天的第一条之前显示日期分隔器',
|
||||
'date_divider_format': '日期分隔器格式',
|
||||
'date_divider_mode': '日期分隔器',
|
||||
'date_divider_mode_desc': '选择日期分隔器的显示模式',
|
||||
'date_divider_mode_none': '不使用',
|
||||
'date_divider_mode_year': '年',
|
||||
'date_divider_mode_month': '月',
|
||||
'date_divider_mode_day': '日',
|
||||
},
|
||||
'ja': {
|
||||
// 通知メッジ
|
||||
|
|
@ -531,10 +564,12 @@ export const TRANSLATIONS: Translations = {
|
|||
// 設定
|
||||
'grid_view_settings': 'グリッドビュー設定',
|
||||
'media_files_settings': 'メディアファイル設定',
|
||||
'show_media_files': '画像と動画を表示',
|
||||
'show_media_files_desc': 'グリッドビューで画像と動画ファイルを表示する',
|
||||
'show_media_files': 'メディアファイルを表示',
|
||||
'show_media_files_desc': 'グリッドビューでメディアファイルを表示する',
|
||||
'show_video_thumbnails': '動画のサムネイルを表示',
|
||||
'show_video_thumbnails_desc': 'グリッドビューで動画のサムネイルを表示する、無効の場合は再生アイコンを表示',
|
||||
'show_note_tags': 'ノートのタグを表示',
|
||||
'show_note_tags_desc': 'グリッドビューでノートのタグを表示する',
|
||||
'ignored_folders': '無視するフォルダ',
|
||||
'ignored_folders_desc': '無視するフォルダを設定する',
|
||||
'add_ignored_folder': '無視するフォルダを追加',
|
||||
|
|
@ -579,9 +614,9 @@ export const TRANSLATIONS: Translations = {
|
|||
'show_random_note_mode': 'ランダムノートモードを表示',
|
||||
'random_note_count': 'ランダムノートモード表示筆数',
|
||||
'random_note_notes_only': 'ノートのみ',
|
||||
'random_note_include_media_files': 'メディアを含む',
|
||||
'random_note_include_media_files': 'メディアファイルを含む',
|
||||
|
||||
// 「親フォルダ」オプション設定を表示
|
||||
// "親フォルダ"オプション設定を表示
|
||||
'show_parent_folder_item': '「親フォルダ」項目を表示',
|
||||
'show_parent_folder_item_desc': 'グリッドの最初の項目として「親フォルダ」項目を表示します',
|
||||
'parent_folder': '親フォルダ',
|
||||
|
|
@ -642,5 +677,14 @@ export const TRANSLATIONS: Translations = {
|
|||
'rename_folder': 'フォルダを再命名',
|
||||
'enter_new_folder_name': '新しいフォルダ名を入力',
|
||||
'search_selection_in_grid_view': '... をグリッドビューで検索',
|
||||
'show_date_dividers': '日付区切りを表示',
|
||||
'show_date_dividers_desc': '日付関連の並び替え時、各日の最初のアイテムの前に日付区切りを表示する',
|
||||
'date_divider_format': '日付区切りフォーマット',
|
||||
'date_divider_mode': '日付区切り',
|
||||
'date_divider_mode_desc': '日付区切りの表示モードを選択',
|
||||
'date_divider_mode_none': '使用しない',
|
||||
'date_divider_mode_year': '年',
|
||||
'date_divider_mode_month': '月',
|
||||
'date_divider_mode_day': '日',
|
||||
}
|
||||
}
|
||||
|
|
|
|||
40
styles.css
40
styles.css
|
|
@ -143,6 +143,10 @@
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.ge-grid-item:hover p {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.ge-content-area p:empty {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
@ -167,6 +171,30 @@
|
|||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 標籤樣式 */
|
||||
.ge-tags-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.ge-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0 6px;
|
||||
font-size: 0.8em;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 5px;
|
||||
background-color: var(--background-secondary-alt);
|
||||
color: var(--text-accent);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 資料夾項目的特殊樣式 */
|
||||
.ge-grid-item.ge-folder-item {
|
||||
background-color: var(--background-primary-alt);
|
||||
|
|
@ -210,6 +238,18 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
/* 日期分隔器樣式 */
|
||||
.ge-date-divider {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
color: var(--text-normal);
|
||||
margin-left: 8px;
|
||||
grid-column: 1 / -1;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
/* 頂部按鈕區域樣式 */
|
||||
.ge-header-buttons {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"1.9.11": "1.1.0"
|
||||
"1.9.12": "1.1.0"
|
||||
}
|
||||
Loading…
Reference in a new issue