diff --git a/src/app/blog/[id]/page.tsx b/src/app/blog/[id]/page.tsx
index b2f3bb9..a2e0179 100644
--- a/src/app/blog/[id]/page.tsx
+++ b/src/app/blog/[id]/page.tsx
@@ -11,6 +11,8 @@ import styles from "./styles.module.scss"
import { HTMLText } from '@/components/Text/HTMLText'
import { Button } from '@/components/Button/Button'
import { ContactSection } from '@/compositions/ContactSection/ContactSection'
+import { Gallery } from '@/components/Gallery/Gallery'
+import { transformGallery } from '@/utils/dto/gallery'
async function fetchBlog(id: string) {
const res = await fetch(`http://localhost:3000/api/blog/${id}`)
@@ -77,6 +79,14 @@ export default async function BlogPage({ params }: { params: Promise<{id: string
)
}
+
+ if (item.blockType === "gallery") {
+ return (
+
+ )
+ }
})}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 5af4ee2..3408e31 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -103,7 +103,7 @@ export default async function Home() {
-
+
>
)
}
diff --git a/src/collections/Blog.ts b/src/collections/Blog.ts
index 49c6d99..3baab58 100644
--- a/src/collections/Blog.ts
+++ b/src/collections/Blog.ts
@@ -3,6 +3,7 @@ import { isAdminOrEmployee } from '@/collections/access/admin'
import { ParagraphBlock } from '@/collections/blocks/Paragraph'
import { DocumentBlock } from '@/collections/blocks/Document'
import { ContactformBlock } from '@/collections/blocks/Contactform'
+import { GalleryBlock } from '@/collections/blocks/Gallery'
export const Blog: CollectionConfig = {
@@ -54,7 +55,8 @@ export const Blog: CollectionConfig = {
blocks: [
ParagraphBlock,
DocumentBlock,
- ContactformBlock
+ ContactformBlock,
+ GalleryBlock
],
required: true
},
diff --git a/src/collections/Media.ts b/src/collections/Media.ts
index fce39df..5342c6a 100644
--- a/src/collections/Media.ts
+++ b/src/collections/Media.ts
@@ -26,13 +26,15 @@ export const Media: CollectionConfig = {
height: 400,
position: 'centre',
},
+ {
+ name: 'gallery',
+ height: 500,
+ width: undefined,
+ position: 'centre',
+ },
{
name: 'tablet',
width: 1024,
- // By specifying `undefined` or leaving a height undefined,
- // the image will be sized to a certain width,
- // but it will retain its original aspect ratio
- // and calculate a height automatically.
height: undefined,
position: 'centre',
},
diff --git a/src/collections/blocks/Gallery.ts b/src/collections/blocks/Gallery.ts
new file mode 100644
index 0000000..f4bb06d
--- /dev/null
+++ b/src/collections/blocks/Gallery.ts
@@ -0,0 +1,28 @@
+import { Block } from 'payload'
+
+export const GalleryBlock: Block = {
+ slug: 'gallery',
+ fields: [
+ {
+ name: 'items',
+ label: {
+ de: 'Bilder'
+ },
+ type: 'array',
+ required: true,
+ fields: [
+ {
+ name: 'photo',
+ label: {
+ de: 'Bild'
+ },
+ type: 'upload',
+ relationTo: 'media',
+ required: true
+ },
+ ],
+ minRows: 3,
+ maxRows: 12
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/components/Gallery/Gallery.tsx b/src/components/Gallery/Gallery.tsx
new file mode 100644
index 0000000..48528b1
--- /dev/null
+++ b/src/components/Gallery/Gallery.tsx
@@ -0,0 +1,76 @@
+'use client'
+
+import styles from './styles.module.scss'
+import Image, { StaticImageData } from 'next/image'
+import { useCallback, useState } from 'react'
+
+type ImageType = {
+ url: string,
+ width: number,
+ height: number
+}
+
+export type GalleryItem = {
+ id: string;
+ thumbnail: ImageType ;
+ image: ImageType;
+ alt: string;
+}
+
+type GalleryItemProps = {
+ thumbnail: ImageType,
+ alt: string,
+ onClick?: () => void
+}
+
+type GalleryProps = {
+ items: GalleryItem[];
+}
+
+const GalleryItem = ({ thumbnail, alt, onClick }: GalleryItemProps) => {
+ return (
+
+ )
+}
+
+export const Gallery = ({ items }: GalleryProps) => {
+ const [display, setDisplay] = useState(false)
+ const [idx, setIdx] = useState(0)
+ const { image, alt } = items[idx]
+ const displayImage = useCallback((n: number) => {
+ setIdx(n);
+ setDisplay(true);
+ }, [setDisplay, setIdx]);
+
+ const next = useCallback(() => {
+ setIdx((idx + 1) % items.length)
+ }, [idx, setIdx, items])
+
+ return (
+ <>
+
+ {items.map((item, index) =>
+ displayImage(index)}
+ key={item.id}
+ thumbnail={item.thumbnail}
+ alt={item.alt}
+ />)}
+
+ {display &&
+
+
setDisplay(false)}>x
+
+
+ }
+
+ >
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/Gallery/styles.module.scss b/src/components/Gallery/styles.module.scss
new file mode 100644
index 0000000..c7c172c
--- /dev/null
+++ b/src/components/Gallery/styles.module.scss
@@ -0,0 +1,69 @@
+@import "template.scss";
+
+.container {
+ display: flex;
+ gap: 30px;
+ flex-wrap: nowrap;
+ overflow: hidden;
+ --width: -500px;
+}
+
+.display {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 99;
+ width: 100vw;
+ height: 100vh;
+ background-color: rgba(63, 63, 63, 0.82);
+ backdrop-filter: blur(8px);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.displayImage {
+ display: block;
+ max-height: 90vh;
+ max-width: 90vw;
+ object-fit: contain;
+}
+
+.close {
+ color: #ffffff;
+ font-weight: bold;
+ position: fixed;
+ top: 10px;
+ right: 10px;
+ background-color: $base-color;
+ border-radius: 50%;
+ width: 50px;
+ height: 50px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+}
+
+.close:hover {
+ background-color: $shade1;
+}
+@keyframes slide {
+ 0% {
+ transform: translateX(var(--width));
+ }
+ 50% {
+ transform: translateX(0);
+ }
+ 100% {
+ transform: translateX(var(--width));
+ }
+}
+
+.item {
+ animation-name: slide;
+ animation-duration: 60s;
+ animation-iteration-count: infinite;
+ animation-timing-function: linear;
+ cursor: pointer;
+}
\ No newline at end of file
diff --git a/src/pageComponents/Home/Home.tsx b/src/pageComponents/Home/Home.tsx
index d49b7e2..e2cbdfe 100644
--- a/src/pageComponents/Home/Home.tsx
+++ b/src/pageComponents/Home/Home.tsx
@@ -65,7 +65,6 @@ export const Home = () => {
backgroundColor={"soft"}
/>
-
>
)
}
\ No newline at end of file
diff --git a/src/payload-types.ts b/src/payload-types.ts
index cfc2314..5e3472a 100644
--- a/src/payload-types.ts
+++ b/src/payload-types.ts
@@ -165,6 +165,14 @@ export interface Media {
filesize?: number | null;
filename?: string | null;
};
+ gallery?: {
+ url?: string | null;
+ width?: number | null;
+ height?: number | null;
+ mimeType?: string | null;
+ filesize?: number | null;
+ filename?: string | null;
+ };
tablet?: {
url?: string | null;
width?: number | null;
@@ -251,6 +259,15 @@ export interface Blog {
blockName?: string | null;
blockType: 'contactform';
}
+ | {
+ items: {
+ photo: string | Media;
+ id?: string | null;
+ }[];
+ id?: string | null;
+ blockName?: string | null;
+ blockType: 'gallery';
+ }
)[];
updatedAt: string;
createdAt: string;
@@ -609,6 +626,18 @@ export interface BlogSelect {
id?: T;
blockName?: T;
};
+ gallery?:
+ | T
+ | {
+ items?:
+ | T
+ | {
+ photo?: T;
+ id?: T;
+ };
+ id?: T;
+ blockName?: T;
+ };
};
updatedAt?: T;
createdAt?: T;
@@ -787,6 +816,16 @@ export interface MediaSelect {
filesize?: T;
filename?: T;
};
+ gallery?:
+ | T
+ | {
+ url?: T;
+ width?: T;
+ height?: T;
+ mimeType?: T;
+ filesize?: T;
+ filename?: T;
+ };
tablet?:
| T
| {
diff --git a/src/utils/dto/gallery.ts b/src/utils/dto/gallery.ts
new file mode 100644
index 0000000..f3d3784
--- /dev/null
+++ b/src/utils/dto/gallery.ts
@@ -0,0 +1,41 @@
+import { Media } from '@/payload-types'
+import { GalleryItem } from '@/components/Gallery/Gallery'
+
+type Items = {
+ photo: string | Media;
+ id?: string | null;
+}[];
+
+export const transformGallery = (items: Items) => {
+ const galleryItems: GalleryItem[] = []
+
+ items.forEach(item => {
+ if (typeof item === "object" && typeof item.photo === "object" && item.id) {
+ const thumbnail = item.photo.sizes?.gallery?.url;
+ const tWidth = item.photo.sizes?.gallery?.width;
+ const tHeight = item.photo.sizes?.gallery?.height;
+ const image = item.photo.sizes?.tablet?.url;
+ const iWidth = item.photo.sizes?.tablet?.width;
+ const iHeight = item.photo.sizes?.tablet?.height;
+
+ if (thumbnail && image && tWidth && tHeight && iWidth && iHeight) {
+ galleryItems.push({
+ alt: item.photo.alt,
+ id: item.id,
+ thumbnail: {
+ url: thumbnail,
+ width: tWidth,
+ height: tHeight,
+ },
+ image: {
+ url: image,
+ width: iWidth,
+ height: iHeight
+ }
+ })
+ }
+ }
+ })
+
+ return galleryItems
+}
\ No newline at end of file