diff --git a/manifest.json b/manifest.json index e200c99..261b0f8 100644 --- a/manifest.json +++ b/manifest.json @@ -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 diff --git a/package-lock.json b/package-lock.json index 4bc43f7..31a736e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 6463bf3..e0ab78e 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/src/fullscreen.ts b/src/fullscreen.ts index e23091d..d8392e4 100644 --- a/src/fullscreen.ts +++ b/src/fullscreen.ts @@ -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' } }); diff --git a/src/galleryBlock.ts b/src/galleryBlock.ts index 406c86e..f371b32 100644 --- a/src/galleryBlock.ts +++ b/src/galleryBlock.ts @@ -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) { diff --git a/src/settings.ts b/src/settings.ts index c264a97..3d85973 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -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 => { diff --git a/src/translations.ts b/src/translations.ts index b302aba..0581270 100644 --- a/src/translations.ts +++ b/src/translations.ts @@ -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': '有効にすると、画像はウォーターフォール(メーソンリー)レイアウトで表示されます' }, }; diff --git a/styles.css b/styles.css index bb22ec4..9ebb66d 100644 --- a/styles.css +++ b/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; }