mirror of
https://github.com/devon22/obsidian-gridexplorer.git
synced 2026-07-22 12:00:25 +00:00
2.4.0
This commit is contained in:
parent
1718504eab
commit
55638f0eb7
14 changed files with 423 additions and 270 deletions
|
|
@ -61,6 +61,10 @@ Available colors:
|
|||
- purple
|
||||
- pink
|
||||
|
||||
|
||||
CSS Class: `.ge-grid-item.ge-foldernote`
|
||||
|
||||
|
||||
## Settings
|
||||
|
||||
In the plugin's settings page, you can:
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ color: red
|
|||
- purple
|
||||
- pink
|
||||
|
||||
|
||||
CSS Class: `.ge-grid-item.ge-foldernote`
|
||||
|
||||
|
||||
## 設定
|
||||
|
||||
プラグインの設定ページでは、以下のことができます:
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ color: red
|
|||
- purple
|
||||
- pink
|
||||
|
||||
|
||||
CSS Class: `.ge-grid-item.ge-foldernote`
|
||||
|
||||
|
||||
## 設定
|
||||
|
||||
在插件的設定頁面中,您可以:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "gridexplorer",
|
||||
"name": "GridExplorer",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"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": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gridexplorer",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "gridexplorer",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"description": "Browse note files in a grid view.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export interface FolderNoteSettings {
|
|||
sort: string;
|
||||
color: string;
|
||||
icon: string;
|
||||
isPinned: boolean;
|
||||
}
|
||||
|
||||
export function showFolderNoteSettingsModal(app: App, plugin: GridExplorerPlugin, folder: TFolder, gridView: GridView) {
|
||||
|
|
@ -20,7 +21,8 @@ export class FolderNoteSettingsModal extends Modal {
|
|||
settings: FolderNoteSettings = {
|
||||
sort: '',
|
||||
color: '',
|
||||
icon: '📁'
|
||||
icon: '📁',
|
||||
isPinned: false
|
||||
};
|
||||
existingFile: TFile | null = null;
|
||||
|
||||
|
|
@ -105,6 +107,19 @@ export class FolderNoteSettingsModal extends Modal {
|
|||
});
|
||||
});
|
||||
|
||||
// 置頂勾選框
|
||||
new Setting(contentEl)
|
||||
.setName(t('pinned'))
|
||||
.setDesc(t('pinned_desc'))
|
||||
.addToggle(toggle => {
|
||||
toggle
|
||||
.setValue(this.settings.isPinned)
|
||||
.onChange(value => {
|
||||
this.settings.isPinned = value;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// 按鈕區域
|
||||
const buttonSetting = new Setting(contentEl);
|
||||
|
||||
|
|
@ -142,6 +157,16 @@ export class FolderNoteSettingsModal extends Modal {
|
|||
if ('icon' in fileCache.frontmatter) {
|
||||
this.settings.icon = fileCache.frontmatter.icon || '📁';
|
||||
}
|
||||
|
||||
// 讀取置頂設定
|
||||
if (fileCache.frontmatter?.pinned && Array.isArray(fileCache.frontmatter.pinned)) {
|
||||
this.settings.isPinned = fileCache.frontmatter.pinned.some((item: any) => {
|
||||
if (!item) return false;
|
||||
const pinnedName = item.toString();
|
||||
const pinnedNameWithoutExt = pinnedName.replace(/\.\w+$/, '');
|
||||
return pinnedNameWithoutExt === this.folder.name;
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('無法讀取資料夾筆記設定', error);
|
||||
|
|
@ -184,6 +209,27 @@ export class FolderNoteSettingsModal extends Modal {
|
|||
} else {
|
||||
delete frontmatter['icon'];
|
||||
}
|
||||
const folderName = `${this.folder.name}.md`;
|
||||
if (this.settings.isPinned) {
|
||||
// 如果原本就有 pinned 陣列,則添加或更新
|
||||
if (Array.isArray(frontmatter['pinned'])) {
|
||||
if (!frontmatter['pinned'].includes(folderName)) {
|
||||
frontmatter['pinned'] = [folderName, ...frontmatter['pinned']];
|
||||
}
|
||||
} else {
|
||||
// 如果沒有 pinned 陣列,則創建一個新的
|
||||
frontmatter['pinned'] = [folderName];
|
||||
}
|
||||
} else if (Array.isArray(frontmatter['pinned'])) {
|
||||
// 如果取消置頂,則從陣列中移除
|
||||
frontmatter['pinned'] = frontmatter['pinned'].filter(
|
||||
(item: any) => item !== folderName
|
||||
);
|
||||
// 如果陣列為空,則刪除該欄位
|
||||
if (frontmatter['pinned'].length === 0) {
|
||||
delete frontmatter['pinned'];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 強制更新 metadata cache
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { App, Modal, Setting, TFolder } from 'obsidian';
|
||||
import { App, Modal, Setting, TFolder, normalizePath } from 'obsidian';
|
||||
import { t } from './translations';
|
||||
import GridExplorerPlugin from '../main';
|
||||
import { GridView } from './GridView';
|
||||
|
|
@ -57,7 +57,9 @@ export class FolderRenameModal extends Modal {
|
|||
|
||||
async renameFolder() {
|
||||
try {
|
||||
await this.app.fileManager.renameFile(this.folder, this.newName);
|
||||
const parentPath = this.folder.parent ? this.folder.parent.path : '';
|
||||
const newPath = normalizePath(parentPath ? `${parentPath}/${this.newName}` : this.newName);
|
||||
await this.app.fileManager.renameFile(this.folder, newPath);
|
||||
// 重新渲染視圖
|
||||
setTimeout(() => {
|
||||
this.gridView.render();
|
||||
|
|
|
|||
|
|
@ -246,10 +246,32 @@ export class FolderSelectionModal extends Modal {
|
|||
|
||||
// 建立資料夾選項
|
||||
folders.forEach(folder => {
|
||||
// 計算資料夾層級
|
||||
const depth = (folder.path.match(/\//g) || []).length;
|
||||
const displayName = folder.path.split('/').pop() || '/';
|
||||
|
||||
const folderOption = this.folderOptionsContainer.createEl('div', {
|
||||
cls: 'ge-grid-view-folder-option',
|
||||
text: `📁 ${folder.path || '/'}`
|
||||
attr: {
|
||||
'data-depth': depth.toString(),
|
||||
'data-path': folder.path
|
||||
}
|
||||
});
|
||||
|
||||
// 產生 ascii tree 前綴
|
||||
const prefixSpan = document.createElement('span');
|
||||
prefixSpan.className = 'ge-folder-tree-prefix';
|
||||
prefixSpan.textContent = depth > 0 ? ' '.repeat(depth - 1) + '└ ' : '';
|
||||
folderOption.appendChild(prefixSpan);
|
||||
|
||||
// 資料夾圖示與名稱
|
||||
const icon = document.createElement('span');
|
||||
icon.textContent = '📁 ';
|
||||
folderOption.appendChild(icon);
|
||||
|
||||
const nameSpan = document.createElement('span');
|
||||
nameSpan.textContent = displayName;
|
||||
folderOption.appendChild(nameSpan);
|
||||
|
||||
folderOption.addEventListener('click', () => {
|
||||
if (this.activeView) {
|
||||
|
|
@ -359,7 +381,8 @@ export class FolderSelectionModal extends Modal {
|
|||
|
||||
this.folderOptions.forEach(option => {
|
||||
const text = option.textContent?.toLowerCase() || '';
|
||||
if (searchTerm === '' || text.includes(searchTerm)) {
|
||||
const fullPath = option.getAttribute('data-path')?.toLowerCase() || '';
|
||||
if (searchTerm === '' || text.includes(searchTerm) || fullPath.includes(searchTerm)) {
|
||||
option.style.display = 'block';
|
||||
hasVisibleOptions = true;
|
||||
} else {
|
||||
|
|
|
|||
505
src/GridView.ts
505
src/GridView.ts
|
|
@ -1,4 +1,4 @@
|
|||
import { WorkspaceLeaf, ItemView, TFolder, TFile, Menu, Notice, Platform, setIcon, getFrontMatterInfo, FrontMatterCache } from 'obsidian';
|
||||
import { WorkspaceLeaf, ItemView, TFolder, TFile, Menu, Notice, Platform, setIcon, getFrontMatterInfo, FrontMatterCache, normalizePath } from 'obsidian';
|
||||
import { showFolderSelectionModal } from './FolderSelectionModal';
|
||||
import { findFirstImageInNote } from './mediaUtils';
|
||||
import { MediaModal } from './MediaModal';
|
||||
|
|
@ -186,100 +186,7 @@ export class GridView extends ItemView {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 為頂部按鈕區域添加右鍵選單事件
|
||||
headerButtonsDiv.addEventListener('contextmenu', (event: MouseEvent) => {
|
||||
// 只有當點擊的是頂部按鈕區域本身(而不是其中的按鈕)時才觸發捲動
|
||||
if (event.target === headerButtonsDiv) {
|
||||
event.preventDefault();
|
||||
const menu = new Menu();
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_new_grid_view'))
|
||||
.setIcon('grid')
|
||||
.onClick(() => {
|
||||
const { workspace } = this.app;
|
||||
let leaf = null;
|
||||
workspace.getLeavesOfType('grid-view');
|
||||
switch (this.plugin.settings.defaultOpenLocation) {
|
||||
case 'left':
|
||||
leaf = workspace.getLeftLeaf(false);
|
||||
break;
|
||||
case 'right':
|
||||
leaf = workspace.getRightLeaf(false);
|
||||
break;
|
||||
case 'tab':
|
||||
default:
|
||||
leaf = workspace.getLeaf('tab');
|
||||
break;
|
||||
}
|
||||
if (!leaf) {
|
||||
// 如果無法獲取指定位置的 leaf,則回退到新分頁
|
||||
leaf = workspace.getLeaf('tab');
|
||||
}
|
||||
leaf.setViewState({ type: 'grid-view', active: true });
|
||||
// 設定資料來源
|
||||
if (leaf.view instanceof GridView) {
|
||||
leaf.view.setSource('folder', '/');
|
||||
}
|
||||
// 確保視圖是活躍的
|
||||
workspace.revealLeaf(leaf);
|
||||
});
|
||||
});
|
||||
//如果目前是資料夾模式且有資料夾筆記,則增加"打開資料夾筆記"選項
|
||||
if (this.sourceMode === 'folder' && this.sourcePath && this.sourcePath !== '/') {
|
||||
const folderName = this.sourcePath.split('/').pop() || '';
|
||||
const notePath = `${this.sourcePath}/${folderName}.md`;
|
||||
const noteFile = this.app.vault.getAbstractFileByPath(notePath);
|
||||
if (noteFile instanceof TFile) {
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_folder_note'))
|
||||
.setIcon('panel-left-open')
|
||||
.onClick(() => {
|
||||
this.app.workspace.getLeaf().openFile(noteFile);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
// 最小化模式選項
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('min_mode'))
|
||||
.setIcon('minimize-2')
|
||||
.setChecked(this.minMode)
|
||||
.onClick(() => {
|
||||
this.minMode = !this.minMode;
|
||||
this.app.workspace.requestSaveLayout();
|
||||
this.render();
|
||||
});
|
||||
});
|
||||
// 顯示忽略資料夾選項
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('show_ignored_folders'))
|
||||
.setIcon('folder-open-dot')
|
||||
.setChecked(this.showIgnoredFolders)
|
||||
.onClick(() => {
|
||||
this.showIgnoredFolders = !this.showIgnoredFolders;
|
||||
this.app.workspace.requestSaveLayout();
|
||||
this.render();
|
||||
});
|
||||
});
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_settings'))
|
||||
.setIcon('settings')
|
||||
.onClick(() => {
|
||||
// 打開插件設定頁面
|
||||
(this.app as any).setting.open();
|
||||
(this.app as any).setting.openTabById(this.plugin.manifest.id);
|
||||
});
|
||||
});
|
||||
menu.showAtMouseEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 添加新增筆記按鈕
|
||||
const newNoteButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('new_note') } });
|
||||
newNoteButton.addEventListener('click', async () => {
|
||||
|
|
@ -363,97 +270,6 @@ export class GridView extends ItemView {
|
|||
menu.showAtMouseEvent(event);
|
||||
});
|
||||
|
||||
// 添加回上層按鈕(僅在資料夾模式且不在根目錄時顯示)
|
||||
if (this.sourceMode === 'folder' && this.sourcePath !== '/' && this.searchQuery === '') {
|
||||
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, true);
|
||||
this.clearSelection();
|
||||
});
|
||||
setIcon(upButton, 'arrow-up');
|
||||
|
||||
if(Platform.isDesktop) {
|
||||
// 為上層按鈕添加拖曳目標功能
|
||||
upButton.addEventListener('dragover', (event) => {
|
||||
// 防止預設行為以允許放置
|
||||
event.preventDefault();
|
||||
// 設定拖曳效果為移動
|
||||
event.dataTransfer!.dropEffect = 'move';
|
||||
// 顯示可放置的視覺提示
|
||||
upButton.addClass('ge-dragover');
|
||||
});
|
||||
|
||||
upButton.addEventListener('dragleave', () => {
|
||||
// 移除視覺提示
|
||||
upButton.removeClass('ge-dragover');
|
||||
});
|
||||
|
||||
upButton.addEventListener('drop', async (event) => {
|
||||
// 防止預設行為
|
||||
event.preventDefault();
|
||||
// 移除視覺提示
|
||||
upButton.removeClass('ge-dragover');
|
||||
|
||||
// 獲取上一層資料夾路徑
|
||||
const parentPath = this.sourcePath.split('/').slice(0, -1).join('/') || '/';
|
||||
if (!parentPath) return;
|
||||
|
||||
// 獲取資料夾物件
|
||||
const folder = this.app.vault.getAbstractFileByPath(parentPath);
|
||||
if (!(folder instanceof TFolder)) return;
|
||||
|
||||
// 檢查是否有多個檔案被拖曳
|
||||
const filesData = event.dataTransfer?.getData('application/obsidian-grid-explorer-files');
|
||||
if (filesData) {
|
||||
try {
|
||||
// 解析檔案路徑列表
|
||||
const filePaths = JSON.parse(filesData);
|
||||
|
||||
// 移動所有檔案
|
||||
for (const filePath of filePaths) {
|
||||
const file = this.app.vault.getAbstractFileByPath(filePath);
|
||||
if (file instanceof TFile) {
|
||||
// 計算新的檔案路徑
|
||||
const newPath = `${parentPath}/${file.name}`;
|
||||
// 移動檔案
|
||||
await this.app.fileManager.renameFile(file, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
// 重新渲染視圖
|
||||
this.render();
|
||||
} catch (error) {
|
||||
console.error('An error occurred while moving multiple files to parent folder:', error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果沒有多個檔案資料,嘗試獲取單個檔案路徑(向後兼容)
|
||||
const filePath = event.dataTransfer?.getData('text/plain');
|
||||
if (!filePath) return;
|
||||
|
||||
const cleanedFilePath = filePath.replace(/!?\[\[(.*?)\]\]/, '$1');
|
||||
|
||||
// 獲取檔案物件
|
||||
const file = this.app.vault.getAbstractFileByPath(cleanedFilePath);
|
||||
|
||||
if (file instanceof TFile) {
|
||||
try {
|
||||
// 計算新的檔案路徑
|
||||
const newPath = `${parentPath}/${file.name}`;
|
||||
// 移動檔案
|
||||
await this.app.fileManager.renameFile(file, newPath);
|
||||
// 重新渲染視圖
|
||||
this.render();
|
||||
} catch (error) {
|
||||
console.error('An error occurred while moving the file to parent folder:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 添加重新選擇資料夾按鈕
|
||||
const reselectButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('reselect') } });
|
||||
reselectButton.addEventListener('click', () => {
|
||||
|
|
@ -722,6 +538,226 @@ export class GridView extends ItemView {
|
|||
});
|
||||
}
|
||||
|
||||
// 添加設定按鈕
|
||||
if (this.searchQuery === '') {
|
||||
const moreOptionsButton = headerButtonsDiv.createEl('button', { attr: { 'aria-label': t('more_options') } });
|
||||
setIcon(moreOptionsButton, 'ellipsis-vertical');
|
||||
const menu = new Menu();
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_new_grid_view'))
|
||||
.setIcon('grid')
|
||||
.onClick(() => {
|
||||
const { workspace } = this.app;
|
||||
let leaf = null;
|
||||
workspace.getLeavesOfType('grid-view');
|
||||
switch (this.plugin.settings.defaultOpenLocation) {
|
||||
case 'left':
|
||||
leaf = workspace.getLeftLeaf(false);
|
||||
break;
|
||||
case 'right':
|
||||
leaf = workspace.getRightLeaf(false);
|
||||
break;
|
||||
case 'tab':
|
||||
default:
|
||||
leaf = workspace.getLeaf('tab');
|
||||
break;
|
||||
}
|
||||
if (!leaf) {
|
||||
// 如果無法獲取指定位置的 leaf,則回退到新分頁
|
||||
leaf = workspace.getLeaf('tab');
|
||||
}
|
||||
leaf.setViewState({ type: 'grid-view', active: true });
|
||||
// 設定資料來源
|
||||
if (leaf.view instanceof GridView) {
|
||||
leaf.view.setSource('folder', '/');
|
||||
}
|
||||
// 確保視圖是活躍的
|
||||
workspace.revealLeaf(leaf);
|
||||
});
|
||||
});
|
||||
//如果目前是資料夾模式且有資料夾筆記,則增加"打開資料夾筆記"選項
|
||||
if (this.sourceMode === 'folder' && this.sourcePath && this.sourcePath !== '/') {
|
||||
const folder = this.app.vault.getAbstractFileByPath(this.sourcePath);
|
||||
const folderName = this.sourcePath.split('/').pop() || '';
|
||||
const notePath = `${this.sourcePath}/${folderName}.md`;
|
||||
const noteFile = this.app.vault.getAbstractFileByPath(notePath);
|
||||
if (noteFile instanceof TFile) {
|
||||
//打開資料夾筆記
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_folder_note'))
|
||||
.setIcon('panel-left-open')
|
||||
.onClick(() => {
|
||||
this.app.workspace.getLeaf().openFile(noteFile);
|
||||
});
|
||||
});
|
||||
//編輯資料夾筆記設定
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('edit_folder_note_settings'))
|
||||
.setIcon('settings-2')
|
||||
.onClick(() => {
|
||||
if (folder instanceof TFolder) {
|
||||
showFolderNoteSettingsModal(this.app, this.plugin, folder, this);
|
||||
}
|
||||
});
|
||||
});
|
||||
//刪除資料夾筆記
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('delete_folder_note'))
|
||||
.setIcon('folder-x')
|
||||
.onClick(() => {
|
||||
this.app.fileManager.trashFile(noteFile as TFile);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
//建立Folder note
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('create_folder_note'))
|
||||
.setIcon('file-cog')
|
||||
.onClick(() => {
|
||||
if (folder instanceof TFolder) {
|
||||
showFolderNoteSettingsModal(this.app, this.plugin, folder, this);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
// 最小化模式選項
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('min_mode'))
|
||||
.setIcon('minimize-2')
|
||||
.setChecked(this.minMode)
|
||||
.onClick(() => {
|
||||
this.minMode = !this.minMode;
|
||||
this.app.workspace.requestSaveLayout();
|
||||
this.render();
|
||||
});
|
||||
});
|
||||
// 顯示忽略資料夾選項
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('show_ignored_folders'))
|
||||
.setIcon('folder-open-dot')
|
||||
.setChecked(this.showIgnoredFolders)
|
||||
.onClick(() => {
|
||||
this.showIgnoredFolders = !this.showIgnoredFolders;
|
||||
this.app.workspace.requestSaveLayout();
|
||||
this.render();
|
||||
});
|
||||
});
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_settings'))
|
||||
.setIcon('settings')
|
||||
.onClick(() => {
|
||||
// 打開插件設定頁面
|
||||
(this.app as any).setting.open();
|
||||
(this.app as any).setting.openTabById(this.plugin.manifest.id);
|
||||
});
|
||||
});
|
||||
|
||||
moreOptionsButton.addEventListener('click', (event) => {
|
||||
menu.showAtMouseEvent(event);
|
||||
});
|
||||
}
|
||||
|
||||
// 如果是資料夾模式且沒有搜尋結果,顯示目前資料夾名稱
|
||||
if (this.sourceMode === 'folder' && this.searchQuery === '' && this.sourcePath !== '/') {
|
||||
const pathParts = this.sourcePath.split('/');
|
||||
const parentPath = pathParts.slice(0, -1).join('/') || '/';
|
||||
let parentFolderName = pathParts.slice(-2, -1)[0] || '/';
|
||||
const currentFolderName = pathParts.pop() || t('root');
|
||||
|
||||
// 若為根目錄,以 'root' 顯示
|
||||
if (parentPath === '/' || parentFolderName === '/' || parentFolderName === '') {
|
||||
parentFolderName = t('root');
|
||||
}
|
||||
|
||||
const folderNameContainer = this.containerEl.createDiv('ge-foldername-content');
|
||||
|
||||
// 建立可點擊的上層資料夾名稱
|
||||
const customFolderIcon = this.plugin.settings.customFolderIcon;
|
||||
const parentFolderLink = folderNameContainer.createEl('a', {
|
||||
text: `${customFolderIcon} ${parentFolderName}`.trim(),
|
||||
cls: 'ge-parent-folder-link'
|
||||
});
|
||||
|
||||
parentFolderLink.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.setSource('folder', parentPath, true);
|
||||
this.clearSelection();
|
||||
});
|
||||
|
||||
// 分隔符號
|
||||
folderNameContainer.createEl('span', { text: ' > ' });
|
||||
|
||||
// 目前資料夾名稱
|
||||
folderNameContainer.createEl('span', { text: currentFolderName });
|
||||
|
||||
if (Platform.isDesktop) {
|
||||
// 為上層按鈕添加拖曳目標功能
|
||||
parentFolderLink.addEventListener('dragover', (event) => {
|
||||
event.preventDefault();
|
||||
event.dataTransfer!.dropEffect = 'move';
|
||||
parentFolderLink.addClass('ge-dragover');
|
||||
});
|
||||
|
||||
parentFolderLink.addEventListener('dragleave', () => {
|
||||
parentFolderLink.removeClass('ge-dragover');
|
||||
});
|
||||
|
||||
parentFolderLink.addEventListener('drop', async (event) => {
|
||||
event.preventDefault();
|
||||
parentFolderLink.removeClass('ge-dragover');
|
||||
|
||||
const parentPath = this.sourcePath.split('/').slice(0, -1).join('/') || '/';
|
||||
if (!parentPath) return;
|
||||
|
||||
const folder = this.app.vault.getAbstractFileByPath(parentPath);
|
||||
if (!(folder instanceof TFolder)) return;
|
||||
|
||||
const filesData = event.dataTransfer?.getData('application/obsidian-grid-explorer-files');
|
||||
if (filesData) {
|
||||
try {
|
||||
const filePaths = JSON.parse(filesData);
|
||||
for (const filePath of filePaths) {
|
||||
const file = this.app.vault.getAbstractFileByPath(filePath);
|
||||
if (file instanceof TFile) {
|
||||
const newPath = normalizePath(`${parentPath}/${file.name}`);
|
||||
await this.app.fileManager.renameFile(file, newPath);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('An error occurred while moving multiple files to parent folder:', error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const filePath = event.dataTransfer?.getData('text/plain');
|
||||
if (!filePath) return;
|
||||
|
||||
const cleanedFilePath = filePath.replace(/!?\[\[(.*?)\]\]/, '$1');
|
||||
const file = this.app.vault.getAbstractFileByPath(cleanedFilePath);
|
||||
|
||||
if (file instanceof TFile) {
|
||||
try {
|
||||
const newPath = normalizePath(`${parentPath}/${file.name}`);
|
||||
await this.app.fileManager.renameFile(file, newPath);
|
||||
this.render();
|
||||
} catch (error) {
|
||||
console.error('An error occurred while moving the file to parent folder:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 創建內容區域
|
||||
const contentEl = this.containerEl.createDiv('view-content');
|
||||
|
||||
|
|
@ -735,8 +771,20 @@ export class GridView extends ItemView {
|
|||
const noteFile = this.app.vault.getAbstractFileByPath(notePath);
|
||||
if (noteFile instanceof TFile) {
|
||||
const metadata = this.app.metadataCache.getFileCache(noteFile)?.frontmatter;
|
||||
if (metadata && Array.isArray(metadata['pinned'])) {
|
||||
this.pinnedList = metadata['pinned'] as string[];
|
||||
if (metadata) {
|
||||
if (Array.isArray(metadata['pinned'])) {
|
||||
if (this.plugin.settings.folderNoteDisplaySettings === 'pinned') {
|
||||
// 先過濾掉所有重複的資料夾筆記
|
||||
this.pinnedList = metadata['pinned'].filter((name: string) => name !== `${folderName}.md`);
|
||||
// 將資料夾筆記添加到最前面
|
||||
this.pinnedList.unshift(`${folderName}.md`);
|
||||
} else {
|
||||
this.pinnedList = metadata['pinned'];
|
||||
}
|
||||
} else if (this.plugin.settings.folderNoteDisplaySettings === 'pinned') {
|
||||
// 如果沒有置頂清單,則建立一個僅包含資料夾筆記的清單
|
||||
this.pinnedList = [`${folderName}.md`];
|
||||
}
|
||||
} else {
|
||||
this.pinnedList = [];
|
||||
}
|
||||
|
|
@ -762,7 +810,7 @@ export class GridView extends ItemView {
|
|||
}
|
||||
|
||||
async grid_render() {
|
||||
const container = this.containerEl.children[1] as HTMLElement;
|
||||
const container = this.containerEl.querySelector('.view-content') as HTMLElement;
|
||||
container.empty();
|
||||
container.addClass('ge-grid-container');
|
||||
|
||||
|
|
@ -805,45 +853,6 @@ export class GridView extends ItemView {
|
|||
return;
|
||||
}
|
||||
|
||||
// 如果是資料夾模式且沒有搜尋結果,顯示目前資料夾名稱
|
||||
if (this.sourceMode === 'folder' && this.searchQuery === '' &&
|
||||
this.plugin.settings.showParentFolderItem && this.sourcePath !== '/') {
|
||||
const pathParts = this.sourcePath.split('/');
|
||||
const parentPath = pathParts.slice(0, -1).join('/') || '/';
|
||||
let parentFolderName = pathParts.slice(-2, -1)[0] || '/';
|
||||
const currentFolderName = pathParts.pop() || t('root');
|
||||
|
||||
// 若為根目錄,以 'root' 顯示
|
||||
if (parentPath === '/' || parentFolderName === '/' || parentFolderName === '') {
|
||||
parentFolderName = t('root');
|
||||
}
|
||||
|
||||
const folderNameContainer = container.createDiv('ge-foldername-content');
|
||||
|
||||
if (folderNameContainer) {
|
||||
// 建立可點擊的上層資料夾名稱
|
||||
const customFolderIcon = this.plugin.settings.customFolderIcon;
|
||||
const parentFolderLink = folderNameContainer.createEl('a', {
|
||||
text: `${customFolderIcon} ${parentFolderName}`.trim(),
|
||||
cls: 'ge-parent-folder-link'
|
||||
});
|
||||
|
||||
// 點擊後跳轉到上層資料夾
|
||||
parentFolderLink.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.setSource('folder', parentPath, true);
|
||||
this.clearSelection();
|
||||
});
|
||||
|
||||
// 分隔符號
|
||||
folderNameContainer.createEl('span', { text: ' > ' });
|
||||
|
||||
// 目前資料夾名稱
|
||||
folderNameContainer.createEl('span', { text: currentFolderName });
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是資料夾模式,先顯示所有子資料夾
|
||||
if (this.sourceMode === 'folder' && this.searchQuery === '') {
|
||||
const currentFolder = this.app.vault.getAbstractFileByPath(this.sourcePath || '/');
|
||||
|
|
@ -989,6 +998,7 @@ export class GridView extends ItemView {
|
|||
const notePath = `${folder.path}/${folder.name}.md`;
|
||||
let noteFile = this.app.vault.getAbstractFileByPath(notePath);
|
||||
if (noteFile instanceof TFile) {
|
||||
//打開資料夾筆記
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('open_folder_note'))
|
||||
|
|
@ -997,6 +1007,7 @@ export class GridView extends ItemView {
|
|||
this.app.workspace.getLeaf().openFile(noteFile);
|
||||
});
|
||||
});
|
||||
//編輯資料夾筆記設定
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle(t('edit_folder_note_settings'))
|
||||
|
|
@ -1014,10 +1025,6 @@ export class GridView extends ItemView {
|
|||
.setIcon('folder-x')
|
||||
.onClick(() => {
|
||||
this.app.fileManager.trashFile(noteFile as TFile);
|
||||
// 重新渲染視圖
|
||||
setTimeout(() => {
|
||||
this.render();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
|
@ -1087,8 +1094,8 @@ export class GridView extends ItemView {
|
|||
});
|
||||
}
|
||||
|
||||
// 資料夾渲染完插入 break(僅當有資料夾時或有顯示回上一層資料夾項目時)
|
||||
if (subfolders.length > 0 || (subfolders.length === 0 && this.plugin.settings.dateDividerMode !== 'none' && this.plugin.settings.showParentFolderItem)) {
|
||||
// 資料夾渲染完插入 break(僅當有資料夾)
|
||||
if (subfolders.length > 0) {
|
||||
container.createDiv('ge-break');
|
||||
}
|
||||
}
|
||||
|
|
@ -1224,6 +1231,16 @@ export class GridView extends ItemView {
|
|||
const otherFiles = files.filter(f => !this.pinnedList.includes(f.name));
|
||||
files = [...pinnedFiles, ...otherFiles];
|
||||
}
|
||||
|
||||
if (this.sourceMode === 'folder' && this.sourcePath !== '/') {
|
||||
if (this.plugin.settings.folderNoteDisplaySettings === 'hidden') {
|
||||
const currentFolder = this.app.vault.getAbstractFileByPath(this.sourcePath);
|
||||
if (currentFolder instanceof TFolder) {
|
||||
const folderName = currentFolder.name;
|
||||
files = files.filter(f => f.name !== `${folderName}.md`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 創建 Intersection Observer
|
||||
const observer = new IntersectionObserver((entries, observer) => {
|
||||
|
|
@ -1599,6 +1616,14 @@ export class GridView extends ItemView {
|
|||
this.gridItems.push(fileEl); // 添加到網格項目數組
|
||||
fileEl.dataset.filePath = file.path;
|
||||
|
||||
// 如果檔案與父資料夾同名,添加 ge-foldernote 類別
|
||||
const parentPath = file.parent?.path || '';
|
||||
const parentName = parentPath.split('/').pop() || '';
|
||||
const fileName = file.basename;
|
||||
if (parentName === fileName) {
|
||||
fileEl.addClass('ge-foldernote');
|
||||
}
|
||||
|
||||
// 創建左側內容區,包含圖示和標題
|
||||
const contentArea = fileEl.createDiv('ge-content-area');
|
||||
|
||||
|
|
@ -1897,7 +1922,7 @@ export class GridView extends ItemView {
|
|||
if (file instanceof TFile) {
|
||||
try {
|
||||
// 計算新的檔案路徑
|
||||
const newPath = `${folderPath}/${file.name}`;
|
||||
const newPath = normalizePath(`${folderPath}/${file.name}`);
|
||||
// 移動檔案
|
||||
await this.app.fileManager.renameFile(file, newPath);
|
||||
} catch (error) {
|
||||
|
|
@ -1905,10 +1930,9 @@ export class GridView extends ItemView {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重新渲染視圖
|
||||
// this.render();
|
||||
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error parsing dragged files data:', error);
|
||||
}
|
||||
|
|
@ -1931,11 +1955,10 @@ export class GridView extends ItemView {
|
|||
if (file instanceof TFile && folder instanceof TFolder) {
|
||||
try {
|
||||
// 計算新的檔案路徑
|
||||
const newPath = `${folderPath}/${file.name}`;
|
||||
const newPath = normalizePath(`${folderPath}/${file.name}`);
|
||||
// 移動檔案
|
||||
await this.app.fileManager.renameFile(file, newPath);
|
||||
// 重新渲染視圖
|
||||
// this.render();
|
||||
|
||||
} catch (error) {
|
||||
console.error('An error occurred while moving the file:', error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ export interface GallerySettings {
|
|||
showMediaFiles: boolean; // 是否顯示圖片和影片
|
||||
showVideoThumbnails: boolean; // 是否顯示影片縮圖
|
||||
defaultOpenLocation: string; // 預設開啟位置
|
||||
showParentFolderItem: boolean; // 是否显示"返回上级文件夹"选项
|
||||
reuseExistingLeaf: boolean; // 是否重用現有的網格視圖
|
||||
showBookmarksMode: boolean; // 是否顯示書籤模式
|
||||
showSearchMode: boolean; // 是否顯示搜尋結果模式
|
||||
|
|
@ -38,6 +37,7 @@ export interface GallerySettings {
|
|||
showNoteTags: boolean; // 是否顯示筆記標籤
|
||||
dateDividerMode: string; // 日期分隔器模式:none, year, month, day
|
||||
showCodeBlocksInSummary: boolean; // 是否在摘要中顯示程式碼區塊
|
||||
folderNoteDisplaySettings: string; // 資料夾筆記設定
|
||||
}
|
||||
|
||||
// 預設設定
|
||||
|
|
@ -55,7 +55,6 @@ export const DEFAULT_SETTINGS: GallerySettings = {
|
|||
showMediaFiles: true, // 預設顯示圖片和影片
|
||||
showVideoThumbnails: true, // 預設顯示影片縮圖
|
||||
defaultOpenLocation: 'tab', // 預設開啟位置:新分頁
|
||||
showParentFolderItem: false, // 預設不顯示"返回上層資料夾"選項
|
||||
reuseExistingLeaf: false, // 預設不重用現有的網格視圖
|
||||
showBookmarksMode: true, // 預設顯示書籤模式
|
||||
showSearchMode: true, // 預設顯示搜尋結果模式
|
||||
|
|
@ -77,6 +76,7 @@ export const DEFAULT_SETTINGS: GallerySettings = {
|
|||
showNoteTags: false, // 預設不顯示筆記標籤
|
||||
dateDividerMode: 'none', // 預設不使用日期分隔器
|
||||
showCodeBlocksInSummary: false, // 預設不在摘要中顯示程式碼區塊
|
||||
folderNoteDisplaySettings: 'default', // 預設不處理資料夾筆記
|
||||
};
|
||||
|
||||
// 設定頁面類別
|
||||
|
|
@ -436,19 +436,6 @@ export class GridExplorerSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
// 顯示"回上層資料夾"選項設定
|
||||
new Setting(containerEl)
|
||||
.setName(t('show_parent_folder_item'))
|
||||
.setDesc(t('show_parent_folder_item_desc'))
|
||||
.addToggle(toggle => {
|
||||
toggle
|
||||
.setValue(this.plugin.settings.showParentFolderItem)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.showParentFolderItem = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
// 顯示筆記標籤設定
|
||||
new Setting(containerEl)
|
||||
|
|
@ -565,7 +552,25 @@ export class GridExplorerSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 資料夾筆記設定區域
|
||||
containerEl.createEl('h3', { text: t('folder_note_settings') });
|
||||
|
||||
// 資料夾筆記設定 (預設、置頂、隱藏)
|
||||
new Setting(containerEl)
|
||||
.setName(t('foldernote_display_settings'))
|
||||
.setDesc(t('foldernote_display_settings_desc'))
|
||||
.addDropdown(dropdown => {
|
||||
dropdown
|
||||
.addOption('default', t('default'))
|
||||
.addOption('pinned', t('pinned'))
|
||||
.addOption('hidden', t('hidden'))
|
||||
.setValue(this.plugin.settings.folderNoteDisplaySettings)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.folderNoteDisplaySettings = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
// 忽略資料夾設定區域
|
||||
containerEl.createEl('h3', { text: t('ignored_folders_settings') });
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'files': '個檔案',
|
||||
'add': '新增',
|
||||
'root': '根目錄',
|
||||
'more_options': '更多選項',
|
||||
|
||||
// 視圖標題
|
||||
'grid_view_title': '網格視圖',
|
||||
|
|
@ -130,7 +131,11 @@ export const TRANSLATIONS: Translations = {
|
|||
'task_filter': '任務分類',
|
||||
'uncompleted': '未完成',
|
||||
'completed': '已完成',
|
||||
'foldernote_display_settings': '資料夾筆記顯示設定',
|
||||
'foldernote_display_settings_desc': '設定資料夾筆記的顯示方式',
|
||||
'all': '全部',
|
||||
'default': '預設',
|
||||
'hidden': '隱藏',
|
||||
|
||||
// 顯示"返回上層資料夾"選項設定
|
||||
'show_parent_folder_item': '顯示「返回上層資料夾」',
|
||||
|
|
@ -243,6 +248,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'files': 'files',
|
||||
'add': 'Add',
|
||||
'root': 'Root',
|
||||
'more_options': 'More options',
|
||||
|
||||
// View Titles
|
||||
'grid_view_title': 'Grid view',
|
||||
|
|
@ -330,7 +336,11 @@ export const TRANSLATIONS: Translations = {
|
|||
'task_filter': 'Task filter',
|
||||
'uncompleted': 'Uncompleted',
|
||||
'completed': 'Completed',
|
||||
'foldernote_display_settings': 'Folder note display settings',
|
||||
'foldernote_display_settings_desc': 'Set the display mode of folder notes',
|
||||
'all': 'All',
|
||||
'default': 'Default',
|
||||
'hidden': 'Hidden',
|
||||
|
||||
// Show "Parent Folder" option setting
|
||||
'show_parent_folder_item': 'Show "Parent Folder" item',
|
||||
|
|
@ -443,6 +453,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'files': '个文件',
|
||||
'add': '添加',
|
||||
'root': '根目录',
|
||||
'more_options': '更多选项',
|
||||
|
||||
// 视图标题
|
||||
'grid_view_title': '网格视图',
|
||||
|
|
@ -530,7 +541,11 @@ export const TRANSLATIONS: Translations = {
|
|||
'task_filter': '任务分类',
|
||||
'uncompleted': '未完成',
|
||||
'completed': '已完成',
|
||||
'foldernote_display_settings': '文件夹笔记显示设置',
|
||||
'foldernote_display_settings_desc': '设置文件夹笔记的显示方式',
|
||||
'all': '全部',
|
||||
'default': '默认',
|
||||
'hidden': '隐藏',
|
||||
|
||||
// 显示"返回上级文件夹"选项设置
|
||||
'show_parent_folder_item': '显示「返回上级文件夹」',
|
||||
|
|
@ -643,6 +658,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'files': 'ファイル',
|
||||
'add': '追加',
|
||||
'root': 'ルート',
|
||||
'more_options': 'もっと選択肢',
|
||||
|
||||
// ビュータイトル
|
||||
'grid_view_title': 'グリッドビュー',
|
||||
|
|
@ -730,7 +746,11 @@ export const TRANSLATIONS: Translations = {
|
|||
'task_filter': 'タスクフィルタ',
|
||||
'uncompleted': '未完了',
|
||||
'completed': '完了',
|
||||
'foldernote_display_settings': 'フォルダノートの表示設定',
|
||||
'foldernote_display_settings_desc': 'フォルダノートの表示方法を設定します',
|
||||
'all': 'すべて',
|
||||
'default': 'デフォルト',
|
||||
'hidden': '隠す',
|
||||
|
||||
// "親フォルダ"オプション設定を表示
|
||||
'show_parent_folder_item': '「親フォルダ」項目を表示',
|
||||
|
|
@ -843,6 +863,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'files': 'файлы',
|
||||
'add': 'Добавить',
|
||||
'root': 'Корень',
|
||||
'more_options': 'Больше опций',
|
||||
|
||||
// View Titles
|
||||
'grid_view_title': 'Сеточный вид',
|
||||
|
|
@ -930,7 +951,11 @@ export const TRANSLATIONS: Translations = {
|
|||
'task_filter': 'Фильтр задач',
|
||||
'uncompleted': 'Незавершенные',
|
||||
'completed': 'Завершенные',
|
||||
'foldernote_display_settings': 'Настройки отображения заметок папок',
|
||||
'foldernote_display_settings_desc': 'Установить режим отображения заметок папок',
|
||||
'all': 'Все',
|
||||
'default': 'По умолчанию',
|
||||
'hidden': 'Скрытые',
|
||||
|
||||
// Show "Parent Folder" option setting
|
||||
'show_parent_folder_item': 'Показывать элемент "Родительская папка"',
|
||||
|
|
@ -1043,6 +1068,7 @@ export const TRANSLATIONS: Translations = {
|
|||
'files': 'файли',
|
||||
'add': 'Додати',
|
||||
'root': 'Корень',
|
||||
'more_options': 'Більше опцій',
|
||||
|
||||
// View Titles
|
||||
'grid_view_title': 'Сітковий вигляд',
|
||||
|
|
@ -1130,7 +1156,11 @@ export const TRANSLATIONS: Translations = {
|
|||
'task_filter': 'Фільтр завдань',
|
||||
'uncompleted': 'Незавершені',
|
||||
'completed': 'Завершені',
|
||||
'foldernote_display_settings': 'Налаштування відображення нотаток папки',
|
||||
'foldernote_display_settings_desc': 'Встановіть режим відображення нотаток папки',
|
||||
'all': 'Всі',
|
||||
'default': 'По умолчанию',
|
||||
'hidden': 'Сховати',
|
||||
|
||||
// Show "Parent Folder" option setting
|
||||
'show_parent_folder_item': 'Показувати елемент "Батьківська папка"',
|
||||
|
|
|
|||
20
styles.css
20
styles.css
|
|
@ -16,6 +16,13 @@
|
|||
background-color: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
/* ascii tree prefix */
|
||||
.ge-folder-tree-prefix {
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* Grid 樣式 */
|
||||
.ge-grid-container {
|
||||
display: grid;
|
||||
|
|
@ -327,11 +334,10 @@
|
|||
}
|
||||
|
||||
.ge-foldername-content {
|
||||
grid-column: 1 / -1;
|
||||
margin-top: -2px;
|
||||
margin-bottom: -3px;
|
||||
margin-left: 7px;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
background-color: var(--background-secondary);
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.ge-foldername-content span {
|
||||
|
|
@ -341,6 +347,7 @@
|
|||
|
||||
/* 為資料夾名稱、分隔符等元素添加間距 */
|
||||
.ge-foldername-content > *:nth-child(1) {
|
||||
margin-left: 11px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
|
|
@ -359,6 +366,11 @@
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ge-parent-folder-link.ge-dragover {
|
||||
border: 2px dashed var(--interactive-accent);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* 搜尋對話框樣式 */
|
||||
.ge-search-container {
|
||||
margin-bottom: 8px;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"2.3.0": "1.1.0"
|
||||
"2.4.0": "1.1.0"
|
||||
}
|
||||
Loading…
Reference in a new issue