make main a version off dev

This commit is contained in:
2025-07-23 21:25:24 +02:00
parent 5247bd9816
commit 74e4799ea9
49 changed files with 6594 additions and 280 deletions

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
# jetbrains setting folder
.idea/

4
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

11
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

View File

@ -1,18 +1,26 @@
name: deploy
steps:
deploy:
image: node:20
environment:
FLY_API_TOKEN:
from_secret: FLY_API_TOKEN
pipeline:
build:
image: node:20-alpine
commands:
- curl -L https://fly.io/install.sh | sh
- export PATH="$HOME/.fly/bin:$PATH"
- flyctl deploy --config fly.toml --app gallus-pub
- npm ci
- npm run build
when:
branch: main
event: [push, pull_request]
deploy:
depends_on: [build]
image: flyio/flyctl:latest
secrets: [fly_api_token]
commands:
- flyctl deploy --remote-only
when:
branch: main
event: push
when:
branch:
- main
event:
- push
branches:
include: [main, dev]
cache:
mount:
- node_modules
- .npm

View File

@ -1,18 +1,25 @@
FROM nginx:alpine
FROM node:20-alpine AS build
# Kopiere statische Dateien ins Nginx-Verzeichnis
COPY src/ /usr/share/nginx/html/
WORKDIR /app
# Konfiguriere NGINX für Single-Page-Applications (optional)
RUN echo 'server { \
listen 80; \
root /usr/share/nginx/html; \
index index.html; \
location / { \
try_files $uri $uri/ /index.html; \
} \
}' > /etc/nginx/conf.d/default.conf
COPY package*.json ./
RUN npm ci
EXPOSE 80
COPY ../backup/backup .
CMD ["nginx", "-g", "daemon off;"]
RUN npm run build
FROM node:20-alpine AS production
WORKDIR /app
RUN npm install -g serve
COPY --from=build /app/dist /app
EXPOSE 3000
CMD ["serve", "-s", ".", "-l", "3000"]
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -qO- http://localhost:3000/ || exit 1

47
README.md Normal file
View File

@ -0,0 +1,47 @@
# Astro Starter Kit: Minimal
```sh
npm create astro@latest -- --template minimal
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/minimal)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/minimal)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/minimal/devcontainer.json)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```text
/
├── public/
├── src/
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

5
astro.config.mjs Normal file
View File

@ -0,0 +1,5 @@
// @ts-check
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({});

View File

@ -1,28 +1,42 @@
app = 'gallus-pub'
primary_region = 'fra'
[experimental]
auto_rollback = true
app = "gallus-pub"
primary_region = "fra" # Frankfurt region, change if needed
kill_signal = "SIGINT"
kill_timeout = 5
[build]
dockerfile = 'Dockerfile'
dockerfile = "Dockerfile"
[env]
PORT = "3000"
NODE_ENV = "production"
[http_service]
internal_port = 80
internal_port = 3000
force_https = true
auto_stop_machines = 'stop'
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ['app']
processes = ["app"]
[http_service.concurrency]
type = "connections"
hard_limit = 1000
soft_limit = 500
[[http_service.checks]]
interval = '10s'
timeout = '2s'
grace_period = '5s'
method = 'GET'
path = '/'
interval = "30s"
timeout = "5s"
grace_period = "10s"
method = "GET"
path = "/"
protocol = "http"
tls_skip_verify = false
[metrics]
port = 9091
path = "/metrics"
[[vm]]
memory = '1gb'
cpu_kind = 'shared'
cpus = 1
memory = "512MB"
cpu_kind = "shared"
cpus = 1

4875
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

14
package.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"astro": "^5.12.0"
}
}

9
public/favicon.svg Normal file
View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
<style>
path { fill: #000; }
@media (prefers-color-scheme: dark) {
path { fill: #FFF; }
}
</style>
</svg>

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

BIN
public/images/Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
public/images/Welcome.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
public/images/karaoke.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

BIN
public/images/pub_quiz.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
public/pdf/Menu.pdf Normal file

Binary file not shown.

View File

@ -0,0 +1,11 @@
---
import Layout from "../components/Layout.astro";
---
<Layout>
<h1>About</h1>
<p>Hier findest du alle aktuellen und kommenden About im Gallus Pub.</p>
</Layout>

View File

@ -0,0 +1,42 @@
---
import Layout from "../components/Layout.astro";
import "../../styles/components/ContactForm.css";
---
<Layout>
<div class="contact-container">
<h1 class="contact-title">Kontakt</h1>
<form class="contact-form">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">E-Mail</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="subject">Betreff</label>
<input type="text" id="subject" name="subject" required>
</div>
<div class="form-group">
<label for="message">Nachricht</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<button type="submit" class="submit-button">Senden</button>
</form>
<div class="whatsapp-container">
<p>Oder kontaktiere uns direkt über WhatsApp:</p>
<a href="https://wa.me/41772322770" class="whatsapp-link" target="_blank" rel="noopener noreferrer">
<span class="whatsapp-icon">📱</span>
<span>WhatsApp Chat starten</span>
</a>
</div>
</div>
</Layout>

View File

@ -0,0 +1,35 @@
---
import "../../styles/components/Drinks.css"
const { id } = Astro.props;
---
<section id={id} class="Drinks">
<h2 class="title">Drinks</h2>
<a href="/pdf/Menu.pdf" class="card-link" target="_blank" rel="noopener noreferrer">Getränkekarte</a>
<h3 class="monats-hit">Monats Hit</h3>
<div class="mate-vodka">
<div class="circle" title="Mate Vodka">
<span class="circle-label">Mate Vodka</span>
</div>
<div>Mate Vodka</div>
</div>
<div class="circle-row">
<div class="circle" title="Bier">
<span class="circle-label">Bier</span>
</div>
<div class="circle" title="Wein">
<span class="circle-label">Wein</span>
</div>
<div class="circle" title="Cocktails">
<span class="circle-label">Cocktails</span>
</div>
</div>
<p class="note">
Wir bieten eine Auswahl an erlesenen Getränken für jeden Geschmack. Besuche uns und entdecke unsere saisonalen Spezialitäten und Klassiker.
</p>
</section>

View File

@ -0,0 +1,31 @@
---
// src/components/EventsGrid.astro
import HoverCard from "./HoverCard.astro";
interface Event {
image: string;
title: string;
date: string;
description: string;
}
const { events = [], id }: { events?: Event[]; id?: string } = Astro.props as {
events?: Event[];
id?: string;
};
import "../../styles/components/EventsGrid.css";
---
<h2 class="section-title">Events</h2>
<section id={id} class="events-gird container">
{
events.map((event: Event) => (
<HoverCard
title={event.title}
date={event.date}
description={event.description}
image={event.image}
/>
))
}
</section>

View File

@ -0,0 +1,44 @@
---
// src/components/Footer.astro
import "/styles/components/Footer.css"
const currentYear = new Date().getFullYear();
---
<footer class="footer">
<div class="footer-content">
<div class="copyright">
&copy; {currentYear} Gallus Pub. Alle Rechte vorbehalten.
</div>
<div class="footer-sections">
<div class="footer-section">
<h3>Öffnungszeiten</h3>
<p>Mittwoch: 19:00 - 00:00</p>
<p>Donnerstag: 19:00 - 00:00</p>
<p>Freitag: 19:00 - 01:00</p>
<p>Samstag: 19:00 - 01:00</p>
</div>
<div class="footer-section">
<h3>Kontakt</h3>
<p>Gallus Pub</p>
<p>Metzgergasse 13</p>
<p>9000 St. Gallen</p>
<p>Reservierungen via Whatsapp</p>
<p><a href="tel:0772322770">077 232 27 70</a></p>
</div>
<div class="footer-section">
<h3>Raumreservationen</h3>
<p>Du planst einen Event?</p>
<p>Der "St.Gallerruum" im 2.OG</p>
<p>kann gemietet werden.</p>
<br/>
<p>Gerne öffnen wir auf Anfrage</p>
<p>auch ausserhalb unserer</p>
<p>Betriebszeiten.</p>
</div>
</div>
</div>
</footer>

View File

@ -0,0 +1,28 @@
---
// src/components/Header.astro
const { url } = Astro;
import "../../styles/components/Header.css";
---
<header class="header">
<div class="logo-container">
<a href="/">
<img src="/images/Logo.png" alt="Logo" class="logo" />
</a>
</div>
<!-- Hauptnavigation: immer Home, About, Contact -->
<nav class="nav-main">
<div>
<a href="/#hero">Home</a>
<a href="/#events">Events</a>
<a href="/#gallery">Galerie</a>
<a href="/#drinks">Drinks</a>
<a href="/#openings">Openings</a>
<!--<a href="/#about">About</a>
<a href="/#contact">Contact</a>-->
</div>
</nav>
</header>
<div class="header-spacer"></div>

27
src/components/Hero.astro Normal file
View File

@ -0,0 +1,27 @@
---
// src/components/Hero.astro
import "../../styles/components/Hero.css"
const { id } = Astro.props;
---
<section id={id} class="hero container">
<div class="hero-overlay">
<div class="hero-content">
<h1>Dein Irish Pub</h1>
<p>Im Herzen von St.Gallen</p>
<a href="#" class="button">Aktuelles ↓</a>
</div>
</div>
</section>
<style>
</style>

View File

@ -0,0 +1,18 @@
---
// src/components/HoverCard.astro
import "../../styles/components/HoverCard.css";
const { title, description, image = "", date } = Astro.props;
---
<article class="hover-card">
<div class="image-container">
<img class="card-image" src={image} alt={title} />
</div>
<h3 class="card-title" set:html={title} />
<h4 class="card_date">{date}</h4>
<div class="hover-text">
<p set:html={description} />
</div>
</article>

View File

@ -0,0 +1,114 @@
---
// src/components/ImageCarousel.astro
import "../../styles/components/ImageCarousel.css";
interface Image {
src: string;
alt: string;
}
const { images = [], id } = Astro.props as { images: Image[], id?: string };
---
<section id={id} class="image-carousel-container">
<h2 class="section-title">Galerie</h2>
<div class="image-carousel">
<button class="nav-button prev-button" aria-label="Previous image">
<span class="arrow">&#10094;</span>
</button>
<div class="carousel-images">
<div class="carousel-track">
{images.map((image, index) => (
<div class="carousel-slide" data-index={index}>
<img src={image.src} alt={image.alt} class="carousel-image" />
</div>
))}
</div>
</div>
<button class="nav-button next-button" aria-label="Next image">
<span class="arrow">&#10095;</span>
</button>
</div>
<div class="carousel-indicators">
{images.map((_, index) => (
<button
class="indicator-dot"
data-index={index}
aria-label={`Go to slide ${index + 1}`}
></button>
))}
</div>
</section>
<script>
// Initialize carousel functionality
function initCarousel() {
const carousel = document.querySelector('.image-carousel');
const track = document.querySelector('.carousel-track');
const slides = document.querySelectorAll('.carousel-slide');
const prevButton = document.querySelector('.prev-button');
const nextButton = document.querySelector('.next-button');
const indicators = document.querySelectorAll('.indicator-dot');
if (!carousel || !track || !slides.length || !prevButton || !nextButton) return;
let currentIndex = 0;
const slideCount = slides.length;
// Set initial active state
updateCarousel();
// Add event listeners
prevButton.addEventListener('click', () => {
currentIndex = (currentIndex - 1 + slideCount) % slideCount;
updateCarousel();
});
nextButton.addEventListener('click', () => {
currentIndex = (currentIndex + 1) % slideCount;
updateCarousel();
});
// Add click events to indicators
indicators.forEach((dot, index) => {
dot.addEventListener('click', () => {
currentIndex = index;
updateCarousel();
});
});
// Function to update carousel display
function updateCarousel() {
// Update active class on slides
slides.forEach((slide, index) => {
const position = index - currentIndex;
// Remove all position classes
slide.classList.remove('prev', 'current', 'next');
// Add appropriate position class
if (position === -1 || (position === slideCount - 1 && currentIndex === 0)) {
slide.classList.add('prev');
} else if (position === 0) {
slide.classList.add('current');
} else if (position === 1 || (position === -(slideCount - 1) && currentIndex === slideCount - 1)) {
slide.classList.add('next');
}
});
// Update indicators
indicators.forEach((dot, index) => {
dot.classList.toggle('active', index === currentIndex);
});
}
}
// Run initialization when DOM is loaded
document.addEventListener('DOMContentLoaded', initCarousel);
// Re-initialize on astro:page-load for Astro View Transitions
document.addEventListener('astro:page-load', initCarousel);
</script>

View File

@ -0,0 +1,35 @@
---
// src/components/Layout.astro
import Header from "./Header.astro";
import Footer from "./Footer.astro";
import "../../styles/components/Layout.css"
---
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Gallus Pub</title>
<link rel="stylesheet" href="/styles/variables.css" />
<link rel="stylesheet" href="/styles/index.css" />
</head>
<body>
<Header />
<main class="container">
<slot />
</main>
<Footer />
</body>
</html>

View File

@ -0,0 +1,57 @@
---
// src/components/Welcome.astro
import "../../styles/components/Welcome.css"
const { id } = Astro.props;
---
<section id={id} class="welcome container">
<div class="welcome-text">
<h2>Herzlich willkommen im Gallus Pub!</h2>
<p>
Wie die meisten bereits wissen, ist hier jeder willkommen - ob jung
oder alt, Rocker, Elf, Nerd, Meerjungfrau oder einfach nur du
selbst. Unsere Türen stehen offen für alle, die Spass haben wollen
und gute Gesellschaft suchen!
</p>
<p><b>Unsere Highlights:</b></p>
<ul>
<li>
<b>Karaoke:</b> Von Mittwoch bis Samstag kannst du deine
Stimme auf zwei Stockwerken zum Besten geben. Keine Sorge, es geht
nicht darum, perfekt zu sein, sondern einfach Spass zu haben! Du singst
gerne, aber lieber für dich? Dann kannst du den 2. OG auch privat
mieten.
</li>
<li>
<b>Pub Quiz:</b> Jeden Freitag ab 20:00 Uhr testet ihr
euer Wissen in verschiedenen Runden. Jede Woche gibt es ein neues
Thema und einen neuen Champion.
</li>
<li>
<b>Getränke:</b> Geniesst frisches Guinness, Smithwicks,
Gallus Old Style Ale und unsere leckeren Cocktails. Für Whisky-Liebhaber
haben wir erlesene Sorten aus Schottland und Irland im Angebot.
</li>
</ul>
<p>
Wir freuen uns darauf, euch bald bei uns begrüssen zu können! Lasst
uns gemeinsam unvergessliche Abende feiern. - Sabrina & Raphael
</p>
</div>
<div class="welcome-image">
<img src="/images/Welcome.png" alt="Welcome backgrount image" />
</div>
</section>

View File

@ -1,47 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Coming Soon - Gallus Pub</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
<div class="container">
<div class="logo-container">
<img src="public/Logo.png" alt="Gallus Pub Logo">
</div>
<h1 class="coming-soon">Coming Soon</h1>
<div class="social-links">
<a href="https://www.instagram.com/galluspubsanktgallen/" target="_blank" class="social-link">
<i class="fab fa-instagram"></i> Instagram
</a>
<a href="mailto:info@gallus-pub.ch" class="social-link">
<i class="far fa-envelope"></i> Email
</a>
<a href="https://wa.me/+41772322770" target="_blank" class="social-link">
<i class="fab fa-whatsapp"></i> WhatsApp Business
</a>
</div>
<div class="opening-hours">
<h2>Öffnungszeiten</h2>
<p>Mittwoch: 19:00 - 24:00</p>
<p>Donnerstag: 19:00 - 24:00</p>
<p>Freitag: 19:00 - 01:00</p>
<p>Samstag: 19:00 - 01:00</p>
</div>
<div class="events-note">
<p>Aktuelle Events findest du</p>
<p>auf unserem Social Media.</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

11
src/pages/Gallery.astro Normal file
View File

@ -0,0 +1,11 @@
---
import Layout from "../components/Layout.astro";
---
<Layout>
<h1>Gallery</h1>
<p>Hier findest du alle aktuellen und kommenden Gallery im Gallus Pub.</p>
</Layout>

11
src/pages/Openings.astro Normal file
View File

@ -0,0 +1,11 @@
---
import Layout from "../components/Layout.astro";
---
<Layout>
<h1>Openings</h1>
<p>Hier findest du alle aktuellen und kommenden Openings im Gallus Pub.</p>
</Layout>

76
src/pages/index.astro Normal file
View File

@ -0,0 +1,76 @@
---
// src/pages/index.astro
import Layout from "../components/Layout.astro";
import Hero from "../components/Hero.astro";
import Welcome from "../components/Welcome.astro";
import EventsGrid from "../components/EventsGrid.astro";
import Drinks from "../components/Drinks.astro";
import ImageCarousel from "../components/ImageCarousel.astro";
import Contact from "../components/Contact.astro";
import About from "../components/About.astro";
const events = [
{
image: "/images/karaoke.jpg",
title: "Karaoke",
date: "Mittwoch - Samstag",
description: `
Bei uns gibt es Karaoke Mi-Sa!! <br>
Seid ihr eine Gruppe und lieber unter euch? ..unseren 2.Stock kannst du auch mieten ;) <br>
Reserviere am besten gleich per Whatsapp <a href="tel:+41772322770">077 232 27 70</a>
`,
},
{
image: "/images/pub_quiz.jpg",
title: "Pub Quiz",
date: "Jeden Freitag",
description: `
Jeden Freitag findet unser <b>Pub Quiz</b> statt. Gespielt wird tischweise in 3-4 Runden. <br>
Jede Woche gibt es ein anderes Thema. Es geht um Ruhm und Ehre und zusätzlich werden die Sieger der Herzen durch das Publikum gekürt! <3 <br>
Auch Einzelpersonen sind herzlich willkommen! <br>
*zum mitmachen minimum 1 Getränk konsumieren oder 5CHF
`,
},
{
image: "/images/crepes_sucette.jpg",
title: "Crepes Sucette <br /> Live Music im Gallus Pub!",
date: "Do, 04. September 2025",
description: `
<b>20:00 Uhr</b> <br>
<a href="Metzgergasse 13, 9000 St. Gallen">Metzgergasse 13, 9000 St. Gallen</a> <br>
Erlebt einen musikalischen Abend mit der Band <b>Crepes Sucette</b> <br>
Jetzt reservieren: <a href="tel:+41772322770">077 232 27 70</a>`,
},
{
image: "/images/kevin_mcflannigan.jpeg",
title: "Kevin McFlannigan <br> Live Music im Gallus Pub!",
date: "Sa, 27. September 2025",
description: `
<b>ab 20:00 Uhr</b> <br>
Singer & Songwriter Kevin McFlannigan <br>
Eintritt ist Frei / Hutkollekte <br>
`,
},
];
const images = [
{ src: "/images/Logo.png", alt: "Erstes Bild" },
{ src: "/images/Logo.png", alt: "Zweites Bild" },
{ src: "/images/Logo.png", alt: "Drittes Bild" },
{ src: "/images/Logo.png", alt: "Viertes Bild" },
{ src: "/images/Logo.png", alt: "Fünftes Bild" },
{ src: "/images/Logo.png", alt: "Sechstes Bild" },
{ src: "/images/Logo.png", alt: "Siebtes Bild" },
{ src: "/images/Logo.png", alt: "Achtes Bild" },
{ src: "/images/Logo.png", alt: "Neuntes Bild" },
{ src: "/images/Logo.png", alt: "Zehntes Bild" },
];
---
<Layout>
<Hero id="hero" />
<Welcome id="welcome" />
<EventsGrid id="events" events={events} />
<ImageCarousel id="gallery" images={images} />
<Drinks id="drinks" />
</Layout>

View File

@ -1,37 +0,0 @@
// Wait for the DOM to be fully loaded
document.addEventListener('DOMContentLoaded', function() {
// Add a fade-in effect to the main elements
const elements = [
document.querySelector('.logo'),
document.querySelector('.coming-soon'),
document.querySelector('.social-links'),
document.querySelector('.opening-hours'),
document.querySelector('.events-note')
];
// Apply fade-in animation with delay for each element
elements.forEach((element, index) => {
if (element) {
element.style.opacity = '0';
element.style.transition = 'opacity 1s ease-in-out';
// Stagger the animations
setTimeout(() => {
element.style.opacity = '1';
}, 300 * index);
}
});
// Add a subtle hover effect to the logo
const logo = document.querySelector('.logo');
if (logo) {
logo.addEventListener('mouseover', function() {
this.style.transform = 'scale(1.05)';
this.style.transition = 'transform 0.3s ease';
});
logo.addEventListener('mouseout', function() {
this.style.transform = 'scale(1)';
});
}
});

View File

@ -1,149 +0,0 @@
/* Global styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background-color: #213b28;
color: #ceb39b;
line-height: 1.6;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 40px 20px;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}
/* Logo styles */
.logo-container {
margin-bottom: 30px;
width: 100%;
max-width: 100%;
}
.logo-container img {
max-width: 100%;
height: auto;
display: block;
margin: 0 auto;
}
.logo {
font-size: 48px;
font-weight: bold;
color: #333;
padding: 20px;
border: 3px solid #333;
display: inline-block;
}
.logo img {
max-width: 200px;
height: auto;
display: block;
}
/* Coming soon text */
.coming-soon {
font-size: 36px;
margin-bottom: 40px;
text-transform: uppercase;
letter-spacing: 4px;
}
/* Social links */
.social-links {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 40px;
}
.social-link {
display: inline-flex;
align-items: center;
padding: 10px 20px;
background-color: #333;
color: white;
text-decoration: none;
border-radius: 30px;
transition: all 0.3s ease;
}
.social-link i {
margin-right: 10px;
font-size: 18px;
}
.social-link:hover {
background-color: #555;
transform: translateY(-3px);
}
/* Opening hours */
.opening-hours {
margin-bottom: 30px;
padding: 20px;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
width: 100%;
max-width: 500px;
}
.opening-hours h2 {
margin-bottom: 15px;
font-size: 24px;
}
.opening-hours p {
margin-bottom: 5px;
}
/* Events note */
.events-note {
font-style: italic;
margin-top: 20px;
padding: 10px;
background-color: #2F2F2F;
color: #fff;
border-radius: 5px;
}
/* Responsive adjustments */
@media (max-width: 600px) {
.social-links {
flex-direction: column;
gap: 10px;
}
.logo {
font-size: 36px;
}
.coming-soon {
font-size: 28px;
}
.container {
padding: 20px 10px;
}
.logo-container img {
max-width: 90%;
}
}

View File

@ -0,0 +1,127 @@
/* styles/components/ContactForm.css */
.contact-container {
max-width: 800px;
margin: 2rem auto;
padding: 0 1rem;
}
.contact-title {
margin-top: 70px;
padding-top: 2rem;
text-align: center;
margin-bottom: 2rem;
font-size: 2.5rem;
color: var(--color-text);
}
.contact-form {
background-color: rgba(33, 59, 40, 0.05);
padding: 2rem;
border-radius: 8px;
margin-bottom: 2rem;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
color: var(--color-text);
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ccc;
border-radius: 4px;
font-family: inherit;
font-size: 1rem;
background-color: #fff;
}
.form-group textarea {
resize: vertical;
}
.form-group input:focus,
.form-group textarea:focus {
outline: none;
border-color: #213b28;
box-shadow: 0 0 0 2px rgba(33, 59, 40, 0.2);
}
.submit-button {
background-color: #213b28;
color: white;
border: none;
padding: 0.75rem 1.5rem;
font-size: 1rem;
font-weight: bold;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.submit-button:hover {
background-color: #2a4c35;
}
.whatsapp-container {
text-align: center;
margin: 2rem 0;
}
.whatsapp-link {
display: inline-flex;
align-items: center;
background-color: #25D366;
color: white;
text-decoration: none;
padding: 0.75rem 1.5rem;
border-radius: 4px;
font-weight: bold;
transition: background-color 0.3s ease;
margin-top: 0.5rem;
}
.whatsapp-link:hover {
background-color: #128C7E;
}
.whatsapp-icon {
font-size: 1.2rem;
margin-right: 0.5rem;
display: inline-block;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.contact-form {
padding: 1.5rem;
}
.contact-title {
font-size: 2rem;
}
}
@media (max-width: 480px) {
.contact-form {
padding: 1rem;
}
.contact-title {
font-size: 1.75rem;
}
.submit-button,
.whatsapp-link {
width: 100%;
justify-content: center;
}
}

View File

@ -0,0 +1,195 @@
.Drinks {
font-family: var(--font-family-primary);
display: flex;
flex-direction: column;
align-items: center;
margin-top: 2rem;
text-align: center;
background-color: var(--color-accent-green);
color: var(--color-accent-beige);
padding: 2rem;
width: 100%;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
}
.title {
font-size: var(--font-size-large);
margin-bottom: 1.5rem;
font-weight: bold;
color: var(--color-text);
text-transform: uppercase;
letter-spacing: 1px;
}
.card-link {
border: 2px solid var(--color-accent-beige);
padding: 0.75rem 1.5rem;
margin-bottom: 2.5rem;
color: var(--color-text);
background-color: var(--color-background);
text-decoration: none;
border-radius: var(--border-radius);
font-weight: bold;
transition: all var(--transition-standard);
display: inline-block;
}
.card-link:hover {
background-color: var(--color-accent-beige);
color: var(--color-accent-green);
transform: translateY(-3px);
box-shadow: var(--box-shadow);
}
.monats-hit {
margin-bottom: 1.5rem;
font-size: var(--font-size-medium);
color: var(--color-text);
font-weight: bold;
position: relative;
padding-bottom: 0.5rem;
}
.monats-hit::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 50px;
height: 2px;
background-color: var(--color-accent-beige);
}
.mate-vodka {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 1.5rem;
padding: 1rem;
background-color: rgba(0, 0, 0, 0.2);
border-radius: var(--border-radius);
width: 80%;
max-width: 300px;
}
.mate-vodka div:not(.circle) {
margin-top: 0.5rem;
font-weight: bold;
color: var(--color-accent-beige);
}
.circle {
height: 6em;
width: 6em;
border: 2px solid var(--color-accent-beige);
border-radius: 50%;
margin: 0.5rem;
background: radial-gradient(circle at 30% 30%, rgba(206, 179, 155, 0.2), transparent 70%);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
transition: all var(--transition-standard);
position: relative;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.circle:hover {
transform: scale(1.05);
border-color: var(--color-text);
}
.circle-label {
opacity: 0;
color: var(--color-text);
font-weight: bold;
font-size: 0.8rem;
text-align: center;
transition: opacity var(--transition-standard);
position: absolute;
}
.circle:hover .circle-label {
opacity: 1;
}
.circle-row {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 1.5rem;
margin: 1.5rem 0;
}
.note {
margin-top: 2rem;
font-style: italic;
text-align: center;
color: var(--color-text);
max-width: 80%;
line-height: 1.6;
padding: 1rem;
border-top: 1px solid rgba(206, 179, 155, 0.3);
border-bottom: 1px solid rgba(206, 179, 155, 0.3);
}
/* Responsive Design */
@media (max-width: 768px) {
.Drinks {
padding: 1.5rem;
}
.title {
font-size: calc(var(--font-size-medium) + 0.2rem);
}
.mate-vodka {
width: 90%;
}
.circle {
height: 5em;
width: 5em;
}
.circle-label {
font-size: 0.7rem;
}
/* Make labels always visible on touch devices */
.circle-label {
opacity: 1;
background-color: rgba(0, 0, 0, 0.5);
padding: 2px 5px;
border-radius: 3px;
}
.circle-row {
gap: 1rem;
}
.note {
max-width: 95%;
}
}
@media (max-width: 480px) {
.circle-row {
flex-direction: column;
align-items: center;
}
.card-link {
padding: 0.5rem 1rem;
}
.circle {
margin: 1rem 0;
}
.mate-vodka {
padding: 0.8rem;
}
}

View File

@ -0,0 +1,28 @@
.section-title {
text-align: center;
margin-bottom: 1.5rem;
font-size: 2rem;
font-weight: bold;
color: var(--color-text);
}
.events-gird {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: var(--gap-standard);
padding: var(--padding-vertical) var(--padding-horizontal);
width: 100%;
}
@media (min-width: 1600px) {
.events-gird {
justify-content: space-between;
}
}
@media (max-width: 1599px) {
.events-gird {
justify-content: space-around;
}
}

View File

@ -0,0 +1,62 @@
.footer {
background-color: #213b28;
color: white;
padding: 3rem 0;
margin-top: 4rem;
}
.footer-content {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
.copyright {
text-align: center;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.footer-sections {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
justify-content: center;
}
.footer-section {
text-align: center;
}
.footer-section h3 {
color: #ffffff;
margin-bottom: 1rem;
font-size: 1.2rem;
}
.footer-section p {
margin: 0.5rem 0;
color: #cccccc;
font-size: 0.9rem;
}
.footer-section a {
color: #ffffff;
text-decoration: none;
}
.footer-section a:hover {
text-decoration: underline;
}
@media (max-width: 768px) {
.footer-sections {
grid-template-columns: 1fr;
gap: 2rem;
}
.footer-section {
padding: 0 1rem;
}
}

View File

@ -0,0 +1,92 @@
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: #0e0c0c;
z-index: 1000;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(5px);
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
height: 70px;
width: 100%;
border-bottom: 1px solid #444;
}
.header-spacer {
height: 70px;
/* Should match the header height */
}
.logo-container {
display: flex;
align-items: center;
}
.logo {
margin-left: 2em;
height: 4em;
width: auto;
transition: transform 0.3s ease;
}
.logo:hover {
transform: scale(1.05);
}
.nav-main {
display: flex;
align-items: center;
}
.nav-main a {
margin: 0 1rem;
color: white;
text-decoration: none;
font-size: 1rem;
cursor: pointer;
}
.nav-main a:hover {
color: #ffa500;
}
@media (max-width: 768px) {
.header {
height: 65px;
}
.logo {
margin-left: 1em;
height: 3em;
}
.header-spacer {
height: 65px;
}
}
@media (max-width: 480px) {
.header {
padding: 0.5rem;
height: 60px;
}
.logo {
margin-left: 0.5em;
height: 2.5em;
}
.nav-main a {
margin: 0 0.5rem;
font-size: 0.9rem;
}
.header-spacer {
height: 60px;
}
}

View File

@ -0,0 +1,66 @@
/* === Hero === */
.hero-overlay {
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 1)), url('/images/Background.png');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
margin-top: 2em;
}
h1 {
padding-top: 2em;
}
.hero {
position: relative;
height: 70vh;
display: flex;
align-items: center;
justify-content: center;
color: white;
margin-bottom: 2rem;
}
.hero-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* Background is set in the component */
}
.hero-content {
position: relative;
text-align: center;
z-index: 1;
}
.hero-content h1 {
font-size: 4rem;
font-weight: bold;
}
.hero-content p {
margin: 0.5rem 0 1rem 0;
font-size: 1.2rem;
}
.button {
margin-top: 2rem;
padding: 0.8rem 2rem;
background: linear-gradient(45deg, #ffa500, #ff7f00);
color: white;
border: none;
border-radius: 30px;
font-size: 1rem;
font-weight: bold;
text-decoration: none;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
transition: transform 0.2s, box-shadow 0.2s;
}
.button:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
}

View File

@ -0,0 +1,114 @@
.hover-card {
position: relative;
width: 350px;
height: 400px;
border-radius: var(--border-radius);
background-color: var(--color-accent-green);
box-shadow: var(--box-shadow);
transition: transform var(--transition-standard);
overflow: hidden;
margin: var(--margin-standard);
display: flex;
flex-direction: column;
}
.hover-card:hover {
transform: translateY(-5px);
}
.card-title {
padding: 15px 15px 5px 15px;
margin: 0;
color: var(--color-accent-beige);
font-size: var(--font-size-medium);
text-align: center;
order: -2;
}
.card_date {
padding: 0 15px 15px 15px;
margin: 0;
color: var(--color-accent-beige);
font-size: var(--font-size-small);
text-align: center;
font-style: italic;
order: -1;
}
.image-container {
flex-grow: 1;
position: relative;
overflow: hidden;
}
.card-image {
width: 100%;
height: 100%;
object-fit: cover;
transition: opacity 0.3s ease;
}
.hover-text {
font-size: var(--font-size-small-medium);
text-align: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: var(--color-accent-green-transparent);
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
opacity: 0;
transition: opacity var(--transition-standard);
}
.hover-text div {
color: var(--color-accent-beige);
text-align: center;
max-height: 100%;
width: 100%;
overflow-y: auto;
padding-right: 5px;
}
.hover-text div::-webkit-scrollbar {
width: 5px;
}
.hover-text div::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 10px;
}
.hover-text div::-webkit-scrollbar-thumb {
background: var(--color-accent-beige);
border-radius: 10px;
}
.hover-text div {
scrollbar-width: thin;
scrollbar-color: var(--color-accent-beige) rgba(0, 0, 0, 0.1);
}
.hover-card:hover .hover-text {
opacity: 1;
}
.hover-card:hover .card-image {
opacity: 0.1;
}
.hover-text p {
margin: 0;
padding: 0;
}
@media (max-width: 768px) {
.hover-card {
width: 100%;
max-width: 350px;
}
}

View File

@ -0,0 +1,176 @@
/* styles/components/ImageCarousel.css */
.image-carousel-container {
width: 100%;
max-width: 1200px;
margin: 2rem auto;
padding: 0 1rem;
}
.section-title {
text-align: center;
margin-bottom: 1.5rem;
font-size: 2rem;
font-weight: bold;
color: var(--color-text);
}
.image-carousel {
position: relative;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
height: 400px;
}
.carousel-images {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.carousel-track {
display: flex;
height: 100%;
position: relative;
}
.carousel-slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: all 0.5s ease;
display: flex;
align-items: center;
justify-content: center;
transform: scale(0.8);
z-index: 1;
}
/* Current slide - center and fully visible */
.carousel-slide.current {
opacity: 1;
transform: scale(1);
z-index: 3;
}
/* Previous slide - left side, partially visible */
.carousel-slide.prev {
opacity: 0.7;
transform: translateX(-30%) scale(0.85);
z-index: 2;
}
/* Next slide - right side, partially visible */
.carousel-slide.next {
opacity: 0.7;
transform: translateX(30%) scale(0.85);
z-index: 2;
}
.carousel-image {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
/* Navigation buttons */
.nav-button {
position: absolute;
top: 50%;
transform: translateY(-50%);
background-color: rgba(255, 255, 255, 0.7);
border: none;
border-radius: 50%;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 10;
transition: background-color 0.3s ease;
}
.nav-button:hover {
background-color: rgba(255, 255, 255, 0.9);
}
.prev-button {
left: 10px;
}
.next-button {
right: 10px;
}
.arrow {
font-size: 18px;
font-weight: bold;
}
/* Indicators */
.carousel-indicators {
display: flex;
justify-content: center;
margin-top: 1rem;
gap: 8px;
}
.indicator-dot {
width: 12px;
height: 12px;
border-radius: 50%;
background-color: #ccc;
border: none;
cursor: pointer;
transition: background-color 0.3s ease;
}
.indicator-dot.active {
background-color: #333;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.image-carousel {
height: 300px;
}
.carousel-slide.prev,
.carousel-slide.next {
opacity: 0.5;
transform: scale(0.7);
}
.carousel-slide.prev {
transform: translateX(-20%) scale(0.7);
}
.carousel-slide.next {
transform: translateX(20%) scale(0.7);
}
}
@media (max-width: 480px) {
.image-carousel {
height: 250px;
}
.carousel-slide.prev,
.carousel-slide.next {
display: none;
}
.nav-button {
width: 30px;
height: 30px;
}
}

View File

@ -0,0 +1,15 @@
html, body {
height: 100%;
margin: 0;
}
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1;
padding: 0 1rem;
}

View File

@ -0,0 +1,41 @@
/* === Welcome === */
.welcome {
display: flex;
flex-wrap: wrap;
align-items: center;
background-color: #1f3a2d;
padding: 3rem 0;
margin-bottom: 2rem;
gap: 2rem;
}
.welcome-text {
order: 1;
flex: 2 1 400px;
padding: 0 1.6rem 0 2rem;
color: #fff3e0;
}
.welcome-text h2 {
font-size: 2.5rem;
margin-bottom: 1rem;
color: #e8c6a7;
}
.welcome-text ul {
margin: 1rem 0;
padding-left: 1.2rem;
}
.welcome-image {
order: 2;
height: 100%;
flex: 1 1 300px;
margin-right: 2em;
}
.welcome-image img {
width: 100%;
height: auto;
border-radius: 8px;
}

34
styles/index.css Normal file
View File

@ -0,0 +1,34 @@
/* === Global Reset === */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Add smooth scrolling behavior */
html {
scroll-behavior: smooth;
}
body {
font-family: var(--font-family-primary), serif;
background-color: var(--color-background);
color: var(--color-text);
line-height: var(--line-height);
}
/* === Container für zentralen Content === */
.container {
max-width: var(--container-max-width);
width: var(--container-width);
margin: 0 auto;
}
a {
color: #ffa500;
}
a:hover {
text-decoration: none;
}

34
styles/variables.css Normal file
View File

@ -0,0 +1,34 @@
:root {
/* Colors */
--color-background: #000;
--color-text: #f5f5f5;
--color-accent-green: #213b28;
--color-accent-beige: #ceb39b;
--color-accent-green-transparent: rgba(33, 59, 40, 0.95);
--color-shadow: rgba(0, 0, 0, 0.2);
--color-orange1: #ffa500;
/* Font Sizes */
--font-family-primary: 'Georgia', serif;
--font-size-small: 1rem;
--font-size-small-medium: 1.2rem;
--font-size-medium: 1.5rem;
--font-size-large: 2rem;
--line-height: 1.6;
--container-width: 100%;
--container-max-width: 1600px;
--padding-vertical: 2rem;
--padding-horizontal: 0;
--margin-standard: 1rem;
--gap-standard: 30px;
--border-radius: 8px;
--box-shadow: 0 4px 8px var(--color-shadow);
--transition-standard: 0.3s ease;
--breakpoint-mobile: 768px;
--breakpoint-desktop: 1600px;
}

5
tsconfig.json Normal file
View File

@ -0,0 +1,5 @@
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}