@simple-photo-gallery/theme-modern 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/astro.config.ts +3 -0
- package/package.json +4 -2
- package/src/features/themes/base-theme/components/gallery-section/GallerySection.astro +7 -3
- package/src/features/themes/base-theme/components/gallery-section/GallerySectionHeader.astro +1 -1
- package/src/features/themes/base-theme/components/gallery-section/GallerySectionItem.astro +39 -11
- package/src/features/themes/base-theme/components/hero/Hero.astro +69 -12
- package/src/features/themes/base-theme/components/sub-galleries/SubGalleries.astro +3 -13
- package/src/features/themes/base-theme/layouts/MainHead.astro +19 -1
- package/src/features/themes/base-theme/layouts/MainLayout.astro +1 -1
- package/src/features/themes/base-theme/pages/index.astro +24 -8
- package/public/images/gallery-placeholder.png +0 -0
- package/public/images/hero-placeholder.png +0 -0
- package/src/config/index.ts +0 -1
- package/src/features/themes/base-theme/types/gallery.ts +0 -56
package/astro.config.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simple-photo-gallery/theme-modern",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Modern theme for Simple Photo Gallery",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Vladimir Haltakov, Tomasz Rusin",
|
|
@@ -27,14 +27,16 @@
|
|
|
27
27
|
"check": "npm run lint && npm run format"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@types/photoswipe": "^4.1.6",
|
|
31
30
|
"astro": "^5.11.0",
|
|
32
31
|
"astro-relative-links": "^0.4.2",
|
|
32
|
+
"blurhash": "^2.0.5",
|
|
33
33
|
"photoswipe": "^5.4.4"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@eslint/eslintrc": "^3.3.1",
|
|
37
37
|
"@eslint/js": "^9.30.1",
|
|
38
|
+
"@simple-photo-gallery/common": "1.0.0",
|
|
39
|
+
"@types/photoswipe": "^4.1.6",
|
|
38
40
|
"@typescript-eslint/eslint-plugin": "^8.35.1",
|
|
39
41
|
"@typescript-eslint/parser": "^8.35.1",
|
|
40
42
|
"eslint": "^9.30.1",
|
|
@@ -3,7 +3,7 @@ import Container from '@/features/themes/base-theme/components/container/Contain
|
|
|
3
3
|
import GallerySectionHeader from '@/features/themes/base-theme/components/gallery-section/GallerySectionHeader.astro';
|
|
4
4
|
import GallerySectionItem from '@/features/themes/base-theme/components/gallery-section/GallerySectionItem.astro';
|
|
5
5
|
|
|
6
|
-
import type { GallerySection as GallerySectionType } from '
|
|
6
|
+
import type { GallerySection as GallerySectionType } from '@simple-photo-gallery/common/src/gallery';
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
9
9
|
section: GallerySectionType;
|
|
@@ -14,7 +14,7 @@ interface Props {
|
|
|
14
14
|
const { section, sectionIndex, mediaBaseUrl } = Astro.props;
|
|
15
15
|
|
|
16
16
|
const validImages = section.images.filter(
|
|
17
|
-
(image) => image.width > 0 && image.height > 0 && image.thumbnail?.width > 0 && image.thumbnail?.height > 0,
|
|
17
|
+
(image) => image.width > 0 && image.height > 0 && (image.thumbnail?.width || 0) > 0 && (image.thumbnail?.height || 0) > 0,
|
|
18
18
|
);
|
|
19
19
|
---
|
|
20
20
|
|
|
@@ -22,7 +22,11 @@ const validImages = section.images.filter(
|
|
|
22
22
|
<Container>
|
|
23
23
|
<GallerySectionHeader section={section} />
|
|
24
24
|
<div class="gallery-section__gallery" id={`gallery-${sectionIndex}`}>
|
|
25
|
-
{
|
|
25
|
+
{
|
|
26
|
+
validImages.map((image) => (
|
|
27
|
+
<GallerySectionItem image={image} mediaBaseUrl={mediaBaseUrl} blurHash={image.thumbnail?.blurHash} />
|
|
28
|
+
))
|
|
29
|
+
}
|
|
26
30
|
</div>
|
|
27
31
|
</Container>
|
|
28
32
|
</section>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { getPhotoPath, getRelativePath } from '@/features/themes/base-theme/utils';
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { MediaFile } from '@simple-photo-gallery/common/src/gallery';
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
|
-
image:
|
|
7
|
+
image: MediaFile;
|
|
8
8
|
mediaBaseUrl?: string;
|
|
9
|
+
blurHash?: string;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
const { image, mediaBaseUrl } = Astro.props;
|
|
12
|
+
const { image, mediaBaseUrl, blurHash } = Astro.props;
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
<a
|
|
@@ -20,14 +21,20 @@ const { image, mediaBaseUrl } = Astro.props;
|
|
|
20
21
|
data-pswp-type={image.type}
|
|
21
22
|
data-pswp-caption={image.alt ? `<p class="image-caption">${image.alt}</p>` : ''}
|
|
22
23
|
style={`--w: ${image.thumbnail?.width}; --h: ${image.thumbnail?.height}`}>
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
<canvas data-blur-hash={blurHash} width={32} height={32}></canvas>
|
|
25
|
+
|
|
26
|
+
{
|
|
27
|
+
image.thumbnail && (
|
|
28
|
+
<img
|
|
29
|
+
src={getRelativePath(image.thumbnail.path)}
|
|
30
|
+
srcset={`${getRelativePath(image.thumbnail.path)} 1x, ${getRelativePath(image.thumbnail.pathRetina)} 2x`}
|
|
31
|
+
alt={image.alt}
|
|
32
|
+
loading="lazy"
|
|
33
|
+
width={image.thumbnail.width}
|
|
34
|
+
height={image.thumbnail.height}
|
|
35
|
+
/>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
31
38
|
</a>
|
|
32
39
|
|
|
33
40
|
<style>
|
|
@@ -45,6 +52,8 @@ const { image, mediaBaseUrl } = Astro.props;
|
|
|
45
52
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
46
53
|
transition: all 0.3s ease;
|
|
47
54
|
cursor: pointer;
|
|
55
|
+
position: relative;
|
|
56
|
+
z-index: 1;
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
.gallery-section__item:hover {
|
|
@@ -57,12 +66,31 @@ const { image, mediaBaseUrl } = Astro.props;
|
|
|
57
66
|
height: auto;
|
|
58
67
|
display: block;
|
|
59
68
|
transition: transform 0.5s ease;
|
|
69
|
+
position: relative;
|
|
70
|
+
z-index: 2;
|
|
71
|
+
color: transparent;
|
|
72
|
+
font-size: 0;
|
|
60
73
|
}
|
|
61
74
|
|
|
62
75
|
.gallery-section__item:hover img {
|
|
63
76
|
transform: scale(1.05);
|
|
64
77
|
}
|
|
65
78
|
|
|
79
|
+
.gallery-section__item canvas {
|
|
80
|
+
position: absolute;
|
|
81
|
+
top: 0;
|
|
82
|
+
left: 0;
|
|
83
|
+
z-index: 1;
|
|
84
|
+
width: 100%;
|
|
85
|
+
height: 100%;
|
|
86
|
+
display: block;
|
|
87
|
+
transition: transform 0.5s ease;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.gallery-section__item:hover canvas {
|
|
91
|
+
transform: scale(1.05);
|
|
92
|
+
}
|
|
93
|
+
|
|
66
94
|
@media (min-width: 640px) {
|
|
67
95
|
:root {
|
|
68
96
|
--row-height: 8rem;
|
|
@@ -1,23 +1,66 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { DEFAULT_STATIC_ASSETS_PATH } from '@/config';
|
|
3
2
|
import HeroScrollToGalleryBtn from '@/features/themes/base-theme/components/hero/HeroScrollToGalleryBtn.astro';
|
|
4
|
-
import { getPhotoPath } from '@/features/themes/base-theme/utils';
|
|
5
3
|
|
|
6
4
|
interface Props {
|
|
7
5
|
title: string;
|
|
8
6
|
description?: string;
|
|
9
|
-
backgroundImage: string;
|
|
10
|
-
mediaBaseUrl?: string;
|
|
11
7
|
}
|
|
12
8
|
|
|
13
|
-
const { title, description
|
|
9
|
+
const { title, description } = Astro.props;
|
|
14
10
|
---
|
|
15
11
|
|
|
16
12
|
<section class="hero">
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
<picture class="hero__bg">
|
|
14
|
+
<!-- Portrait -->
|
|
15
|
+
<source
|
|
16
|
+
type="image/avif"
|
|
17
|
+
media="(max-aspect-ratio: 3/4)"
|
|
18
|
+
srcset="
|
|
19
|
+
gallery/images/header_portrait_360.avif 360w,
|
|
20
|
+
gallery/images/header_portrait_480.avif 480w,
|
|
21
|
+
gallery/images/header_portrait_720.avif 720w,
|
|
22
|
+
gallery/images/header_portrait_1080.avif 1080w"
|
|
23
|
+
sizes="(max-aspect-ratio: 3/4) 160vw, 100vw"
|
|
24
|
+
/>
|
|
25
|
+
<source
|
|
26
|
+
type="image/jpeg"
|
|
27
|
+
media="(max-aspect-ratio: 3/4)"
|
|
28
|
+
srcset="
|
|
29
|
+
gallery/images/header_portrait_360.jpg 360w,
|
|
30
|
+
gallery/images/header_portrait_480.jpg 480w,
|
|
31
|
+
gallery/images/header_portrait_720.jpg 720w,
|
|
32
|
+
gallery/images/header_portrait_1080.jpg 1080w"
|
|
33
|
+
sizes="(max-aspect-ratio: 3/4) 160vw, 100vw"
|
|
34
|
+
/>
|
|
35
|
+
|
|
36
|
+
<!-- Landscape -->
|
|
37
|
+
<source
|
|
38
|
+
type="image/avif"
|
|
39
|
+
srcset="
|
|
40
|
+
gallery/images/header_landscape_640.avif 640w,
|
|
41
|
+
gallery/images/header_landscape_960.avif 960w,
|
|
42
|
+
gallery/images/header_landscape_1280.avif 1280w,
|
|
43
|
+
gallery/images/header_landscape_1920.avif 1920w,
|
|
44
|
+
gallery/images/header_landscape_2560.avif 2560w,
|
|
45
|
+
gallery/images/header_landscape_3840.avif 3840w"
|
|
46
|
+
sizes="100vw"
|
|
47
|
+
/>
|
|
48
|
+
<source
|
|
49
|
+
type="image/jpg"
|
|
50
|
+
srcset="
|
|
51
|
+
gallery/images/header_landscape_640.jpg 640w,
|
|
52
|
+
gallery/images/header_landscape_960.jpg 960w,
|
|
53
|
+
gallery/images/header_landscape_1280.jpg 1280w,
|
|
54
|
+
gallery/images/header_landscape_1920.jpg 1920w,
|
|
55
|
+
gallery/images/header_landscape_2560.jpg 2560w,
|
|
56
|
+
gallery/images/header_landscape_3840.jpg 3840w"
|
|
57
|
+
sizes="100vw"
|
|
58
|
+
/>
|
|
59
|
+
|
|
60
|
+
<!-- Fallback -->
|
|
61
|
+
<img src="gallery/images/header_landscape_1920.jpg" alt={title} />
|
|
62
|
+
</picture>
|
|
63
|
+
<div class="hero__overlay"></div>
|
|
21
64
|
<div class="hero__content">
|
|
22
65
|
<h1 class="hero__title">{title}</h1>
|
|
23
66
|
{description && <p class="hero__description">{description}</p>}
|
|
@@ -42,9 +85,23 @@ const { title, description, backgroundImage, mediaBaseUrl } = Astro.props;
|
|
|
42
85
|
left: 0;
|
|
43
86
|
width: 100%;
|
|
44
87
|
height: 100%;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.hero__bg img {
|
|
91
|
+
width: 100%;
|
|
92
|
+
height: 100%;
|
|
93
|
+
object-fit: cover;
|
|
94
|
+
object-position: center;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.hero__overlay {
|
|
98
|
+
position: absolute;
|
|
99
|
+
top: 0;
|
|
100
|
+
left: 0;
|
|
101
|
+
width: 100%;
|
|
102
|
+
height: 100%;
|
|
103
|
+
background-color: rgba(0, 0, 0, 0.4);
|
|
104
|
+
z-index: 5;
|
|
48
105
|
}
|
|
49
106
|
|
|
50
107
|
.hero__content {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { DEFAULT_STATIC_ASSETS_PATH } from '@/config';
|
|
3
2
|
import Container from '@/features/themes/base-theme/components/container/Container.astro';
|
|
4
3
|
import { getRelativePath, getSubgalleryThumbnailPath } from '@/features/themes/base-theme/utils';
|
|
5
4
|
|
|
@@ -11,20 +10,18 @@ interface SubGallery {
|
|
|
11
10
|
|
|
12
11
|
interface Props {
|
|
13
12
|
title?: string;
|
|
14
|
-
description?: string;
|
|
15
13
|
subGalleries: SubGallery[];
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
const { title,
|
|
16
|
+
const { title, subGalleries } = Astro.props;
|
|
19
17
|
---
|
|
20
18
|
|
|
21
19
|
<section class="sub-galleries">
|
|
22
20
|
<Container>
|
|
23
21
|
{
|
|
24
|
-
(title
|
|
22
|
+
(title) && (
|
|
25
23
|
<div class="sub-galleries__header">
|
|
26
24
|
{title && <h2 class="sub-galleries__header-title">{title}</h2>}
|
|
27
|
-
{description && <p class="sub-galleries__header-description">{description}</p>}
|
|
28
25
|
</div>
|
|
29
26
|
)
|
|
30
27
|
}
|
|
@@ -33,14 +30,7 @@ const { title, description, subGalleries } = Astro.props;
|
|
|
33
30
|
subGalleries.map((subgallery) => (
|
|
34
31
|
<a href={getRelativePath(subgallery.path)} class="sub-galleries__item">
|
|
35
32
|
<div class="sub-galleries__item-image">
|
|
36
|
-
<img
|
|
37
|
-
src={
|
|
38
|
-
getSubgalleryThumbnailPath(subgallery.headerImage) ||
|
|
39
|
-
`${DEFAULT_STATIC_ASSETS_PATH}/images/gallery-placeholder.png`
|
|
40
|
-
}
|
|
41
|
-
alt={subgallery.title}
|
|
42
|
-
loading="lazy"
|
|
43
|
-
/>
|
|
33
|
+
<img src={getSubgalleryThumbnailPath(subgallery.headerImage)} alt={subgallery.title} loading="lazy" />
|
|
44
34
|
</div>
|
|
45
35
|
<div class="sub-galleries__item-content">
|
|
46
36
|
<h3 class="sub-galleries__item-title">{subgallery.title}</h3>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { GalleryMetadata } from '
|
|
2
|
+
import type { GalleryMetadata } from '@simple-photo-gallery/common';
|
|
3
3
|
|
|
4
4
|
interface Props {
|
|
5
5
|
title: string;
|
|
@@ -69,4 +69,22 @@ const { title, description, url, metadata } = Astro.props;
|
|
|
69
69
|
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap"
|
|
70
70
|
rel="stylesheet"
|
|
71
71
|
/>
|
|
72
|
+
<link
|
|
73
|
+
rel="preload"
|
|
74
|
+
as="image"
|
|
75
|
+
type="image/avif"
|
|
76
|
+
media="(max-aspect-ratio: 3/4)"
|
|
77
|
+
imagesrcset="gallery/images/header_portrait_360.avif 360w, gallery/images/header_portrait_480.avif 480w, gallery/images/header_portrait_720.avif 720w, gallery/images/header_portrait_1080.avif 1080w"
|
|
78
|
+
imagesizes="(max-aspect-ratio: 3/4) 160vw, 100vw"
|
|
79
|
+
fetchpriority="high"
|
|
80
|
+
/>
|
|
81
|
+
<link
|
|
82
|
+
rel="preload"
|
|
83
|
+
as="image"
|
|
84
|
+
type="image/avif"
|
|
85
|
+
media="(min-aspect-ratio: 3/4)"
|
|
86
|
+
imagesrcset="gallery/images/header_landscape_640.avif 640w, gallery/images/header_landscape_960.avif 960w, gallery/images/header_landscape_1280.avif 1280w, gallery/images/header_landscape_1920.avif 1920w, gallery/images/header_landscape_2560.avif 2560w, gallery/images/header_landscape_3840.avif 3840w"
|
|
87
|
+
imagesizes="100vw"
|
|
88
|
+
fetchpriority="high"
|
|
89
|
+
/>
|
|
72
90
|
</head>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import MainHead from '@/features/themes/base-theme/layouts/MainHead.astro';
|
|
3
3
|
|
|
4
|
-
import type { GalleryMetadata } from '
|
|
4
|
+
import type { GalleryMetadata } from '@simple-photo-gallery/common';
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
7
|
title: string;
|
|
@@ -8,7 +8,7 @@ import PhotoSwipe from '@/features/themes/base-theme/components/lightbox/PhotoSw
|
|
|
8
8
|
import SubGalleries from '@/features/themes/base-theme/components/sub-galleries/SubGalleries.astro';
|
|
9
9
|
import MainLayout from '@/features/themes/base-theme/layouts/MainLayout.astro';
|
|
10
10
|
|
|
11
|
-
import type { GalleryData } from '
|
|
11
|
+
import type { GalleryData } from '@simple-photo-gallery/common/src/gallery';
|
|
12
12
|
|
|
13
13
|
// Dynamically import gallery.json from source path or fallback to local
|
|
14
14
|
const galleryJsonPath = process.env.GALLERY_JSON_PATH || './gallery.json';
|
|
@@ -16,19 +16,35 @@ const galleryData = JSON.parse(fs.readFileSync(galleryJsonPath, 'utf8'));
|
|
|
16
16
|
|
|
17
17
|
const gallery = galleryData as GalleryData;
|
|
18
18
|
|
|
19
|
-
const { title, description,
|
|
19
|
+
const { title, description, metadata, sections, subGalleries, mediaBaseUrl, url } = gallery;
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
+
<script>
|
|
23
|
+
import { decode } from 'blurhash';
|
|
24
|
+
|
|
25
|
+
const blurHashCanvases = document.querySelectorAll<HTMLCanvasElement>('canvas[data-blur-hash]');
|
|
26
|
+
|
|
27
|
+
for (const canvas of blurHashCanvases) {
|
|
28
|
+
const blurHashValue = canvas.dataset.blurHash;
|
|
29
|
+
|
|
30
|
+
if (blurHashValue) {
|
|
31
|
+
const pixels = decode(blurHashValue, 32, 32);
|
|
32
|
+
const ctx = canvas.getContext('2d');
|
|
33
|
+
|
|
34
|
+
if (pixels && ctx) {
|
|
35
|
+
const imageData = new ImageData(new Uint8ClampedArray(pixels), 32, 32);
|
|
36
|
+
ctx.putImageData(imageData, 0, 0);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
22
42
|
<MainLayout title={title} description={description} metadata={metadata} url={url}>
|
|
23
|
-
<Hero title={title} description={description}
|
|
43
|
+
<Hero title={title} description={description} />
|
|
24
44
|
|
|
25
45
|
{
|
|
26
46
|
subGalleries && subGalleries.galleries.length > 0 && (
|
|
27
|
-
<SubGalleries
|
|
28
|
-
title={subGalleries.title}
|
|
29
|
-
description={subGalleries.description}
|
|
30
|
-
subGalleries={subGalleries.galleries}
|
|
31
|
-
/>
|
|
47
|
+
<SubGalleries title={subGalleries.title} subGalleries={subGalleries.galleries} />
|
|
32
48
|
)
|
|
33
49
|
}
|
|
34
50
|
{
|
|
Binary file
|
|
Binary file
|
package/src/config/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_STATIC_ASSETS_PATH = 'gallery';
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
export interface GalleryImage {
|
|
2
|
-
path: string;
|
|
3
|
-
alt?: string;
|
|
4
|
-
width: number;
|
|
5
|
-
height: number;
|
|
6
|
-
type: 'image' | 'video';
|
|
7
|
-
thumbnail: {
|
|
8
|
-
path: string;
|
|
9
|
-
pathRetina: string;
|
|
10
|
-
width: number;
|
|
11
|
-
height: number;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface GallerySection {
|
|
16
|
-
title?: string;
|
|
17
|
-
description?: string;
|
|
18
|
-
images: GalleryImage[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface SubGallery {
|
|
22
|
-
title: string;
|
|
23
|
-
headerImage: string;
|
|
24
|
-
path: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface GalleryMetadata {
|
|
28
|
-
image?: string;
|
|
29
|
-
imageWidth?: number;
|
|
30
|
-
imageHeight?: number;
|
|
31
|
-
ogUrl?: string;
|
|
32
|
-
ogType?: string;
|
|
33
|
-
ogSiteName?: string;
|
|
34
|
-
twitterSite?: string;
|
|
35
|
-
twitterCreator?: string;
|
|
36
|
-
author?: string;
|
|
37
|
-
keywords?: string;
|
|
38
|
-
canonicalUrl?: string;
|
|
39
|
-
language?: string;
|
|
40
|
-
robots?: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface GalleryData {
|
|
44
|
-
title: string;
|
|
45
|
-
description: string;
|
|
46
|
-
url?: string;
|
|
47
|
-
headerImage: string;
|
|
48
|
-
metadata?: GalleryMetadata;
|
|
49
|
-
mediaBaseUrl?: string;
|
|
50
|
-
sections: GallerySection[];
|
|
51
|
-
subGalleries?: {
|
|
52
|
-
title?: string;
|
|
53
|
-
description?: string;
|
|
54
|
-
galleries: SubGallery[];
|
|
55
|
-
};
|
|
56
|
-
}
|