This commit is contained in:
Bastian Masanek
2025-10-30 08:24:44 +01:00
commit 6e50ec7034
73 changed files with 27355 additions and 0 deletions

5
app/app.vue Normal file
View File

@@ -0,0 +1,5 @@
<template>
<div>
<NuxtPage />
</div>
</template>

View File

@@ -0,0 +1,152 @@
<script setup lang="ts">
const currentYear = new Date().getFullYear()
</script>
<template>
<footer class="footer">
<div class="footer-content">
<div class="footer-main">
<!-- Logo & Description Column -->
<div class="footer-section">
<div class="footer-logo">
<NuxtLink to="/">
<img src="/img/experimenta-logo-white.svg" alt="experimenta Logo" class="footer-logo-svg" />
</NuxtLink>
</div>
<p>
experimenta ist Deutschlands größtes Science Center. Mit über 275 Mitmachstationen, vier
Kreativstudios, neun Laboren und einer Sternwarte.
</p>
</div>
<!-- Quick Links Column -->
<div class="footer-section">
<h3>Rechtliches</h3>
<ul class="footer-links">
<li><a href="#">Impressum</a></li>
<li><a href="#">Datenschutz</a></li>
<li><a href="#">AGB</a></li>
</ul>
</div>
<!-- Info Column -->
<div class="footer-section">
<h3>Über uns</h3>
<ul class="footer-links">
<li><a href="#">experimenta Shop</a></li>
<li><a href="#">Kontakt</a></li>
</ul>
</div>
<!-- Contact Column -->
<div class="footer-section">
<h3>Kontakt</h3>
<p>experimenta gGmbH<br />Kranenstraße 14<br />74072 Heilbronn</p>
<p>
<a href="mailto:info@experimenta.science" class="footer-link">info@experimenta.science</a>
</p>
</div>
</div>
<!-- Footer Bottom -->
<div class="footer-bottom">
<p>&copy; {{ currentYear }} experimenta gGmbH. Alle Rechte vorbehalten.</p>
</div>
</div>
</footer>
</template>
<style scoped>
.footer {
background: linear-gradient(135deg, #1a0a3a 0%, #0f051d 100%);
margin-top: 80px;
position: relative;
}
.footer-content {
max-width: 1200px;
margin: 0 auto;
padding: 60px 20px 30px;
}
.footer-main {
display: grid;
grid-template-columns: 2.5fr 1fr 1fr 1.5fr;
gap: 50px;
margin-bottom: 50px;
}
.footer-section h3 {
color: #f59d24;
margin-bottom: 20px;
font-size: 1.25rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.footer-section p {
margin-bottom: 15px;
color: rgba(255, 255, 255, 0.8);
line-height: 1.6;
font-size: 14px;
}
.footer-links {
list-style: none;
padding: 0;
margin: 0;
}
.footer-links li {
margin-bottom: 8px;
}
.footer-links a,
.footer-link {
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
font-size: 14px;
transition: color 0.3s ease;
}
.footer-links a:hover,
.footer-link:hover {
color: #ff4081;
}
.footer-logo {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.footer-logo-svg {
width: 200px;
height: auto;
}
.footer-bottom {
border-top: 1px solid rgba(255, 255, 255, 0.1);
padding-top: 30px;
text-align: center;
}
.footer-bottom p {
color: rgba(255, 255, 255, 0.8);
font-size: 14px;
margin: 0;
}
/* Responsive Design */
@media (max-width: 768px) {
.footer-main {
grid-template-columns: 1fr;
gap: 30px;
}
.footer-logo-svg {
width: 150px;
}
}
</style>

View File

@@ -0,0 +1,63 @@
<script setup lang="ts">
// experimenta header with branding
</script>
<template>
<header class="header-wrapper">
<div class="header-content">
<NuxtLink to="/" class="logo">
<img src="/img/experimenta-logo-white.svg" alt="experimenta Logo" class="logo-svg" />
</NuxtLink>
</div>
</header>
</template>
<style scoped>
.header-wrapper {
background: rgba(46, 16, 101, 0.95);
backdrop-filter: blur(10px);
position: relative;
z-index: 100;
padding: 30px 0;
}
.header-content {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
display: flex;
justify-content: center;
align-items: center;
}
.logo {
display: flex;
align-items: center;
text-decoration: none;
color: white;
transition: all 0.3s ease;
}
.logo:hover {
transform: scale(1.05);
}
.logo-svg {
width: 300px;
height: auto;
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
}
@media (max-width: 768px) {
.logo-svg {
width: 250px;
max-width: 90%;
}
}
@media (max-width: 480px) {
.logo-svg {
width: 200px;
}
}
</style>

View File

@@ -0,0 +1,28 @@
<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import type { ButtonVariants } from '.'
import { Primitive } from 'reka-ui'
import { cn } from '~/lib/utils'
import { buttonVariants } from '.'
interface Props extends PrimitiveProps {
variant?: ButtonVariants['variant']
size?: ButtonVariants['size']
class?: HTMLAttributes['class']
}
const props = withDefaults(defineProps<Props>(), {
as: 'button',
})
</script>
<template>
<Primitive
:as="as"
:as-child="asChild"
:class="cn(buttonVariants({ variant, size }), props.class)"
>
<slot />
</Primitive>
</template>

View File

@@ -0,0 +1,36 @@
import type { VariantProps } from 'class-variance-authority'
import { cva } from 'class-variance-authority'
export { default as Button } from './Button.vue'
export const buttonVariants = cva(
'inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{
variants: {
variant: {
default: 'btn-experimenta',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90 rounded-md',
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground rounded-md',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80 rounded-md',
ghost: 'hover:bg-accent hover:text-accent-foreground rounded-md',
link: 'text-primary underline-offset-4 hover:underline',
experimenta: 'btn-experimenta',
},
size: {
default: 'px-[30px] py-[10px] text-lg leading-[1.7em]',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10',
'icon-sm': 'size-9',
'icon-lg': 'size-11',
experimenta: 'px-[30px] py-[10px] text-lg leading-[1.7em]',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
}
)
export type ButtonVariants = VariantProps<typeof buttonVariants>

18
app/layouts/default.vue Normal file
View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
// Default layout with Header and Footer components
</script>
<template>
<div class="min-h-screen flex flex-col">
<!-- Header -->
<CommonHeader />
<!-- Main content -->
<main class="flex-1">
<slot />
</main>
<!-- Footer -->
<CommonFooter />
</div>
</template>

10
app/lib/utils.ts Normal file
View File

@@ -0,0 +1,10 @@
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
/**
* Utility function to merge Tailwind CSS classes
* Combines clsx for conditional classes and twMerge for Tailwind-specific merging
*/
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

68
app/pages/index.vue Normal file
View File

@@ -0,0 +1,68 @@
<script setup lang="ts">
// Home page - MVP placeholder with shadcn-nuxt test
// Sample button click handler
const handleClick = () => {
console.log('shadcn-nuxt Button clicked!')
}
</script>
<template>
<NuxtLayout name="default">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<h1 class="text-4xl font-bold mb-4">Welcome to experimenta Shop</h1>
<p class="text-lg mb-8 text-white/90">Your gateway to Makerspace annual passes and more.</p>
<div class="card-info mb-8">
<h2 class="text-xl font-semibold mb-2">MVP Development in Progress</h2>
<p>
This is a placeholder page. The full e-commerce functionality will be implemented in
upcoming phases.
</p>
</div>
<!-- experimenta Button Showcase -->
<div class="card-glass mb-8">
<h3 class="text-xl font-semibold mb-4 text-experimenta-accent">experimenta Button</h3>
<p class="mb-6 text-white/90">
Der offizielle experimenta-Button mit animiertem Gradient-Effekt beim Hovern:
</p>
<div class="flex flex-wrap gap-4 items-center">
<UiButton variant="experimenta" size="experimenta" as="a" href="https://www.experimenta.science/">
Zur experimenta Startseite
</UiButton>
<UiButton variant="experimenta" size="experimenta" @click="handleClick">
Mit Click Handler
</UiButton>
</div>
<p class="mt-6 text-sm text-white/70">
Hinweis: Der Button hat einen animierten Gradient-Effekt von Pink zu Rot beim Hovern.
</p>
</div>
<!-- shadcn-nuxt Button Component Test -->
<div class="card-glass">
<h3 class="text-xl font-semibold mb-4 text-experimenta-accent">shadcn-nuxt Components Test</h3>
<p class="mb-6 text-white/90">Testing shadcn-nuxt Button component integration:</p>
<div class="flex flex-wrap gap-4">
<UiButton variant="default" @click="handleClick"> Default Button </UiButton>
<UiButton variant="destructive" @click="handleClick"> Destructive </UiButton>
<UiButton variant="outline" @click="handleClick"> Outline </UiButton>
<UiButton variant="secondary" @click="handleClick"> Secondary </UiButton>
<UiButton variant="ghost" @click="handleClick"> Ghost </UiButton>
<UiButton variant="link" @click="handleClick"> Link </UiButton>
</div>
<p class="mt-6 text-sm text-white/70">Open browser console to see button click events.</p>
</div>
</div>
</NuxtLayout>
</template>