Compare commits
76 Commits
89e1683eee
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f94bbca15 | |||
| 5ef15f0b5c | |||
| 020bfca731 | |||
| ac864ba054 | |||
| e93ba5d29b | |||
| feb137471d | |||
| 0622d190d1 | |||
| 2867678223 | |||
| 096ac9f789 | |||
| 3006ccd5a0 | |||
| 8a8bcc304a | |||
| 54c6f205e0 | |||
| 48fddf7b15 | |||
| 2733c2e7f4 | |||
| 9502123b89 | |||
| ca2d724bd8 | |||
| 38229ac5e9 | |||
| a11c838d2a | |||
| f9fe914c32 | |||
| 21e09f7155 | |||
| 0b37f73634 | |||
| c764f892a1 | |||
| 78f367530a | |||
| b539329420 | |||
| 3e93e8ce3b | |||
| 2fab4bf70b | |||
| 1a6be67af1 | |||
| fea45fc4f8 | |||
| 761bd6be80 | |||
| 8e6bd12da5 | |||
| 548a2d6f53 | |||
| 01edb8d575 | |||
| c498b19afb | |||
| 74a8e7b393 | |||
| 9c4b6ec425 | |||
| dc3f0b53d7 | |||
| b215592292 | |||
| 9c7ecc97df | |||
| 0fd4fbe61f | |||
| 6e489ceac3 | |||
| 21d51732e5 | |||
| f1c94ed438 | |||
| 493c2a94f0 | |||
| 3a3a36e2ea | |||
| 535c82bd81 | |||
| 64aa08c699 | |||
| 6f3edc8977 | |||
| 9ac87b82e9 | |||
| 74e4799ea9 | |||
| 0a939975c3 | |||
| 7e0f052ce7 | |||
| 77c5d5df82 | |||
| f0afa677a0 | |||
| f356b37c9e | |||
| 096883b0ee | |||
| 749b3e5079 | |||
| 3c1a6fae2c | |||
| f3952e7e81 | |||
| 00213204c4 | |||
| 15dedfabcf | |||
| 0f13e8eb66 | |||
| b830f2edaf | |||
| 3b011bc463 | |||
| 5247bd9816 | |||
| 50c06b3a8a | |||
| 5ab62f2b3b | |||
| 6120f04c95 | |||
| 179de67386 | |||
| 3da1b63a50 | |||
| 6b79e08684 | |||
| 7d5e77df76 | |||
| 23b47a7e85 | |||
| f4c75ea941 | |||
| 58522f2ae0 | |||
| 2a0aa7a6c8 | |||
| bcd86c9c68 |
2
Gallus_Pub_v1/.gitignore → .gitignore
vendored
@ -1,5 +1,6 @@
|
||||
# build output
|
||||
dist/
|
||||
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
@ -12,7 +13,6 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
8
.idea/.gitignore
generated
vendored
@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
13
.idea/Gallus_Pub.iml
generated
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="font-awesome" level="application" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Gallus_Pub.iml" filepath="$PROJECT_DIR$/.idea/Gallus_Pub.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
3
.vscode/settings.json
vendored
@ -1,3 +0,0 @@
|
||||
{
|
||||
"editor.formatOnSave": false
|
||||
}
|
||||
16
.woodpecker.yml
Normal file
@ -0,0 +1,16 @@
|
||||
steps:
|
||||
deploy:
|
||||
image: node:20
|
||||
environment:
|
||||
FLY_API_TOKEN:
|
||||
from_secret: FLY_API_TOKEN
|
||||
commands:
|
||||
- curl -L https://fly.io/install.sh | sh
|
||||
- export PATH="$HOME/.fly/bin:$PATH"
|
||||
- flyctl deploy --config fly.toml --app gallus-pub
|
||||
|
||||
when:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
- push
|
||||
@ -1,25 +1,22 @@
|
||||
FROM node:20-alpine AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
|
||||
# Ensure CSS variables are present
|
||||
RUN mkdir -p public/styles
|
||||
RUN cp -r styles/* public/styles/ || true
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-alpine AS production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm install -g serve
|
||||
|
||||
COPY --from=build /app/dist /app
|
||||
COPY --from=build /app/dist ./dist
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["serve", "-s", ".", "-l", "3000"]
|
||||
CMD ["serve", "-s", "dist", "-l", "3000"]
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget -qO- http://localhost:3000/ || exit 1
|
||||
37
Gallus_Pub/.gitignore
vendored
@ -1,37 +0,0 @@
|
||||
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# Expo
|
||||
.expo/
|
||||
dist/
|
||||
web-build/
|
||||
expo-env.d.ts
|
||||
|
||||
# Native
|
||||
.kotlin/
|
||||
*.orig.*
|
||||
*.jks
|
||||
*.p8
|
||||
*.p12
|
||||
*.key
|
||||
*.mobileprovision
|
||||
|
||||
# Metro
|
||||
.metro-health-check*
|
||||
|
||||
# debug
|
||||
npm-debug.*
|
||||
yarn-debug.*
|
||||
yarn-error.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
@ -1,28 +0,0 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||
import { View } from 'react-native';
|
||||
import LoginScreen from './src/pages/LoginPage';
|
||||
import AdminScreen from './src/pages/AdminPage';
|
||||
import HomeScreen from './src/pages/HomePage';
|
||||
import ProtectedRoute from './src/components/ProtectedRoute';
|
||||
import { AuthProvider } from './src/AuthContext';
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<BrowserRouter>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Routes>
|
||||
<Route path="/" element={<HomeScreen />} />
|
||||
<Route path="/admin/login" element={<LoginScreen />} />
|
||||
<Route path="/admin" element={
|
||||
<ProtectedRoute>
|
||||
<AdminScreen />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
</Routes>
|
||||
</View>
|
||||
</BrowserRouter>
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "Gallus_Pub",
|
||||
"slug": "Gallus_Pub",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"newArchEnabled": true,
|
||||
"splash": {
|
||||
"image": "./assets/splash-icon.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"edgeToEdgeEnabled": true
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 17 KiB |
@ -1,8 +0,0 @@
|
||||
import { registerRootComponent } from 'expo';
|
||||
|
||||
import App from './App';
|
||||
|
||||
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
|
||||
// It also ensures that whether you load the app in Expo Go or in a native build,
|
||||
// the environment is set up appropriately
|
||||
registerRootComponent(App);
|
||||
8417
Gallus_Pub/package-lock.json
generated
@ -1,27 +0,0 @@
|
||||
{
|
||||
"name": "gallus_pub",
|
||||
"version": "1.0.0",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"start": "expo start",
|
||||
"android": "expo start --android",
|
||||
"ios": "expo start --ios",
|
||||
"web": "expo start --web"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/metro-runtime": "~5.0.4",
|
||||
"expo": "~53.0.9",
|
||||
"expo-status-bar": "~2.2.3",
|
||||
"react": "19.0.0",
|
||||
"react-native": "0.79.2",
|
||||
"react-native-web": "^0.20.0",
|
||||
"react-router-dom": "^7.6.0",
|
||||
"react-dom": "19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@types/react": "~19.0.10",
|
||||
"typescript": "~5.8.3"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
import React, { createContext, useState, useContext, ReactNode } from 'react';
|
||||
|
||||
type AuthContextType = {
|
||||
isAdmin: boolean;
|
||||
login: (username: string, password: string) => Promise<void>;
|
||||
logout: () => void;
|
||||
};
|
||||
|
||||
const AuthContext = createContext<AuthContextType | null>(null);
|
||||
|
||||
export const AuthProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
|
||||
const login = async (username: string, password: string) => {
|
||||
// Hier würden Sie normalerweise API-Anfragen machen, um die Anmeldedaten zu überprüfen
|
||||
// Einfache Validierung für das Beispiel:
|
||||
if (username === 'admin' && password === 'password') {
|
||||
setIsAdmin(true);
|
||||
// In einer echten Anwendung würden Sie hier einen Token im localStorage speichern
|
||||
localStorage.setItem('isAdmin', 'true');
|
||||
return;
|
||||
}
|
||||
throw new Error('Falsche Anmeldedaten');
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
setIsAdmin(false);
|
||||
localStorage.removeItem('isAdmin');
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ isAdmin, login, logout }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAuth = () => {
|
||||
const context = useContext(AuthContext);
|
||||
if (!context) {
|
||||
throw new Error('useAuth muss innerhalb eines AuthProviders verwendet werden');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@ -1,20 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
import { useAuth } from '../AuthContext';
|
||||
|
||||
type ProtectedRouteProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
|
||||
const { isAdmin } = useAuth();
|
||||
|
||||
if (!isAdmin) {
|
||||
// Wenn nicht angemeldet, zur Login-Seite umleiten
|
||||
return <Navigate to="/admin/login" replace />;
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export default ProtectedRoute;
|
||||
@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useAuth } from '../AuthContext';
|
||||
|
||||
const AdminPage: React.FC = () => {
|
||||
const { logout } = useAuth();
|
||||
|
||||
return (
|
||||
<div style={styles.container}>
|
||||
<h1>Admin</h1>
|
||||
<p>Willkommen im Admin-Bereich! Hier können Sie Ihr Gallus Pub verwalten.</p>
|
||||
<button onClick={logout} style={styles.button}>Abmelden</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = {
|
||||
container: {
|
||||
maxWidth: '800px',
|
||||
margin: '50px auto',
|
||||
padding: '20px',
|
||||
boxShadow: '0 0 10px rgba(0,0,0,0.1)',
|
||||
borderRadius: '5px',
|
||||
},
|
||||
button: {
|
||||
padding: '10px',
|
||||
backgroundColor: '#f44336',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '3px',
|
||||
cursor: 'pointer',
|
||||
marginTop: '20px',
|
||||
}
|
||||
};
|
||||
|
||||
export default AdminPage;
|
||||
@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
import { View, Text, StyleSheet } from 'react-native';
|
||||
|
||||
export default function HomeScreen() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>Willkommen bei Gallus Pub</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: 20,
|
||||
},
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
});
|
||||
@ -1,93 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../AuthContext';
|
||||
|
||||
const LoginPage: React.FC = () => {
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const { login } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError('');
|
||||
|
||||
try {
|
||||
await login(username, password);
|
||||
navigate('/admin');
|
||||
} catch (err) {
|
||||
setError('Anmeldung fehlgeschlagen. Bitte überprüfen Sie Ihre Anmeldedaten.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={styles.container}>
|
||||
<h2>Admin-Login</h2>
|
||||
{error && <p style={styles.error}>{error}</p>}
|
||||
<form onSubmit={handleSubmit} style={styles.form}>
|
||||
<div style={styles.inputGroup}>
|
||||
<label htmlFor="username">Benutzername:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
style={styles.input}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div style={styles.inputGroup}>
|
||||
<label htmlFor="password">Passwort:</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
style={styles.input}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" style={styles.button}>Anmelden</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = {
|
||||
container: {
|
||||
maxWidth: '400px',
|
||||
margin: '100px auto',
|
||||
padding: '20px',
|
||||
boxShadow: '0 0 10px rgba(0,0,0,0.1)',
|
||||
borderRadius: '5px',
|
||||
},
|
||||
form: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column' as 'column',
|
||||
},
|
||||
inputGroup: {
|
||||
marginBottom: '15px',
|
||||
},
|
||||
input: {
|
||||
width: '100%',
|
||||
padding: '10px',
|
||||
borderRadius: '3px',
|
||||
border: '1px solid #ddd',
|
||||
marginTop: '5px',
|
||||
},
|
||||
button: {
|
||||
padding: '10px',
|
||||
backgroundColor: '#4CAF50',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '3px',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
error: {
|
||||
color: 'red',
|
||||
marginBottom: '15px',
|
||||
}
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "expo/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
pipeline:
|
||||
build:
|
||||
image: node:20-alpine
|
||||
commands:
|
||||
- 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
|
||||
|
||||
branches:
|
||||
include: [main, dev]
|
||||
|
||||
cache:
|
||||
mount:
|
||||
- node_modules
|
||||
- .npm
|
||||
@ -1,47 +0,0 @@
|
||||
# Astro Starter Kit: Minimal
|
||||
|
||||
```sh
|
||||
npm create astro@latest -- --template minimal
|
||||
```
|
||||
|
||||
[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/minimal)
|
||||
[](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/minimal)
|
||||
[](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).
|
||||
4875
Gallus_Pub_v1/package-lock.json
generated
@ -1,25 +0,0 @@
|
||||
---
|
||||
import "../../styles/components/Drinks.css"
|
||||
---
|
||||
<div class="Drinks">
|
||||
<div class="title">Drinks</div>
|
||||
|
||||
<a href="/pdf/Menu.pdf" class="card-link" target="_blank" rel="noopener noreferrer">Getränkekarte</a>
|
||||
|
||||
<div class="monats-hit">Monats Hit</div>
|
||||
|
||||
<div class="mate-vodka">
|
||||
<div class="circle"></div>
|
||||
<div>Mate Vodka</div>
|
||||
</div>
|
||||
|
||||
<div class="circle-row">
|
||||
<div class="circle"></div>
|
||||
<div class="circle"></div>
|
||||
<div class="circle"></div>
|
||||
</div>
|
||||
|
||||
<div class="note">
|
||||
Wir bieten eine Auswahl...
|
||||
</div>
|
||||
</div>
|
||||
@ -1,27 +0,0 @@
|
||||
---
|
||||
// src/components/EventsGrid.astro
|
||||
interface Event {
|
||||
title: string;
|
||||
date: Date;
|
||||
description: string;
|
||||
}
|
||||
const { events = [] }: { events?: Event[] } = Astro.props as { events?: Event[] };
|
||||
import '/styles/components/EventsGrid.css';
|
||||
---
|
||||
|
||||
<section class="events-gird container">
|
||||
|
||||
{events.map((event: Event) => (
|
||||
|
||||
<article class="event-card">
|
||||
|
||||
<h3>{event.title}</h3>
|
||||
|
||||
<p class="date">{event.date}</p>
|
||||
<p class="description">{event.description}</p>
|
||||
|
||||
</article>
|
||||
|
||||
))}
|
||||
|
||||
</section>
|
||||
@ -1,39 +0,0 @@
|
||||
---
|
||||
// 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 class="dropdown">
|
||||
|
||||
<a href="/" class="dropdbtn">Home</a>
|
||||
|
||||
<div class="dropdown-content">
|
||||
|
||||
<a href="/events">Events</a>
|
||||
<a href="/gallery">Gallery</a>
|
||||
<a href="/openings">Openings</a>
|
||||
<a href="/drinks">Drinks</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<a href="/about">About</a>
|
||||
<a href="/contact">Contact</a>
|
||||
|
||||
</nav>
|
||||
|
||||
</header>
|
||||
<div class="header-spacer"></div>
|
||||
@ -1,36 +0,0 @@
|
||||
---
|
||||
// src/components/Hero.astro
|
||||
import "../../styles/components/Hero.css"
|
||||
---
|
||||
|
||||
<section class="hero container">
|
||||
|
||||
<div class="hero-overlay">
|
||||
|
||||
<div class="hero-content">
|
||||
|
||||
<h1>Dein Irish Pub</h1>
|
||||
|
||||
<p>Dein Irish Pub</p>
|
||||
|
||||
<a href="#" class="button">Aktuelles ↓</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.hero-overlay {
|
||||
background-image: url('/images/Background.png');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
padding-top: 2em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
---
|
||||
// src/components/HoverCard.astro
|
||||
const { title, description, image, link } = Astro.props;
|
||||
---
|
||||
|
||||
<article class="hover-card">
|
||||
|
||||
<a href={link}>
|
||||
|
||||
<img src={image} alt={title} />
|
||||
|
||||
<div class="info">
|
||||
|
||||
<h3>{title}</h3>
|
||||
|
||||
<p>{description}</p>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</article>
|
||||
@ -1,11 +0,0 @@
|
||||
---
|
||||
import Layout from "../components/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
|
||||
<h1>Contact</h1>
|
||||
|
||||
<p>Hier findest du alle aktuellen und kommenden Contact im Gallus Pub.</p>
|
||||
|
||||
</Layout>
|
||||
@ -1,24 +0,0 @@
|
||||
---
|
||||
// src/pages/index.astro
|
||||
import "../../styles/index.css"
|
||||
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";
|
||||
|
||||
const events = [
|
||||
{ title: 'Karaoke Night', date: 'Mi, 23. Juli 2025', description: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua' },
|
||||
{ title: 'Pub Quiz', date: 'Fr, 25. Juli 2025', description: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptuaLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua' },
|
||||
{ title: 'Live-Musik', date: 'Sa, 26. Juli 2025', description: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod' },
|
||||
{ title: 'Cocktail-Abend', date: 'So, 27. Juli 2025', description: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua' }
|
||||
];
|
||||
---
|
||||
|
||||
<Layout>
|
||||
|
||||
<Hero />
|
||||
<Welcome />
|
||||
<EventsGrid events={events} />
|
||||
<Drinks />
|
||||
</Layout>
|
||||
@ -1,57 +0,0 @@
|
||||
.Drinks {
|
||||
font-family: sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 2rem;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
color: #ceb39b;
|
||||
padding: 2rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.card-link {
|
||||
border: 1px solid #000;
|
||||
padding: 0.5rem 1rem;
|
||||
margin-bottom: 2rem;
|
||||
color: #fff;
|
||||
background: linear-gradient(45deg, #ffa500, #ff7f00);
|
||||
}
|
||||
|
||||
.monats-hit {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mate-vodka {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.circle {
|
||||
height: 6em;
|
||||
width: 6em;
|
||||
border: 2px solid #000;
|
||||
border-radius: 50%;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.circle-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 2rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.note {
|
||||
margin-top: 2rem;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
article {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.events-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||
gap: 2rem;
|
||||
margin: 3rem 0;
|
||||
}
|
||||
.event-card {
|
||||
background-color: #2a2a2a;
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.event-card:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
.event-card h3 {
|
||||
margin-bottom: 0.5rem;
|
||||
color: #ffa500;
|
||||
}
|
||||
.event-card .date {
|
||||
font-size: 0.9rem;
|
||||
color: #ccc;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.event-card .description {
|
||||
font-size: 1rem;
|
||||
color: #eee;
|
||||
}
|
||||
@ -1,94 +0,0 @@
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(26, 26, 26, 0.95);
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
|
||||
.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;
|
||||
margin-right: 377px;
|
||||
}
|
||||
|
||||
.nav-main a,
|
||||
.dropdbtn {
|
||||
margin: 0 1rem;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-main a:hover,
|
||||
.dropdbtn:hover {
|
||||
color: #ffa500;
|
||||
}
|
||||
|
||||
/* Dropdown für Home */
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: #0e0c0c;
|
||||
min-width: 160px;
|
||||
z-index: 1;
|
||||
border: 1px solid #444;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.dropdown-content a {
|
||||
color: #f5f5f5;
|
||||
padding: 0.5rem 1rem;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdown-content a:hover {
|
||||
background-color: #1f1a1a;
|
||||
color: #ffa500;
|
||||
}
|
||||
|
||||
.dropdown:hover .dropdown-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.nav-container {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
/* === Header & Nav === */
|
||||
.header {
|
||||
background-color: #0e0c0c;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 2rem;
|
||||
border-bottom: 1px solid #444;
|
||||
}
|
||||
|
||||
.nav-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 377px;
|
||||
}
|
||||
|
||||
.nav-main a,
|
||||
.dropdbtn {
|
||||
margin: 0 1rem;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-main a:hover,
|
||||
.dropdbtn:hover {
|
||||
color: #ffa500;
|
||||
}
|
||||
|
||||
/* Dropdown für Home */
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: #0e0c0c;
|
||||
min-width: 160px;
|
||||
z-index: 1;
|
||||
border: 1px solid #444;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.dropdown-content a {
|
||||
color: #f5f5f5;
|
||||
padding: 0.5rem 1rem;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdown-content a:hover {
|
||||
background-color: #1f1a1a;
|
||||
color: #ffa500;
|
||||
}
|
||||
|
||||
.dropdown:hover .dropdown-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.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: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
/* === Global Reset === */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Georgia', serif;
|
||||
background-color: #1f1414;
|
||||
color: #f5f5f5;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* === Container für zentralen Content === */
|
||||
.container {
|
||||
max-width: 1140px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
51
README.md
@ -1,6 +1,47 @@
|
||||
# Gallus_Pub
|
||||
# Astro Starter Kit: Minimal
|
||||
|
||||
Reposetory für die Website vom Gallus Pub
|
||||
|
||||
Auftragsgeber: Sabrina Signer
|
||||
Geschäfft: Gallus Pub
|
||||
```sh
|
||||
npm create astro@latest -- --template minimal
|
||||
```
|
||||
|
||||
[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/minimal)
|
||||
[](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/minimal)
|
||||
[](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).
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
app = "gallus-pub"
|
||||
primary_region = "fra" # Frankfurt region, change if needed
|
||||
primary_region = "fra"
|
||||
kill_signal = "SIGINT"
|
||||
kill_timeout = 5
|
||||
|
||||
@ -26,7 +26,7 @@ kill_timeout = 5
|
||||
[[http_service.checks]]
|
||||
interval = "30s"
|
||||
timeout = "5s"
|
||||
grace_period = "10s"
|
||||
grace_period = "30s"
|
||||
method = "GET"
|
||||
path = "/"
|
||||
protocol = "http"
|
||||
4871
package-lock.json
generated
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "gallus-pub-v1",
|
||||
"name": "",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
@ -9,6 +9,6 @@
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^5.11.0"
|
||||
"astro": "^5.12.0"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 749 B After Width: | Height: | Size: 749 B |
BIN
public/images/Background.png
Normal file
|
After Width: | Height: | Size: 706 KiB |
BIN
public/images/Event1.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
public/images/Event2.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
public/images/Event3.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
public/images/Event4.png
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
public/images/Gallery1.png
Normal file
|
After Width: | Height: | Size: 800 KiB |
BIN
public/images/Gallery2.png
Normal file
|
After Width: | Height: | Size: 747 KiB |
BIN
public/images/Gallery3.png
Normal file
|
After Width: | Height: | Size: 398 KiB |
BIN
public/images/Gallery4.png
Normal file
|
After Width: | Height: | Size: 604 KiB |
BIN
public/images/Gallery5.png
Normal file
|
After Width: | Height: | Size: 580 KiB |
BIN
public/images/Gallery6.png
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
public/images/Gallery7.png
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
public/images/Gallery8.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
public/images/Gallery9.png
Normal file
|
After Width: | Height: | Size: 567 KiB |
BIN
public/images/Logo.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
public/images/MonthlyHit.png
Normal file
|
After Width: | Height: | Size: 250 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
BIN
public/images/Whiskey1.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
public/images/Whiskey2.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
public/images/Whiskey3.png
Normal file
|
After Width: | Height: | Size: 196 KiB |
BIN
public/images/karaoke.jpg
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
public/images/pub_quiz.jpg
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
public/pdf/Getraenke_Gallus_2025.pdf
Normal file
42
src/components/Contact.astro
Normal 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>
|
||||
44
src/components/Drinks.astro
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
import "../styles/components/Drinks.css"
|
||||
|
||||
const { id } = Astro.props;
|
||||
---
|
||||
<section id={id} class="Drinks">
|
||||
<h2 class="title">Drinks</h2>
|
||||
|
||||
<p class="note">
|
||||
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. Natürlich dürfen auch Cocktails nicht fehlen. Vieles kreieren wir auch selber - Sláinte!
|
||||
</p>
|
||||
|
||||
<a href="/pdf/Getraenke_Gallus_2025.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">
|
||||
<img src="/images/MonthlyHit.png" alt="Monats Hit" class="circle-image" />
|
||||
<span class="circle-label"></span>
|
||||
</div>
|
||||
<div>Mate Vodka</div>
|
||||
</div>
|
||||
|
||||
<p class="note">
|
||||
Für Whisky-Liebhaber haben wir erlesene Sorten aus Schottland und Irland im Angebot.
|
||||
</p>
|
||||
|
||||
<div class="circle-row">
|
||||
<div class="circle whiskey-circle" title="Whiskey 1">
|
||||
<img src="/images/Whiskey1.png" alt="Whiskey 1" class="circle-image" />
|
||||
<span class="circle-label"></span>
|
||||
</div>
|
||||
<div class="circle whiskey-circle" title="Whiskey 2">
|
||||
<img src="/images/Whiskey2.png" alt="Whiskey 2" class="circle-image" />
|
||||
<span class="circle-label"></span>
|
||||
</div>
|
||||
<div class="circle whiskey-circle" title="Whiskey 3">
|
||||
<img src="/images/Whiskey3.png" alt="Whiskey 3" class="circle-image" />
|
||||
<span class="circle-label"></span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
31
src/components/EventsGrid.astro
Normal 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>
|
||||
@ -1,14 +1,12 @@
|
||||
---
|
||||
// src/components/Footer.astro
|
||||
import "/styles/components/Footer.css"
|
||||
import "../styles/components/Footer.css"
|
||||
const currentYear = new Date().getFullYear();
|
||||
---
|
||||
|
||||
<footer class="footer">
|
||||
<footer class="footer" id="footer">
|
||||
<div class="footer-content">
|
||||
<div class="copyright">
|
||||
© {currentYear} Gallus Pub. Alle Rechte vorbehalten.
|
||||
</div>
|
||||
|
||||
|
||||
<div class="footer-sections">
|
||||
<div class="footer-section">
|
||||
@ -24,8 +22,8 @@ const currentYear = new Date().getFullYear();
|
||||
<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>
|
||||
<p><a href="mailto:info@gallus-pub.ch">info@gallus-pub.ch</a></p>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
@ -33,12 +31,12 @@ const currentYear = new Date().getFullYear();
|
||||
<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>
|
||||
<p>Reservierungen via Whatsapp</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="copyright">
|
||||
© {currentYear} Gallus Pub. Alle Rechte vorbehalten.
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
81
src/components/Header.astro
Normal file
@ -0,0 +1,81 @@
|
||||
---
|
||||
// src/components/Header.astro
|
||||
const { url } = Astro;
|
||||
import "../styles/components/Header.css";
|
||||
---
|
||||
|
||||
<header class="header">
|
||||
<!-- Desktop Layout -->
|
||||
<div class="desktop-layout">
|
||||
<div class="logo-container">
|
||||
<a href="/">
|
||||
<img src="/images/Logo.png" alt="Logo" class="logo" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<nav class="nav-main">
|
||||
<div class="desktop-menu">
|
||||
<a href="/#hero">Home</a>
|
||||
<a href="/#events">Events</a>
|
||||
<a href="/#gallery">Galerie</a>
|
||||
<a href="/#drinks">Drinks</a>
|
||||
<a href="/#footer">Contact</a>
|
||||
<!--<a href="/#about">About</a>
|
||||
<a href="/#contact">Contact</a>-->
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Layout -->
|
||||
<div class="mobile-layout">
|
||||
<!-- Centered Logo -->
|
||||
<div class="mobile-logo-container">
|
||||
<a href="/">
|
||||
<img src="/images/Logo.png" alt="Logo" class="logo" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Burger Menu Below Logo -->
|
||||
<div class="burger-menu">
|
||||
<div class="burger-icon">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Navigation Menu (Dropdown) -->
|
||||
<div class="mobile-menu">
|
||||
<a href="/#hero">Home</a>
|
||||
<a href="/#events">Events</a>
|
||||
<a href="/#gallery">Galerie</a>
|
||||
<a href="/#drinks">Drinks</a>
|
||||
<a href="/#footer">Contact</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="header-spacer"></div>
|
||||
|
||||
<script>
|
||||
// Toggle mobile menu when burger icon is clicked
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const burgerIcon = document.querySelector('.burger-icon');
|
||||
const mobileMenu = document.querySelector('.mobile-menu');
|
||||
const mobileMenuLinks = document.querySelectorAll('.mobile-menu a');
|
||||
|
||||
// Toggle menu when burger icon is clicked
|
||||
burgerIcon.addEventListener('click', () => {
|
||||
burgerIcon.classList.toggle('active');
|
||||
mobileMenu.classList.toggle('active');
|
||||
});
|
||||
|
||||
// Close menu when a navigation link is clicked
|
||||
mobileMenuLinks.forEach(link => {
|
||||
link.addEventListener('click', () => {
|
||||
burgerIcon.classList.remove('active');
|
||||
mobileMenu.classList.remove('active');
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
27
src/components/Hero.astro
Normal 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>
|
||||
48
src/components/HoverCard.astro
Normal file
@ -0,0 +1,48 @@
|
||||
---
|
||||
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>
|
||||
|
||||
<div class="hover-text">
|
||||
<div>
|
||||
<p set:html={description} />
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const hoverCards = document.querySelectorAll('.hover-card');
|
||||
|
||||
hoverCards.forEach(card => {
|
||||
card.addEventListener('click', (e) => {
|
||||
// Only toggle on mobile devices
|
||||
if (window.innerWidth <= 768) {
|
||||
e.preventDefault();
|
||||
|
||||
// Close all other active cards first
|
||||
hoverCards.forEach(otherCard => {
|
||||
if (otherCard !== card) {
|
||||
otherCard.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle current card
|
||||
card.classList.toggle('active');
|
||||
}
|
||||
});
|
||||
|
||||
// Close card when clicking outside (mobile only)
|
||||
document.addEventListener('click', (e) => {
|
||||
if (window.innerWidth <= 768 && !card.contains(e.target)) {
|
||||
card.classList.remove('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
114
src/components/ImageCarousel.astro
Normal 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">❮</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">❯</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>
|
||||
@ -2,6 +2,9 @@
|
||||
// src/components/Layout.astro
|
||||
import Header from "./Header.astro";
|
||||
import Footer from "./Footer.astro";
|
||||
import "../styles/components/Layout.css"
|
||||
import "../styles/variables.css"
|
||||
import "../styles/index.css"
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
@ -13,8 +16,6 @@ import Footer from "./Footer.astro";
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Gallus Pub</title>
|
||||
<link rel="stylesheet" href="/Gallus_Pub_v1/styles/index.css" />
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@ -1,13 +1,16 @@
|
||||
---
|
||||
// src/components/Welcome.astro
|
||||
import "../../styles/components/Welcome.css"
|
||||
import "../styles/components/Welcome.css"
|
||||
|
||||
const { id } = Astro.props;
|
||||
---
|
||||
|
||||
<section class="welcome container">
|
||||
<section id={id} class="welcome container">
|
||||
|
||||
<div class="welcome-text">
|
||||
|
||||
<h2>Herzlich willkommen im Gallus Pub!</h2>
|
||||
<h2>Herzlich willkommen im</h2>
|
||||
<h2>Gallus Pub!</h2>
|
||||
|
||||
<p>
|
||||
Wie die meisten bereits wissen, ist hier jeder willkommen - ob jung
|
||||
@ -49,7 +52,7 @@ import "../../styles/components/Welcome.css"
|
||||
|
||||
|
||||
<div class="welcome-image">
|
||||
<img src="/images/Welcome.png" alt="Welcome backgrount image" />
|
||||
<img src="/images/Welcome.png" alt="Welcome background image" />
|
||||
</div>
|
||||
|
||||
</section>
|
||||
88
src/pages/index.astro
Normal file
@ -0,0 +1,88 @@
|
||||
---
|
||||
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/Event3.png",
|
||||
title: "Karaoke tes",
|
||||
date: "Mittwoch - Samstag",
|
||||
description: `
|
||||
`,
|
||||
},
|
||||
{
|
||||
image: "/images/Event2.png",
|
||||
title: "Karaoke test",
|
||||
date: "Mittwoch - Samstag",
|
||||
description: `
|
||||
`,
|
||||
},
|
||||
{
|
||||
image: "/images/Event1.png",
|
||||
title: "Crepes Sucette <br /> Live Music im Gallus Pub!",
|
||||
date: "Do, 04. September 2025",
|
||||
description: `
|
||||
<b>ab 19 Uhr geht’s los, bis max. 21.30 Uhr</b> <br>
|
||||
Kosten? CHF 10 pro Spielgast
|
||||
Reservieren unter <a href="tel:+41772322770">077 232 27 70</a>
|
||||
`,
|
||||
},
|
||||
{
|
||||
image: "/images/Event4.png",
|
||||
title: "Kevin McFlannigan <br> Live Music im Gallus Pub!",
|
||||
date: "Sa, 27. September 2025",
|
||||
description: `
|
||||
<b>ab 20:00 Uhr</b> <br>
|
||||
Eintritt ist Frei / Hutkollekte <br>
|
||||
Reservieren unter <a href="tel:+41772322770">077 232 27 70</a>
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
const images = [
|
||||
{ src: "/images/Gallery7.png", alt: "Siebtes Bild" },
|
||||
{ src: "/images/Gallery8.png", alt: "Achtes Bild" },
|
||||
{ src: "/images/Gallery9.png", alt: "Neuntes Bild" },
|
||||
{ src: "/images/Gallery6.png", alt: "Sechstes Bild" },
|
||||
{ src: "/images/Gallery1.png", alt: "Erstes Bild" },
|
||||
{ src: "/images/Gallery2.png", alt: "Zweites Bild" },
|
||||
{ src: "/images/Gallery3.png", alt: "Drittes Bild" },
|
||||
{ src: "/images/Gallery4.png", alt: "Viertes Bild" },
|
||||
{ src: "/images/Gallery5.png", alt: "Fünftes Bild" },
|
||||
];
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<Hero id="hero" />
|
||||
<Welcome id="welcome" />
|
||||
<EventsGrid id="events" events={events} />
|
||||
<ImageCarousel id="gallery" images={images} />
|
||||
<Drinks id="drinks" />
|
||||
</Layout>
|
||||
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
9
src/public/favicon.svg
Normal 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 |
|
Before Width: | Height: | Size: 506 KiB After Width: | Height: | Size: 506 KiB |
BIN
src/public/images/Logo.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
src/public/images/Welcome.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
src/public/images/crepes_sucette.jpg
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
src/public/images/karaoke.jpg
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
src/public/images/kevin_mcflannigan.jpeg
Normal file
|
After Width: | Height: | Size: 384 KiB |
BIN
src/public/images/pub_quiz.jpg
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
src/public/pdf/Menu.pdf
Normal file
125
src/styles/components/ContactForm.css
Normal file
@ -0,0 +1,125 @@
|
||||
.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;
|
||||
}
|
||||
}
|
||||
205
src/styles/components/Drinks.css
Normal file
@ -0,0 +1,205 @@
|
||||
.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: 0.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-top: 2.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;
|
||||
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: 35vh;
|
||||
width: 35vh;
|
||||
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;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.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;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.circle:hover .circle-label {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.circle-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
border-radius: 50%;
|
||||
z-index: 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-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;
|
||||
}
|
||||
}
|
||||
28
src/styles/components/EventsGrid.css
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -13,9 +13,9 @@
|
||||
|
||||
.copyright {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
margin-top: 2rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.footer-sections {
|
||||
190
src/styles/components/Header.css
Normal file
@ -0,0 +1,190 @@
|
||||
.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);
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #444;
|
||||
}
|
||||
|
||||
.header-spacer {
|
||||
height: 70px;
|
||||
/* Should match the header height */
|
||||
}
|
||||
|
||||
/* Desktop Layout */
|
||||
.desktop-layout {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1rem 2rem;
|
||||
height: 70px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Mobile Layout */
|
||||
.mobile-layout {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.mobile-logo-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.mobile-logo-container .logo {
|
||||
margin: 0;
|
||||
height: 3.5em;
|
||||
}
|
||||
|
||||
/* Burger Menu Styles */
|
||||
.burger-menu {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.burger-icon {
|
||||
width: 30px;
|
||||
height: 24px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.burger-icon span {
|
||||
display: block;
|
||||
height: 3px;
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
border-radius: 3px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.burger-icon.active span:nth-child(1) {
|
||||
transform: translateY(10.5px) rotate(45deg);
|
||||
}
|
||||
|
||||
.burger-icon.active span:nth-child(2) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.burger-icon.active span:nth-child(3) {
|
||||
transform: translateY(-10.5px) rotate(-45deg);
|
||||
}
|
||||
|
||||
/* Mobile Menu Styles */
|
||||
.mobile-menu {
|
||||
display: none;
|
||||
width: 100%;
|
||||
background-color: #0e0c0c;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.mobile-menu.active {
|
||||
max-height: 300px; /* Adjust based on content */
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.mobile-menu a {
|
||||
margin: 0.5rem 0;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 1.2rem;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
padding: 0.5rem 0;
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
|
||||
.mobile-menu a:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.mobile-menu a:hover {
|
||||
color: #ffa500;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.header-spacer {
|
||||
height: 120px; /* Adjusted for the taller mobile header */
|
||||
}
|
||||
|
||||
/* Hide desktop layout, show mobile layout */
|
||||
.desktop-layout {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-layout {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Show mobile menu when active */
|
||||
.mobile-menu.active {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.header-spacer {
|
||||
height: 110px; /* Slightly smaller for very small screens */
|
||||
}
|
||||
|
||||
.mobile-logo-container .logo {
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.burger-icon {
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||