Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0d6a1c5de | ||
|
|
d678d80116 | ||
|
|
bce973679b | ||
|
|
45f705a104 | ||
|
|
c4f17d5f78 | ||
|
|
247f6ea272 | ||
|
|
ebcfec4ec7 | ||
|
|
e22ccfeda3 | ||
|
|
3729639596 | ||
|
|
4887f599fd | ||
|
|
69db8de6d7 | ||
|
|
7bb5f339c0 | ||
|
|
5982a1bfd1 | ||
|
|
f46a24ee4e | ||
|
|
76c4d5c9bf |
@@ -1,4 +1,4 @@
|
|||||||
FROM node:20-alpine AS build
|
FROM node:22-alpine AS build
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
@@ -7,7 +7,7 @@ RUN npm ci || npm install
|
|||||||
COPY . .
|
COPY . .
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
FROM node:20-alpine AS production
|
FROM node:22-alpine AS production
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN npm install -g serve
|
RUN npm install -g serve
|
||||||
|
|||||||
@@ -28,7 +28,12 @@ export const env = {
|
|||||||
FRONTEND_URL: process.env.FRONTEND_URL || 'http://localhost:5173',
|
FRONTEND_URL: process.env.FRONTEND_URL || 'http://localhost:5173',
|
||||||
|
|
||||||
// Upload
|
// Upload
|
||||||
MAX_FILE_SIZE: parseInt(process.env.MAX_FILE_SIZE || '5242880', 10),
|
// Bilder werden ohnehin auf 1600px heruntergerechnet, die Grenze muss nur
|
||||||
|
// gross genug fuer ein unbearbeitetes Handyfoto sein.
|
||||||
|
MAX_FILE_SIZE: parseInt(process.env.MAX_FILE_SIZE || String(20 * 1024 * 1024), 10),
|
||||||
|
// PDFs werden unveraendert abgelegt. Eine Getraenkekarte mit Bildern liegt
|
||||||
|
// schnell bei 15-20 MB, deshalb ein eigener, groesserer Wert.
|
||||||
|
MAX_PDF_SIZE: parseInt(process.env.MAX_PDF_SIZE || String(40 * 1024 * 1024), 10),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate required environment variables
|
// Validate required environment variables
|
||||||
|
|||||||
@@ -73,9 +73,11 @@ fastify.register(jwt, {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Der globale Wert ist die Obergrenze fuer alles. Die Routen setzen ihn per
|
||||||
|
// request.file({ limits }) auf ihren eigenen, engeren Wert herunter.
|
||||||
fastify.register(multipart, {
|
fastify.register(multipart, {
|
||||||
limits: {
|
limits: {
|
||||||
fileSize: env.MAX_FILE_SIZE,
|
fileSize: Math.max(env.MAX_FILE_SIZE, env.MAX_PDF_SIZE),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { contentSections } from '../db/schema.js';
|
|||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { saveUploadedImage } from '../services/upload.service.js';
|
import { saveUploadedImage } from '../services/upload.service.js';
|
||||||
import { dropImageIfUnused, extractImageUrls } from '../services/image-refs.service.js';
|
import { dropImageIfUnused, extractImageUrls } from '../services/image-refs.service.js';
|
||||||
|
import { env } from '../config/env.js';
|
||||||
|
|
||||||
// Fastify JSON schema for content section body
|
// Fastify JSON schema for content section body
|
||||||
const contentBodyJsonSchema = {
|
const contentBodyJsonSchema = {
|
||||||
@@ -106,7 +107,7 @@ const contentRoute: FastifyPluginAsync = async (fastify) => {
|
|||||||
preHandler: [fastify.authenticate],
|
preHandler: [fastify.authenticate],
|
||||||
}, async (request, reply) => {
|
}, async (request, reply) => {
|
||||||
try {
|
try {
|
||||||
const file = await (request as any).file();
|
const file = await (request as any).file({ limits: { fileSize: env.MAX_FILE_SIZE } });
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return reply.code(400).send({ error: 'No file uploaded' });
|
return reply.code(400).send({ error: 'No file uploaded' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { events } from '../db/schema.js';
|
|||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { dropImageIfUnused } from '../services/image-refs.service.js';
|
import { dropImageIfUnused } from '../services/image-refs.service.js';
|
||||||
import { saveUploadedImage } from '../services/upload.service.js';
|
import { saveUploadedImage } from '../services/upload.service.js';
|
||||||
|
import { env } from '../config/env.js';
|
||||||
|
|
||||||
/** Raeumt eine Bilddatei weg, ohne dass ein Fehler die Antwort kippt. */
|
/** Raeumt eine Bilddatei weg, ohne dass ein Fehler die Antwort kippt. */
|
||||||
async function dropUnusedImage(fastify: any, url: string | null | undefined, reason: string) {
|
async function dropUnusedImage(fastify: any, url: string | null | undefined, reason: string) {
|
||||||
@@ -102,7 +103,7 @@ const eventsRoute: FastifyPluginAsync = async (fastify) => {
|
|||||||
}, async (request, reply) => {
|
}, async (request, reply) => {
|
||||||
try {
|
try {
|
||||||
// Expect a single file field named "file"
|
// Expect a single file field named "file"
|
||||||
const file = await (request as any).file();
|
const file = await (request as any).file({ limits: { fileSize: env.MAX_FILE_SIZE } });
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return reply.code(400).send({ error: 'No file uploaded' });
|
return reply.code(400).send({ error: 'No file uploaded' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { galleryImages } from '../db/schema.js';
|
|||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { dropImageIfUnused } from '../services/image-refs.service.js';
|
import { dropImageIfUnused } from '../services/image-refs.service.js';
|
||||||
import { saveUploadedImage } from '../services/upload.service.js';
|
import { saveUploadedImage } from '../services/upload.service.js';
|
||||||
|
import { env } from '../config/env.js';
|
||||||
|
|
||||||
/** Raeumt eine Bilddatei weg, ohne dass ein Fehler die Antwort kippt. */
|
/** Raeumt eine Bilddatei weg, ohne dass ein Fehler die Antwort kippt. */
|
||||||
async function dropUnusedImage(fastify: any, url: string | null | undefined, reason: string) {
|
async function dropUnusedImage(fastify: any, url: string | null | undefined, reason: string) {
|
||||||
@@ -81,7 +82,7 @@ const galleryRoute: FastifyPluginAsync = async (fastify) => {
|
|||||||
}, async (request, reply) => {
|
}, async (request, reply) => {
|
||||||
try {
|
try {
|
||||||
// Expect a single file field named "file"
|
// Expect a single file field named "file"
|
||||||
const file = await (request as any).file();
|
const file = await (request as any).file({ limits: { fileSize: env.MAX_FILE_SIZE } });
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return reply.code(400).send({ error: 'No file uploaded' });
|
return reply.code(400).send({ error: 'No file uploaded' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const pdfRoute: FastifyPluginAsync = async (fastify) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const file = await (request as any).file();
|
const file = await (request as any).file({ limits: { fileSize: env.MAX_PDF_SIZE } });
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return reply.code(400).send({ error: 'No file uploaded' });
|
return reply.code(400).send({ error: 'No file uploaded' });
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ const pdfRoute: FastifyPluginAsync = async (fastify) => {
|
|||||||
const buffer = Buffer.concat(chunks);
|
const buffer = Buffer.concat(chunks);
|
||||||
|
|
||||||
if ((file.file as any)?.truncated) {
|
if ((file.file as any)?.truncated) {
|
||||||
const limit = Math.round(env.MAX_FILE_SIZE / 1024 / 1024);
|
const limit = Math.round(env.MAX_PDF_SIZE / 1024 / 1024);
|
||||||
return reply.code(413).send({ error: `PDF too large. Maximum is ${limit} MB` });
|
return reply.code(413).send({ error: `PDF too large. Maximum is ${limit} MB` });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ const pdfRoute: FastifyPluginAsync = async (fastify) => {
|
|||||||
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err?.code === 'FST_REQ_FILE_TOO_LARGE') {
|
if (err?.code === 'FST_REQ_FILE_TOO_LARGE') {
|
||||||
const limit = Math.round(env.MAX_FILE_SIZE / 1024 / 1024);
|
const limit = Math.round(env.MAX_PDF_SIZE / 1024 / 1024);
|
||||||
return reply.code(413).send({ error: `PDF too large. Maximum is ${limit} MB` });
|
return reply.code(413).send({ error: `PDF too large. Maximum is ${limit} MB` });
|
||||||
}
|
}
|
||||||
fastify.log.error({ err }, 'PDF upload failed');
|
fastify.log.error({ err }, 'PDF upload failed');
|
||||||
|
|||||||
@@ -9,6 +9,6 @@
|
|||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^5.12.0"
|
"astro": "^7.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 523 KiB |
|
Before Width: | Height: | Size: 523 KiB |
|
Before Width: | Height: | Size: 523 KiB |
|
Before Width: | Height: | Size: 523 KiB |
|
Before Width: | Height: | Size: 469 KiB |
|
Before Width: | Height: | Size: 523 KiB |
|
Before Width: | Height: | Size: 398 KiB |
|
Before Width: | Height: | Size: 604 KiB |
|
Before Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 567 KiB |
|
Before Width: | Height: | Size: 469 KiB |
|
Before Width: | Height: | Size: 728 KiB |
|
Before Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 1021 KiB |
|
Before Width: | Height: | Size: 1021 KiB |
|
Before Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 488 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 90 KiB |
@@ -7,19 +7,19 @@ const { id } = Astro.props;
|
|||||||
<h2 class="title">Drinks</h2>
|
<h2 class="title">Drinks</h2>
|
||||||
|
|
||||||
<p class="note">
|
<p class="note">
|
||||||
Ob frisch gezapftes Pint, edler Whisky oder ein gemütliches Glas Wein – bei uns genießt du das Leben in entspannter Atmosphäre. Auch Cocktails dürfen nicht fehlen: Vieles kreieren wir selbst. Sláinte!
|
Ob ein frisch gezapftes Pint, ein edler Tropfen Whiskey oder ein gemütliches Glas Wein – hier kannst du in entspannter Atmosphäre das Leben genießen.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a href="/pdf/Getraenke_Gallus_2025.pdf" class="card-link" target="_blank" rel="noopener noreferrer">Getränkekarte</a>
|
<a href="/pdf/gallus-getraenkekarte-2026.pdf" class="card-link" target="_blank" rel="noopener noreferrer">Getränkekarte</a>
|
||||||
|
|
||||||
<h3 class="monats-hit">Monats Hit</h3>
|
<h3 class="monats-hit">Monats Hit</h3>
|
||||||
|
|
||||||
<div class="mate-vodka">
|
<div class="mate-vodka">
|
||||||
<div class="circle" title="Mate Vodka">
|
<div class="circle" title="mit oder ohne Schuss ;)">
|
||||||
<img src="/images/MonthlyHit.png" alt="Monats Hit" class="circle-image" />
|
<img src="/images/content/mit-oder-ohne-schuss.avif" alt="Monats Hit" class="circle-image" />
|
||||||
<span class="circle-label"></span>
|
<span class="circle-label"></span>
|
||||||
</div>
|
</div>
|
||||||
<div>Mate Vodka</div>
|
<div>mit oder ohne Schuss ;)</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="note">
|
<p class="note">
|
||||||
@@ -28,15 +28,15 @@ const { id } = Astro.props;
|
|||||||
|
|
||||||
<div class="circle-row">
|
<div class="circle-row">
|
||||||
<div class="circle whiskey-circle" title="Whiskey 1">
|
<div class="circle whiskey-circle" title="Whiskey 1">
|
||||||
<img src="/images/whiskey/Whiskey1.png" alt="Whiskey 1" class="circle-image" />
|
<img src="/images/content/whiskey-1.avif" alt="Whiskey 1" class="circle-image" />
|
||||||
<span class="circle-label"></span>
|
<span class="circle-label"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="circle whiskey-circle" title="Whiskey 2">
|
<div class="circle whiskey-circle" title="Whiskey 2">
|
||||||
<img src="/images/whiskey/Whiskey2.png" alt="Whiskey 2" class="circle-image" />
|
<img src="/images/content/whiskey-2.avif" alt="Whiskey 2" class="circle-image" />
|
||||||
<span class="circle-label"></span>
|
<span class="circle-label"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="circle whiskey-circle" title="Whiskey 3">
|
<div class="circle whiskey-circle" title="Whiskey 3">
|
||||||
<img src="/images/whiskey/Whiskey3.png" alt="Whiskey 3" class="circle-image" />
|
<img src="/images/content/whiskey-3.avif" alt="Whiskey 3" class="circle-image" />
|
||||||
<span class="circle-label"></span>
|
<span class="circle-label"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,27 +28,20 @@ Plätze sind begrenzt! Jetzt reservieren unter 🍀WA 077 232 27 70
|
|||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "/images/events/msogsj4l-bmlcxc.jpeg",
|
image: "/images/events/noeg.avif",
|
||||||
title: "SG Fest",
|
title: "NOeg",
|
||||||
date: "2026-08-14",
|
date: "2026-09-16",
|
||||||
description: `
|
description: `
|
||||||
Das Stadt-Fest steht vor der Tür! Wir haben OFFEN ab 17:00Uhr mit Karaoke! Wir freuen uns auf euch!
|
🎤 Singe die größten Hits auf Spanisch, Italienisch, Französisch, Türkisch oder vielleicht sogar Japanisch?!
|
||||||
|
✨ Lass das Gallus zum Leben erwachen – bei unserer multilingualen Karaoke-Nacht!
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "/images/events/mr82c7eh-yp87hy.jpeg",
|
image: "/images/events/yutaro.avif",
|
||||||
title: "Richie Live",
|
title: "Yutaro",
|
||||||
date: "2026-08-27",
|
date: "2026-09-17",
|
||||||
description: `
|
description: `
|
||||||
SOLD OUT! - Richie hat das Image eines Weltenbummlers und Musikkünstlers. In der Ostschweiz ist er bereits bestens bekannt.🍀Warteliste: WA 077 232 27 70
|
Mit seiner Gitarre und seiner markanten Stimme verbindet er Singer-Songwriter-Sound mit Einflüssen aus Rock, Blues und Progressive Rock. 🍀Reservationen🍀via WA 077 232 27 70
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: "/images/events/mrnpux59-b3075p.jpeg",
|
|
||||||
title: "Hannes LIVE",
|
|
||||||
date: "2026-09-10",
|
|
||||||
description: `
|
|
||||||
Er ist zurück!🥰🍀Johannes ist wieder bei uns! Eine weitere unvergessliche Irish-Night!!🍀Sei dabei! Reservationen🍀via WA 077 232 27 70
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -59,21 +52,52 @@ Plätze sind begrenzt! Jetzt reservieren unter 🍀WA 077 232 27 70
|
|||||||
SOLD OUT! - First time on stage – und das direkt im Gallus Pub!🎤✨
|
SOLD OUT! - First time on stage – und das direkt im Gallus Pub!🎤✨
|
||||||
Danielle & Nina bringen Irish Folk & liebevolle Cover Songs.🍀Warteliste: WA 077 232 27 70
|
Danielle & Nina bringen Irish Folk & liebevolle Cover Songs.🍀Warteliste: WA 077 232 27 70
|
||||||
`,
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "/images/events/dirty-karaoke.avif",
|
||||||
|
title: "Dirty Karaoke",
|
||||||
|
date: "2026-10-07",
|
||||||
|
description: `
|
||||||
|
*Nicht für alle Ohren geeignet! Ob eindeutig zweideutig, hemmungslos daneben oder einfach nur zum Fremdschämen – an diesem Abend gilt: Was gesungen wird, bleibt auf der Bühne.😉
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "/images/events/voices.avif",
|
||||||
|
title: "Voices",
|
||||||
|
date: "2026-10-22",
|
||||||
|
description: `
|
||||||
|
Ein Abend voller Songs, Stimmen & Live Music.
|
||||||
|
Mit besonderen Stimmen, guter Stimmung und ganz viel musikalischer Energie. 🍀Reservationen🍀via WA 077 232 27 70
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "/images/events/disney-karaoke.avif",
|
||||||
|
title: "Disney Karaoke",
|
||||||
|
date: "2026-10-28",
|
||||||
|
description: `
|
||||||
|
Die nächste Disney Karaoke Night steht an – und passend zur Gruselweek: wer mit Grusel-Kostüm kommt, kriegt einen Glitzer-Shot auf's Haus.🎤✨
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "/images/events/katy-elias.avif",
|
||||||
|
title: "Katy & Elias",
|
||||||
|
date: "2026-11-21",
|
||||||
|
description: `
|
||||||
|
ACHTUNG Kurz-Konzert 19:30-20:30! Danach geht’s für die beiden direkt weiter zu einem zweiten Konzert in der Lukas Bar in St. Georgen.
|
||||||
|
🍀Reservationen🍀via WA 077 232 27 70
|
||||||
|
`,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const images = [
|
const images = [
|
||||||
{ src: "/images/gallery/mndhrrtl-s4o8dn.png", alt: "mndhrrtl-s4o8dn.png" },
|
|
||||||
{ src: "/images/gallery/mndhtjvz-965yra.jpeg", alt: "mndhtjvz-965yra.jpeg" },
|
{ src: "/images/gallery/mndhtjvz-965yra.jpeg", alt: "mndhtjvz-965yra.jpeg" },
|
||||||
{ src: "/images/gallery/mndi3625-lnnggc.jpeg", alt: "mndi3625-lnnggc.jpeg" },
|
|
||||||
{ src: "/images/gallery/mndi7upa-qxukqg.jpeg", alt: "mndi7upa-qxukqg.jpeg" },
|
{ src: "/images/gallery/mndi7upa-qxukqg.jpeg", alt: "mndi7upa-qxukqg.jpeg" },
|
||||||
{ src: "/images/gallery/mndi8kzg-oazjp8.jpeg", alt: "mndi8kzg-oazjp8.jpeg" },
|
|
||||||
{ src: "/images/gallery/mndiabuo-m29xj0.jpeg", alt: "mndiabuo-m29xj0.jpeg" },
|
|
||||||
{ src: "/images/gallery/mndicr59-n8suoy.jpeg", alt: "mndicr59-n8suoy.jpeg" },
|
|
||||||
{ src: "/images/gallery/mndieqns-mjs7xe.jpeg", alt: "mndieqns-mjs7xe.jpeg" },
|
|
||||||
{ src: "/images/gallery/mndif8nv-aptjf6.jpeg", alt: "mndif8nv-aptjf6.jpeg" },
|
{ src: "/images/gallery/mndif8nv-aptjf6.jpeg", alt: "mndif8nv-aptjf6.jpeg" },
|
||||||
{ src: "/images/gallery/mndiggta-hnldkv.jpeg", alt: "mndiggta-hnldkv.jpeg" },
|
{ src: "/images/gallery/halloween.avif", alt: "Halloween" },
|
||||||
{ src: "/images/gallery/mndih8lp-woprt4.webp", alt: "mndih8lp-woprt4.webp" }
|
{ src: "/images/gallery/sangallerruum.avif", alt: "Sangallerruum" },
|
||||||
|
{ src: "/images/gallery/welovegalluspub.avif", alt: "WeLoveGallusPub" },
|
||||||
|
{ src: "/images/gallery/raphi-sabrina.jpeg", alt: "Raphi&Sabrina" },
|
||||||
|
{ src: "/images/gallery/pubquiz.avif", alt: "PubQuiz" }
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||