mirror of
https://github.com/devon22/obsidian-mediaviewer.git
synced 2026-07-22 11:50:28 +00:00
2.1.10
This commit is contained in:
parent
1a68669cbf
commit
f371ff328b
8 changed files with 213 additions and 55 deletions
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"id": "mediaviewer",
|
||||
"name": "Media Viewer",
|
||||
"version": "2.1.9",
|
||||
"version": "2.1.10",
|
||||
"minAppVersion": "1.8.7",
|
||||
"description": "View and manage media files within your notes.",
|
||||
"description": "Transform your notes with beautiful interactive media galleries. Seamlessly view, zoom, and manage images, videos, and audio files directly in Obsidian.",
|
||||
"author": "Devon22",
|
||||
"authorUrl": "https://github.com/Devon22",
|
||||
"isDesktopOnly": false
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "mediaviewer",
|
||||
"version": "2.1.9",
|
||||
"version": "2.1.10",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mediaviewer",
|
||||
"version": "2.1.9",
|
||||
"version": "2.1.10",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "mediaviewer",
|
||||
"version": "2.1.9",
|
||||
"version": "2.1.10",
|
||||
"description": "View and manage media files within your notes.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ export class FullScreenModal extends Modal {
|
|||
|
||||
if (url) {
|
||||
let type = 'image';
|
||||
const isYoutubeUrl = getYoutubeId(url) !== null;
|
||||
const isYoutubeUrl = getYoutubeId(url) !== null && !Platform.isIosApp;
|
||||
if (isYoutubeUrl) {
|
||||
type = 'youtube';
|
||||
} else {
|
||||
|
|
@ -240,6 +240,10 @@ export class FullScreenModal extends Modal {
|
|||
'--mv-gallery-thumbnail-width': `${width}px`
|
||||
});
|
||||
|
||||
if (this.plugin.settings.galleryWaterfall) {
|
||||
galleryContent.addClass('waterfall');
|
||||
}
|
||||
|
||||
galleryContent.toggleClass('is-hidden', this.openType !== 'command');
|
||||
|
||||
galleryContent.addEventListener('click', (e) => {
|
||||
|
|
@ -373,7 +377,7 @@ export class FullScreenModal extends Modal {
|
|||
cls: 'mv-full-iframe',
|
||||
attr: {
|
||||
frameborder: '0',
|
||||
allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
|
||||
allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture',
|
||||
allowfullscreen: 'true'
|
||||
}
|
||||
});
|
||||
|
|
@ -1294,7 +1298,7 @@ export class FullScreenModal extends Modal {
|
|||
cls: 'mv-full-iframe',
|
||||
attr: {
|
||||
frameborder: '0',
|
||||
allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
|
||||
allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture',
|
||||
allowfullscreen: 'true'
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ interface ContainerInfo {
|
|||
addButtonEnabled: boolean;
|
||||
gridSize: string;
|
||||
paginationEnabled: number;
|
||||
waterfall?: boolean;
|
||||
}
|
||||
|
||||
interface MediaUrlsData {
|
||||
|
|
@ -152,6 +153,7 @@ export class GalleryBlock {
|
|||
let gridSize = this.plugin.settings.galleryGridSize || 'medium';
|
||||
let paginationEnabled = this.plugin.settings.itemsPerPage || 0; // 設定變數以決定是否開啟分頁功能
|
||||
let filterKeyword: string | null = null; // 新增搜尋關鍵字
|
||||
let waterfall = this.plugin.settings.galleryWaterfall || false;
|
||||
|
||||
// 產生基於內容的唯一識別碼
|
||||
const galleryId = 'gallery-' + this.hashString(content.trim());
|
||||
|
|
@ -267,6 +269,8 @@ export class GalleryBlock {
|
|||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 檢查是否為容器標題設定
|
||||
const containerTitleMatch = trimmedLine.match(/^title:\s*(.+)$/);
|
||||
if (containerTitleMatch) {
|
||||
|
|
@ -476,7 +480,7 @@ export class GalleryBlock {
|
|||
const ytMatch = cleanUrl.match(youtubeRegex);
|
||||
const ytId = ytMatch ? ytMatch[1] : null;
|
||||
|
||||
if (ytId) {
|
||||
if (ytId && !Platform.isIosApp) {
|
||||
if (!currentThumbnail) {
|
||||
currentThumbnail = `https://img.youtube.com/vi/${ytId}/hqdefault.jpg`;
|
||||
}
|
||||
|
|
@ -678,7 +682,8 @@ export class GalleryBlock {
|
|||
title: containerTitle,
|
||||
addButtonEnabled: addButtonEnabled,
|
||||
gridSize: gridSize,
|
||||
paginationEnabled: paginationEnabled
|
||||
paginationEnabled: paginationEnabled,
|
||||
waterfall: waterfall
|
||||
},
|
||||
galleryId: galleryId,
|
||||
sourcePath: sourcePath,
|
||||
|
|
@ -687,9 +692,10 @@ export class GalleryBlock {
|
|||
}
|
||||
|
||||
hashString(str: string) {
|
||||
const normalized = str.replace(/\r\n/g, '\n');
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
for (let i = 0; i < normalized.length; i++) {
|
||||
const char = normalized.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash; // Convert to 32bit integer
|
||||
}
|
||||
|
|
@ -784,6 +790,9 @@ export class GalleryBlock {
|
|||
|
||||
// 根據 size 參數添加對應的 class 並設定寬度
|
||||
galleryDiv.addClass(`size-${containerInfo.gridSize}`);
|
||||
if (containerInfo.waterfall) {
|
||||
galleryDiv.addClass('waterfall');
|
||||
}
|
||||
const propertyName = `galleryGridSize${containerInfo.gridSize.charAt(0).toUpperCase() + containerInfo.gridSize.slice(1)}` as keyof MediaViewSettings;
|
||||
const width = this.plugin.settings[propertyName];
|
||||
galleryDiv.setCssProps({
|
||||
|
|
@ -849,13 +858,14 @@ export class GalleryBlock {
|
|||
// 當 itemsPerPage 為 0 或項目數量不足時,顯示所有項目
|
||||
if (itemsPerPage <= 0 || items.length <= itemsPerPage) {
|
||||
// 顯示所有項目
|
||||
const itemElements: HTMLElement[] = [];
|
||||
items.forEach((item: GalleryItem, index: number) => {
|
||||
if (item.type === 'note') {
|
||||
const noteContainer = this.createNoteContainer(item, index, items, galleryId, sourcePath, mediaUrlsData.isFiltered);
|
||||
galleryDiv.appendChild(noteContainer);
|
||||
itemElements.push(noteContainer);
|
||||
} else {
|
||||
const mediaContainer = this.createMediaContainer(item, index, items, galleryId, sourcePath, mediaUrlsData.isFiltered);
|
||||
galleryDiv.appendChild(mediaContainer);
|
||||
itemElements.push(mediaContainer);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -885,8 +895,9 @@ export class GalleryBlock {
|
|||
modal.open();
|
||||
};
|
||||
|
||||
galleryDiv.appendChild(addContainer);
|
||||
itemElements.push(addContainer);
|
||||
}
|
||||
this.renderGalleryItems(galleryDiv, itemElements);
|
||||
} else {
|
||||
// 使用分頁顯示
|
||||
const totalPages = Math.ceil(items.length / itemsPerPage);
|
||||
|
|
@ -1279,6 +1290,54 @@ export class GalleryBlock {
|
|||
return container;
|
||||
}
|
||||
|
||||
renderGalleryItems(galleryDiv: HTMLElement, itemElements: HTMLElement[]) {
|
||||
if (galleryDiv.classList.contains('waterfall')) {
|
||||
// 清理舊的 observer
|
||||
const observedDiv = galleryDiv as HTMLElement & { _resizeObserver?: ResizeObserver };
|
||||
if (observedDiv._resizeObserver) {
|
||||
observedDiv._resizeObserver.disconnect();
|
||||
}
|
||||
|
||||
const styleVal = galleryDiv.style.getPropertyValue('--mv-gallery-thumbnail-width');
|
||||
let colWidth = parseInt(styleVal) || 150;
|
||||
if (!colWidth) {
|
||||
let size = 'medium';
|
||||
if (galleryDiv.classList.contains('size-small')) size = 'small';
|
||||
else if (galleryDiv.classList.contains('size-large')) size = 'large';
|
||||
const propertyName = `galleryGridSize${size.charAt(0).toUpperCase() + size.slice(1)}` as keyof MediaViewSettings;
|
||||
colWidth = (this.plugin.settings[propertyName] as number) || 150;
|
||||
}
|
||||
|
||||
let currentCols = 0;
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
const width = entry.contentRect.width;
|
||||
if (width <= 0) continue;
|
||||
const cols = Math.max(1, Math.floor(width / (colWidth + 2))); // 2px gap
|
||||
if (cols !== currentCols) {
|
||||
currentCols = cols;
|
||||
galleryDiv.replaceChildren();
|
||||
const colDivs: HTMLDivElement[] = [];
|
||||
for (let c = 0; c < cols; c++) {
|
||||
const colDiv = activeDocument.createElement('div');
|
||||
colDiv.className = 'mvgb-waterfall-column';
|
||||
galleryDiv.appendChild(colDiv);
|
||||
colDivs.push(colDiv);
|
||||
}
|
||||
itemElements.forEach((el, idx) => {
|
||||
colDivs[idx % cols].appendChild(el);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
resizeObserver.observe(galleryDiv);
|
||||
observedDiv._resizeObserver = resizeObserver;
|
||||
} else {
|
||||
galleryDiv.replaceChildren();
|
||||
itemElements.forEach(el => galleryDiv.appendChild(el));
|
||||
}
|
||||
}
|
||||
|
||||
updateGalleryPage(galleryDiv: HTMLElement, items: GalleryItem[], page: number, itemsPerPage: number, sourcePath?: string, isFiltered?: boolean) {
|
||||
const start = (page - 1) * itemsPerPage;
|
||||
const end = start + itemsPerPage;
|
||||
|
|
@ -1294,14 +1353,15 @@ export class GalleryBlock {
|
|||
const galleryId = galleryDiv.getAttribute('data-gallery-id') || '';
|
||||
|
||||
// 新增新的項目
|
||||
const itemElements: HTMLElement[] = [];
|
||||
currentPageItems.forEach((item: GalleryItem, index: number) => {
|
||||
const absoluteIndex = start + index;
|
||||
if (item.type === 'note') {
|
||||
const noteContainer = this.createNoteContainer(item, absoluteIndex, items, galleryId, sourcePath, isFiltered);
|
||||
galleryDiv.appendChild(noteContainer);
|
||||
itemElements.push(noteContainer);
|
||||
} else {
|
||||
const mediaContainer = this.createMediaContainer(item, absoluteIndex, items, galleryId, sourcePath, isFiltered);
|
||||
galleryDiv.appendChild(mediaContainer);
|
||||
itemElements.push(mediaContainer);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -1312,10 +1372,12 @@ export class GalleryBlock {
|
|||
const placeholder = activeDocument.createElement('div');
|
||||
placeholder.className = 'mv-media-thumbnail-container placeholder';
|
||||
placeholder.addClass('is-placeholder-hidden'); // 隱藏但保持佔位
|
||||
galleryDiv.appendChild(placeholder);
|
||||
itemElements.push(placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
this.renderGalleryItems(galleryDiv, itemElements);
|
||||
|
||||
// 更新分頁控制項
|
||||
if (galleryDiv.parentElement) {
|
||||
const paginationDiv = galleryDiv.parentElement.querySelector('.mvgb-pagination');
|
||||
|
|
@ -1398,6 +1460,7 @@ export class GalleryBlock {
|
|||
}
|
||||
} else {
|
||||
// 處理音樂檔案
|
||||
container.addClass('mvgb-audio-thumbnail');
|
||||
// 如果有自訂縮圖,使用縮圖顯示
|
||||
if (media.thumbnail) {
|
||||
const img = activeDocument.createElement('img');
|
||||
|
|
@ -1691,7 +1754,7 @@ export class GalleryBlock {
|
|||
const content = await this.app.vault.read(targetFile);
|
||||
|
||||
// 尋找包含當前 gallery ID 的 gallery 區塊
|
||||
const galleryBlockRegex = /```gallery\n([\s\S]*?)```/g;
|
||||
const galleryBlockRegex = /```gallery\r?\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
let galleryContent = '';
|
||||
let matchPosition = { start: 0, end: 0 };
|
||||
|
|
@ -1760,7 +1823,7 @@ export class GalleryBlock {
|
|||
const content = await this.app.vault.read(targetFile);
|
||||
|
||||
// 尋找包含當前 gallery ID 的 gallery 區塊
|
||||
const galleryBlockRegex = /```gallery\n([\s\S]*?)```/g;
|
||||
const galleryBlockRegex = /```gallery\r?\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
let matchPosition = { start: 0, end: 0 };
|
||||
|
||||
|
|
@ -1849,7 +1912,7 @@ export class GalleryBlock {
|
|||
}
|
||||
|
||||
const content = await this.app.vault.read(activeFile);
|
||||
const galleryBlockRegex = /```gallery\n([\s\S]*?)```/g;
|
||||
const galleryBlockRegex = /```gallery\r?\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
|
||||
while ((match = galleryBlockRegex.exec(content)) !== null) {
|
||||
|
|
@ -1929,7 +1992,7 @@ export class GalleryBlock {
|
|||
}
|
||||
|
||||
const content = await this.app.vault.read(activeFile);
|
||||
const galleryBlockRegex = /```gallery\n([\s\S]*?)```/g;
|
||||
const galleryBlockRegex = /```gallery\r?\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
|
||||
while ((match = galleryBlockRegex.exec(content)) !== null) {
|
||||
|
|
@ -2007,7 +2070,7 @@ export class GalleryBlock {
|
|||
}
|
||||
|
||||
const content = await this.app.vault.read(activeFile);
|
||||
const galleryBlockRegex = /```gallery\n([\s\S]*?)```/g;
|
||||
const galleryBlockRegex = /```gallery\r?\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
|
||||
while ((match = galleryBlockRegex.exec(content)) !== null) {
|
||||
|
|
@ -2080,7 +2143,7 @@ export class GalleryBlock {
|
|||
|
||||
if (activeFile) {
|
||||
const content = await this.app.vault.read(activeFile);
|
||||
const galleryBlockRegex = /```gallery\n([\s\S]*?)```/g;
|
||||
const galleryBlockRegex = /```gallery\r?\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
|
||||
while ((match = galleryBlockRegex.exec(content)) !== null) {
|
||||
|
|
|
|||
|
|
@ -3,37 +3,39 @@ import MediaViewPlugin from './main';
|
|||
import { t } from './translations';
|
||||
|
||||
export interface MediaViewSettings {
|
||||
showImageInfo: boolean;
|
||||
allowMediaDeletion: boolean;
|
||||
autoOpenFirstImage: boolean;
|
||||
openMediaBrowserOnClick: boolean;
|
||||
disableClickToOpenMediaOnGallery: boolean;
|
||||
muteVideoOnOpen: boolean;
|
||||
galleryGridSize: string;
|
||||
galleryGridSizeSmall: number;
|
||||
galleryGridSizeMedium: number;
|
||||
galleryGridSizeLarge: number;
|
||||
itemsPerPage: number;
|
||||
insertAtEnd: boolean;
|
||||
displayOriginalSize: boolean;
|
||||
autoPlayInterval: number;
|
||||
showImageInfo: boolean; // 是否顯示圖片資訊 (例如尺寸、檔案大小等)
|
||||
allowMediaDeletion: boolean; // 是否允許刪除媒體檔案
|
||||
autoOpenFirstImage: boolean; // 當打開畫廊時是否自動開啟第一張圖片
|
||||
openMediaBrowserOnClick: boolean; // 點擊圖片時是否打開媒體瀏覽器
|
||||
disableClickToOpenMediaOnGallery: boolean; // 是否停用在畫廊中點擊圖片以打開媒體瀏覽器的功能
|
||||
muteVideoOnOpen: boolean; // 打開影片時是否預設靜音
|
||||
galleryGridSize: string; // 畫廊網格大小的預設等級 (small, medium, large)
|
||||
galleryGridSizeSmall: number; // 小網格的大小 (像素)
|
||||
galleryGridSizeMedium: number; // 中網格的大小 (像素)
|
||||
galleryGridSizeLarge: number; // 大網格的大小 (像素)
|
||||
itemsPerPage: number; // 每頁顯示的項目數量 (0 代表不分頁)
|
||||
insertAtEnd: boolean; // 新加入的媒體是否插入在最後面
|
||||
displayOriginalSize: boolean; // 檢視時是否顯示原始尺寸
|
||||
autoPlayInterval: number; // 自動播放的時間間隔 (秒,0 代表不自動播放)
|
||||
galleryWaterfall: boolean; // 畫廊是否使用瀑布流顯示圖片
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: MediaViewSettings = {
|
||||
showImageInfo: true,
|
||||
showImageInfo: true, // 預設顯示圖片資訊
|
||||
allowMediaDeletion: false, // 預設不允許刪除圖片
|
||||
autoOpenFirstImage: false, // 預設不自動打開第一張圖片
|
||||
openMediaBrowserOnClick: true,
|
||||
disableClickToOpenMediaOnGallery: false,
|
||||
muteVideoOnOpen: false,
|
||||
galleryGridSize: 'medium',
|
||||
galleryGridSizeSmall: 100,
|
||||
galleryGridSizeMedium: 150,
|
||||
galleryGridSizeLarge: 200,
|
||||
openMediaBrowserOnClick: true, // 預設點擊圖片時打開媒體瀏覽器
|
||||
disableClickToOpenMediaOnGallery: false, // 預設不停用畫廊點擊事件
|
||||
muteVideoOnOpen: false, // 預設不靜音
|
||||
galleryGridSize: 'medium', // 預設畫廊網格大小為中
|
||||
galleryGridSizeSmall: 100, // 預設小網格大小為 100px
|
||||
galleryGridSizeMedium: 150, // 預設中網格大小為 150px
|
||||
galleryGridSizeLarge: 200, // 預設大網格大小為 200px
|
||||
itemsPerPage: 0, // 預設不分頁
|
||||
insertAtEnd: true, // 預設插入在最後
|
||||
displayOriginalSize: false, // 預設不顯示原始尺寸
|
||||
autoPlayInterval: 0, // 預設不自動播放
|
||||
galleryWaterfall: false, // 預設不使用瀑布流 (使用正方形裁剪)
|
||||
};
|
||||
|
||||
export class MediaViewSettingTab extends PluginSettingTab {
|
||||
|
|
@ -48,6 +50,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
|
||||
// 1. 是否顯示圖片資訊 (例如尺寸、檔案大小等)
|
||||
new Setting(containerEl)
|
||||
.setName(t('show_image_info'))
|
||||
.setDesc(t('show_image_info_desc'))
|
||||
|
|
@ -58,6 +61,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 2. 是否允許在媒體檢視器中直接刪除媒體檔案
|
||||
new Setting(containerEl)
|
||||
.setName(t('allow_media_deletion'))
|
||||
.setDesc(t('allow_media_deletion_desc'))
|
||||
|
|
@ -68,6 +72,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 3. 打開畫廊時是否自動開啟第一張圖片
|
||||
new Setting(containerEl)
|
||||
.setName(t('auto_open_first_image'))
|
||||
.setDesc(t('auto_open_first_image_desc'))
|
||||
|
|
@ -78,6 +83,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 4. 檢視時是否以原始大小尺寸顯示
|
||||
new Setting(containerEl)
|
||||
.setName(t('display_original_size'))
|
||||
.setDesc(t('display_original_size_desc'))
|
||||
|
|
@ -88,6 +94,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 5. 點擊圖片時是否打開媒體瀏覽器
|
||||
new Setting(containerEl)
|
||||
.setName(t('click_to_open_media'))
|
||||
.setDesc(t('click_to_open_media_desc'))
|
||||
|
|
@ -98,7 +105,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 禁用 Gallery 內圖片的點擊事件 (以便相容其他圖片類插件)
|
||||
// 6. 是否停用畫廊內的圖片點擊事件 (用以相容其他圖片類外掛)
|
||||
new Setting(containerEl)
|
||||
.setName(t('disable_click_to_open_media_on_gallery'))
|
||||
.setDesc(t('disable_click_to_open_media_on_gallery_desc'))
|
||||
|
|
@ -109,6 +116,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 7. 打開影片檔案時是否預設靜音播放
|
||||
new Setting(containerEl)
|
||||
.setName(t('mute_video_on_open'))
|
||||
.setDesc(t('mute_video_on_open_desc'))
|
||||
|
|
@ -119,6 +127,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 8. 投影片自動播放的間隔時間 (秒,0 代表停用)
|
||||
new Setting(containerEl)
|
||||
.setName(t('auto_play_interval'))
|
||||
.setDesc(t('auto_play_interval_desc'))
|
||||
|
|
@ -131,6 +140,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 9. 畫廊網格大小的預設等級 (小、中、大)
|
||||
new Setting(containerEl)
|
||||
.setName(t('grid_size'))
|
||||
.setDesc(t('grid_size_desc'))
|
||||
|
|
@ -144,6 +154,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 10. 小尺寸網格的自訂寬度 (像素)
|
||||
new Setting(containerEl)
|
||||
.setName(t('grid_size_small_width'))
|
||||
.setDesc(t('grid_size_small_width_desc'))
|
||||
|
|
@ -156,6 +167,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 11. 中尺寸網格的自訂寬度 (像素)
|
||||
new Setting(containerEl)
|
||||
.setName(t('grid_size_medium_width'))
|
||||
.setDesc(t('grid_size_medium_width_desc'))
|
||||
|
|
@ -168,6 +180,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 12. 大尺寸網格的自訂寬度 (像素)
|
||||
new Setting(containerEl)
|
||||
.setName(t('grid_size_large_width'))
|
||||
.setDesc(t('grid_size_large_width_desc'))
|
||||
|
|
@ -180,6 +193,18 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 13. 畫廊圖片是否使用瀑布流顯示
|
||||
new Setting(containerEl)
|
||||
.setName(t('gallery_waterfall'))
|
||||
.setDesc(t('gallery_waterfall_desc'))
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.galleryWaterfall)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.galleryWaterfall = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 14. 畫廊分頁設定,每頁顯示的項目數量 (0 代表不啟用分頁)
|
||||
new Setting(containerEl)
|
||||
.setName(t('items_per_page'))
|
||||
.setDesc(t('items_per_page_desc'))
|
||||
|
|
@ -192,6 +217,7 @@ export class MediaViewSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// 15. 媒體檔案的插入位置 (最前面或最後面)
|
||||
new Setting(containerEl)
|
||||
.setName(t('insert_position'))
|
||||
.addDropdown(dropdown => {
|
||||
|
|
|
|||
|
|
@ -99,7 +99,11 @@ const TRANSLATIONS: Translations = {
|
|||
'gallery_size': 'Gallery 尺寸',
|
||||
'gallery_size_desc': '選擇 Gallery 中圖片的顯示大小',
|
||||
'gallery_add_button': '顯示上傳按鈕',
|
||||
'gallery_add_button_desc': '是否在 Gallery 中顯示上傳圖片的按鈕'
|
||||
'gallery_add_button_desc': '是否在 Gallery 中顯示上傳圖片的按鈕',
|
||||
'gallery_original_ratio': '原始比例顯示',
|
||||
'gallery_original_ratio_desc': '開啟後圖片將以原始比例顯示,不限制為正方形',
|
||||
'gallery_waterfall': '瀑布流顯示',
|
||||
'gallery_waterfall_desc': '開啟後圖片將以瀑布流格式顯示'
|
||||
},
|
||||
'en': {
|
||||
// Notifications
|
||||
|
|
@ -181,7 +185,11 @@ const TRANSLATIONS: Translations = {
|
|||
'gallery_size': 'Gallery size',
|
||||
'gallery_size_desc': 'Choose the display size of images in the gallery',
|
||||
'gallery_add_button': 'Show upload button',
|
||||
'gallery_add_button_desc': 'Whether to show the upload button in the gallery'
|
||||
'gallery_add_button_desc': 'Whether to show the upload button in the gallery',
|
||||
'gallery_original_ratio': 'Display original ratio',
|
||||
'gallery_original_ratio_desc': 'When enabled, images will be displayed in their original ratio instead of square',
|
||||
'gallery_waterfall': 'Waterfall Layout',
|
||||
'gallery_waterfall_desc': 'When enabled, images will be displayed in a waterfall (masonry) layout'
|
||||
},
|
||||
'zh': {
|
||||
// 通知信息
|
||||
|
|
@ -263,7 +271,11 @@ const TRANSLATIONS: Translations = {
|
|||
'gallery_size': '相册尺寸',
|
||||
'gallery_size_desc': '选择相册中图片的显示大小',
|
||||
'gallery_add_button': '显示上传按钮',
|
||||
'gallery_add_button_desc': '是否在相册中显示上传图片的按钮'
|
||||
'gallery_add_button_desc': '是否在相册中显示上传图片的按钮',
|
||||
'gallery_original_ratio': '原始比例顯示',
|
||||
'gallery_original_ratio_desc': '開啟後圖片將以原始比例顯示,不限制為正方形',
|
||||
'gallery_waterfall': '瀑布流顯示',
|
||||
'gallery_waterfall_desc': '開啟後圖片將以瀑布流格式顯示'
|
||||
},
|
||||
'ja': {
|
||||
// 通知メッジ
|
||||
|
|
@ -341,6 +353,10 @@ const TRANSLATIONS: Translations = {
|
|||
'gallery_size': 'ギャラリーサイズ',
|
||||
'gallery_size_desc': 'ギャラリー内の画像表示サイズを選択',
|
||||
'gallery_add_button': 'アップロードボタンを表示',
|
||||
'gallery_add_button_desc': 'ギャラリーにアップロードボタンを表示するかどうか'
|
||||
'gallery_add_button_desc': 'ギャラリーにアップロードボタンを表示するかどうか',
|
||||
'gallery_original_ratio': '元の比率で表示',
|
||||
'gallery_original_ratio_desc': '有効にすると、画像は正方形ではなく元の比率で表示されます',
|
||||
'gallery_waterfall': 'ウォーターフォール表示',
|
||||
'gallery_waterfall_desc': '有効にすると、画像はウォーターフォール(メーソンリー)レイアウトで表示されます'
|
||||
},
|
||||
};
|
||||
|
|
|
|||
57
styles.css
57
styles.css
|
|
@ -122,8 +122,9 @@
|
|||
|
||||
.mv-video-indicator {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
|
|
@ -184,7 +185,7 @@
|
|||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
z-index: 1000;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
|
|
@ -195,7 +196,7 @@
|
|||
}
|
||||
|
||||
.mv-full-media-view.is-thumbnail-open {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
.mv-full-media-view.is-scroll-x {
|
||||
|
|
@ -437,6 +438,45 @@
|
|||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.mvgb-media-gallery-grid.waterfall,
|
||||
.mvgb-media-gallery-grid.waterfall.size-small,
|
||||
.mvgb-media-gallery-grid.waterfall.size-medium,
|
||||
.mvgb-media-gallery-grid.waterfall.size-large {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
gap: 15px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.mvgb-waterfall-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
gap: 15px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.mvgb-media-gallery-grid.waterfall .mv-media-thumbnail-container {
|
||||
aspect-ratio: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mvgb-media-gallery-grid.waterfall .mv-media-thumbnail-container.mvgb-note-thumbnail,
|
||||
.mvgb-media-gallery-grid.waterfall .mv-media-thumbnail-container.mvgb-audio-thumbnail,
|
||||
.mvgb-media-gallery-grid.waterfall .mv-media-thumbnail-container.mvgb-add-media-button,
|
||||
.mvgb-media-gallery-grid.waterfall .mv-media-thumbnail-container.placeholder {
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.mvgb-media-gallery-grid.waterfall .mv-media-thumbnail-container > img,
|
||||
.mvgb-media-gallery-grid.waterfall .mv-media-thumbnail-container > video {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mvgb-gallery-controls {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
@ -617,6 +657,15 @@
|
|||
object-fit: cover;
|
||||
}
|
||||
|
||||
.mv-gallery-content.waterfall .mv-media-thumbnail-container img,
|
||||
.mv-gallery-content.waterfall .mv-media-thumbnail-container video {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.mv-gallery-content.waterfall .mv-media-thumbnail-container {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.mv-media-thumbnail-container.is-placeholder-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue