This commit is contained in:
Devon22 2026-02-11 21:53:42 +08:00
parent e41bc14634
commit 8fe1469616
6 changed files with 208 additions and 8 deletions

View file

@ -1,7 +1,7 @@
{
"id": "gridexplorer",
"name": "GridExplorer",
"version": "3.0.7",
"version": "3.0.8",
"minAppVersion": "1.1.0",
"description": "Browse note files in a grid view.",
"author": "Devon22",

6
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "gridexplorer",
"version": "3.0.7",
"version": "3.0.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gridexplorer",
"version": "3.0.7",
"version": "3.0.8",
"license": "MIT",
"dependencies": {
"@esbuild/linux-x64": "0.17.3",
@ -2315,4 +2315,4 @@
}
}
}
}
}

View file

@ -1,6 +1,6 @@
{
"name": "gridexplorer",
"version": "3.0.7",
"version": "3.0.8",
"description": "Browse note files in a grid view.",
"main": "main.js",
"scripts": {
@ -25,4 +25,4 @@
"@esbuild/linux-x64": "^0.17.3",
"@esbuild/win32-x64": "^0.17.3"
}
}
}

View file

@ -2016,7 +2016,9 @@ export class GridView extends ItemView {
// 筆記標題
const noteTitle = leftBar.createDiv('ge-note-title');
noteTitle.textContent = file.basename;
setTooltip(noteTitle, file.basename);
if (Platform.isDesktop) {
setTooltip(noteTitle, file.basename);
}
// 編輯按鈕
const editButton = rightBar.createEl('button', { cls: 'ge-note-edit-button' });
@ -2025,6 +2027,10 @@ export class GridView extends ItemView {
this.getLeafByMode(file).openFile(file);
});
// Metadata 切換按鈕
const infoButton = rightBar.createEl('button', { cls: 'ge-note-info-button' });
setIcon(infoButton, 'info')
// 關閉按鈕
const closeButton = rightBar.createEl('button', { cls: 'ge-note-close-button' });
setIcon(closeButton, 'x');
@ -2049,6 +2055,134 @@ export class GridView extends ItemView {
noteContent.style.padding = '15px';
}
// 取得 Metadata (Frontmatter)
const fileCache = this.app.metadataCache.getFileCache(file);
const frontmatter = fileCache?.frontmatter;
if (frontmatter) {
// 檢查是否除了 position 以外還有其他屬性
const keys = Object.keys(frontmatter).filter(k => k !== 'position');
if (keys.length > 0) {
const metadataContainer = noteContent.createDiv('ge-note-metadata-container');
// 綁定切換事件
infoButton.addEventListener('click', () => {
metadataContainer.classList.toggle('is-visible');
scrollContainer.scrollTo(0, 0);
});
const metadataContent = metadataContainer.createDiv('ge-note-metadata-content');
for (const key of keys) {
const item = metadataContent.createDiv('ge-note-metadata-item');
item.createSpan({ cls: 'ge-note-metadata-key', text: `${key}: ` });
const value = frontmatter[key];
const valueSpan = item.createSpan({ cls: 'ge-note-metadata-value' });
const values = Array.isArray(value) ? value : [value];
values.forEach((val, index) => {
const valStr = String(val);
// 處理內部連結 [[link]] 或 [[link|alias]]
const wikilinkRegex = /\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g;
// 處理 URL
const urlRegex = /(https?:\/\/[^\s]+)/g;
// 處理 Tag
const tagRegex = /#([^\s#]+)/g;
if (wikilinkRegex.test(valStr)) {
wikilinkRegex.lastIndex = 0;
let lastIndex = 0;
let match;
while ((match = wikilinkRegex.exec(valStr)) !== null) {
// 插入匹配前的文字
if (match.index > lastIndex) {
valueSpan.createSpan({ text: valStr.substring(lastIndex, match.index) });
}
const linkPath = match[1];
const linkAlias = match[2] || linkPath;
const linkEl = valueSpan.createEl('a', {
cls: 'internal-link',
text: linkAlias,
attr: { 'data-href': linkPath }
});
linkEl.addEventListener('click', (e) => {
e.preventDefault();
const linkedFile = this.app.metadataCache.getFirstLinkpathDest(linkPath, file.path);
if (linkedFile) {
this.getLeafByMode(linkedFile).openFile(linkedFile);
}
});
lastIndex = wikilinkRegex.lastIndex;
}
if (lastIndex < valStr.length) {
valueSpan.createSpan({ text: valStr.substring(lastIndex) });
}
} else if (urlRegex.test(valStr)) {
urlRegex.lastIndex = 0;
let lastIndex = 0;
let match;
while ((match = urlRegex.exec(valStr)) !== null) {
if (match.index > lastIndex) {
valueSpan.createSpan({ text: valStr.substring(lastIndex, match.index) });
}
const url = match[1];
valueSpan.createEl('a', {
cls: 'external-link',
text: url,
attr: { 'href': url, 'target': '_blank', 'rel': 'noopener' }
});
lastIndex = urlRegex.lastIndex;
}
if (lastIndex < valStr.length) {
valueSpan.createSpan({ text: valStr.substring(lastIndex) });
}
} else if (key.toLowerCase() === 'tags' || key.toLowerCase() === 'tag' || tagRegex.test(valStr)) {
if ((key.toLowerCase() === 'tags' || key.toLowerCase() === 'tag') && !valStr.startsWith('#')) {
const tagEl = valueSpan.createEl('a', {
cls: 'tag',
text: '#' + valStr,
attr: { 'href': '#' + valStr }
});
tagEl.addEventListener('click', (e) => {
e.preventDefault();
(this.app as any).internalPlugins?.getPluginById('global-search')?.instance?.openGlobalSearch('tag:#' + valStr);
});
} else {
tagRegex.lastIndex = 0;
let lastIndex = 0;
let match;
while ((match = tagRegex.exec(valStr)) !== null) {
if (match.index > lastIndex) {
valueSpan.createSpan({ text: valStr.substring(lastIndex, match.index) });
}
const tagName = match[1];
const tagEl = valueSpan.createEl('a', {
cls: 'tag',
text: '#' + tagName,
attr: { 'href': '#' + tagName }
});
tagEl.addEventListener('click', (e) => {
e.preventDefault();
(this.app as any).internalPlugins?.getPluginById('global-search')?.instance?.openGlobalSearch('tag:#' + tagName);
});
lastIndex = tagRegex.lastIndex;
}
if (lastIndex < valStr.length) {
valueSpan.createSpan({ text: valStr.substring(lastIndex) });
}
}
} else {
valueSpan.createSpan({ text: valStr });
}
if (index < values.length - 1) {
const isTag = key.toLowerCase() === 'tags' || key.toLowerCase() === 'tag';
valueSpan.createSpan({ text: isTag ? ' ' : ', ' });
}
});
}
}
}
// 創建筆記內容區域
const noteContentArea = noteContent.createDiv('ge-note-content');

View file

@ -2070,6 +2070,17 @@ a.ge-current-folder:hover {
text-overflow: ellipsis;
}
.is-mobile .ge-note-title {
overflow-x: auto;
text-overflow: clip;
/* 或者 unset */
}
/* 隱藏行動裝置上的捲軸,保持簡潔 */
.is-mobile .ge-note-title::-webkit-scrollbar {
display: none;
}
.ge-note-content {
line-height: 1.6;
color: var(--text-normal);
@ -2092,6 +2103,61 @@ a.ge-current-folder:hover {
/* --------------------------------------------------------------------------- */
/* 筆記 Metadata 區塊 */
.ge-note-metadata-container {
margin-bottom: 20px;
border: 1px solid var(--background-modifier-border);
border-radius: 6px;
background-color: var(--background-secondary-alt);
overflow: hidden;
display: none;
/* 預設隱藏 */
}
.ge-note-metadata-container.is-visible {
display: block;
}
.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;
cursor: pointer;
transition: background-color 0.2s, transform 0.1s;
}
.ge-note-info-button:hover {
transform: translateY(-1px);
}
.ge-note-metadata-content {
padding: 10px 15px;
}
.ge-note-metadata-item {
margin-bottom: 4px;
font-size: 0.8em;
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.ge-note-metadata-key {
color: var(--text-faint);
font-weight: 500;
}
.ge-note-metadata-value {
color: var(--text-normal);
}
/* --------------------------------------------------------------------------- */
.ge-note-content>p:nth-child(2) {
margin-block-start: 0;
}

View file

@ -1,3 +1,3 @@
{
"3.0.7": "1.1.0"
"3.0.8": "1.1.0"
}