Add files via upload

This commit is contained in:
Devon22 2025-02-10 00:46:29 +08:00 committed by GitHub
parent b33234b9c5
commit 9a3a806a39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 202 additions and 131 deletions

BIN
demo1.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 186 KiB

View file

@ -1,4 +1,4 @@
const { Plugin, ItemView, TFolder, Setting, Menu } = require('obsidian');
const { Plugin, ItemView, TFolder, Setting, Menu, setIcon } = require('obsidian');
// 語系檔案
const TRANSLATIONS = {
@ -38,6 +38,10 @@ const TRANSLATIONS = {
'DEFAULT_SORT_TYPE_DESC': '設定開啟網格視圖時的預設排序方式',
'GRID_ITEM_WIDTH': '網格項目寬度',
'GRID_ITEM_WIDTH_DESC': '設定網格項目的寬度',
'IMAGE_AREA_WIDTH': '圖片區域寬度',
'IMAGE_AREA_WIDTH_DESC': '設定圖片預覽區域的寬度',
'IMAGE_AREA_HEIGHT': '圖片區域高度',
'IMAGE_AREA_HEIGHT_DESC': '設定圖片預覽區域的高度',
// 選擇資料夾對話框
'SELECT_FOLDERS': '選擇資料夾',
@ -80,6 +84,10 @@ const TRANSLATIONS = {
'DEFAULT_SORT_TYPE_DESC': 'Set the default sorting method when opening Grid View',
'GRID_ITEM_WIDTH': 'Grid Item Width',
'GRID_ITEM_WIDTH_DESC': 'Set the width of grid items',
'IMAGE_AREA_WIDTH': 'Image Area Width',
'IMAGE_AREA_WIDTH_DESC': 'Set the width of the image preview area',
'IMAGE_AREA_HEIGHT': 'Image Area Height',
'IMAGE_AREA_HEIGHT_DESC': 'Set the height of the image preview area',
// Folder Selection Dialog
'SELECT_FOLDERS': 'Select Folder',
@ -122,6 +130,10 @@ const TRANSLATIONS = {
'DEFAULT_SORT_TYPE_DESC': '设置开启网格视图时的預设排序方式',
'GRID_ITEM_WIDTH': '网格项目宽度',
'GRID_ITEM_WIDTH_DESC': '设置网格项目的宽度',
'IMAGE_AREA_WIDTH': '圖片區域寬度',
'IMAGE_AREA_WIDTH_DESC': '设置圖片預覽區域的寬度',
'IMAGE_AREA_HEIGHT': '圖片區域高度',
'IMAGE_AREA_HEIGHT_DESC': '设置圖片預覽區域的高度',
// 选择资料夹对话框
'SELECT_FOLDERS': '选择文件夹',
@ -164,6 +176,10 @@ const TRANSLATIONS = {
'DEFAULT_SORT_TYPE_DESC': 'グリッドビューを開くときのデフォルトのソート方法を設定します',
'GRID_ITEM_WIDTH': 'グリッドアイテムの幅',
'GRID_ITEM_WIDTH_DESC': 'グリッドアイテムの幅を設定します',
'IMAGE_AREA_WIDTH': '画像エリア幅',
'IMAGE_AREA_WIDTH_DESC': '画像プレビュー領域の幅を設定します',
'IMAGE_AREA_HEIGHT': '画像エリア高さ',
'IMAGE_AREA_HEIGHT_DESC': '画像プレビュー領域の高さを設定します',
// フォルダ選択ダイアログ
'SELECT_FOLDERS': 'フォルダを選択',
@ -256,7 +272,6 @@ class GridView extends ItemView {
this.sourceMode = ''; // 預設為書籤模式
this.sourcePath = null; // 用於資料夾模式的路徑
this.sortType = this.plugin.settings.defaultSortType; // 使用設定中的預設排序模式
this.initHeaderButtons();
}
getViewType() {
@ -281,79 +296,6 @@ class GridView extends ItemView {
}
}
// 初始化導航列
initHeaderButtons() {
// 添加排序選單
this.sortSelect = this.addAction('sort-desc', t('SORTING'), (evt) => {
const menu = new Menu();
const sortOptions = [
{ value: 'name-asc', label: t('SORT_NAME_ASC'), icon: 'sort-ascending' },
{ value: 'name-desc', label: t('SORT_NAME_DESC'), icon: 'sort-descending' },
{ value: 'mtime-desc', label: t('SORT_MTIME_DESC'), icon: 'clock' },
{ value: 'mtime-asc', label: t('SORT_MTIME_ASC'), icon: 'clock' },
{ value: 'ctime-desc', label: t('SORT_CTIME_DESC'), icon: 'calendar' },
{ value: 'ctime-asc', label: t('SORT_CTIME_ASC'), icon: 'calendar' },
{ value: 'random', label: t('SORT_RANDOM'), icon: 'dice' },
];
sortOptions.forEach(option => {
menu.addItem((item) => {
item
.setTitle(option.label)
.setIcon(option.icon)
.setChecked(this.sortType === option.value)
.onClick(() => {
this.sortType = option.value;
this.rerender();
});
});
});
menu.showAtMouseEvent(evt);
});
// 添加重新選擇位置按鈕
this.addAction('folder', t('RESELECT_FOLDER'), () => {
showFolderSelectionModal(this.app, this.plugin, this);
});
// 添加重新整理按鈕
this.addAction('refresh-cw', t('REFRESH'), () => {
this.rerender();
});
// 添加回上層目錄按鈕(僅在資料夾模式且不在根目錄時顯示)
this.upSelect = this.addAction('arrow-up', t('GO_UP'), () => {
if (this.sourceMode === 'folder' && this.sourcePath !== '/') {
const parentPath = this.sourcePath.split('/').slice(0, -1).join('/') || '/';
this.setSource('folder', parentPath);
}
});
// 根據當前模式設定排序選單的顯示狀態
this.updateSortSelectVisibility();
}
// 更新排序選單的顯示狀態
updateSortSelectVisibility() {
if (this.sortSelect) {
if (this.sourceMode === 'bookmarks') {
this.sortSelect.style.display = 'none';
} else {
this.sortSelect.style.display = '';
}
}
if (this.upSelect) {
if (this.sourceMode === 'folder') {
this.upSelect.style.display = '';
} else {
this.upSelect.style.display = 'none';
}
}
}
async getFiles() {
if (this.sourceMode === 'folder' && this.sourcePath) {
// 獲取指定資料夾內的所有 Markdown 檔案
@ -475,51 +417,99 @@ class GridView extends ItemView {
}
}
async rerender() {
setSource(mode, path = null) {
this.sourceMode = mode;
this.sourcePath = path;
this.render();
}
async render() {
// 儲存當前捲動位置
const scrollContainer = this.containerEl.querySelector('.view-content');
const scrollTop = scrollContainer ? scrollContainer.scrollTop : 0;
// 清空容器
const contentEl = this.containerEl.querySelector('.view-content');
if (contentEl) {
contentEl.empty();
// 清空整個容器
this.containerEl.empty();
// 創建頂部按鈕區域
const headerButtonsDiv = this.containerEl.createDiv('header-buttons');
// 添加回上層按鈕(僅在資料夾模式且不在根目錄時顯示)
if (this.sourceMode === 'folder' && this.sourcePath !== '/') {
const upButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('GO_UP') } });
upButton.addEventListener('click', () => {
const parentPath = this.sourcePath.split('/').slice(0, -1).join('/') || '/';
this.setSource('folder', parentPath);
});
setIcon(upButton, 'arrow-up');
}
// 添加重新整理按鈕
const refreshButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('REFRESH') } });
refreshButton.addEventListener('click', () => {
this.render();
});
setIcon(refreshButton, 'refresh-ccw');
// 添加重新選擇資料夾按鈕
const reselectButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('RESELECT_FOLDER') } });
reselectButton.addEventListener('click', () => {
showFolderSelectionModal(this.app, this.plugin, this);
});
setIcon(reselectButton, "folder");
// 添加排序按鈕
if (this.sourceMode !== 'bookmarks') {
const sortButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('SORTING') } });
sortButton.addEventListener('click', (evt) => {
const menu = new Menu();
const sortOptions = [
{ value: 'name-asc', label: t('SORT_NAME_ASC'), icon: 'a-arrow-up' },
{ value: 'name-desc', label: t('SORT_NAME_DESC'), icon: 'a-arrow-down' },
{ value: 'mtime-desc', label: t('SORT_MTIME_DESC'), icon: 'clock' },
{ value: 'mtime-asc', label: t('SORT_MTIME_ASC'), icon: 'clock' },
{ value: 'ctime-desc', label: t('SORT_CTIME_DESC'), icon: 'calendar' },
{ value: 'ctime-asc', label: t('SORT_CTIME_ASC'), icon: 'calendar' },
{ value: 'random', label: t('SORT_RANDOM'), icon: 'dice' },
];
sortOptions.forEach(option => {
menu.addItem((item) => {
item
.setTitle(option.label)
.setIcon(option.icon)
.setChecked(this.sortType === option.value)
.onClick(() => {
this.sortType = option.value;
this.render();
});
});
});
menu.showAtMouseEvent(evt);
});
setIcon(sortButton, 'arrow-down-up');
}
// 創建內容區域
const contentEl = this.containerEl.createDiv('view-content');
// 重新渲染內容
await this.render();
await this.grid_render();
this.leaf.updateHeader()
if (this.sourceMode === '') {
this.leaf.view.titleEl.textContent = t('GRID_VIEW_TITLE');
} else if (this.sourceMode === 'bookmarks') {
this.leaf.view.titleEl.textContent = t('BOOKMARKS_MODE');
} else if (this.sourceMode === 'folder') {
this.leaf.view.titleEl.textContent = this.sourcePath;
} else if (this.sourceMode === 'search') {
this.leaf.view.titleEl.textContent = t('SEARCH_RESULTS');
} else if (this.sourceMode === 'backlinks') {
this.leaf.view.titleEl.textContent = t('BACKLINKS_MODE');
}
// 恢復捲動位置
if (scrollContainer) {
scrollContainer.scrollTop = scrollTop;
contentEl.scrollTop = scrollTop;
}
}
setSource(mode, path = null) {
this.sourceMode = mode;
this.sourcePath = path;
this.updateSortSelectVisibility();
this.rerender();
}
async render() {
async grid_render() {
const container = this.containerEl.children[1];
container.empty();
container.addClass('grid-container');
container.style.setProperty('--grid-item-width', this.plugin.settings.gridItemWidth + 'px');
container.style.setProperty('--image-area-width', this.plugin.settings.imageAreaWidth + 'px');
container.style.setProperty('--image-area-height', this.plugin.settings.imageAreaHeight + 'px');
// 如果是書籤模式且書籤插件未啟用,顯示提示
if (this.sourceMode === 'bookmarks' && !this.app.internalPlugins.plugins.bookmarks?.enabled) {
@ -532,22 +522,6 @@ class GridView extends ItemView {
new Notice(t(t(t('NO_BACKLINKS'))));
return;
}
// 如果是資料夾模式,添加上層資料夾連結(除了根目錄)
if (this.sourceMode === 'folder' && this.sourcePath !== '/') {
const parentPath = this.sourcePath.split('/').slice(0, -1).join('/') || '/';
const parentEl = container.createDiv('grid-item folder-item');
parentEl.addClass('parent-folder');
const contentArea = parentEl.createDiv('content-area');
const titleEl = contentArea.createEl('h3');
titleEl.textContent = '📁 ..';
// 點擊時切換到上層資料夾
parentEl.addEventListener('click', () => {
this.setSource('folder', parentPath);
});
}
// 如果是資料夾模式,先顯示所有子資料夾
if (this.sourceMode === 'folder') {
@ -555,7 +529,13 @@ class GridView extends ItemView {
if (currentFolder instanceof TFolder) {
// 只取得當前資料夾中的 Markdown 檔案,不包含子資料夾
const subfolders = currentFolder.children
.filter(child => child instanceof TFolder)
.filter(child => {
if (!(child instanceof TFolder)) return false;
// 檢查資料夾是否在忽略清單中
return !this.plugin.settings.ignoredFolders.some(
ignoredPath => child.path === ignoredPath || child.path.startsWith(ignoredPath + '/')
);
})
.sort((a, b) => a.name.localeCompare(b.name));
for (const folder of subfolders) {
@ -664,7 +644,7 @@ class GridView extends ItemView {
this.sourceMode = state.state.sourceMode || '';
this.sourcePath = state.state.sourcePath || null;
this.sortType = state.state.sortType || 'mtime-desc';
this.rerender();
this.render();
}
}
}
@ -673,7 +653,9 @@ class GridView extends ItemView {
const DEFAULT_SETTINGS = {
ignoredFolders: [],
defaultSortType: 'mtime-desc', // 預設排序模式:修改時間倒序
gridItemWidth: 300 // 網格項目寬度,預設 300
gridItemWidth: 300, // 網格項目寬度,預設 300
imageAreaWidth: 100, // 圖片區域寬度,預設 100
imageAreaHeight: 100 // 圖片區域高度,預設 100
};
// 設定頁面類別
@ -735,6 +717,32 @@ class GridExplorerSettingTab extends require('obsidian').PluginSettingTab {
this.plugin.settings.gridItemWidth = value;
await this.plugin.saveSettings();
}));
// 圖片區域寬度設定
new Setting(containerEl)
.setName(t('IMAGE_AREA_WIDTH'))
.setDesc(t('IMAGE_AREA_WIDTH_DESC'))
.addSlider(slider => slider
.setLimits(50, 200, 10)
.setValue(this.plugin.settings.imageAreaWidth)
.setDynamicTooltip()
.onChange(async (value) => {
this.plugin.settings.imageAreaWidth = value;
await this.plugin.saveSettings();
}));
// 圖片區域高度設定
new Setting(containerEl)
.setName(t('IMAGE_AREA_HEIGHT'))
.setDesc(t('IMAGE_AREA_HEIGHT_DESC'))
.addSlider(slider => slider
.setLimits(50, 200, 10)
.setValue(this.plugin.settings.imageAreaHeight)
.setDynamicTooltip()
.onChange(async (value) => {
this.plugin.settings.imageAreaHeight = value;
await this.plugin.saveSettings();
}));
}
}

View file

@ -1,7 +1,7 @@
{
"id": "gridexplorer",
"name": "GridExplorer",
"version": "1.1.1",
"version": "1.2.3",
"minAppVersion": "0.15.0",
"description": "Browse note files in a grid view.",
"main": "main.js",

View file

@ -6,22 +6,26 @@
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--grid-item-width, 300px), 1fr));
gap: 15px;
padding: 15px;
gap: 12px;
padding: 12px;
align-items: start;
background: var(--background-secondary) !important;
border-top: 1px solid var(--background-modifier-border);
}
.view-content {
flex: 1;
overflow-y: auto;
}
.grid-item {
background-color: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: 8px;
padding: 16px;
padding: 14px;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
display: flex;
gap: 16px;
gap: 14px;
height: 100%;
}
@ -37,8 +41,8 @@
}
.image-area {
width: 100px;
height: 100px;
width: var(--image-area-width);
height: var(--image-area-height);
flex-shrink: 0;
}
@ -51,7 +55,7 @@
.grid-item h3 {
margin: 0 0 8px 0;
font-size: 1.2em;
font-size: 1.1em;
color: var(--text-normal);
overflow: hidden;
text-overflow: ellipsis;
@ -61,7 +65,7 @@
.grid-item p {
margin: 0;
color: var(--text-muted);
font-size: 0.9em;
font-size: 0.85em;
line-height: 1.4;
overflow: hidden;
display: -webkit-box;
@ -101,4 +105,63 @@
display: flex;
align-items: center;
min-height: 0px;
}
/* 頂部按鈕區域樣式 */
.header-buttons {
display: flex;
gap: 8px;
padding: 12px 16px;
background: var(--background-primary);
border-bottom: 1px solid var(--background-modifier-border);
flex-shrink: 0;
justify-content: center;
}
.header-buttons button {
display: flex;
align-items: center;
gap: 4px;
padding: 6px 12px;
background-color: var(--interactive-normal);
border-radius: 4px;
color: var(--text-normal);
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s, transform 0.1s;
min-width: 45px;
}
.header-buttons button:hover {
background-color: var(--interactive-hover);
transform: translateY(-1px);
}
.header-buttons button:active {
transform: translateY(0);
}
/* 特定按鈕樣式 */
.header-buttons .sort-button,
.header-buttons .reselect-button,
.header-buttons .refresh-button,
.header-buttons .up-button {
display: inline-flex;
align-items: center;
}
.header-buttons .sort-button::before {
content: "↕";
}
.header-buttons .reselect-button::before {
content: "📁";
}
.header-buttons .refresh-button::before {
content: "↻";
}
.header-buttons .up-button::before {
content: "↑";
}