feat(landing): Add landing Nuxt page
This commit is contained in:
24
landing/.gitignore
vendored
Normal file
24
landing/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
1
landing/.npmrc
Normal file
1
landing/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
shamefully-hoist=true
|
||||
1
landing/.nvmrc
Normal file
1
landing/.nvmrc
Normal file
@@ -0,0 +1 @@
|
||||
22
|
||||
7
landing/.prettierignore
Normal file
7
landing/.prettierignore
Normal file
@@ -0,0 +1,7 @@
|
||||
# Ignore artifacts:
|
||||
build
|
||||
coverage
|
||||
.nuxt
|
||||
.output
|
||||
.api-client
|
||||
pnpm-lock.yaml
|
||||
6
landing/.prettierrc
Normal file
6
landing/.prettierrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"trailingComma": "none",
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 120
|
||||
}
|
||||
75
landing/README.md
Normal file
75
landing/README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Nuxt Minimal Starter
|
||||
|
||||
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
Make sure to install dependencies:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
|
||||
# pnpm
|
||||
pnpm install
|
||||
|
||||
# yarn
|
||||
yarn install
|
||||
|
||||
# bun
|
||||
bun install
|
||||
```
|
||||
|
||||
## Development Server
|
||||
|
||||
Start the development server on `http://localhost:3000`:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run dev
|
||||
|
||||
# pnpm
|
||||
pnpm dev
|
||||
|
||||
# yarn
|
||||
yarn dev
|
||||
|
||||
# bun
|
||||
bun run dev
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
Build the application for production:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run build
|
||||
|
||||
# pnpm
|
||||
pnpm build
|
||||
|
||||
# yarn
|
||||
yarn build
|
||||
|
||||
# bun
|
||||
bun run build
|
||||
```
|
||||
|
||||
Locally preview production build:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run preview
|
||||
|
||||
# pnpm
|
||||
pnpm preview
|
||||
|
||||
# yarn
|
||||
yarn preview
|
||||
|
||||
# bun
|
||||
bun run preview
|
||||
```
|
||||
|
||||
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||
98
landing/app/app.config.ts
Normal file
98
landing/app/app.config.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
// Primary color for the app - Teal
|
||||
colors: {
|
||||
primary: 'primary',
|
||||
neutral: 'slate',
|
||||
success: 'success',
|
||||
warning: 'warning',
|
||||
error: 'red'
|
||||
},
|
||||
|
||||
// Button customizations
|
||||
button: {
|
||||
defaultVariants: {
|
||||
size: 'lg'
|
||||
}
|
||||
},
|
||||
|
||||
// Card customizations with enhanced hover states
|
||||
card: {
|
||||
slots: {
|
||||
root: 'rounded-2xl overflow-hidden transition-all duration-300'
|
||||
}
|
||||
},
|
||||
|
||||
// Page Hero customizations for landing page
|
||||
pageHero: {
|
||||
slots: {
|
||||
root: 'relative isolate overflow-hidden',
|
||||
title: 'font-heading text-5xl sm:text-6xl lg:text-7xl text-pretty tracking-tight font-bold text-highlighted',
|
||||
description: 'text-lg sm:text-xl text-muted max-w-3xl'
|
||||
}
|
||||
},
|
||||
|
||||
// Page Section customizations
|
||||
pageSection: {
|
||||
slots: {
|
||||
title: 'font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-highlighted',
|
||||
description: 'text-base sm:text-lg text-muted'
|
||||
}
|
||||
},
|
||||
|
||||
// Page Feature customizations
|
||||
pageFeature: {
|
||||
slots: {
|
||||
title: 'text-lg font-semibold text-highlighted',
|
||||
description: 'text-base text-muted'
|
||||
}
|
||||
},
|
||||
|
||||
// Page Card customizations
|
||||
pageCard: {
|
||||
slots: {
|
||||
root: 'rounded-2xl transition-all duration-300',
|
||||
title: 'text-lg font-semibold text-highlighted',
|
||||
description: 'text-base text-muted'
|
||||
}
|
||||
},
|
||||
|
||||
// Page CTA customizations
|
||||
pageCTA: {
|
||||
slots: {
|
||||
title: 'font-heading text-3xl sm:text-4xl text-pretty tracking-tight font-bold',
|
||||
description: 'text-base sm:text-lg'
|
||||
}
|
||||
},
|
||||
|
||||
// Header customizations - transparent with blur
|
||||
header: {
|
||||
slots: {
|
||||
root: 'bg-white/80 dark:bg-gray-950/80 backdrop-blur-xl border-b border-gray-200/50 dark:border-gray-800/50',
|
||||
title: 'font-heading text-xl font-bold'
|
||||
}
|
||||
},
|
||||
|
||||
// Footer customizations
|
||||
footer: {
|
||||
slots: {
|
||||
root: 'border-t border-gray-200 dark:border-gray-800'
|
||||
}
|
||||
},
|
||||
|
||||
// Input customizations for newsletter form
|
||||
input: {
|
||||
defaultVariants: {
|
||||
size: 'lg'
|
||||
}
|
||||
},
|
||||
|
||||
// Accordion customizations
|
||||
accordion: {
|
||||
slots: {
|
||||
trigger: 'text-base font-medium',
|
||||
content: 'text-base text-muted'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
222
landing/app/app.vue
Normal file
222
landing/app/app.vue
Normal file
@@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<UApp>
|
||||
<!-- Skip link for accessibility -->
|
||||
<a href="#main-content" class="skip-link"> Zum Hauptinhalt springen </a>
|
||||
|
||||
<NuxtRouteAnnouncer />
|
||||
|
||||
<!-- Header with transparent background and blur on scroll -->
|
||||
<UHeader
|
||||
:title="'LegalConsentHub'"
|
||||
:ui="{
|
||||
root: [
|
||||
'fixed top-0 left-0 right-0 z-50 transition-all duration-300',
|
||||
isScrolled
|
||||
? 'bg-white/90 dark:bg-gray-950/90 backdrop-blur-xl shadow-sm border-b border-gray-200/50 dark:border-gray-800/50'
|
||||
: 'bg-transparent border-transparent'
|
||||
].join(' ')
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<NuxtLink to="/" class="flex items-center gap-3 group">
|
||||
<div
|
||||
class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center shadow-lg shadow-primary-500/25 group-hover:shadow-primary-500/40 transition-shadow"
|
||||
>
|
||||
<UIcon name="i-lucide-scale" class="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<span
|
||||
class="font-heading text-xl font-bold bg-gradient-to-r from-primary-600 to-cyan-600 bg-clip-text text-transparent"
|
||||
>
|
||||
LegalConsentHub
|
||||
</span>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
<UNavigationMenu
|
||||
:items="navigationItems"
|
||||
:ui="{
|
||||
link: 'text-gray-700 dark:text-gray-200 hover:text-primary-600 dark:hover:text-primary-400 font-medium transition-colors'
|
||||
}"
|
||||
/>
|
||||
|
||||
<template #right>
|
||||
<UColorModeButton
|
||||
:ui="{
|
||||
base: 'text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400'
|
||||
}"
|
||||
/>
|
||||
<UButton
|
||||
to="#newsletter"
|
||||
class="btn-gradient px-5 py-2.5 rounded-xl font-semibold shadow-lg shadow-primary-500/25 hover:shadow-primary-500/40 transition-shadow"
|
||||
>
|
||||
<span>Informiert bleiben</span>
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
<template #body>
|
||||
<UNavigationMenu
|
||||
:items="navigationItems"
|
||||
orientation="vertical"
|
||||
class="-mx-2.5"
|
||||
:ui="{
|
||||
link: 'text-gray-700 dark:text-gray-200 hover:text-primary-600 dark:hover:text-primary-400 font-medium'
|
||||
}"
|
||||
/>
|
||||
<div class="mt-6 pt-6 border-t border-gray-200 dark:border-gray-800">
|
||||
<UButton to="#newsletter" size="lg" block class="btn-gradient rounded-xl font-semibold">
|
||||
Informiert bleiben
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UHeader>
|
||||
|
||||
<!-- Main Content -->
|
||||
<UMain id="main-content">
|
||||
<NuxtPage />
|
||||
</UMain>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-800">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 lg:py-16">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-8 lg:gap-12">
|
||||
<!-- Brand column -->
|
||||
<div class="md:col-span-2">
|
||||
<NuxtLink to="/" class="flex items-center gap-3 mb-4">
|
||||
<div
|
||||
class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center"
|
||||
>
|
||||
<UIcon name="i-lucide-scale" class="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<span class="font-heading text-xl font-bold text-gray-900 dark:text-white"> LegalConsentHub </span>
|
||||
</NuxtLink>
|
||||
<p class="text-gray-600 dark:text-gray-400 max-w-sm mb-6">
|
||||
Digitale Mitbestimmung für IT- und KI-Systeme. Strukturierte Prozesse, revisionssichere Dokumentation.
|
||||
</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<UButton
|
||||
icon="i-lucide-linkedin"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
to="https://linkedin.com"
|
||||
target="_blank"
|
||||
aria-label="LinkedIn"
|
||||
class="hover:text-primary-600 dark:hover:text-primary-400"
|
||||
/>
|
||||
<UButton
|
||||
icon="i-lucide-mail"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
to="mailto:info@legalconsenthub.de"
|
||||
aria-label="E-Mail"
|
||||
class="hover:text-primary-600 dark:hover:text-primary-400"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Links column -->
|
||||
<div>
|
||||
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">Navigation</h4>
|
||||
<ul class="space-y-3">
|
||||
<li v-for="item in navigationItems" :key="item.label">
|
||||
<NuxtLink
|
||||
:to="item.to"
|
||||
class="text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
||||
>
|
||||
{{ item.label }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Legal column -->
|
||||
<div>
|
||||
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">Rechtliches</h4>
|
||||
<ul class="space-y-3">
|
||||
<li v-for="item in footerLinks" :key="item.label">
|
||||
<NuxtLink
|
||||
:to="item.to"
|
||||
class="text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
||||
>
|
||||
{{ item.label }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom bar -->
|
||||
<div class="mt-12 pt-8 border-t border-gray-200 dark:border-gray-800">
|
||||
<div class="flex flex-col sm:flex-row justify-between items-center gap-4">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
© {{ new Date().getFullYear() }} LegalConsentHub. Alle Rechte vorbehalten.
|
||||
</p>
|
||||
<div class="flex items-center gap-6 text-sm text-gray-500 dark:text-gray-400">
|
||||
<div class="flex items-center gap-2">
|
||||
<UIcon name="i-lucide-server" class="w-4 h-4" />
|
||||
<span>Hosted in Germany</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<UIcon name="i-lucide-shield-check" class="w-4 h-4" />
|
||||
<span>DSGVO-konform</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</UApp>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||
|
||||
// Track scroll position for header styling
|
||||
const isScrolled = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
const handleScroll = () => {
|
||||
isScrolled.value = window.scrollY > 50
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true })
|
||||
handleScroll() // Check initial position
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
})
|
||||
})
|
||||
|
||||
const navigationItems = computed<NavigationMenuItem[]>(() => [
|
||||
{
|
||||
label: 'Für Betriebsräte',
|
||||
to: '#betriebsraete'
|
||||
},
|
||||
{
|
||||
label: 'Für Unternehmen',
|
||||
to: '#unternehmen'
|
||||
},
|
||||
{
|
||||
label: 'Features',
|
||||
to: '#features'
|
||||
},
|
||||
{
|
||||
label: 'Kontakt',
|
||||
to: '#kontakt'
|
||||
}
|
||||
])
|
||||
|
||||
const footerLinks = computed<NavigationMenuItem[]>(() => [
|
||||
{
|
||||
label: 'Impressum',
|
||||
to: '/impressum'
|
||||
},
|
||||
{
|
||||
label: 'Datenschutz',
|
||||
to: '/datenschutz'
|
||||
},
|
||||
{
|
||||
label: 'AGB',
|
||||
to: '/agb'
|
||||
}
|
||||
])
|
||||
</script>
|
||||
820
landing/app/assets/css/main.css
Normal file
820
landing/app/assets/css/main.css
Normal file
@@ -0,0 +1,820 @@
|
||||
@import 'tailwindcss';
|
||||
@import '@nuxt/ui';
|
||||
|
||||
/* Theme configuration with new teal/cyan/violet palette */
|
||||
@theme {
|
||||
/* Typography - Bricolage Grotesque for headings, DM Sans for body */
|
||||
--font-sans: 'DM Sans', system-ui, sans-serif;
|
||||
--font-heading: 'Bricolage Grotesque', system-ui, sans-serif;
|
||||
|
||||
/* Primary color - Teal/Cyan gradient base */
|
||||
--color-primary-50: #f0fdfa;
|
||||
--color-primary-100: #ccfbf1;
|
||||
--color-primary-200: #99f6e4;
|
||||
--color-primary-300: #5eead4;
|
||||
--color-primary-400: #2dd4bf;
|
||||
--color-primary-500: #14b8a6;
|
||||
--color-primary-600: #0d9488;
|
||||
--color-primary-700: #0f766e;
|
||||
--color-primary-800: #115e59;
|
||||
--color-primary-900: #134e4a;
|
||||
--color-primary-950: #042f2e;
|
||||
|
||||
/* Accent color - Violet for highlights */
|
||||
--color-accent-50: #f5f3ff;
|
||||
--color-accent-100: #ede9fe;
|
||||
--color-accent-200: #ddd6fe;
|
||||
--color-accent-300: #c4b5fd;
|
||||
--color-accent-400: #a78bfa;
|
||||
--color-accent-500: #8b5cf6;
|
||||
--color-accent-600: #7c3aed;
|
||||
--color-accent-700: #6d28d9;
|
||||
--color-accent-800: #5b21b6;
|
||||
--color-accent-900: #4c1d95;
|
||||
--color-accent-950: #2e1065;
|
||||
|
||||
/* Cyan for gradient effects */
|
||||
--color-cyan-50: #ecfeff;
|
||||
--color-cyan-100: #cffafe;
|
||||
--color-cyan-200: #a5f3fc;
|
||||
--color-cyan-300: #67e8f9;
|
||||
--color-cyan-400: #22d3ee;
|
||||
--color-cyan-500: #06b6d4;
|
||||
--color-cyan-600: #0891b2;
|
||||
--color-cyan-700: #0e7490;
|
||||
--color-cyan-800: #155e75;
|
||||
--color-cyan-900: #164e63;
|
||||
--color-cyan-950: #083344;
|
||||
|
||||
/* Success color - Emerald */
|
||||
--color-success-50: #ecfdf5;
|
||||
--color-success-100: #d1fae5;
|
||||
--color-success-200: #a7f3d0;
|
||||
--color-success-300: #6ee7b7;
|
||||
--color-success-400: #34d399;
|
||||
--color-success-500: #10b981;
|
||||
--color-success-600: #059669;
|
||||
--color-success-700: #047857;
|
||||
--color-success-800: #065f46;
|
||||
--color-success-900: #064e3b;
|
||||
--color-success-950: #022c22;
|
||||
|
||||
/* Warning color - Amber */
|
||||
--color-warning-50: #fffbeb;
|
||||
--color-warning-100: #fef3c7;
|
||||
--color-warning-200: #fde68a;
|
||||
--color-warning-300: #fcd34d;
|
||||
--color-warning-400: #fbbf24;
|
||||
--color-warning-500: #f59e0b;
|
||||
--color-warning-600: #d97706;
|
||||
--color-warning-700: #b45309;
|
||||
--color-warning-800: #92400e;
|
||||
--color-warning-900: #78350f;
|
||||
--color-warning-950: #451a03;
|
||||
|
||||
/* Animation durations */
|
||||
--animate-duration-slow: 1s;
|
||||
--animate-duration-normal: 0.5s;
|
||||
--animate-duration-fast: 0.2s;
|
||||
}
|
||||
|
||||
/* Heading styles with Bricolage Grotesque */
|
||||
.font-heading {
|
||||
font-family: var(--font-heading);
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-family: var(--font-heading);
|
||||
}
|
||||
|
||||
/* Gradient text effect */
|
||||
.gradient-text {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
var(--color-primary-500) 0%,
|
||||
var(--color-cyan-500) 50%,
|
||||
var(--color-accent-500) 100%
|
||||
);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.gradient-text-teal {
|
||||
background: linear-gradient(135deg, var(--color-primary-600) 0%, var(--color-cyan-500) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ANIMATIONS
|
||||
============================================ */
|
||||
|
||||
/* Fade in up animation */
|
||||
@keyframes fade-in-up {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fade in animation */
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Float animation for orbs */
|
||||
@keyframes orb-float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translate(0, 0) scale(1);
|
||||
}
|
||||
25% {
|
||||
transform: translate(10px, -20px) scale(1.05);
|
||||
}
|
||||
50% {
|
||||
transform: translate(-5px, -10px) scale(0.95);
|
||||
}
|
||||
75% {
|
||||
transform: translate(-15px, -25px) scale(1.02);
|
||||
}
|
||||
}
|
||||
|
||||
/* Slower float for large elements - more noticeable movement */
|
||||
@keyframes float-slow {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-15px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fast float for small elements */
|
||||
@keyframes float-fast {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px) rotate(2deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Gradient rotation for backgrounds */
|
||||
@keyframes gradient-rotate {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Shimmer effect */
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pulse glow effect */
|
||||
@keyframes pulse-glow {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 0.5;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.8;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
/* Particle drift */
|
||||
@keyframes particle-drift {
|
||||
0% {
|
||||
transform: translate(0, 0) rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
10% {
|
||||
opacity: 1;
|
||||
}
|
||||
90% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translate(var(--drift-x, 100px), var(--drift-y, -100px)) rotate(360deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scale in animation */
|
||||
@keyframes scale-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Border gradient animation */
|
||||
@keyframes border-dance {
|
||||
0%,
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Count up number animation */
|
||||
@keyframes count-pulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tilt hover animation */
|
||||
@keyframes tilt-hover {
|
||||
0%,
|
||||
100% {
|
||||
transform: perspective(1000px) rotateX(0deg) rotateY(0deg);
|
||||
}
|
||||
25% {
|
||||
transform: perspective(1000px) rotateX(2deg) rotateY(-2deg);
|
||||
}
|
||||
75% {
|
||||
transform: perspective(1000px) rotateX(-2deg) rotateY(2deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ANIMATION UTILITY CLASSES
|
||||
============================================ */
|
||||
|
||||
.animate-fade-in-up {
|
||||
animation: fade-in-up 0.7s ease-out forwards;
|
||||
}
|
||||
|
||||
.animate-fade-in {
|
||||
animation: fade-in 0.5s ease-out forwards;
|
||||
}
|
||||
|
||||
.animate-orb-float {
|
||||
animation: orb-float 20s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-float-slow {
|
||||
animation: float-slow 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-float-fast {
|
||||
animation: float-fast 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-gradient-rotate {
|
||||
animation: gradient-rotate 20s linear infinite;
|
||||
}
|
||||
|
||||
.animate-shimmer {
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 2s infinite;
|
||||
}
|
||||
|
||||
.animate-pulse-glow {
|
||||
animation: pulse-glow 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-scale-in {
|
||||
animation: scale-in 0.6s ease-out forwards;
|
||||
}
|
||||
|
||||
.animate-border-dance {
|
||||
background-size: 200% 200%;
|
||||
animation: border-dance 4s ease infinite;
|
||||
}
|
||||
|
||||
.animate-tilt-hover {
|
||||
animation: tilt-hover 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Staggered animation delays */
|
||||
.delay-75 {
|
||||
animation-delay: 75ms;
|
||||
}
|
||||
.delay-100 {
|
||||
animation-delay: 100ms;
|
||||
}
|
||||
.delay-150 {
|
||||
animation-delay: 150ms;
|
||||
}
|
||||
.delay-200 {
|
||||
animation-delay: 200ms;
|
||||
}
|
||||
.delay-300 {
|
||||
animation-delay: 300ms;
|
||||
}
|
||||
.delay-400 {
|
||||
animation-delay: 400ms;
|
||||
}
|
||||
.delay-500 {
|
||||
animation-delay: 500ms;
|
||||
}
|
||||
.delay-600 {
|
||||
animation-delay: 600ms;
|
||||
}
|
||||
.delay-700 {
|
||||
animation-delay: 700ms;
|
||||
}
|
||||
.delay-800 {
|
||||
animation-delay: 800ms;
|
||||
}
|
||||
.delay-1000 {
|
||||
animation-delay: 1000ms;
|
||||
}
|
||||
|
||||
/* Initial state for animated elements */
|
||||
.animate-on-scroll {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.animate-on-scroll.is-visible {
|
||||
animation: fade-in-up 0.7s ease-out forwards;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
REDUCED MOTION SUPPORT
|
||||
============================================ */
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
|
||||
.animate-orb-float,
|
||||
.animate-float-slow,
|
||||
.animate-float-fast,
|
||||
.animate-gradient-rotate,
|
||||
.animate-shimmer,
|
||||
.animate-pulse-glow,
|
||||
.animate-border-dance,
|
||||
.animate-tilt-hover {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
GRADIENT BACKGROUNDS
|
||||
============================================ */
|
||||
|
||||
/* Light hero gradient with orbs */
|
||||
.hero-gradient-light {
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f0fdfa 50%, #ecfeff 100%);
|
||||
}
|
||||
|
||||
/* Dark hero gradient */
|
||||
.dark .hero-gradient-light {
|
||||
background: linear-gradient(180deg, #0a0a0a 0%, #042f2e 50%, #083344 100%);
|
||||
}
|
||||
|
||||
/* Gradient orb styles */
|
||||
.gradient-orb {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(80px);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.gradient-orb-teal {
|
||||
background: linear-gradient(135deg, var(--color-primary-400), var(--color-cyan-400));
|
||||
}
|
||||
|
||||
.gradient-orb-violet {
|
||||
background: linear-gradient(135deg, var(--color-accent-400), var(--color-accent-600));
|
||||
}
|
||||
|
||||
.gradient-orb-cyan {
|
||||
background: linear-gradient(135deg, var(--color-cyan-300), var(--color-primary-400));
|
||||
}
|
||||
|
||||
.dark .gradient-orb {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/* Mesh gradient for CTAs */
|
||||
.mesh-gradient-cta {
|
||||
background:
|
||||
radial-gradient(at 40% 20%, var(--color-primary-500) 0px, transparent 50%),
|
||||
radial-gradient(at 80% 0%, var(--color-cyan-400) 0px, transparent 50%),
|
||||
radial-gradient(at 0% 50%, var(--color-accent-500) 0px, transparent 50%),
|
||||
radial-gradient(at 80% 50%, var(--color-primary-400) 0px, transparent 50%),
|
||||
radial-gradient(at 0% 100%, var(--color-cyan-500) 0px, transparent 50%),
|
||||
linear-gradient(135deg, var(--color-primary-600) 0%, var(--color-accent-600) 100%);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
GLASS MORPHISM
|
||||
============================================ */
|
||||
|
||||
.glass {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.dark .glass {
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.glass-subtle {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.dark .glass-subtle {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
CARD EFFECTS
|
||||
============================================ */
|
||||
|
||||
/* Card with gradient border on hover */
|
||||
.card-gradient-border {
|
||||
position: relative;
|
||||
background: white;
|
||||
border-radius: 1rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.card-gradient-border::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: -2px;
|
||||
border-radius: inherit;
|
||||
background: linear-gradient(135deg, var(--color-primary-400), var(--color-cyan-400), var(--color-accent-400));
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.card-gradient-border:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.dark .card-gradient-border {
|
||||
background: #1a1a1a;
|
||||
}
|
||||
|
||||
/* Card hover lift effect - subtle version without clipping issues */
|
||||
.card-hover-lift {
|
||||
transition:
|
||||
transform 0.3s ease,
|
||||
box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.card-hover-lift:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow:
|
||||
0 10px 25px -5px rgba(0, 0, 0, 0.1),
|
||||
0 8px 10px -6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Spotlight effect for cards */
|
||||
.card-spotlight {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-spotlight::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(
|
||||
600px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
|
||||
rgba(20, 184, 166, 0.1),
|
||||
transparent 40%
|
||||
);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.card-spotlight:hover::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 3D tilt effect */
|
||||
.card-3d {
|
||||
transform-style: preserve-3d;
|
||||
perspective: 1000px;
|
||||
}
|
||||
|
||||
.card-3d-inner {
|
||||
transition: transform 0.3s ease;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.card-3d:hover .card-3d-inner {
|
||||
transform: rotateX(5deg) rotateY(-5deg);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
BUTTON STYLES
|
||||
============================================ */
|
||||
|
||||
/* Gradient button */
|
||||
.btn-gradient {
|
||||
background: linear-gradient(135deg, var(--color-primary-500) 0%, var(--color-cyan-500) 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-gradient::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(135deg, var(--color-cyan-500) 0%, var(--color-accent-500) 100%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-gradient:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn-gradient span {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Outline gradient button */
|
||||
.btn-outline-gradient {
|
||||
position: relative;
|
||||
background: transparent;
|
||||
border: 2px solid transparent;
|
||||
background-image:
|
||||
linear-gradient(white, white), linear-gradient(135deg, var(--color-primary-500), var(--color-cyan-500));
|
||||
background-origin: border-box;
|
||||
background-clip: padding-box, border-box;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dark .btn-outline-gradient {
|
||||
background-image:
|
||||
linear-gradient(#1a1a1a, #1a1a1a), linear-gradient(135deg, var(--color-primary-500), var(--color-cyan-500));
|
||||
}
|
||||
|
||||
.btn-outline-gradient:hover {
|
||||
background-image:
|
||||
linear-gradient(var(--color-primary-50), var(--color-primary-50)),
|
||||
linear-gradient(135deg, var(--color-primary-500), var(--color-cyan-500));
|
||||
}
|
||||
|
||||
.dark .btn-outline-gradient:hover {
|
||||
background-image:
|
||||
linear-gradient(var(--color-primary-950), var(--color-primary-950)),
|
||||
linear-gradient(135deg, var(--color-primary-500), var(--color-cyan-500));
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
DECORATIVE ELEMENTS
|
||||
============================================ */
|
||||
|
||||
/* Dots pattern */
|
||||
.dots-pattern {
|
||||
background-image: radial-gradient(var(--color-primary-200) 1px, transparent 1px);
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
|
||||
.dark .dots-pattern {
|
||||
background-image: radial-gradient(var(--color-primary-800) 1px, transparent 1px);
|
||||
}
|
||||
|
||||
/* Grid pattern */
|
||||
.grid-pattern {
|
||||
background-image:
|
||||
linear-gradient(to right, var(--color-primary-100) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, var(--color-primary-100) 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
}
|
||||
|
||||
.dark .grid-pattern {
|
||||
background-image:
|
||||
linear-gradient(to right, var(--color-primary-900) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, var(--color-primary-900) 1px, transparent 1px);
|
||||
}
|
||||
|
||||
/* Section divider with gradient */
|
||||
.section-divider {
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, var(--color-primary-300), var(--color-cyan-300), transparent);
|
||||
}
|
||||
|
||||
.dark .section-divider {
|
||||
background: linear-gradient(90deg, transparent, var(--color-primary-700), var(--color-cyan-700), transparent);
|
||||
}
|
||||
|
||||
/* Gradient line accent */
|
||||
.gradient-line {
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(90deg, var(--color-primary-500), var(--color-cyan-500), var(--color-accent-500));
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ACCESSIBILITY
|
||||
============================================ */
|
||||
|
||||
/* Focus styles */
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--color-primary-500);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Skip link */
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
top: -40px;
|
||||
left: 0;
|
||||
background: var(--color-primary-600);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
z-index: 100;
|
||||
transition: top 0.3s;
|
||||
border-radius: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.skip-link:focus {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
PARTICLES (for newsletter section)
|
||||
============================================ */
|
||||
|
||||
.particle {
|
||||
position: absolute;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-primary-400);
|
||||
opacity: 0;
|
||||
animation: particle-drift 8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.particle:nth-child(1) {
|
||||
--drift-x: 80px;
|
||||
--drift-y: -120px;
|
||||
animation-delay: 0s;
|
||||
left: 10%;
|
||||
top: 80%;
|
||||
}
|
||||
.particle:nth-child(2) {
|
||||
--drift-x: -60px;
|
||||
--drift-y: -100px;
|
||||
animation-delay: 1s;
|
||||
left: 20%;
|
||||
top: 70%;
|
||||
}
|
||||
.particle:nth-child(3) {
|
||||
--drift-x: 100px;
|
||||
--drift-y: -80px;
|
||||
animation-delay: 2s;
|
||||
left: 80%;
|
||||
top: 90%;
|
||||
}
|
||||
.particle:nth-child(4) {
|
||||
--drift-x: -80px;
|
||||
--drift-y: -140px;
|
||||
animation-delay: 3s;
|
||||
left: 70%;
|
||||
top: 75%;
|
||||
}
|
||||
.particle:nth-child(5) {
|
||||
--drift-x: 60px;
|
||||
--drift-y: -90px;
|
||||
animation-delay: 4s;
|
||||
left: 30%;
|
||||
top: 85%;
|
||||
}
|
||||
.particle:nth-child(6) {
|
||||
--drift-x: -100px;
|
||||
--drift-y: -110px;
|
||||
animation-delay: 5s;
|
||||
left: 90%;
|
||||
top: 80%;
|
||||
}
|
||||
.particle:nth-child(7) {
|
||||
--drift-x: 40px;
|
||||
--drift-y: -130px;
|
||||
animation-delay: 6s;
|
||||
left: 50%;
|
||||
top: 95%;
|
||||
}
|
||||
.particle:nth-child(8) {
|
||||
--drift-x: -40px;
|
||||
--drift-y: -70px;
|
||||
animation-delay: 7s;
|
||||
left: 40%;
|
||||
top: 70%;
|
||||
}
|
||||
|
||||
/* Particle color variations */
|
||||
.particle:nth-child(odd) {
|
||||
background: var(--color-cyan-400);
|
||||
}
|
||||
|
||||
.particle:nth-child(3n) {
|
||||
background: var(--color-accent-400);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
BENTO GRID
|
||||
============================================ */
|
||||
|
||||
.bento-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-auto-rows: minmax(200px, auto);
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.bento-item-large {
|
||||
grid-column: span 2;
|
||||
grid-row: span 2;
|
||||
}
|
||||
|
||||
.bento-item-tall {
|
||||
grid-row: span 2;
|
||||
}
|
||||
|
||||
.bento-item-wide {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.bento-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.bento-item-large {
|
||||
grid-column: span 2;
|
||||
grid-row: span 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.bento-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.bento-item-large,
|
||||
.bento-item-wide {
|
||||
grid-column: span 1;
|
||||
}
|
||||
|
||||
.bento-item-tall {
|
||||
grid-row: span 1;
|
||||
}
|
||||
}
|
||||
123
landing/app/components/landing/AdditionalFeatures.vue
Normal file
123
landing/app/components/landing/AdditionalFeatures.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<UPageSection
|
||||
:ui="{
|
||||
root: 'py-16 lg:py-20 bg-gray-50 dark:bg-gray-900/50'
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex flex-col items-center text-center mb-4">
|
||||
<span
|
||||
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-success-100 dark:bg-success-900/30 text-success-700 dark:text-success-300 text-sm font-medium mb-4"
|
||||
>
|
||||
<UIcon name="i-lucide-shield" class="w-4 h-4" />
|
||||
Vertrauen & Sicherheit
|
||||
</span>
|
||||
<h2
|
||||
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white"
|
||||
>
|
||||
Weitere <span class="gradient-text">Vorteile</span>
|
||||
</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #description>
|
||||
<p class="text-center text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
|
||||
Alles aus einer Hand – ohne Drittanbieter, mit Serverstandort in Deutschland.
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<!-- Icon grid with hover animations -->
|
||||
<div class="mt-12 grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div
|
||||
v-for="(feature, index) in features"
|
||||
:key="index"
|
||||
class="group animate-fade-in-up"
|
||||
:style="{ animationDelay: `${index * 100}ms` }"
|
||||
>
|
||||
<div
|
||||
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-transparent transition-all relative overflow-hidden"
|
||||
>
|
||||
<!-- Gradient border on hover -->
|
||||
<div
|
||||
class="absolute inset-0 rounded-2xl bg-gradient-to-br from-primary-500 via-cyan-500 to-accent-500 opacity-0 group-hover:opacity-100 transition-opacity -z-10"
|
||||
/>
|
||||
<div class="absolute inset-[2px] rounded-[14px] bg-white dark:bg-gray-900 -z-10" />
|
||||
|
||||
<div class="flex items-start gap-4">
|
||||
<!-- Icon with gradient background -->
|
||||
<div class="relative shrink-0">
|
||||
<div
|
||||
class="w-14 h-14 rounded-2xl bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<UIcon :name="feature.icon" class="w-7 h-7 text-primary-600 dark:text-primary-400" />
|
||||
</div>
|
||||
<!-- Animated ring on hover -->
|
||||
<div
|
||||
class="absolute inset-0 rounded-2xl ring-2 ring-primary-500/0 group-hover:ring-primary-500/50 transition-all scale-100 group-hover:scale-125 opacity-0 group-hover:opacity-100"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex-1">
|
||||
<h3
|
||||
class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2 group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors"
|
||||
>
|
||||
{{ feature.title }}
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">
|
||||
{{ feature.description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom CTA -->
|
||||
<div class="mt-12 text-center">
|
||||
<p class="text-gray-500 dark:text-gray-400 mb-4">Haben Sie Fragen zu unseren Sicherheitsstandards?</p>
|
||||
<UButton to="#kontakt" variant="outline" class="btn-outline-gradient">
|
||||
<UIcon name="i-lucide-message-circle" class="w-4 h-4 mr-2" />
|
||||
Kontakt aufnehmen
|
||||
</UButton>
|
||||
</div>
|
||||
</UPageSection>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const features = [
|
||||
{
|
||||
icon: 'i-lucide-puzzle',
|
||||
title: 'Keine Zusatztools erforderlich',
|
||||
description:
|
||||
'Keine externen Zusatzlösungen für Prozess, Abstimmung und Dokumentenerstellung – alles läuft in einem System.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-server',
|
||||
title: 'Hosting & Backups in Deutschland',
|
||||
description:
|
||||
'Betrieb und Datensicherung erfolgen in Deutschland – transparente Datenflüsse ohne unerwartete Auslandsverarbeitung.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-lock',
|
||||
title: 'Verschlüsselte Übertragung',
|
||||
description:
|
||||
'Alle Verbindungen sind per TLS/HTTPS verschlüsselt, damit Inhalte und Zugangsdaten beim Transport geschützt sind.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-sparkles',
|
||||
title: 'Einfach zu bedienen',
|
||||
description: 'Nutzerfreundliche, selbsterklärende Oberfläche mit geführten Eingaben – reduziert Schulungsaufwand.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-settings',
|
||||
title: 'Hohe Anpassbarkeit',
|
||||
description:
|
||||
'Templates, Felder und Prozessschritte lassen sich auf Organisation und Abläufe konkret anpassen (auf Anfrage).'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-headphones',
|
||||
title: 'Persönlicher Support',
|
||||
description: 'Bei Fragen steht Ihnen unser Support-Team zur Verfügung – schnell, kompetent und auf Deutsch.'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
101
landing/app/components/landing/AnimatedBackground.vue
Normal file
101
landing/app/components/landing/AnimatedBackground.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div class="absolute inset-0 overflow-hidden pointer-events-none" :class="variant">
|
||||
<!-- Animated gradient orbs -->
|
||||
<div
|
||||
v-for="(orb, index) in orbs"
|
||||
:key="index"
|
||||
class="absolute rounded-full blur-3xl animate-float"
|
||||
:class="orb.color"
|
||||
:style="{
|
||||
width: orb.size,
|
||||
height: orb.size,
|
||||
top: orb.top,
|
||||
left: orb.left,
|
||||
right: orb.right,
|
||||
bottom: orb.bottom,
|
||||
animationDelay: `${index * 2}s`,
|
||||
animationDuration: `${6 + index * 2}s`
|
||||
}"
|
||||
/>
|
||||
|
||||
<!-- Grid pattern -->
|
||||
<div v-if="showGrid" class="absolute inset-0 dots-pattern opacity-20" />
|
||||
|
||||
<!-- Animated lines (for tech feel) -->
|
||||
<svg v-if="showLines" class="absolute inset-0 w-full h-full opacity-10" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" class="[stop-color:var(--color-primary-500)]" stop-opacity="0" />
|
||||
<stop offset="50%" class="[stop-color:var(--color-primary-500)]" stop-opacity="1" />
|
||||
<stop offset="100%" class="[stop-color:var(--color-primary-500)]" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Horizontal animated lines -->
|
||||
<g v-for="i in 3" :key="`h-${i}`">
|
||||
<line
|
||||
x1="0"
|
||||
:y1="`${20 + i * 25}%`"
|
||||
x2="100%"
|
||||
:y2="`${20 + i * 25}%`"
|
||||
stroke="url(#lineGradient)"
|
||||
stroke-width="1"
|
||||
class="animate-pulse-soft"
|
||||
:style="{ animationDelay: `${i * 0.5}s` }"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<!-- Floating particles -->
|
||||
<div v-if="showParticles" class="absolute inset-0">
|
||||
<div
|
||||
v-for="i in 12"
|
||||
:key="`particle-${i}`"
|
||||
class="absolute w-1 h-1 rounded-full bg-primary-400/30 animate-float"
|
||||
:style="{
|
||||
top: `${Math.random() * 100}%`,
|
||||
left: `${Math.random() * 100}%`,
|
||||
animationDelay: `${Math.random() * 5}s`,
|
||||
animationDuration: `${4 + Math.random() * 4}s`
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
variant?: 'hero' | 'section' | 'cta'
|
||||
showGrid?: boolean
|
||||
showLines?: boolean
|
||||
showParticles?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
variant: 'section',
|
||||
showGrid: true,
|
||||
showLines: false,
|
||||
showParticles: false
|
||||
})
|
||||
|
||||
const orbs = computed(() => {
|
||||
switch (props.variant) {
|
||||
case 'hero':
|
||||
return [
|
||||
{ size: '400px', top: '-100px', left: '-100px', color: 'bg-primary-500/20' },
|
||||
{ size: '300px', top: '200px', right: '-50px', color: 'bg-success-500/15' },
|
||||
{ size: '250px', bottom: '-50px', left: '30%', color: 'bg-primary-400/15' }
|
||||
]
|
||||
case 'cta':
|
||||
return [
|
||||
{ size: '300px', top: '-50px', right: '-100px', color: 'bg-white/10' },
|
||||
{ size: '200px', bottom: '-50px', left: '-50px', color: 'bg-white/5' }
|
||||
]
|
||||
default:
|
||||
return [
|
||||
{ size: '200px', top: '10%', left: '-50px', color: 'bg-primary-500/10' },
|
||||
{ size: '150px', bottom: '20%', right: '-30px', color: 'bg-success-500/10' }
|
||||
]
|
||||
}
|
||||
})
|
||||
</script>
|
||||
185
landing/app/components/landing/BenefitsCompany.vue
Normal file
185
landing/app/components/landing/BenefitsCompany.vue
Normal file
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<UPageSection
|
||||
id="unternehmen"
|
||||
:ui="{
|
||||
root: 'scroll-mt-20 py-16 lg:py-20 bg-gray-50 dark:bg-gray-900/50'
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex flex-col items-center text-center mb-4">
|
||||
<span
|
||||
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-accent-100 dark:bg-accent-900/30 text-accent-700 dark:text-accent-300 text-sm font-medium mb-4"
|
||||
>
|
||||
<UIcon name="i-lucide-building-2" class="w-4 h-4" />
|
||||
Für Unternehmen
|
||||
</span>
|
||||
<h2
|
||||
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white"
|
||||
>
|
||||
Vorteile für <span class="gradient-text">Unternehmen</span>
|
||||
</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #description>
|
||||
<p class="text-center text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
|
||||
Schneller zur abgestimmten Einführung von IT- und KI-Systemen mit planbaren Timelines.
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<!-- Comparison view -->
|
||||
<div class="mt-12 grid lg:grid-cols-2 gap-8 lg:gap-12">
|
||||
<!-- Pain points column -->
|
||||
<div class="space-y-6">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div
|
||||
class="w-12 h-12 rounded-2xl bg-gradient-to-br from-warning-500 to-orange-500 flex items-center justify-center shadow-lg shadow-warning-500/25"
|
||||
>
|
||||
<UIcon name="i-lucide-x" class="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-heading text-xl font-bold text-gray-900 dark:text-white">Weg von</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Typische Herausforderungen</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
v-for="(point, index) in painPoints"
|
||||
:key="index"
|
||||
class="group flex gap-4 p-4 rounded-xl bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 hover:border-warning-300 dark:hover:border-warning-600 transition-all animate-fade-in-up"
|
||||
:style="{ animationDelay: `${index * 75}ms` }"
|
||||
>
|
||||
<div
|
||||
class="mt-0.5 w-8 h-8 rounded-lg bg-warning-100 dark:bg-warning-900/30 flex items-center justify-center shrink-0 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<UIcon :name="point.icon" class="w-4 h-4 text-warning-600 dark:text-warning-400" />
|
||||
</div>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed">{{ point.text }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Benefits column -->
|
||||
<div class="space-y-6">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div
|
||||
class="w-12 h-12 rounded-2xl bg-gradient-to-br from-success-500 to-emerald-500 flex items-center justify-center shadow-lg shadow-success-500/25"
|
||||
>
|
||||
<UIcon name="i-lucide-check" class="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-heading text-xl font-bold text-gray-900 dark:text-white">Hin zu</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Mit LegalConsentHub</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
v-for="(benefit, index) in benefits"
|
||||
:key="index"
|
||||
class="group flex gap-4 p-4 rounded-xl bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 hover:border-success-300 dark:hover:border-success-600 transition-all animate-fade-in-up"
|
||||
:style="{ animationDelay: `${index * 75 + 100}ms` }"
|
||||
>
|
||||
<div
|
||||
class="mt-0.5 w-8 h-8 rounded-lg bg-success-100 dark:bg-success-900/30 flex items-center justify-center shrink-0 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<UIcon :name="benefit.icon" class="w-4 h-4 text-success-600 dark:text-success-400" />
|
||||
</div>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed">{{ benefit.text }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Highlights section -->
|
||||
<div class="mt-12">
|
||||
<div class="section-divider mb-8" />
|
||||
<h3 class="font-heading text-2xl sm:text-3xl text-gray-900 dark:text-white text-center mb-10">
|
||||
So wirkt es in der <span class="gradient-text">Praxis</span>
|
||||
</h3>
|
||||
|
||||
<div class="grid sm:grid-cols-3 gap-6">
|
||||
<div
|
||||
v-for="(highlight, index) in highlights"
|
||||
:key="index"
|
||||
class="group animate-fade-in-up"
|
||||
:style="{ animationDelay: `${index * 150}ms` }"
|
||||
>
|
||||
<div
|
||||
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 hover:shadow-xl hover:shadow-accent-500/10 hover:border-accent-200 dark:hover:border-accent-700 transition-all"
|
||||
>
|
||||
<div
|
||||
class="w-12 h-12 rounded-2xl bg-gradient-to-br from-accent-500 to-violet-500 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform shadow-lg shadow-accent-500/25"
|
||||
>
|
||||
<UIcon :name="highlight.icon" class="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<h4 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">{{ highlight.title }}</h4>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300">{{ highlight.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UPageSection>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const painPoints = [
|
||||
{
|
||||
icon: 'i-lucide-refresh-cw',
|
||||
text: 'Unkalkulierbare Schleifen im Mitbestimmungsverfahren (fehlende Infos, Nachforderungen)'
|
||||
},
|
||||
{ icon: 'i-lucide-ban', text: 'Verzögerungen, Projektstopps und Last-Minute-Änderungen kurz vor Go-live' },
|
||||
{ icon: 'i-lucide-files', text: 'Hoher Koordinationsaufwand (E-Mail/Excel/Word) und Versionschaos' },
|
||||
{
|
||||
icon: 'i-lucide-puzzle',
|
||||
text: 'Komplexität und Reibung durch uneinheitliche Prozesse und unterschiedliche Erwartungshaltungen'
|
||||
},
|
||||
{ icon: 'i-lucide-help-circle', text: 'Unklarer Änderungsumfang bei Updates/Modulerweiterungen' },
|
||||
{ icon: 'i-lucide-hourglass', text: 'Verlust wertvoller Zeit und begrenzter Ressourcen' },
|
||||
{ icon: 'i-lucide-wallet', text: 'Vermeidbare Kosten (Einigungsstelle, externe Beratung, Eskalationen)' }
|
||||
]
|
||||
|
||||
const benefits = [
|
||||
{
|
||||
icon: 'i-lucide-calendar-check',
|
||||
text: 'Planbare, schnellere Verfahren durch Standardisierung & klare Prozessschritte'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-users',
|
||||
text: 'Bessere Zusammenarbeit mit BR/PR durch Transparenz und nachvollziehbare Dokumentation'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-gauge',
|
||||
text: 'Risikobasierter Ansatz: Schnellverfahren für Standard-/Low-Risk-Systeme, Fokus auf High-Risk'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-thumbs-up',
|
||||
text: 'Höhere Einigungswahrscheinlichkeit, weil die Verhandlungsgrundlage strukturiert ist'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-file-check-2',
|
||||
text: 'Qualitativ konsistente, robuste Betriebs-/Dienstvereinbarungen (auch bei Änderungen updatefähig)'
|
||||
},
|
||||
{ icon: 'i-lucide-sparkles', text: 'Entlastung von Fachbereichen/IT/HR – mehr Zeit für Wertschöpfung' }
|
||||
]
|
||||
|
||||
const highlights = [
|
||||
{
|
||||
icon: 'i-lucide-repeat',
|
||||
title: 'Weniger Iterationen',
|
||||
description: 'Unterlagen sind vollständig und vergleichbar – Nachforderungen sinken.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-rocket',
|
||||
title: 'Schneller zur Freigabe',
|
||||
description: 'Klare Schritte statt „Hauruck" und kurzfristiger Umplanungen.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-refresh-cw',
|
||||
title: 'Change-ready',
|
||||
description:
|
||||
'Updates, neue Module oder neue Auswertungen werden strukturiert nachgezogen, ohne jedes Mal neu zu starten.'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
209
landing/app/components/landing/BenefitsWorksCouncil.vue
Normal file
209
landing/app/components/landing/BenefitsWorksCouncil.vue
Normal file
@@ -0,0 +1,209 @@
|
||||
<template>
|
||||
<UPageSection
|
||||
id="betriebsraete"
|
||||
:ui="{
|
||||
root: 'scroll-mt-20 py-16 lg:py-20'
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex flex-col items-center text-center mb-4">
|
||||
<span
|
||||
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300 text-sm font-medium mb-4"
|
||||
>
|
||||
<UIcon name="i-lucide-users" class="w-4 h-4" />
|
||||
Für Betriebsräte
|
||||
</span>
|
||||
<h2
|
||||
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white"
|
||||
>
|
||||
Vorteile für <span class="gradient-text">Betriebsräte</span>
|
||||
</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #description>
|
||||
<p class="text-center text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
|
||||
Weg von Informationsjagd und Blackbox-Systemen – hin zu Transparenz und belastbaren Vereinbarungen.
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<!-- Toggle between pain points and benefits -->
|
||||
<div class="mt-12">
|
||||
<!-- Tab switcher -->
|
||||
<div class="flex justify-center mb-10">
|
||||
<div class="inline-flex p-1.5 rounded-2xl glass">
|
||||
<button
|
||||
:class="[
|
||||
'px-6 py-3 rounded-xl text-sm font-semibold transition-all duration-300',
|
||||
activeTab === 'pain'
|
||||
? 'bg-gradient-to-r from-warning-500 to-warning-600 text-white shadow-lg'
|
||||
: 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white'
|
||||
]"
|
||||
@click="activeTab = 'pain'"
|
||||
>
|
||||
<UIcon name="i-lucide-x-circle" class="w-4 h-4 inline mr-2" />
|
||||
Weg von
|
||||
</button>
|
||||
<button
|
||||
:class="[
|
||||
'px-6 py-3 rounded-xl text-sm font-semibold transition-all duration-300',
|
||||
activeTab === 'benefit'
|
||||
? 'bg-gradient-to-r from-success-500 to-success-600 text-white shadow-lg'
|
||||
: 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white'
|
||||
]"
|
||||
@click="activeTab = 'benefit'"
|
||||
>
|
||||
<UIcon name="i-lucide-check-circle" class="w-4 h-4 inline mr-2" />
|
||||
Hin zu
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cards carousel -->
|
||||
<div class="relative">
|
||||
<!-- Pain points cards -->
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-500 ease-out"
|
||||
enter-from-class="opacity-0 translate-x-8"
|
||||
enter-to-class="opacity-100 translate-x-0"
|
||||
leave-active-class="transition-all duration-300 ease-in absolute inset-0"
|
||||
leave-from-class="opacity-100 translate-x-0"
|
||||
leave-to-class="opacity-0 -translate-x-8"
|
||||
>
|
||||
<div v-if="activeTab === 'pain'" class="grid sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
|
||||
<div v-for="(point, index) in painPoints" :key="index" class="group">
|
||||
<div
|
||||
class="h-full p-5 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-warning-300 dark:hover:border-warning-700 shadow-sm hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div
|
||||
class="w-10 h-10 rounded-xl bg-warning-100 dark:bg-warning-900/30 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<UIcon :name="point.icon" class="w-5 h-5 text-warning-600 dark:text-warning-400" />
|
||||
</div>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed">{{ point.text }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<!-- Benefits cards -->
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-500 ease-out"
|
||||
enter-from-class="opacity-0 translate-x-8"
|
||||
enter-to-class="opacity-100 translate-x-0"
|
||||
leave-active-class="transition-all duration-300 ease-in absolute inset-0"
|
||||
leave-from-class="opacity-100 translate-x-0"
|
||||
leave-to-class="opacity-0 -translate-x-8"
|
||||
>
|
||||
<div v-if="activeTab === 'benefit'" class="grid sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
|
||||
<div v-for="(benefit, index) in benefits" :key="index" class="group">
|
||||
<div
|
||||
class="h-full p-5 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-success-300 dark:hover:border-success-700 shadow-sm hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div
|
||||
class="w-10 h-10 rounded-xl bg-success-100 dark:bg-success-900/30 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<UIcon :name="benefit.icon" class="w-5 h-5 text-success-600 dark:text-success-400" />
|
||||
</div>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed">{{ benefit.text }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Highlights section -->
|
||||
<div class="mt-12">
|
||||
<div class="section-divider mb-8" />
|
||||
<h3 class="font-heading text-2xl sm:text-3xl text-gray-900 dark:text-white text-center mb-10">
|
||||
So hilft es im <span class="gradient-text">Alltag</span>
|
||||
</h3>
|
||||
|
||||
<div class="grid sm:grid-cols-3 gap-6">
|
||||
<div
|
||||
v-for="(highlight, index) in highlights"
|
||||
:key="index"
|
||||
class="group animate-fade-in-up"
|
||||
:style="{ animationDelay: `${index * 150}ms` }"
|
||||
>
|
||||
<div
|
||||
class="h-full p-6 rounded-2xl bg-gradient-to-br from-primary-50 to-cyan-50 dark:from-primary-950/50 dark:to-cyan-950/50 border border-primary-100 dark:border-primary-900 hover:shadow-xl hover:shadow-primary-500/10 transition-all"
|
||||
>
|
||||
<div
|
||||
class="w-12 h-12 rounded-2xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform shadow-lg shadow-primary-500/25"
|
||||
>
|
||||
<UIcon :name="highlight.icon" class="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<h4 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">{{ highlight.title }}</h4>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300">{{ highlight.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UPageSection>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const activeTab = ref<'pain' | 'benefit'>('benefit')
|
||||
|
||||
const painPoints = [
|
||||
{
|
||||
icon: 'i-lucide-search',
|
||||
text: 'Informationen zu IT-/KI-Systemen mühsam zusammensuchen (E-Mails, PDFs, PowerPoint, Excel-Chaos)'
|
||||
},
|
||||
{ icon: 'i-lucide-git-branch', text: 'Medienbrüche, Versionschaos und wiederkehrende Rückfragen' },
|
||||
{ icon: 'i-lucide-timer', text: 'Ad-hoc-Systemeinführungen unter Zeitdruck („Hauruck" statt Prozess)' },
|
||||
{ icon: 'i-lucide-brain', text: 'Überforderung durch Menge und Komplexität der Systeme' },
|
||||
{ icon: 'i-lucide-eye-off', text: 'Blackbox bei Funktionen, Auswertungen, Schnittstellen und Änderungen' },
|
||||
{ icon: 'i-lucide-file-question', text: 'Verhandlungen ohne belastbare Datenbasis' },
|
||||
{ icon: 'i-lucide-calendar-x', text: 'Heute geregelt, morgen veraltet' }
|
||||
]
|
||||
|
||||
const benefits = [
|
||||
{
|
||||
icon: 'i-lucide-layout-list',
|
||||
text: 'Strukturierte, vollständige Informationsgrundlage (einheitlich je System/Verarbeitung)'
|
||||
},
|
||||
{ icon: 'i-lucide-route', text: 'Klarer Mitbestimmungsprozess mit bewährten Schritten und Zuständigkeiten' },
|
||||
{
|
||||
icon: 'i-lucide-file-check',
|
||||
text: 'Betriebs-/Dienstvereinbarungen auf belastbarer Grundlage – schneller, konsistenter, leicht aktualisierbar'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-scan-eye',
|
||||
text: 'Transparenz über Systemfähigkeiten – inkl. möglicher Leistungs-/Verhaltenskontrolle'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-git-compare',
|
||||
text: 'Vergleichbarkeit über viele Systeme hinweg durch Standardisierung und einheitliche Templates'
|
||||
},
|
||||
{ icon: 'i-lucide-clock', text: 'Große Zeitersparnis gegenüber konventionellem Verfahren' },
|
||||
{
|
||||
icon: 'i-lucide-shield-check',
|
||||
text: 'Schutzmaßnahmen konsequent dokumentiert und pro Auswertung/Verarbeitung nachvollziehbar'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-heart-handshake',
|
||||
text: 'Spürbare Entlastung: mehr Zeit für andere Mitbestimmungsthemen und kontinuierlichen Arbeitnehmerschutz'
|
||||
}
|
||||
]
|
||||
|
||||
const highlights = [
|
||||
{
|
||||
icon: 'i-lucide-zap',
|
||||
title: 'Schneller prüfen',
|
||||
description: 'Relevante Funktionen und Risiken sind auf einen Blick sichtbar.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-handshake',
|
||||
title: 'Besser verhandeln',
|
||||
description: 'Klare, konsistente Unterlagen statt Interpretationsspielräumen.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-shield',
|
||||
title: 'Nachhaltig absichern',
|
||||
description: 'Änderungen und neue Auswertungen lassen sich strukturiert nachziehen.'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
175
landing/app/components/landing/ExpertAccess.vue
Normal file
175
landing/app/components/landing/ExpertAccess.vue
Normal file
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<section id="kontakt" class="relative py-16 lg:py-20 overflow-hidden scroll-mt-20">
|
||||
<!-- Mesh gradient background -->
|
||||
<div class="absolute inset-0 mesh-gradient-cta" />
|
||||
|
||||
<!-- Animated gradient overlay -->
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-primary-600/90 via-cyan-600/90 to-accent-600/90" />
|
||||
|
||||
<!-- Grid pattern -->
|
||||
<div class="absolute inset-0 grid-pattern opacity-10" />
|
||||
|
||||
<!-- Floating elements -->
|
||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
<div class="absolute top-10 left-10 w-20 h-20 rounded-full bg-white/10 animate-float-slow" />
|
||||
<div
|
||||
class="absolute bottom-20 right-20 w-32 h-32 rounded-full bg-white/5 animate-float-slow"
|
||||
style="animation-delay: 2s"
|
||||
/>
|
||||
<div
|
||||
class="absolute top-1/2 left-1/4 w-16 h-16 rounded-full bg-white/10 animate-float-fast"
|
||||
style="animation-delay: 1s"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
|
||||
<!-- Left: Content -->
|
||||
<div class="text-center lg:text-left">
|
||||
<span
|
||||
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/20 backdrop-blur-sm text-white text-sm font-medium mb-6"
|
||||
>
|
||||
<UIcon name="i-lucide-users" class="w-4 h-4" />
|
||||
Expertennetzwerk
|
||||
</span>
|
||||
|
||||
<h2 class="font-heading text-3xl sm:text-4xl lg:text-5xl font-bold text-white mb-6 animate-fade-in-up">
|
||||
Externer Sachverstand – direkt aus dem Verfahren
|
||||
</h2>
|
||||
|
||||
<p class="text-lg text-white/90 mb-8 animate-fade-in-up" style="animation-delay: 100ms">
|
||||
Wenn Betriebsparteien bei einzelnen Fragen nicht weiterkommen, kann optional externer Sachverstand direkt im
|
||||
System angefragt werden. Anfragen, Rückfragen und Ergebnisse bleiben nachvollziehbar dokumentiert.
|
||||
</p>
|
||||
|
||||
<!-- CTA buttons -->
|
||||
<div
|
||||
class="flex flex-wrap justify-center lg:justify-start gap-4 animate-fade-in-up"
|
||||
style="animation-delay: 200ms"
|
||||
>
|
||||
<UButton
|
||||
to="mailto:info@legalconsenthub.de"
|
||||
size="xl"
|
||||
class="bg-white text-primary-700 hover:bg-white/90 px-8 py-4 text-lg font-semibold rounded-xl shadow-lg"
|
||||
>
|
||||
Kontakt aufnehmen
|
||||
<UIcon name="i-lucide-arrow-right" class="w-5 h-5 ml-2" />
|
||||
</UButton>
|
||||
<UButton
|
||||
to="#features"
|
||||
size="xl"
|
||||
class="bg-white/10 text-white border-2 border-white/30 hover:bg-white/20 px-8 py-4 text-lg font-semibold rounded-xl backdrop-blur-sm"
|
||||
>
|
||||
Mehr erfahren
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right: Expert cards with connection lines -->
|
||||
<div class="flex justify-center animate-scale-in" style="animation-delay: 300ms">
|
||||
<div class="relative">
|
||||
<!-- Connection lines SVG -->
|
||||
<svg class="absolute inset-0 w-full h-full pointer-events-none" viewBox="0 0 400 300">
|
||||
<defs>
|
||||
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" style="stop-color: rgba(255, 255, 255, 0.3)" />
|
||||
<stop offset="50%" style="stop-color: rgba(255, 255, 255, 0.6)" />
|
||||
<stop offset="100%" style="stop-color: rgba(255, 255, 255, 0.3)" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<!-- Animated connection lines -->
|
||||
<path
|
||||
d="M200,150 L100,80"
|
||||
stroke="url(#lineGradient)"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
stroke-dasharray="5,5"
|
||||
class="animate-pulse"
|
||||
/>
|
||||
<path
|
||||
d="M200,150 L300,80"
|
||||
stroke="url(#lineGradient)"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
stroke-dasharray="5,5"
|
||||
class="animate-pulse"
|
||||
style="animation-delay: 0.5s"
|
||||
/>
|
||||
<path
|
||||
d="M200,150 L200,250"
|
||||
stroke="url(#lineGradient)"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
stroke-dasharray="5,5"
|
||||
class="animate-pulse"
|
||||
style="animation-delay: 1s"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<!-- Center hub -->
|
||||
<div class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-10">
|
||||
<div
|
||||
class="w-20 h-20 rounded-full bg-white/20 backdrop-blur-sm border-2 border-white/40 flex items-center justify-center animate-pulse-glow"
|
||||
>
|
||||
<UIcon name="i-lucide-link" class="w-8 h-8 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Expert cards -->
|
||||
<div class="grid grid-cols-2 gap-6 w-80 sm:w-96">
|
||||
<!-- Legal expert card -->
|
||||
<div class="col-span-1 animate-float-slow">
|
||||
<div
|
||||
class="bg-white/15 backdrop-blur-md rounded-2xl p-5 border border-white/20 hover:bg-white/20 transition-all"
|
||||
>
|
||||
<div class="w-12 h-12 rounded-xl bg-white/20 flex items-center justify-center mb-4">
|
||||
<UIcon name="i-lucide-scale" class="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<h4 class="font-heading font-bold text-white mb-1">Arbeitsrecht</h4>
|
||||
<p class="text-sm text-white/70">Fachanwälte für Arbeitsrecht</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Technical expert card -->
|
||||
<div class="col-span-1 animate-float-slow" style="animation-delay: 1s">
|
||||
<div
|
||||
class="bg-white/15 backdrop-blur-md rounded-2xl p-5 border border-white/20 hover:bg-white/20 transition-all"
|
||||
>
|
||||
<div class="w-12 h-12 rounded-xl bg-white/20 flex items-center justify-center mb-4">
|
||||
<UIcon name="i-lucide-cpu" class="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<h4 class="font-heading font-bold text-white mb-1">Technik</h4>
|
||||
<p class="text-sm text-white/70">IT-Sachverständige</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Spacer for center positioning -->
|
||||
<div class="col-span-2 h-24" />
|
||||
|
||||
<!-- Process integration card -->
|
||||
<div class="col-span-2 animate-float-slow" style="animation-delay: 2s">
|
||||
<div
|
||||
class="bg-white/15 backdrop-blur-md rounded-2xl p-5 border border-white/20 hover:bg-white/20 transition-all"
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 rounded-xl bg-white/20 flex items-center justify-center shrink-0">
|
||||
<UIcon name="i-lucide-file-check" class="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-heading font-bold text-white mb-1">Direkt im Verfahren</h4>
|
||||
<p class="text-sm text-white/70">Dokumentiert & nachvollziehbar</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// No additional script needed
|
||||
</script>
|
||||
242
landing/app/components/landing/FeaturesGrid.vue
Normal file
242
landing/app/components/landing/FeaturesGrid.vue
Normal file
@@ -0,0 +1,242 @@
|
||||
<template>
|
||||
<UPageSection
|
||||
id="features"
|
||||
:ui="{
|
||||
root: 'scroll-mt-20 py-16 lg:py-20'
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex flex-col items-center text-center mb-4">
|
||||
<span
|
||||
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-cyan-100 dark:bg-cyan-900/30 text-cyan-700 dark:text-cyan-300 text-sm font-medium mb-4"
|
||||
>
|
||||
<UIcon name="i-lucide-sparkles" class="w-4 h-4" />
|
||||
Features
|
||||
</span>
|
||||
<h2
|
||||
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white"
|
||||
>
|
||||
Features, die Mitbestimmung <span class="gradient-text">effizient</span> machen
|
||||
</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #description>
|
||||
<p class="text-center text-lg text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
|
||||
Eine strukturierte Eingabelogik, klare Prozesse und revisionssichere Dokumentation – damit IT-/KI-Systeme
|
||||
schneller bewertet, abgestimmt und sauber vereinbart werden können.
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<!-- Bento Grid -->
|
||||
<div ref="gridRef" class="mt-12 bento-grid">
|
||||
<!-- Large featured card -->
|
||||
<div class="bento-item-large group card-spotlight animate-fade-in-up" @mousemove="handleMouseMove">
|
||||
<div
|
||||
class="h-full p-8 rounded-3xl bg-gradient-to-br from-primary-500 to-cyan-500 text-white relative overflow-hidden"
|
||||
>
|
||||
<!-- Background pattern -->
|
||||
<div class="absolute inset-0 opacity-10">
|
||||
<div class="absolute inset-0 grid-pattern" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-10">
|
||||
<div
|
||||
class="w-14 h-14 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center mb-6 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<UIcon name="i-lucide-route" class="w-7 h-7 text-white" />
|
||||
</div>
|
||||
<h3 class="font-heading text-2xl sm:text-3xl font-bold mb-4">Geführter Mitbestimmungsprozess</h3>
|
||||
<p class="text-white/90 text-lg leading-relaxed mb-6">
|
||||
Vorgegebene, erweiterbare Eingabeparameter strukturieren den gesamten Ablauf – von der Systembeschreibung
|
||||
bis zur Vereinbarung.
|
||||
</p>
|
||||
|
||||
<!-- Visual element -->
|
||||
<div class="flex items-center gap-3 mt-8">
|
||||
<div class="flex -space-x-2">
|
||||
<div class="w-8 h-8 rounded-full bg-white/30 flex items-center justify-center text-xs font-bold">1</div>
|
||||
<div class="w-8 h-8 rounded-full bg-white/30 flex items-center justify-center text-xs font-bold">2</div>
|
||||
<div class="w-8 h-8 rounded-full bg-white/30 flex items-center justify-center text-xs font-bold">3</div>
|
||||
<div class="w-8 h-8 rounded-full bg-white/30 flex items-center justify-center text-xs font-bold">4</div>
|
||||
</div>
|
||||
<span class="text-sm text-white/80">Strukturierte Prozessschritte</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Regular cards -->
|
||||
<div
|
||||
v-for="(feature, index) in features.slice(1, 5)"
|
||||
:key="index"
|
||||
class="group card-spotlight animate-fade-in-up"
|
||||
:style="{ animationDelay: `${(index + 1) * 100}ms` }"
|
||||
@mousemove="handleMouseMove"
|
||||
>
|
||||
<div
|
||||
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 transition-all hover:shadow-xl hover:shadow-primary-500/10"
|
||||
>
|
||||
<div
|
||||
class="w-12 h-12 rounded-xl bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<UIcon :name="feature.icon" class="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
||||
</div>
|
||||
<h3 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">{{ feature.title }}</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">{{ feature.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tall card -->
|
||||
<div
|
||||
class="bento-item-tall group card-spotlight animate-fade-in-up"
|
||||
style="animation-delay: 500ms"
|
||||
@mousemove="handleMouseMove"
|
||||
>
|
||||
<div
|
||||
class="h-full p-6 rounded-2xl bg-gradient-to-b from-accent-50 to-violet-50 dark:from-accent-950/50 dark:to-violet-950/50 border border-accent-200 dark:border-accent-800 hover:shadow-xl hover:shadow-accent-500/10 transition-all"
|
||||
>
|
||||
<div
|
||||
class="w-12 h-12 rounded-xl bg-gradient-to-br from-accent-500 to-violet-500 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform shadow-lg shadow-accent-500/25"
|
||||
>
|
||||
<UIcon name="i-lucide-history" class="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<h3 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">Versionierung & Audit-Trail</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed mb-6">
|
||||
Änderungen werden versioniert und lückenlos nachvollziehbar dokumentiert – inklusive Historie und Vergleich.
|
||||
</p>
|
||||
|
||||
<!-- Visual timeline -->
|
||||
<div class="space-y-3 mt-auto">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-2 h-2 rounded-full bg-accent-500" />
|
||||
<div class="flex-1 h-px bg-accent-200 dark:bg-accent-800" />
|
||||
<span class="text-xs text-accent-600 dark:text-accent-400">v1.0</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-2 h-2 rounded-full bg-accent-500" />
|
||||
<div class="flex-1 h-px bg-accent-200 dark:bg-accent-800" />
|
||||
<span class="text-xs text-accent-600 dark:text-accent-400">v1.1</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-3 h-3 rounded-full bg-accent-500 ring-4 ring-accent-200 dark:ring-accent-800" />
|
||||
<div class="flex-1 h-px bg-accent-300 dark:bg-accent-700" />
|
||||
<span class="text-xs font-semibold text-accent-700 dark:text-accent-300">v2.0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Wide card -->
|
||||
<div
|
||||
class="bento-item-wide group card-spotlight animate-fade-in-up"
|
||||
style="animation-delay: 600ms"
|
||||
@mousemove="handleMouseMove"
|
||||
>
|
||||
<div
|
||||
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 transition-all hover:shadow-xl hover:shadow-primary-500/10"
|
||||
>
|
||||
<div class="flex flex-col sm:flex-row sm:items-start gap-6">
|
||||
<div
|
||||
class="w-12 h-12 rounded-xl bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center shrink-0 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<UIcon name="i-lucide-file-text" class="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">
|
||||
Automatische BV-/DV-Generierung
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">
|
||||
Nach Abschluss der Eingaben erzeugt das System strukturierte, übersichtliche und signaturbereite
|
||||
Betriebs-/Dienstvereinbarungen.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Remaining cards -->
|
||||
<div
|
||||
v-for="(feature, index) in features.slice(5)"
|
||||
:key="index + 5"
|
||||
class="group card-spotlight animate-fade-in-up"
|
||||
:style="{ animationDelay: `${(index + 7) * 100}ms` }"
|
||||
@mousemove="handleMouseMove"
|
||||
>
|
||||
<div
|
||||
class="h-full p-6 rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 transition-all hover:shadow-xl hover:shadow-primary-500/10"
|
||||
>
|
||||
<div
|
||||
class="w-12 h-12 rounded-xl bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center mb-4 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<UIcon :name="feature.icon" class="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
||||
</div>
|
||||
<h3 class="font-heading text-lg font-bold text-gray-900 dark:text-white mb-2">{{ feature.title }}</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">{{ feature.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UPageSection>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const gridRef = ref<HTMLElement | null>(null)
|
||||
|
||||
// Spotlight effect handler
|
||||
function handleMouseMove(event: MouseEvent) {
|
||||
const card = event.currentTarget as HTMLElement
|
||||
const rect = card.getBoundingClientRect()
|
||||
const x = ((event.clientX - rect.left) / rect.width) * 100
|
||||
const y = ((event.clientY - rect.top) / rect.height) * 100
|
||||
card.style.setProperty('--mouse-x', `${x}%`)
|
||||
card.style.setProperty('--mouse-y', `${y}%`)
|
||||
}
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: 'i-lucide-route',
|
||||
title: 'Geführter Mitbestimmungsprozess',
|
||||
description:
|
||||
'Vorgegebene, erweiterbare Eingabeparameter strukturieren den gesamten Ablauf – von der Systembeschreibung bis zur Vereinbarung.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-shield-alert',
|
||||
title: 'Risikobasierter Assistent',
|
||||
description:
|
||||
'Ein regelbasierter, risikoorientierter Assistent passt die Eingabemaske an Komplexität, Umfang und Potenziale zur Leistungs-/Verhaltensauswertung an.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-gauge',
|
||||
title: 'Ampelsystem & Direktfeedback',
|
||||
description:
|
||||
'Kritikalität wird transparent bewertet und direkt beim Ausfüllen zurückgespielt – für schnelle Orientierung und weniger Schleifen.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-message-square',
|
||||
title: 'Zusammenarbeit per Kommentaren',
|
||||
description: 'Inline-Kommentare ermöglichen Abstimmung direkt an einzelnen Inhalten – ohne Medienbrüche.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-history',
|
||||
title: 'Versionierung & Audit-Trail',
|
||||
description:
|
||||
'Änderungen werden versioniert und lückenlos nachvollziehbar dokumentiert – inklusive Historie und Vergleich.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-pen-tool',
|
||||
title: 'Signaturfähig mit QES (eIDAS)',
|
||||
description: 'Optional rechtsverbindliche Unterzeichnung per qualifizierter elektronischer Signatur nach eIDAS.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-bell',
|
||||
title: 'Benachrichtigungen & News-Center',
|
||||
description: 'Aktuell bleiben über Status-Updates, Änderungen und Aufgaben – per Nachrichten-Center und E-Mail.'
|
||||
},
|
||||
{
|
||||
icon: 'i-lucide-shield-check',
|
||||
title: 'SSO & Governance',
|
||||
description:
|
||||
'SSO-Integration via SAML oder OIDC sowie ein umfangreich konfigurierbares Rollen- und Berechtigungskonzept.'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
210
landing/app/components/landing/FrameworkAgreement.vue
Normal file
210
landing/app/components/landing/FrameworkAgreement.vue
Normal file
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<UPageSection
|
||||
:ui="{
|
||||
root: 'py-16 lg:py-20 scroll-mt-20'
|
||||
}"
|
||||
>
|
||||
<div class="grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
|
||||
<!-- Left: Content -->
|
||||
<div class="order-2 lg:order-1">
|
||||
<span
|
||||
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-accent-100 dark:bg-accent-900/30 text-accent-700 dark:text-accent-300 text-sm font-medium mb-6"
|
||||
>
|
||||
<UIcon name="i-lucide-file-text" class="w-4 h-4" />
|
||||
Optional verfügbar
|
||||
</span>
|
||||
|
||||
<h2
|
||||
class="font-heading text-3xl sm:text-4xl lg:text-5xl text-pretty tracking-tight font-bold text-gray-900 dark:text-white mb-6"
|
||||
>
|
||||
Rahmenbetriebsvereinbarung <span class="gradient-text">IT/KI</span>
|
||||
</h2>
|
||||
|
||||
<p class="text-lg text-gray-600 dark:text-gray-300 mb-8">
|
||||
Für den Einstieg stellen wir auf Nachfrage eine optionale Rahmenbetriebs-/Rahmendienstvereinbarung für IT- und
|
||||
KI-Systeme bereit. Sie ist auf die Struktur des Tools zugeschnitten und enthält praxiserprobte
|
||||
Regelungsbausteine.
|
||||
</p>
|
||||
|
||||
<!-- Animated checklist -->
|
||||
<ul class="space-y-4 mb-8">
|
||||
<li
|
||||
v-for="(point, index) in bulletPoints"
|
||||
:key="index"
|
||||
class="flex gap-4 animate-fade-in-up"
|
||||
:style="{ animationDelay: `${index * 100}ms` }"
|
||||
>
|
||||
<div
|
||||
class="mt-1 w-6 h-6 rounded-full bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center shrink-0"
|
||||
>
|
||||
<UIcon name="i-lucide-check" class="w-3.5 h-3.5 text-white" />
|
||||
</div>
|
||||
<p class="text-gray-700 dark:text-gray-300">{{ point }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Price info -->
|
||||
<div
|
||||
class="p-4 rounded-xl bg-gradient-to-r from-primary-50 to-cyan-50 dark:from-primary-950/50 dark:to-cyan-950/50 border border-primary-200 dark:border-primary-800"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center"
|
||||
>
|
||||
<UIcon name="i-lucide-tag" class="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Preis</p>
|
||||
<p class="font-heading text-lg font-bold text-gray-900 dark:text-white">Auf Anfrage</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CTA -->
|
||||
<div class="mt-8">
|
||||
<UButton
|
||||
to="#kontakt"
|
||||
size="xl"
|
||||
class="btn-gradient px-8 py-4 text-lg font-semibold rounded-xl shadow-lg shadow-primary-500/25"
|
||||
>
|
||||
<span>Mehr erfahren</span>
|
||||
<UIcon name="i-lucide-arrow-right" class="w-5 h-5 ml-2" />
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right: 3D Document Preview -->
|
||||
<div class="order-1 lg:order-2 flex justify-center">
|
||||
<div class="relative animate-scale-in">
|
||||
<!-- 3D Document with tilt effect -->
|
||||
<div
|
||||
class="relative transform-gpu transition-transform duration-500 hover:rotate-0"
|
||||
style="transform: perspective(1000px) rotateY(-8deg) rotateX(5deg)"
|
||||
@mouseenter="isHovered = true"
|
||||
@mouseleave="isHovered = false"
|
||||
>
|
||||
<!-- Shadow layer -->
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-900/20 dark:bg-black/40 blur-2xl rounded-3xl translate-x-4 translate-y-4"
|
||||
/>
|
||||
|
||||
<!-- Document card -->
|
||||
<div
|
||||
class="relative bg-white dark:bg-gray-900 rounded-2xl border border-gray-200 dark:border-gray-700 shadow-2xl overflow-hidden max-w-sm"
|
||||
>
|
||||
<!-- Document header -->
|
||||
<div class="bg-gradient-to-r from-primary-600 to-cyan-600 px-6 py-5">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 rounded-xl bg-white/20 backdrop-blur-sm flex items-center justify-center">
|
||||
<UIcon name="i-lucide-file-text" class="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-heading font-bold text-white text-lg">Rahmen-BV IT/KI</h4>
|
||||
<p class="text-sm text-white/80">Betriebsvereinbarung Vorlage</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Document content preview -->
|
||||
<div class="p-6">
|
||||
<!-- Table of contents -->
|
||||
<div class="space-y-4">
|
||||
<div class="text-xs uppercase tracking-wider text-gray-500 dark:text-gray-400 font-semibold">
|
||||
Inhaltsverzeichnis
|
||||
</div>
|
||||
|
||||
<!-- Section items with staggered animation -->
|
||||
<div
|
||||
v-for="(section, index) in documentSections"
|
||||
:key="index"
|
||||
class="group flex items-center gap-3 p-3 rounded-xl bg-gray-50 dark:bg-gray-800 hover:bg-primary-50 dark:hover:bg-primary-900/20 transition-colors cursor-pointer"
|
||||
:class="{ 'animate-fade-in-up': isHovered }"
|
||||
:style="{ animationDelay: `${index * 100}ms` }"
|
||||
>
|
||||
<div
|
||||
class="w-8 h-8 rounded-lg bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center text-sm font-bold text-primary-600 dark:text-primary-400 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-sm font-medium text-gray-900 dark:text-white truncate">{{ section.title }}</div>
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400 truncate">{{ section.description }}</div>
|
||||
</div>
|
||||
<UIcon
|
||||
:name="section.icon"
|
||||
class="w-4 h-4 text-gray-400 group-hover:text-primary-500 transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer info -->
|
||||
<div class="mt-6 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<UIcon name="i-lucide-layers" class="w-4 h-4 text-gray-400" />
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">12 Regelungsbausteine</span>
|
||||
</div>
|
||||
<UBadge color="success" variant="soft" size="sm">
|
||||
<UIcon name="i-lucide-check-circle" class="w-3 h-3 mr-1" />
|
||||
Praxiserprobt
|
||||
</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Floating badge -->
|
||||
<div class="absolute -top-4 -right-4 z-10 animate-float-fast">
|
||||
<div
|
||||
class="bg-gradient-to-r from-accent-500 to-violet-500 text-white px-4 py-2 rounded-full shadow-lg text-sm font-semibold flex items-center gap-2"
|
||||
>
|
||||
<UIcon name="i-lucide-download" class="w-4 h-4" />
|
||||
Auf Anfrage
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Decorative elements -->
|
||||
<div class="absolute -top-8 -left-8 w-32 h-32 bg-primary-400/20 rounded-full blur-3xl animate-pulse-glow" />
|
||||
<div
|
||||
class="absolute -bottom-8 -right-8 w-40 h-40 bg-accent-400/20 rounded-full blur-3xl animate-pulse-glow"
|
||||
style="animation-delay: 1s"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UPageSection>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const isHovered = ref(false)
|
||||
|
||||
const bulletPoints = [
|
||||
'Vorlage für eine Rahmen-BV/DV zu IT- und KI-Systemen',
|
||||
'Auf die Tool-Logik und Dokumentationsstruktur zugeschnitten',
|
||||
'Enthält praxiserprobte Regelungsbausteine als Startpunkt für systembezogene Vereinbarungen'
|
||||
]
|
||||
|
||||
const documentSections = [
|
||||
{
|
||||
title: 'Geltungsbereich',
|
||||
description: 'Definition der betroffenen Systeme',
|
||||
icon: 'i-lucide-target'
|
||||
},
|
||||
{
|
||||
title: 'Mitbestimmungsverfahren',
|
||||
description: 'Prozessschritte und Zuständigkeiten',
|
||||
icon: 'i-lucide-git-branch'
|
||||
},
|
||||
{
|
||||
title: 'Datenschutz & Kontrolle',
|
||||
description: 'Schutzmaßnahmen und Auswertungen',
|
||||
icon: 'i-lucide-shield'
|
||||
},
|
||||
{
|
||||
title: 'Änderungsmanagement',
|
||||
description: 'Updates und Erweiterungen',
|
||||
icon: 'i-lucide-refresh-cw'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
263
landing/app/components/landing/HeroSection.vue
Normal file
263
landing/app/components/landing/HeroSection.vue
Normal file
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<section class="relative min-h-screen flex items-center justify-center overflow-hidden hero-gradient-light">
|
||||
<!-- Animated gradient orbs -->
|
||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
<!-- Large teal orb -->
|
||||
<div
|
||||
class="gradient-orb gradient-orb-teal w-[600px] h-[600px] -top-40 -left-40 animate-orb-float"
|
||||
style="animation-delay: 0s"
|
||||
/>
|
||||
<!-- Violet orb -->
|
||||
<div
|
||||
class="gradient-orb gradient-orb-violet w-[500px] h-[500px] top-1/4 -right-32 animate-orb-float"
|
||||
style="animation-delay: 3s"
|
||||
/>
|
||||
<!-- Cyan orb -->
|
||||
<div
|
||||
class="gradient-orb gradient-orb-cyan w-[400px] h-[400px] bottom-0 left-1/4 animate-orb-float"
|
||||
style="animation-delay: 6s"
|
||||
/>
|
||||
<!-- Small accent orb -->
|
||||
<div
|
||||
class="gradient-orb gradient-orb-violet w-[200px] h-[200px] top-1/2 left-10 animate-orb-float opacity-40"
|
||||
style="animation-delay: 9s"
|
||||
/>
|
||||
|
||||
<!-- Grid pattern overlay -->
|
||||
<div class="absolute inset-0 grid-pattern opacity-30" />
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="relative z-10 w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 lg:py-32">
|
||||
<div class="text-center max-w-4xl mx-auto">
|
||||
<!-- Badge -->
|
||||
<div class="animate-fade-in-up mb-8">
|
||||
<span
|
||||
class="inline-flex items-center gap-2 px-4 py-2 rounded-full glass text-sm font-medium text-gray-700 dark:text-gray-200"
|
||||
>
|
||||
<span class="relative flex h-2 w-2">
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary-400 opacity-75" />
|
||||
<span class="relative inline-flex rounded-full h-2 w-2 bg-primary-500" />
|
||||
</span>
|
||||
Jetzt verfügbar
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Title with gradient text -->
|
||||
<h1 class="font-heading text-4xl sm:text-5xl md:text-6xl lg:text-7xl tracking-tight mb-6">
|
||||
<span class="animate-fade-in-up block text-gray-900 dark:text-white" style="animation-delay: 100ms">
|
||||
Digitale Mitbestimmung
|
||||
</span>
|
||||
<span class="animate-fade-in-up block gradient-text" style="animation-delay: 200ms">
|
||||
für IT- und KI-Systeme
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<!-- Description -->
|
||||
<p
|
||||
class="animate-fade-in-up text-lg sm:text-xl text-gray-600 dark:text-gray-300 max-w-2xl mx-auto mb-10"
|
||||
style="animation-delay: 300ms"
|
||||
>
|
||||
{{ description }}
|
||||
</p>
|
||||
|
||||
<!-- CTA Buttons -->
|
||||
<div class="flex flex-wrap justify-center gap-4 animate-fade-in-up" style="animation-delay: 400ms">
|
||||
<UButton
|
||||
size="xl"
|
||||
to="#kontakt"
|
||||
trailing-icon="i-lucide-arrow-right"
|
||||
class="btn-gradient px-8 py-4 text-lg font-semibold rounded-xl shadow-lg shadow-primary-500/25 hover:shadow-xl hover:shadow-primary-500/30 transition-all"
|
||||
>
|
||||
<span>Demo anfragen</span>
|
||||
</UButton>
|
||||
<UButton
|
||||
size="xl"
|
||||
to="#features"
|
||||
variant="outline"
|
||||
class="btn-outline-gradient px-8 py-4 text-lg font-semibold rounded-xl"
|
||||
>
|
||||
Features entdecken
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Floating product preview cards -->
|
||||
<div class="mt-16 lg:mt-24 relative animate-scale-in" style="animation-delay: 600ms">
|
||||
<div class="flex flex-col lg:flex-row items-center justify-center gap-6 lg:gap-8">
|
||||
<!-- Left card - tilted -->
|
||||
<div class="card-3d w-full max-w-xs lg:-mr-8 lg:mt-12 order-2 lg:order-1">
|
||||
<div
|
||||
class="card-3d-inner glass rounded-2xl p-5 shadow-xl transform lg:-rotate-6 hover:rotate-0 transition-transform duration-500"
|
||||
>
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div
|
||||
class="w-10 h-10 rounded-xl bg-gradient-to-br from-warning-400 to-warning-500 flex items-center justify-center"
|
||||
>
|
||||
<UIcon name="i-lucide-alert-triangle" class="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-gray-900 dark:text-white text-sm">Risikoprüfung</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">3 Punkte offen</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-4 h-4 rounded bg-warning-100 dark:bg-warning-900/50 flex items-center justify-center">
|
||||
<UIcon name="i-lucide-clock" class="w-2.5 h-2.5 text-warning-600" />
|
||||
</div>
|
||||
<span class="text-xs text-gray-600 dark:text-gray-300">Datenschutz-Folgenabschätzung</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-4 h-4 rounded bg-warning-100 dark:bg-warning-900/50 flex items-center justify-center">
|
||||
<UIcon name="i-lucide-clock" class="w-2.5 h-2.5 text-warning-600" />
|
||||
</div>
|
||||
<span class="text-xs text-gray-600 dark:text-gray-300">Leistungskontrolle prüfen</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-4 h-4 rounded bg-success-100 dark:bg-success-900/50 flex items-center justify-center">
|
||||
<UIcon name="i-lucide-check" class="w-2.5 h-2.5 text-success-600" />
|
||||
</div>
|
||||
<span class="text-xs text-gray-600 dark:text-gray-300">Zugriffsrechte definiert</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Center card - main -->
|
||||
<div class="w-full max-w-md z-10 order-1 lg:order-2">
|
||||
<div class="glass rounded-2xl overflow-hidden shadow-2xl border border-white/50 dark:border-white/10">
|
||||
<!-- Mock header -->
|
||||
<div
|
||||
class="flex items-center justify-between px-5 py-4 bg-white/50 dark:bg-gray-900/50 border-b border-gray-200/50 dark:border-gray-700/50"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="w-8 h-8 rounded-lg bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center"
|
||||
>
|
||||
<UIcon name="i-lucide-file-text" class="w-4 h-4 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-gray-900 dark:text-white text-sm">Microsoft 365</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">Betriebsvereinbarung</p>
|
||||
</div>
|
||||
</div>
|
||||
<UBadge color="primary" variant="soft" size="sm">In Bearbeitung</UBadge>
|
||||
</div>
|
||||
|
||||
<!-- Mock content -->
|
||||
<div class="p-5 space-y-4">
|
||||
<!-- Progress section -->
|
||||
<div>
|
||||
<div class="flex justify-between text-sm mb-2">
|
||||
<span class="text-gray-600 dark:text-gray-300 font-medium">Fortschritt</span>
|
||||
<span class="text-primary-600 dark:text-primary-400 font-semibold">67%</span>
|
||||
</div>
|
||||
<div class="h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
|
||||
<div class="h-full w-[67%] bg-gradient-to-r from-primary-500 to-cyan-500 rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status items -->
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div
|
||||
class="flex items-center gap-2 p-3 rounded-xl bg-success-50 dark:bg-success-900/20 border border-success-200 dark:border-success-800"
|
||||
>
|
||||
<UIcon name="i-lucide-check-circle" class="w-5 h-5 text-success-500" />
|
||||
<div>
|
||||
<p class="text-xs font-medium text-success-700 dark:text-success-300">8 Abschnitte</p>
|
||||
<p class="text-xs text-success-600 dark:text-success-400">abgeschlossen</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center gap-2 p-3 rounded-xl bg-primary-50 dark:bg-primary-900/20 border border-primary-200 dark:border-primary-800"
|
||||
>
|
||||
<UIcon name="i-lucide-message-square" class="w-5 h-5 text-primary-500" />
|
||||
<div>
|
||||
<p class="text-xs font-medium text-primary-700 dark:text-primary-300">4 Kommentare</p>
|
||||
<p class="text-xs text-primary-600 dark:text-primary-400">neu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action button -->
|
||||
<button
|
||||
class="w-full py-3 px-4 rounded-xl bg-gradient-to-r from-primary-500 to-cyan-500 text-white font-semibold text-sm hover:from-primary-600 hover:to-cyan-600 transition-all shadow-lg shadow-primary-500/25"
|
||||
>
|
||||
Weiter bearbeiten
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right card - tilted -->
|
||||
<div class="card-3d w-full max-w-xs lg:-ml-8 lg:mt-12 order-3">
|
||||
<div
|
||||
class="card-3d-inner glass rounded-2xl p-5 shadow-xl transform lg:rotate-6 hover:rotate-0 transition-transform duration-500"
|
||||
>
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div
|
||||
class="w-10 h-10 rounded-xl bg-gradient-to-br from-success-400 to-success-500 flex items-center justify-center"
|
||||
>
|
||||
<UIcon name="i-lucide-check-circle" class="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-gray-900 dark:text-white text-sm">Abgeschlossen</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">Letzte Woche</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center justify-between p-2 rounded-lg bg-success-50 dark:bg-success-900/30">
|
||||
<span class="text-xs text-gray-700 dark:text-gray-200">SAP S/4HANA</span>
|
||||
<UIcon name="i-lucide-check" class="w-4 h-4 text-success-500" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-2 rounded-lg bg-success-50 dark:bg-success-900/30">
|
||||
<span class="text-xs text-gray-700 dark:text-gray-200">Workday HCM</span>
|
||||
<UIcon name="i-lucide-check" class="w-4 h-4 text-success-500" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-2 rounded-lg bg-success-50 dark:bg-success-900/30">
|
||||
<span class="text-xs text-gray-700 dark:text-gray-200">Salesforce CRM</span>
|
||||
<UIcon name="i-lucide-check" class="w-4 h-4 text-success-500" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Floating notification - positioned above all cards with higher z-index -->
|
||||
<div
|
||||
class="absolute top-0 right-8 lg:right-16 xl:right-24 z-20 animate-float-slow hidden lg:block"
|
||||
style="animation-delay: 1s"
|
||||
>
|
||||
<div class="glass rounded-xl px-4 py-3 shadow-lg flex items-center gap-3">
|
||||
<div
|
||||
class="w-8 h-8 rounded-full bg-gradient-to-br from-success-400 to-success-500 flex items-center justify-center"
|
||||
>
|
||||
<UIcon name="i-lucide-sparkles" class="w-4 h-4 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-semibold text-gray-900 dark:text-white">BV erstellt!</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">Bereit zur Unterschrift</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scroll indicator -->
|
||||
<div class="absolute bottom-8 left-1/2 -translate-x-1/2 animate-bounce">
|
||||
<a
|
||||
href="#betriebsraete"
|
||||
class="flex items-center justify-center w-12 h-12 rounded-full glass text-gray-600 dark:text-gray-300 hover:bg-white/80 dark:hover:bg-gray-800/80 transition-colors"
|
||||
aria-label="Nach unten scrollen"
|
||||
>
|
||||
<UIcon name="i-lucide-chevron-down" class="w-6 h-6" />
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const description =
|
||||
'Struktur statt Hauruck: Alle relevanten Informationen an einem Ort, klare Prozessschritte und nachvollziehbare Dokumentation – damit Mitbestimmung schneller, belastbarer und dauerhaft updatefähig wird.'
|
||||
</script>
|
||||
187
landing/app/components/landing/NewsletterSignup.vue
Normal file
187
landing/app/components/landing/NewsletterSignup.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<section id="newsletter" class="relative py-16 lg:py-20 overflow-hidden scroll-mt-20">
|
||||
<!-- Background with gradient and particles -->
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-br from-primary-50 via-cyan-50 to-accent-50 dark:from-gray-950 dark:via-primary-950/30 dark:to-accent-950/30"
|
||||
/>
|
||||
|
||||
<!-- Animated particles -->
|
||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
<div class="particle" />
|
||||
<div class="particle" />
|
||||
<div class="particle" />
|
||||
<div class="particle" />
|
||||
<div class="particle" />
|
||||
<div class="particle" />
|
||||
<div class="particle" />
|
||||
<div class="particle" />
|
||||
</div>
|
||||
|
||||
<!-- Gradient orbs -->
|
||||
<div class="absolute top-0 left-1/4 w-96 h-96 bg-primary-400/20 rounded-full blur-3xl animate-orb-float" />
|
||||
<div
|
||||
class="absolute bottom-0 right-1/4 w-80 h-80 bg-accent-400/20 rounded-full blur-3xl animate-orb-float"
|
||||
style="animation-delay: 3s"
|
||||
/>
|
||||
|
||||
<div class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<!-- Glass card -->
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="glass rounded-3xl p-8 sm:p-12 shadow-2xl">
|
||||
<!-- Icon -->
|
||||
<div class="flex justify-center mb-6">
|
||||
<div
|
||||
class="w-16 h-16 rounded-2xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center animate-float-slow shadow-lg shadow-primary-500/25"
|
||||
>
|
||||
<UIcon name="i-lucide-mail" class="w-8 h-8 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<h2
|
||||
class="font-heading text-3xl sm:text-4xl font-bold text-center text-gray-900 dark:text-white mb-4 animate-fade-in-up"
|
||||
>
|
||||
Bleiben Sie <span class="gradient-text">informiert</span>
|
||||
</h2>
|
||||
|
||||
<!-- Description -->
|
||||
<p
|
||||
class="text-center text-lg text-gray-600 dark:text-gray-300 mb-8 animate-fade-in-up"
|
||||
style="animation-delay: 100ms"
|
||||
>
|
||||
Erhalten Sie Updates zur Entwicklung von LegalConsentHub und seien Sie unter den Ersten, die von neuen
|
||||
Funktionen erfahren.
|
||||
</p>
|
||||
|
||||
<!-- Form -->
|
||||
<UForm
|
||||
:state="formState"
|
||||
:schema="schema"
|
||||
class="animate-fade-in-up"
|
||||
style="animation-delay: 200ms"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<div class="flex flex-col sm:flex-row gap-3">
|
||||
<UFormField name="email" class="flex-1">
|
||||
<UInput
|
||||
v-model="formState.email"
|
||||
type="email"
|
||||
placeholder="Ihre E-Mail-Adresse"
|
||||
size="xl"
|
||||
:disabled="isLoading || isSuccess"
|
||||
:ui="{
|
||||
root: 'w-full',
|
||||
base: 'rounded-xl bg-white dark:bg-gray-900 border-gray-200 dark:border-gray-700 focus:ring-2 focus:ring-primary-500 focus:border-transparent'
|
||||
}"
|
||||
>
|
||||
<template #leading>
|
||||
<UIcon name="i-lucide-mail" class="w-5 h-5 text-gray-400" />
|
||||
</template>
|
||||
</UInput>
|
||||
</UFormField>
|
||||
|
||||
<UButton
|
||||
type="submit"
|
||||
size="xl"
|
||||
:loading="isLoading"
|
||||
:disabled="isSuccess"
|
||||
class="btn-gradient px-8 rounded-xl font-semibold shadow-lg shadow-primary-500/25 whitespace-nowrap"
|
||||
>
|
||||
<template v-if="isSuccess">
|
||||
<UIcon name="i-lucide-check" class="w-5 h-5 mr-2" />
|
||||
<span>Angemeldet!</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>Anmelden</span>
|
||||
</template>
|
||||
</UButton>
|
||||
</div>
|
||||
</UForm>
|
||||
|
||||
<!-- Success message with animation -->
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-500 ease-out"
|
||||
enter-from-class="opacity-0 scale-95 translate-y-4"
|
||||
enter-to-class="opacity-100 scale-100 translate-y-0"
|
||||
leave-active-class="transition-all duration-300 ease-in"
|
||||
leave-from-class="opacity-100 scale-100 translate-y-0"
|
||||
leave-to-class="opacity-0 scale-95 translate-y-4"
|
||||
>
|
||||
<div
|
||||
v-if="isSuccess"
|
||||
class="mt-6 p-4 rounded-xl bg-success-100 dark:bg-success-900/30 border border-success-200 dark:border-success-800"
|
||||
>
|
||||
<div class="flex items-center justify-center gap-3 text-success-700 dark:text-success-300">
|
||||
<div class="w-8 h-8 rounded-full bg-success-500 flex items-center justify-center">
|
||||
<UIcon name="i-lucide-check" class="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<span class="font-medium">Vielen Dank! Wir halten Sie auf dem Laufenden.</span>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<!-- Privacy note -->
|
||||
<p
|
||||
class="mt-6 text-sm text-center text-gray-500 dark:text-gray-400 animate-fade-in-up"
|
||||
style="animation-delay: 300ms"
|
||||
>
|
||||
Mit der Anmeldung stimmen Sie unserer
|
||||
<NuxtLink to="/datenschutz" class="text-primary-600 dark:text-primary-400 hover:underline font-medium">
|
||||
Datenschutzerklärung
|
||||
</NuxtLink>
|
||||
zu. Wir versenden keinen Spam.
|
||||
</p>
|
||||
|
||||
<!-- Trust indicators -->
|
||||
<div
|
||||
class="mt-8 flex flex-wrap justify-center gap-6 text-sm animate-fade-in-up"
|
||||
style="animation-delay: 400ms"
|
||||
>
|
||||
<div class="flex items-center gap-2 text-gray-600 dark:text-gray-300">
|
||||
<div class="w-6 h-6 rounded-full bg-success-100 dark:bg-success-900/30 flex items-center justify-center">
|
||||
<UIcon name="i-lucide-shield-check" class="w-3.5 h-3.5 text-success-600 dark:text-success-400" />
|
||||
</div>
|
||||
<span>DSGVO-konform</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-gray-600 dark:text-gray-300">
|
||||
<div class="w-6 h-6 rounded-full bg-success-100 dark:bg-success-900/30 flex items-center justify-center">
|
||||
<UIcon name="i-lucide-lock" class="w-3.5 h-3.5 text-success-600 dark:text-success-400" />
|
||||
</div>
|
||||
<span>Verschlüsselt</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-gray-600 dark:text-gray-300">
|
||||
<div class="w-6 h-6 rounded-full bg-success-100 dark:bg-success-900/30 flex items-center justify-center">
|
||||
<UIcon name="i-lucide-x-circle" class="w-3.5 h-3.5 text-success-600 dark:text-success-400" />
|
||||
</div>
|
||||
<span>Kein Spam</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { z } from 'zod'
|
||||
import type { FormSubmitEvent } from '@nuxt/ui'
|
||||
|
||||
const { isLoading, isSuccess, submitEmail } = useNewsletterSignup()
|
||||
|
||||
const schema = z.object({
|
||||
email: z
|
||||
.string()
|
||||
.min(1, 'Bitte geben Sie eine E-Mail-Adresse ein')
|
||||
.email('Bitte geben Sie eine gültige E-Mail-Adresse ein')
|
||||
})
|
||||
|
||||
type Schema = z.output<typeof schema>
|
||||
|
||||
const formState = reactive<Partial<Schema>>({
|
||||
email: ''
|
||||
})
|
||||
|
||||
async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||
await submitEmail(event.data.email)
|
||||
}
|
||||
</script>
|
||||
122
landing/app/components/landing/StatsSection.vue
Normal file
122
landing/app/components/landing/StatsSection.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<section
|
||||
class="py-10 lg:py-12 bg-gradient-to-r from-primary-50 via-cyan-50 to-accent-50 dark:from-primary-950/30 dark:via-cyan-950/30 dark:to-accent-950/30"
|
||||
>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<!-- Stats grid -->
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-8 lg:gap-12">
|
||||
<div
|
||||
v-for="(stat, index) in stats"
|
||||
:key="index"
|
||||
class="text-center animate-fade-in-up"
|
||||
:style="{ animationDelay: `${index * 100}ms` }"
|
||||
>
|
||||
<div class="relative inline-block mb-3">
|
||||
<!-- Animated number -->
|
||||
<span ref="counterRefs" class="font-heading text-4xl sm:text-5xl lg:text-6xl font-bold gradient-text">
|
||||
{{ animatedValues[index] }}{{ stat.suffix }}
|
||||
</span>
|
||||
|
||||
<!-- Decorative glow -->
|
||||
<div class="absolute -inset-4 bg-primary-400/20 blur-2xl rounded-full -z-10 animate-pulse-glow" />
|
||||
</div>
|
||||
|
||||
<p class="text-sm sm:text-base text-gray-600 dark:text-gray-300 font-medium">
|
||||
{{ stat.label }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Trust badges -->
|
||||
<div class="mt-10 pt-8 border-t border-gray-200 dark:border-gray-800">
|
||||
<p class="text-center text-sm text-gray-500 dark:text-gray-400 mb-8">Vertrauen & Sicherheit</p>
|
||||
|
||||
<div class="flex flex-wrap justify-center items-center gap-8 lg:gap-12">
|
||||
<div
|
||||
v-for="(badge, index) in trustBadges"
|
||||
:key="index"
|
||||
class="flex items-center gap-3 px-4 py-2 rounded-full bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 shadow-sm hover:shadow-md transition-shadow animate-fade-in-up"
|
||||
:style="{ animationDelay: `${(index + 4) * 100}ms` }"
|
||||
>
|
||||
<div
|
||||
class="w-8 h-8 rounded-full bg-gradient-to-br from-primary-100 to-cyan-100 dark:from-primary-900/50 dark:to-cyan-900/50 flex items-center justify-center"
|
||||
>
|
||||
<UIcon :name="badge.icon" class="w-4 h-4 text-primary-600 dark:text-primary-400" />
|
||||
</div>
|
||||
<span class="text-sm font-medium text-gray-700 dark:text-gray-200">{{ badge.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const stats = [
|
||||
{ value: 70, suffix: '%', label: 'Zeitersparnis im Verfahren' },
|
||||
{ value: 100, suffix: '%', label: 'Revisionssicher dokumentiert' },
|
||||
{ value: 24, suffix: '/7', label: 'Verfügbarkeit' },
|
||||
{ value: 0, suffix: '', label: 'Medienbrüche' }
|
||||
]
|
||||
|
||||
const trustBadges = [
|
||||
{ icon: 'i-lucide-shield-check', label: 'DSGVO-konform' },
|
||||
{ icon: 'i-lucide-server', label: 'Hosting in Deutschland' },
|
||||
{ icon: 'i-lucide-lock', label: 'Ende-zu-Ende verschlüsselt' },
|
||||
{ icon: 'i-lucide-key', label: 'SSO-fähig' }
|
||||
]
|
||||
|
||||
// Animated counter values
|
||||
const animatedValues = ref(stats.map(() => 0))
|
||||
const hasAnimated = ref(false)
|
||||
|
||||
// Counter animation function
|
||||
function animateCounter(index: number, target: number, duration: number = 2000) {
|
||||
const start = 0
|
||||
const startTime = performance.now()
|
||||
|
||||
function update(currentTime: number) {
|
||||
const elapsed = currentTime - startTime
|
||||
const progress = Math.min(elapsed / duration, 1)
|
||||
|
||||
// Easing function (ease-out cubic)
|
||||
const easeOut = 1 - Math.pow(1 - progress, 3)
|
||||
|
||||
animatedValues.value[index] = Math.round(start + (target - start) * easeOut)
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(update)
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(update)
|
||||
}
|
||||
|
||||
// Start animation when section is visible
|
||||
onMounted(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting && !hasAnimated.value) {
|
||||
hasAnimated.value = true
|
||||
stats.forEach((stat, index) => {
|
||||
setTimeout(() => {
|
||||
animateCounter(index, stat.value)
|
||||
}, index * 200)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
{ threshold: 0.3 }
|
||||
)
|
||||
|
||||
const section = document.querySelector('section')
|
||||
if (section) {
|
||||
observer.observe(section)
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
observer.disconnect()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
43
landing/app/composables/useNewsletterSignup.ts
Normal file
43
landing/app/composables/useNewsletterSignup.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
export function useNewsletterSignup() {
|
||||
const isLoading = ref(false)
|
||||
const isSuccess = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
const submitEmail = async (_email: string) => {
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
// Simulate API call - replace with actual newsletter service integration
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500))
|
||||
|
||||
// TODO: Integrate with external newsletter service (e.g., Mailchimp, ConvertKit, etc.)
|
||||
// Example:
|
||||
// await $fetch('/api/newsletter/subscribe', {
|
||||
// method: 'POST',
|
||||
// body: { email }
|
||||
// })
|
||||
|
||||
isSuccess.value = true
|
||||
} catch (e: unknown) {
|
||||
error.value = e instanceof Error ? e.message : 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.'
|
||||
throw e
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
isLoading.value = false
|
||||
isSuccess.value = false
|
||||
error.value = null
|
||||
}
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
isSuccess,
|
||||
error,
|
||||
submitEmail,
|
||||
reset
|
||||
}
|
||||
}
|
||||
87
landing/app/pages/index.vue
Normal file
87
landing/app/pages/index.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="landing-page">
|
||||
<!-- Hero Section -->
|
||||
<LandingHeroSection />
|
||||
|
||||
<!-- Stats Section (Social Proof) -->
|
||||
<LandingStatsSection />
|
||||
|
||||
<!-- Benefits for Works Councils -->
|
||||
<LandingBenefitsWorksCouncil />
|
||||
|
||||
<!-- Benefits for Companies -->
|
||||
<LandingBenefitsCompany />
|
||||
|
||||
<!-- Features Grid (Bento Layout) -->
|
||||
<LandingFeaturesGrid />
|
||||
|
||||
<!-- Additional Features / Trust Signals -->
|
||||
<LandingAdditionalFeatures />
|
||||
|
||||
<!-- Framework Agreement Section -->
|
||||
<LandingFrameworkAgreement />
|
||||
|
||||
<!-- Newsletter Signup (Glass-morphism) -->
|
||||
<LandingNewsletterSignup />
|
||||
|
||||
<!-- Expert Access CTA (Gradient Mesh) -->
|
||||
<LandingExpertAccess />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// SEO Meta
|
||||
useSeoMeta({
|
||||
title: 'LegalConsentHub - Digitale Mitbestimmung für IT- und KI-Systeme',
|
||||
description:
|
||||
'Struktur statt Hauruck: Alle relevanten Informationen an einem Ort, klare Prozessschritte und nachvollziehbare Dokumentation – damit Mitbestimmung schneller, belastbarer und dauerhaft updatefähig wird.',
|
||||
ogTitle: 'LegalConsentHub - Digitale Mitbestimmung für IT- und KI-Systeme',
|
||||
ogDescription: 'Strukturierte IT-Mitbestimmung mit klaren Prozessen und revisionssicherer Dokumentation.',
|
||||
ogImage: '/og-image.png',
|
||||
ogType: 'website',
|
||||
twitterCard: 'summary_large_image'
|
||||
})
|
||||
|
||||
// Structured data for SEO
|
||||
useHead({
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
innerHTML: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'SoftwareApplication',
|
||||
name: 'LegalConsentHub',
|
||||
applicationCategory: 'BusinessApplication',
|
||||
operatingSystem: 'Web',
|
||||
description:
|
||||
'Digitale Mitbestimmung für IT- und KI-Systeme. Strukturierte Eingabelogik, klare Prozesse und revisionssichere Dokumentation.',
|
||||
offers: {
|
||||
'@type': 'Offer',
|
||||
price: '0',
|
||||
priceCurrency: 'EUR',
|
||||
description: 'Kontaktieren Sie uns für Preisdetails'
|
||||
},
|
||||
featureList: [
|
||||
'Geführter Mitbestimmungsprozess',
|
||||
'Risikobasierter Assistent',
|
||||
'Versionierung & Audit-Trail',
|
||||
'Automatische BV-/DV-Generierung',
|
||||
'SSO & Governance'
|
||||
]
|
||||
})
|
||||
}
|
||||
]
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Smooth scrolling for anchor links */
|
||||
.landing-page {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* Add padding to account for fixed header */
|
||||
.landing-page > :deep(section:first-child) {
|
||||
padding-top: 0;
|
||||
}
|
||||
</style>
|
||||
15
landing/eslint.config.mjs
Normal file
15
landing/eslint.config.mjs
Normal file
@@ -0,0 +1,15 @@
|
||||
// @ts-check
|
||||
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||
|
||||
export default withNuxt({
|
||||
rules: {
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
void: 'any'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
42
landing/nuxt.config.ts
Normal file
42
landing/nuxt.config.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2025-07-15',
|
||||
modules: ['@nuxt/ui', '@nuxt/eslint', '@nuxt/fonts'],
|
||||
css: ['~/assets/css/main.css'],
|
||||
devtools: { enabled: true },
|
||||
|
||||
// SSR enabled by default for performance
|
||||
ssr: true,
|
||||
|
||||
// Font configuration - Bricolage Grotesque for headings, DM Sans for body
|
||||
fonts: {
|
||||
families: [
|
||||
{
|
||||
name: 'Bricolage Grotesque',
|
||||
provider: 'google',
|
||||
weights: [400, 500, 600, 700, 800]
|
||||
},
|
||||
{
|
||||
name: 'DM Sans',
|
||||
provider: 'google',
|
||||
weights: [400, 500, 600, 700]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// App configuration
|
||||
app: {
|
||||
head: {
|
||||
htmlAttrs: {
|
||||
lang: 'de'
|
||||
},
|
||||
title: 'LegalConsentHub - Digitale Mitbestimmung für IT- und KI-Systeme',
|
||||
meta: [
|
||||
{
|
||||
name: 'description',
|
||||
content:
|
||||
'Struktur statt Hauruck: Alle relevanten Informationen an einem Ort, klare Prozessschritte und nachvollziehbare Dokumentation für IT-Mitbestimmung.'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
36
landing/package.json
Normal file
36
landing/package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "nuxt-app",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare",
|
||||
"format": "prettier . --write",
|
||||
"type-check": "nuxi typecheck",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"check": "pnpm run lint && pnpm run type-check && pnpm run format && pnpm run test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/eslint": "1.12.1",
|
||||
"@nuxt/fonts": "^0.12.1",
|
||||
"@nuxt/ui": "4.3.0",
|
||||
"eslint": "9.39.2",
|
||||
"nuxt": "4.2.2",
|
||||
"vue": "3.5.26",
|
||||
"vue-router": "4.6.4",
|
||||
"zod": "^4.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.7.4",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"volta": {
|
||||
"node": "22.16.0",
|
||||
"pnpm": "10.11.0"
|
||||
},
|
||||
"packageManager": "pnpm@10.13.1+sha512.37ebf1a5c7a30d5fabe0c5df44ee8da4c965ca0c5af3dbab28c3a1681b70a256218d05c81c9c0dcf767ef6b8551eb5b960042b9ed4300c59242336377e01cfad"
|
||||
}
|
||||
10306
landing/pnpm-lock.yaml
generated
Normal file
10306
landing/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
landing/public/favicon.ico
Normal file
BIN
landing/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
2
landing/public/robots.txt
Normal file
2
landing/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-Agent: *
|
||||
Disallow:
|
||||
18
landing/tsconfig.json
Normal file
18
landing/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.server.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.shared.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user