@simple-photo-gallery/theme-modern 0.0.1 → 2.0.0
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/README.md +3 -50
- package/package.json +1 -1
- package/src/features/themes/base-theme/components/container/Container.astro +0 -1
- package/src/features/themes/base-theme/components/footer/Footer.astro +43 -0
- package/src/features/themes/base-theme/components/gallery-section/GallerySection.astro +17 -33
- package/src/features/themes/base-theme/components/gallery-section/GallerySectionHeader.astro +1 -1
- package/src/features/themes/base-theme/components/gallery-section/GallerySectionItem.astro +48 -22
- package/src/features/themes/base-theme/components/hero/Hero.astro +6 -5
- package/src/features/themes/base-theme/components/lightbox/PhotoSwipe.astro +5 -19
- package/src/features/themes/base-theme/components/sub-galleries/SubGalleries.astro +6 -3
- package/src/features/themes/base-theme/layouts/MainHead.astro +17 -18
- package/src/features/themes/base-theme/layouts/MainLayout.astro +4 -5
- package/src/features/themes/base-theme/pages/index.astro +10 -4
- package/src/features/themes/base-theme/types/gallery.ts +7 -8
- package/src/features/themes/base-theme/utils/index.ts +27 -3
- package/public/images/favicon.ico +0 -0
package/README.md
CHANGED
|
@@ -1,52 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Simple Photo Gallery - Modern Theme
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
npm create astro@latest -- --template basics
|
|
5
|
-
```
|
|
3
|
+
This is the modern theme for Simple Photo Gallery built with Astro. This theme provides a clean, responsive interface for displaying photo galleries.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
[](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
|
|
9
|
-
[](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
|
|
10
|
-
|
|
11
|
-
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
|
12
|
-
|
|
13
|
-

|
|
14
|
-
|
|
15
|
-
## 🚀 Project Structure
|
|
16
|
-
|
|
17
|
-
Inside of your Astro project, you'll see the following folders and files:
|
|
18
|
-
|
|
19
|
-
```text
|
|
20
|
-
/
|
|
21
|
-
├── public/
|
|
22
|
-
│ └── favicon.svg
|
|
23
|
-
├── src
|
|
24
|
-
│ ├── assets
|
|
25
|
-
│ │ └── astro.svg
|
|
26
|
-
│ ├── components
|
|
27
|
-
│ │ └── Welcome.astro
|
|
28
|
-
│ ├── layouts
|
|
29
|
-
│ │ └── Layout.astro
|
|
30
|
-
│ └── pages
|
|
31
|
-
│ └── index.astro
|
|
32
|
-
└── package.json
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
To learn more about the folder structure of an Astro project, refer to [our guide on project structure](https://docs.astro.build/en/basics/project-structure/).
|
|
36
|
-
|
|
37
|
-
## 🧞 Commands
|
|
38
|
-
|
|
39
|
-
All commands are run from the root of the project, from a terminal:
|
|
40
|
-
|
|
41
|
-
| Command | Action |
|
|
42
|
-
| :------------------------ | :----------------------------------------------- |
|
|
43
|
-
| `npm install` | Installs dependencies |
|
|
44
|
-
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
|
45
|
-
| `npm run build` | Build your production site to `./dist/` |
|
|
46
|
-
| `npm run preview` | Preview your build locally, before deploying |
|
|
47
|
-
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
|
48
|
-
| `npm run astro -- --help` | Get help using the Astro CLI |
|
|
49
|
-
|
|
50
|
-
## 👀 Want to learn more?
|
|
51
|
-
|
|
52
|
-
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
|
5
|
+
> Note: advanced theme support is coming soon.
|
package/package.json
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Footer component for Simple Photo Gallery
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<footer class="footer">
|
|
6
|
+
<p class="footer__text">
|
|
7
|
+
Created with <a href="https://simple.photo" class="footer__link" target="_blank" rel="noopener noreferrer"
|
|
8
|
+
>Simple Photo Gallery</a
|
|
9
|
+
>
|
|
10
|
+
</p>
|
|
11
|
+
</footer>
|
|
12
|
+
|
|
13
|
+
<style>
|
|
14
|
+
.footer {
|
|
15
|
+
padding: 2rem 1.5rem 1.5rem;
|
|
16
|
+
text-align: center;
|
|
17
|
+
background-color: transparent;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.footer__text {
|
|
21
|
+
font-size: 0.875rem;
|
|
22
|
+
color: #6b7280;
|
|
23
|
+
margin: 0;
|
|
24
|
+
font-weight: 400;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.footer__link {
|
|
28
|
+
color: #6b7280;
|
|
29
|
+
text-decoration: none;
|
|
30
|
+
transition: color 0.2s ease;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.footer__link:hover {
|
|
34
|
+
color: #374151;
|
|
35
|
+
text-decoration: underline;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.footer__link:focus {
|
|
39
|
+
outline: 2px solid #6b7280;
|
|
40
|
+
outline-offset: 2px;
|
|
41
|
+
border-radius: 2px;
|
|
42
|
+
}
|
|
43
|
+
</style>
|
|
@@ -8,23 +8,28 @@ import type { GallerySection as GallerySectionType } from '@/features/themes/bas
|
|
|
8
8
|
interface Props {
|
|
9
9
|
section: GallerySectionType;
|
|
10
10
|
sectionIndex: number;
|
|
11
|
+
mediaBaseUrl?: string;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
const { section, sectionIndex } = Astro.props;
|
|
14
|
+
const { section, sectionIndex, mediaBaseUrl } = Astro.props;
|
|
15
|
+
|
|
16
|
+
const validImages = section.images.filter(
|
|
17
|
+
(image) => image.width > 0 && image.height > 0 && image.thumbnail?.width > 0 && image.thumbnail?.height > 0,
|
|
18
|
+
);
|
|
14
19
|
---
|
|
15
20
|
|
|
16
21
|
<section class={`gallery-section gallery-section-${sectionIndex}`}>
|
|
17
22
|
<Container>
|
|
18
23
|
<GallerySectionHeader section={section} />
|
|
19
24
|
<div class="gallery-section__gallery" id={`gallery-${sectionIndex}`}>
|
|
20
|
-
{
|
|
25
|
+
{validImages.map((image) => <GallerySectionItem image={image} mediaBaseUrl={mediaBaseUrl} />)}
|
|
21
26
|
</div>
|
|
22
27
|
</Container>
|
|
23
28
|
</section>
|
|
24
29
|
|
|
25
30
|
<style>
|
|
26
31
|
.gallery-section {
|
|
27
|
-
padding:
|
|
32
|
+
padding: 1rem 1rem;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
.gallery-section:nth-child(even) {
|
|
@@ -38,38 +43,17 @@ const { section, sectionIndex } = Astro.props;
|
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
.gallery-section__gallery {
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-wrap: wrap;
|
|
43
48
|
margin-bottom: 1rem;
|
|
44
49
|
}
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.gallery-section__gallery {
|
|
54
|
-
columns: 3;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
@media (min-width: 1024px) {
|
|
59
|
-
.gallery-section__gallery {
|
|
60
|
-
columns: 4;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@media (min-width: 1280px) {
|
|
65
|
-
.gallery-section__gallery {
|
|
66
|
-
columns: 5;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
@media (min-width: 1536px) {
|
|
71
|
-
.gallery-section__gallery {
|
|
72
|
-
columns: 6;
|
|
73
|
-
}
|
|
51
|
+
.gallery-section__gallery::after {
|
|
52
|
+
--w: 2;
|
|
53
|
+
--h: 1;
|
|
54
|
+
--ratio: calc(var(--w) / var(--h));
|
|
55
|
+
content: '';
|
|
56
|
+
flex-basis: calc(var(--ratio) * var(--row-height));
|
|
57
|
+
flex-grow: 1000000;
|
|
74
58
|
}
|
|
75
59
|
</style>
|
|
@@ -1,37 +1,45 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { getPhotoPath, getRelativePath } from '@/features/themes/base-theme/utils';
|
|
3
3
|
|
|
4
4
|
import type { GalleryImage } from '@/features/themes/base-theme/types/gallery';
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
7
|
image: GalleryImage;
|
|
8
|
+
mediaBaseUrl?: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
const { image } = Astro.props;
|
|
11
|
+
const { image, mediaBaseUrl } = Astro.props;
|
|
11
12
|
---
|
|
12
13
|
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
<a
|
|
15
|
+
class="gallery-section__item"
|
|
16
|
+
href={getPhotoPath(image.path, mediaBaseUrl)}
|
|
17
|
+
data-pswp-src={getPhotoPath(image.path, mediaBaseUrl)}
|
|
18
|
+
data-pswp-width={image.width}
|
|
19
|
+
data-pswp-height={image.height}
|
|
20
|
+
data-pswp-type={image.type}
|
|
21
|
+
data-pswp-caption={image.alt ? `<p class="image-caption">${image.alt}</p>` : ''}
|
|
22
|
+
style={`--w: ${image.thumbnail?.width}; --h: ${image.thumbnail?.height}`}>
|
|
23
|
+
<img
|
|
24
|
+
src={getRelativePath(image.thumbnail?.path)}
|
|
25
|
+
srcset={`${getRelativePath(image.thumbnail?.path)} 1x, ${getRelativePath(image.thumbnail?.pathRetina)} 2x`}
|
|
26
|
+
alt={image.alt}
|
|
27
|
+
loading="lazy"
|
|
28
|
+
width={image.thumbnail?.width}
|
|
29
|
+
height={image.thumbnail?.height}
|
|
30
|
+
/>
|
|
31
|
+
</a>
|
|
30
32
|
|
|
31
33
|
<style>
|
|
34
|
+
:root {
|
|
35
|
+
--row-height: 6rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
32
38
|
.gallery-section__item {
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
--ratio: calc(var(--w) / var(--h));
|
|
40
|
+
flex-basis: calc(var(--ratio) * var(--row-height));
|
|
41
|
+
flex-grow: calc(var(--ratio) * 100);
|
|
42
|
+
margin: 0.25rem;
|
|
35
43
|
border-radius: 0.75rem;
|
|
36
44
|
overflow: hidden;
|
|
37
45
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
@@ -51,7 +59,25 @@ const { image } = Astro.props;
|
|
|
51
59
|
transition: transform 0.5s ease;
|
|
52
60
|
}
|
|
53
61
|
|
|
54
|
-
.gallery-
|
|
62
|
+
.gallery-section__item:hover img {
|
|
55
63
|
transform: scale(1.05);
|
|
56
64
|
}
|
|
65
|
+
|
|
66
|
+
@media (min-width: 640px) {
|
|
67
|
+
:root {
|
|
68
|
+
--row-height: 8rem;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@media (min-width: 768px) {
|
|
73
|
+
:root {
|
|
74
|
+
--row-height: 9rem;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@media (min-width: 1024px) {
|
|
79
|
+
:root {
|
|
80
|
+
--row-height: 10rem;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
57
83
|
</style>
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { DEFAULT_STATIC_ASSETS_PATH } from '@/config';
|
|
3
3
|
import HeroScrollToGalleryBtn from '@/features/themes/base-theme/components/hero/HeroScrollToGalleryBtn.astro';
|
|
4
|
-
import {
|
|
4
|
+
import { getPhotoPath } from '@/features/themes/base-theme/utils';
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
7
|
title: string;
|
|
8
8
|
description?: string;
|
|
9
9
|
backgroundImage: string;
|
|
10
|
+
mediaBaseUrl?: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
const { title, description, backgroundImage } = Astro.props;
|
|
13
|
+
const { title, description, backgroundImage, mediaBaseUrl } = Astro.props;
|
|
13
14
|
---
|
|
14
15
|
|
|
15
16
|
<section class="hero">
|
|
16
17
|
<div
|
|
17
18
|
class="hero__bg"
|
|
18
|
-
style={`background-image: linear-gradient(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4)), url('${
|
|
19
|
+
style={`background-image: linear-gradient(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4)), url('${getPhotoPath(backgroundImage, mediaBaseUrl) || `${DEFAULT_STATIC_ASSETS_PATH}/images/hero-placeholder.png`}')`}>
|
|
19
20
|
</div>
|
|
20
21
|
<div class="hero__content">
|
|
21
22
|
<h1 class="hero__title">{title}</h1>
|
|
@@ -28,7 +29,7 @@ const { title, description, backgroundImage } = Astro.props;
|
|
|
28
29
|
.hero {
|
|
29
30
|
position: relative;
|
|
30
31
|
min-height: 450px;
|
|
31
|
-
height:
|
|
32
|
+
height: 100vh;
|
|
32
33
|
display: flex;
|
|
33
34
|
align-items: center;
|
|
34
35
|
justify-content: center;
|
|
@@ -56,7 +57,7 @@ const { title, description, backgroundImage } = Astro.props;
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
.hero__title {
|
|
59
|
-
font-size: clamp(
|
|
60
|
+
font-size: clamp(1.5rem, 6vw, 5rem);
|
|
60
61
|
text-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
|
61
62
|
text-align: center;
|
|
62
63
|
line-height: 1.2;
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
let captionHTML = '';
|
|
40
40
|
if (currSlideElement) {
|
|
41
41
|
const caption = currSlideElement?.getAttribute('data-pswp-caption');
|
|
42
|
-
captionHTML = caption
|
|
42
|
+
captionHTML = caption || currSlideElement?.querySelector('img')?.getAttribute('alt') || '';
|
|
43
43
|
el.innerHTML = captionHTML || '';
|
|
44
44
|
}
|
|
45
45
|
});
|
|
@@ -81,18 +81,15 @@
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
.pswp__caption .image-caption {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
text-align: center;
|
|
85
|
+
background: rgba(128, 128, 128, 0.3);
|
|
86
|
+
backdrop-filter: blur(8px);
|
|
87
|
+
-webkit-backdrop-filter: blur(8px);
|
|
88
88
|
color: white;
|
|
89
89
|
padding: 16px;
|
|
90
90
|
border-radius: 16px;
|
|
91
91
|
margin: 1rem;
|
|
92
92
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
|
93
|
-
animation: glassSlideIn 0.6s ease-out;
|
|
94
|
-
transform-origin: bottom center;
|
|
95
|
-
transition: all 0.3s ease;
|
|
96
93
|
@media (max-width: 768px) {
|
|
97
94
|
padding: 8px 16px;
|
|
98
95
|
font-size: 0.8rem;
|
|
@@ -100,17 +97,6 @@
|
|
|
100
97
|
}
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
@keyframes glassSlideIn {
|
|
104
|
-
0% {
|
|
105
|
-
opacity: 0;
|
|
106
|
-
transform: translateY(20px) scale(0.95);
|
|
107
|
-
}
|
|
108
|
-
100% {
|
|
109
|
-
opacity: 1;
|
|
110
|
-
transform: translateY(0) scale(1);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
100
|
.pswp__caption__center {
|
|
115
101
|
text-align: center;
|
|
116
102
|
max-width: 42rem;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { DEFAULT_STATIC_ASSETS_PATH } from '@/config';
|
|
3
3
|
import Container from '@/features/themes/base-theme/components/container/Container.astro';
|
|
4
|
-
import {
|
|
4
|
+
import { getRelativePath, getSubgalleryThumbnailPath } from '@/features/themes/base-theme/utils';
|
|
5
5
|
|
|
6
6
|
interface SubGallery {
|
|
7
7
|
title: string;
|
|
@@ -31,10 +31,13 @@ const { title, description, subGalleries } = Astro.props;
|
|
|
31
31
|
<div class="sub-galleries__grid">
|
|
32
32
|
{
|
|
33
33
|
subGalleries.map((subgallery) => (
|
|
34
|
-
<a href={
|
|
34
|
+
<a href={getRelativePath(subgallery.path)} class="sub-galleries__item">
|
|
35
35
|
<div class="sub-galleries__item-image">
|
|
36
36
|
<img
|
|
37
|
-
src={
|
|
37
|
+
src={
|
|
38
|
+
getSubgalleryThumbnailPath(subgallery.headerImage) ||
|
|
39
|
+
`${DEFAULT_STATIC_ASSETS_PATH}/images/gallery-placeholder.png`
|
|
40
|
+
}
|
|
38
41
|
alt={subgallery.title}
|
|
39
42
|
loading="lazy"
|
|
40
43
|
/>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { DEFAULT_STATIC_ASSETS_PATH } from '@/config';
|
|
3
|
-
|
|
4
2
|
import type { GalleryMetadata } from '@/features/themes/base-theme/types/gallery';
|
|
5
3
|
|
|
6
4
|
interface Props {
|
|
7
5
|
title: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
url?: string;
|
|
8
8
|
metadata?: GalleryMetadata;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
const { title, metadata } = Astro.props;
|
|
11
|
+
const { title, description, url, metadata } = Astro.props;
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
<head>
|
|
@@ -19,32 +19,32 @@ const { title, metadata } = Astro.props;
|
|
|
19
19
|
<base href="/" />
|
|
20
20
|
|
|
21
21
|
{/* Basic SEO */}
|
|
22
|
+
<meta name="description" content={description} />
|
|
22
23
|
{metadata?.keywords && <meta name="keywords" content={metadata.keywords} />}
|
|
23
24
|
{metadata?.author && <meta name="author" content={metadata.author} />}
|
|
24
|
-
{metadata?.canonicalUrl && <link rel="canonical" href={metadata
|
|
25
|
+
{metadata?.canonicalUrl || (url && <link rel="canonical" href={metadata?.canonicalUrl || url} />)}
|
|
25
26
|
{metadata?.robots && <meta name="robots" content={metadata.robots} />}
|
|
26
27
|
{metadata?.language && <meta name="language" content={metadata.language} />}
|
|
27
28
|
|
|
28
|
-
{/* Favicon */}
|
|
29
|
-
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
|
30
|
-
|
|
31
29
|
{/* Open Graph / Facebook */}
|
|
32
|
-
{metadata?.ogType && <meta property="og:type" content={metadata.ogType} />}
|
|
33
|
-
{metadata?.ogUrl && <meta property="og:url" content={metadata.ogUrl} />}
|
|
34
30
|
<meta property="og:title" content={title} />
|
|
35
|
-
|
|
36
|
-
{metadata?.
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
<meta property="og:description" content={description} />
|
|
32
|
+
{metadata?.image && <meta property="og:image" content={metadata.image} />}
|
|
33
|
+
<meta property="og:image:width" content={String(metadata?.imageWidth) || '1200'} />
|
|
34
|
+
<meta property="og:image:height" content={String(metadata?.imageHeight) || '631'} />
|
|
35
|
+
{metadata?.ogType && <meta property="og:type" content={metadata.ogType} />}
|
|
36
|
+
{metadata?.ogUrl || (url && <meta property="og:url" content={metadata?.ogUrl || url} />)}
|
|
39
37
|
{metadata?.ogSiteName && <meta property="og:site_name" content={metadata.ogSiteName} />}
|
|
40
38
|
|
|
41
39
|
{/* Twitter */}
|
|
42
|
-
|
|
40
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
41
|
+
<meta name="twitter:title" content={title} />
|
|
42
|
+
<meta name="twitter:description" content={description} />
|
|
43
|
+
{metadata?.image && <meta name="twitter:image" content={metadata.image} />}
|
|
44
|
+
<meta name="twitter:image:width" content={String(metadata?.imageWidth) || '1200'} />
|
|
45
|
+
<meta name="twitter:image:height" content={String(metadata?.imageHeight) || '631'} />
|
|
43
46
|
{metadata?.twitterSite && <meta name="twitter:site" content={metadata.twitterSite} />}
|
|
44
47
|
{metadata?.twitterCreator && <meta name="twitter:creator" content={metadata.twitterCreator} />}
|
|
45
|
-
<meta name="twitter:title" content={title} />
|
|
46
|
-
{metadata?.description && <meta name="twitter:description" content={metadata.description} />}
|
|
47
|
-
{metadata?.ogImage && <meta name="twitter:image" content={metadata.ogImage} />}
|
|
48
48
|
|
|
49
49
|
<script is:inline>
|
|
50
50
|
(function () {
|
|
@@ -63,7 +63,6 @@ const { title, metadata } = Astro.props;
|
|
|
63
63
|
})();
|
|
64
64
|
</script>
|
|
65
65
|
|
|
66
|
-
<link rel="icon" href={`${DEFAULT_STATIC_ASSETS_PATH}/images/favicon.ico`} sizes="32x32" />
|
|
67
66
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
68
67
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
69
68
|
<link
|
|
@@ -5,23 +5,22 @@ import type { GalleryMetadata } from '@/features/themes/base-theme/types/gallery
|
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
7
|
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
url?: string;
|
|
8
10
|
metadata?: GalleryMetadata;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
const { title, metadata } = Astro.props;
|
|
13
|
+
const { title, description, metadata, url } = Astro.props;
|
|
12
14
|
---
|
|
13
15
|
|
|
14
16
|
<!doctype html>
|
|
15
17
|
<html lang={metadata?.language || 'en'}>
|
|
16
|
-
<MainHead title={title} metadata={metadata} />
|
|
18
|
+
<MainHead title={title} description={description} metadata={metadata} url={url} />
|
|
17
19
|
<body>
|
|
18
20
|
<slot />
|
|
19
21
|
</body>
|
|
20
22
|
</html>
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
24
|
<style is:global>
|
|
26
25
|
* {
|
|
27
26
|
margin: 0;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
|
|
4
|
+
import Footer from '@/features/themes/base-theme/components/footer/Footer.astro';
|
|
4
5
|
import GallerySection from '@/features/themes/base-theme/components/gallery-section/GallerySection.astro';
|
|
5
6
|
import Hero from '@/features/themes/base-theme/components/hero/Hero.astro';
|
|
6
7
|
import PhotoSwipe from '@/features/themes/base-theme/components/lightbox/PhotoSwipe.astro';
|
|
@@ -15,11 +16,11 @@ const galleryData = JSON.parse(fs.readFileSync(galleryJsonPath, 'utf8'));
|
|
|
15
16
|
|
|
16
17
|
const gallery = galleryData as GalleryData;
|
|
17
18
|
|
|
18
|
-
const { title, description, headerImage, metadata, sections, subGalleries } = gallery;
|
|
19
|
+
const { title, description, headerImage, metadata, sections, subGalleries, mediaBaseUrl, url } = gallery;
|
|
19
20
|
---
|
|
20
21
|
|
|
21
|
-
<MainLayout title={title} metadata={metadata}>
|
|
22
|
-
<Hero title={title} description={description} backgroundImage={headerImage} />
|
|
22
|
+
<MainLayout title={title} description={description} metadata={metadata} url={url}>
|
|
23
|
+
<Hero title={title} description={description} backgroundImage={headerImage} mediaBaseUrl={mediaBaseUrl} />
|
|
23
24
|
|
|
24
25
|
{
|
|
25
26
|
subGalleries && subGalleries.galleries.length > 0 && (
|
|
@@ -30,7 +31,12 @@ const { title, description, headerImage, metadata, sections, subGalleries } = ga
|
|
|
30
31
|
/>
|
|
31
32
|
)
|
|
32
33
|
}
|
|
33
|
-
{
|
|
34
|
+
{
|
|
35
|
+
sections.map((section, sectionIndex) => (
|
|
36
|
+
<GallerySection section={section} sectionIndex={sectionIndex} mediaBaseUrl={mediaBaseUrl} />
|
|
37
|
+
))
|
|
38
|
+
}
|
|
34
39
|
|
|
40
|
+
<Footer />
|
|
35
41
|
<PhotoSwipe />
|
|
36
42
|
</MainLayout>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export interface GalleryImage {
|
|
2
2
|
path: string;
|
|
3
3
|
alt?: string;
|
|
4
|
-
description?: string;
|
|
5
4
|
width: number;
|
|
6
5
|
height: number;
|
|
7
6
|
type: 'image' | 'video';
|
|
8
7
|
thumbnail: {
|
|
9
8
|
path: string;
|
|
9
|
+
pathRetina: string;
|
|
10
10
|
width: number;
|
|
11
11
|
height: number;
|
|
12
12
|
};
|
|
@@ -25,14 +25,12 @@ export interface SubGallery {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export interface GalleryMetadata {
|
|
28
|
-
|
|
28
|
+
image?: string;
|
|
29
|
+
imageWidth?: number;
|
|
30
|
+
imageHeight?: number;
|
|
29
31
|
ogUrl?: string;
|
|
30
|
-
ogImage?: string;
|
|
31
|
-
ogImageWidth?: number;
|
|
32
|
-
ogImageHeight?: number;
|
|
33
32
|
ogType?: string;
|
|
34
33
|
ogSiteName?: string;
|
|
35
|
-
twitterCard?: string;
|
|
36
34
|
twitterSite?: string;
|
|
37
35
|
twitterCreator?: string;
|
|
38
36
|
author?: string;
|
|
@@ -44,10 +42,11 @@ export interface GalleryMetadata {
|
|
|
44
42
|
|
|
45
43
|
export interface GalleryData {
|
|
46
44
|
title: string;
|
|
47
|
-
description
|
|
48
|
-
|
|
45
|
+
description: string;
|
|
46
|
+
url?: string;
|
|
49
47
|
headerImage: string;
|
|
50
48
|
metadata?: GalleryMetadata;
|
|
49
|
+
mediaBaseUrl?: string;
|
|
51
50
|
sections: GallerySection[];
|
|
52
51
|
subGalleries?: {
|
|
53
52
|
title?: string;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Normalizes resource paths to be relative to the gallery root directory
|
|
4
|
+
* Normalizes resource paths to be relative to the gallery root directory.
|
|
5
5
|
*
|
|
6
6
|
* @param resourcePath - The resource path (file or directory), typically relative to the gallery.json file
|
|
7
7
|
* @returns The normalized path relative to the gallery root directory
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
|
-
export const getGalleryPath = (resourcePath: string) => {
|
|
9
|
+
export const getRelativePath = (resourcePath: string) => {
|
|
11
10
|
const galleryConfigPath = path.resolve(process.env.GALLERY_JSON_PATH || '');
|
|
12
11
|
const galleryConfigDir = path.dirname(galleryConfigPath);
|
|
13
12
|
|
|
@@ -16,3 +15,28 @@ export const getGalleryPath = (resourcePath: string) => {
|
|
|
16
15
|
|
|
17
16
|
return path.relative(baseDir, absoluteResourcePath);
|
|
18
17
|
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get the path to a photo that is always in the gallery root directory.
|
|
21
|
+
*
|
|
22
|
+
* @param resourcePath - The path to the photo on the hard disk
|
|
23
|
+
* @returns The normalized path relative to the gallery root directory
|
|
24
|
+
*/
|
|
25
|
+
export const getPhotoPath = (photoPath: string, mediaBaseUrl?: string) => {
|
|
26
|
+
const resourceBasename = path.basename(photoPath);
|
|
27
|
+
|
|
28
|
+
return mediaBaseUrl ? `${mediaBaseUrl}/${resourceBasename}` : path.join('.', resourceBasename);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get the path to a subgallery thumbnail that is always in the subgallery directory.
|
|
33
|
+
*
|
|
34
|
+
* @param subgalleryHeaderImagePath - The path to the subgallery header image on the hard disk
|
|
35
|
+
* @returns The normalized path relative to the subgallery directory
|
|
36
|
+
*/
|
|
37
|
+
export const getSubgalleryThumbnailPath = (subgalleryHeaderImagePath: string) => {
|
|
38
|
+
const photoBasename = path.basename(subgalleryHeaderImagePath);
|
|
39
|
+
const subgalleryFolderName = path.basename(path.dirname(subgalleryHeaderImagePath));
|
|
40
|
+
|
|
41
|
+
return path.join(subgalleryFolderName, 'gallery', 'thumbnails', photoBasename);
|
|
42
|
+
};
|
|
Binary file
|