mirror of
https://github.com/devon22/obsidian-gridexplorer.git
synced 2026-07-22 05:38:16 +00:00
3.0.8
This commit is contained in:
parent
e41bc14634
commit
8fe1469616
6 changed files with 208 additions and 8 deletions
|
|
@ -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
6
package-lock.json
generated
|
|
@ -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 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
136
src/GridView.ts
136
src/GridView.ts
|
|
@ -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');
|
||||
|
||||
|
|
|
|||
66
styles.css
66
styles.css
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"3.0.7": "1.1.0"
|
||||
"3.0.8": "1.1.0"
|
||||
}
|
||||
Loading…
Reference in a new issue