feat(landing): Add i18n

This commit is contained in:
2026-01-05 19:13:41 +01:00
parent a086763c80
commit 01df3e622e
17 changed files with 4049 additions and 406 deletions

View File

@@ -10,19 +10,20 @@
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
{{ $t('additionalFeatures.badge') }}
</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>
{{ $t('additionalFeatures.title', { highlight: '' })
}}<span class="gradient-text">{{ $t('additionalFeatures.titleHighlight') }}</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.
{{ $t('additionalFeatures.description') }}
</p>
</template>
@@ -74,50 +75,32 @@
<!-- 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>
<p class="text-gray-500 dark:text-gray-400 mb-4">{{ $t('additionalFeatures.ctaQuestion') }}</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
{{ $t('additionalFeatures.ctaButton') }}
</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.'
}
const { t } = useI18n()
const featureIcons = [
'i-lucide-puzzle',
'i-lucide-server',
'i-lucide-lock',
'i-lucide-sparkles',
'i-lucide-settings',
'i-lucide-headphones'
]
const features = computed(() =>
featureIcons.map((icon, index) => ({
icon,
title: t(`additionalFeatures.items[${index}].title`),
description: t(`additionalFeatures.items[${index}].description`)
}))
)
</script>

View File

@@ -11,19 +11,20 @@
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
{{ $t('company.badge') }}
</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>
{{ $t('company.title', { highlight: '' })
}}<span class="gradient-text">{{ $t('company.titleHighlight') }}</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.
{{ $t('company.description') }}
</p>
</template>
@@ -38,8 +39,10 @@
<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>
<h3 class="font-heading text-xl font-bold text-gray-900 dark:text-white">
{{ $t('company.awayFrom.title') }}
</h3>
<p class="text-sm text-gray-500 dark:text-gray-400">{{ $t('company.awayFrom.subtitle') }}</p>
</div>
</div>
@@ -69,8 +72,10 @@
<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>
<h3 class="font-heading text-xl font-bold text-gray-900 dark:text-white">
{{ $t('company.towards.title') }}
</h3>
<p class="text-sm text-gray-500 dark:text-gray-400">{{ $t('company.towards.subtitle') }}</p>
</div>
</div>
@@ -96,7 +101,8 @@
<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>
{{ $t('company.highlightsTitle', { highlight: '' })
}}<span class="gradient-text">{{ $t('company.highlightsTitleHighlight') }}</span>
</h3>
<div class="grid sm:grid-cols-3 gap-6">
@@ -124,62 +130,48 @@
</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 { t } = useI18n()
const painPointIcons = [
'i-lucide-refresh-cw',
'i-lucide-ban',
'i-lucide-files',
'i-lucide-puzzle',
'i-lucide-help-circle',
'i-lucide-hourglass',
'i-lucide-wallet'
]
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 benefitIcons = [
'i-lucide-calendar-check',
'i-lucide-users',
'i-lucide-gauge',
'i-lucide-thumbs-up',
'i-lucide-file-check-2',
'i-lucide-sparkles'
]
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.'
}
]
const highlightIcons = ['i-lucide-repeat', 'i-lucide-rocket', 'i-lucide-refresh-cw']
const painPoints = computed(() =>
painPointIcons.map((icon, index) => ({
icon,
text: t(`company.painPoints[${index}]`)
}))
)
const benefits = computed(() =>
benefitIcons.map((icon, index) => ({
icon,
text: t(`company.benefits[${index}]`)
}))
)
const highlights = computed(() =>
highlightIcons.map((icon, index) => ({
icon,
title: t(`company.highlights[${index}].title`),
description: t(`company.highlights[${index}].description`)
}))
)
</script>

View File

@@ -11,19 +11,20 @@
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
{{ $t('worksCouncil.badge') }}
</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>
{{ $t('worksCouncil.title', { highlight: '' })
}}<span class="gradient-text">{{ $t('worksCouncil.titleHighlight') }}</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.
{{ $t('worksCouncil.description') }}
</p>
</template>
@@ -42,7 +43,7 @@
@click="activeTab = 'pain'"
>
<UIcon name="i-lucide-x-circle" class="w-4 h-4 inline mr-2" />
Weg von
{{ $t('worksCouncil.tabs.awayFrom') }}
</button>
<button
:class="[
@@ -54,7 +55,7 @@
@click="activeTab = 'benefit'"
>
<UIcon name="i-lucide-check-circle" class="w-4 h-4 inline mr-2" />
Hin zu
{{ $t('worksCouncil.tabs.towards') }}
</button>
</div>
</div>
@@ -117,7 +118,8 @@
<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>
{{ $t('worksCouncil.highlightsTitle', { highlight: '' })
}}<span class="gradient-text">{{ $t('worksCouncil.highlightsTitleHighlight') }}</span>
</h3>
<div class="grid sm:grid-cols-3 gap-6">
@@ -145,65 +147,51 @@
</template>
<script setup lang="ts">
const { t } = useI18n()
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 painPointIcons = [
'i-lucide-search',
'i-lucide-git-branch',
'i-lucide-timer',
'i-lucide-brain',
'i-lucide-eye-off',
'i-lucide-file-question',
'i-lucide-calendar-x'
]
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 benefitIcons = [
'i-lucide-layout-list',
'i-lucide-route',
'i-lucide-file-check',
'i-lucide-scan-eye',
'i-lucide-git-compare',
'i-lucide-clock',
'i-lucide-shield-check',
'i-lucide-heart-handshake'
]
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.'
}
]
const highlightIcons = ['i-lucide-zap', 'i-lucide-handshake', 'i-lucide-shield']
const painPoints = computed(() =>
painPointIcons.map((icon, index) => ({
icon,
text: t(`worksCouncil.painPoints[${index}]`)
}))
)
const benefits = computed(() =>
benefitIcons.map((icon, index) => ({
icon,
text: t(`worksCouncil.benefits[${index}]`)
}))
)
const highlights = computed(() =>
highlightIcons.map((icon, index) => ({
icon,
title: t(`worksCouncil.highlights[${index}].title`),
description: t(`worksCouncil.highlights[${index}].description`)
}))
)
</script>

View File

@@ -30,16 +30,15 @@
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
{{ $t('expertAccess.badge') }}
</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
{{ $t('expertAccess.title') }}
</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.
{{ $t('expertAccess.description') }}
</p>
<!-- CTA buttons -->
@@ -52,7 +51,7 @@
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
{{ $t('expertAccess.cta.contact') }}
<UIcon name="i-lucide-arrow-right" class="w-5 h-5 ml-2" />
</UButton>
<UButton
@@ -60,7 +59,7 @@
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
{{ $t('expertAccess.cta.learnMore') }}
</UButton>
</div>
</div>
@@ -125,8 +124,8 @@
<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>
<h4 class="font-heading font-bold text-white mb-1">{{ $t('expertAccess.experts.labor.title') }}</h4>
<p class="text-sm text-white/70">{{ $t('expertAccess.experts.labor.description') }}</p>
</div>
</div>
@@ -138,8 +137,10 @@
<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>
<h4 class="font-heading font-bold text-white mb-1">
{{ $t('expertAccess.experts.technical.title') }}
</h4>
<p class="text-sm text-white/70">{{ $t('expertAccess.experts.technical.description') }}</p>
</div>
</div>
@@ -156,8 +157,10 @@
<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>
<h4 class="font-heading font-bold text-white mb-1">
{{ $t('expertAccess.experts.process.title') }}
</h4>
<p class="text-sm text-white/70">{{ $t('expertAccess.experts.process.description') }}</p>
</div>
</div>
</div>
@@ -171,5 +174,5 @@
</template>
<script setup lang="ts">
// No additional script needed
// No additional script needed - using $t() from i18n
</script>

View File

@@ -10,24 +10,21 @@
<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
<UIcon name="i-lucide-sparkles" class="w-4 h-4" />
{{ $t('features.badge') }}
</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
{{ $t('features.title', { highlight: '' })
}}<span class="gradient-text">{{ $t('features.titleHighlight') }}</span>
</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.
{{ $t('features.description') }}
</p>
</template>
@@ -49,57 +46,25 @@
</template>
<script setup lang="ts">
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-history',
title: 'Versionierung & Audit-Trail',
description:
'Änderungen werden versioniert und lückenlos nachvollziehbar dokumentiert inklusive Historie und Vergleich.'
},
{
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-file-text',
title: 'Automatische BV-/DV-Generierung',
description:
'Nach Abschluss der Eingaben erzeugt das System strukturierte, übersichtliche und signaturbereite Betriebs-/Dienstvereinbarungen.'
},
{
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.'
}
const { t } = useI18n()
const featureIcons = [
'i-lucide-route',
'i-lucide-shield-alert',
'i-lucide-gauge',
'i-lucide-history',
'i-lucide-message-square',
'i-lucide-file-text',
'i-lucide-pen-tool',
'i-lucide-bell',
'i-lucide-shield-check'
]
const features = computed(() =>
featureIcons.map((icon, index) => ({
icon,
title: t(`features.items[${index}].title`),
description: t(`features.items[${index}].description`)
}))
)
</script>

View File

@@ -11,19 +11,18 @@
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
{{ $t('frameworkAgreement.badge') }}
</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>
{{ $t('frameworkAgreement.title', { highlight: '' })
}}<span class="gradient-text">{{ $t('frameworkAgreement.titleHighlight') }}</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.
{{ $t('frameworkAgreement.description') }}
</p>
<!-- Animated checklist -->
@@ -54,8 +53,8 @@
<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>
<p class="text-sm text-gray-500 dark:text-gray-400">{{ $t('common.price') }}</p>
<p class="font-heading text-lg font-bold text-gray-900 dark:text-white">{{ $t('common.onRequest') }}</p>
</div>
</div>
</div>
@@ -67,7 +66,7 @@
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>
<span>{{ $t('common.learnMore') }}</span>
<UIcon name="i-lucide-arrow-right" class="w-5 h-5 ml-2" />
</UButton>
</div>
@@ -99,8 +98,10 @@
<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>
<h4 class="font-heading font-bold text-white text-lg">
{{ $t('frameworkAgreement.document.title') }}
</h4>
<p class="text-sm text-white/80">{{ $t('frameworkAgreement.document.subtitle') }}</p>
</div>
</div>
</div>
@@ -110,7 +111,7 @@
<!-- 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
{{ $t('frameworkAgreement.document.tableOfContents') }}
</div>
<!-- Section items with staggered animation -->
@@ -142,11 +143,13 @@
<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>
<span class="text-xs text-gray-500 dark:text-gray-400">{{
$t('frameworkAgreement.document.regulationBlocks')
}}</span>
</div>
<UBadge color="success" variant="soft" size="sm">
<UIcon name="i-lucide-check-circle" class="w-3 h-3 mr-1" />
Praxiserprobt
{{ $t('frameworkAgreement.document.fieldTested') }}
</UBadge>
</div>
</div>
@@ -159,7 +162,7 @@
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
{{ $t('common.onRequest') }}
</div>
</div>
</div>
@@ -177,34 +180,21 @@
</template>
<script setup lang="ts">
const { t } = useI18n()
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 bulletPointCount = 3
const bulletPoints = computed(() =>
Array.from({ length: bulletPointCount }, (_, index) => t(`frameworkAgreement.bulletPoints[${index}]`))
)
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'
}
]
const sectionIcons = ['i-lucide-target', 'i-lucide-git-branch', 'i-lucide-shield', 'i-lucide-refresh-cw']
const documentSections = computed(() =>
sectionIcons.map((icon, index) => ({
icon,
title: t(`frameworkAgreement.document.sections[${index}].title`),
description: t(`frameworkAgreement.document.sections[${index}].description`)
}))
)
</script>

View File

@@ -39,17 +39,17 @@
<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
{{ $t('hero.badge') }}
</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
{{ $t('hero.title1') }}
</span>
<span class="animate-fade-in-up block gradient-text" style="animation-delay: 200ms">
für IT- und KI-Systeme
{{ $t('hero.title2') }}
</span>
</h1>
@@ -58,7 +58,7 @@
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 }}
{{ $t('hero.description') }}
</p>
<!-- CTA Buttons -->
@@ -69,7 +69,7 @@
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>
<span>{{ $t('hero.cta.requestDemo') }}</span>
</UButton>
<UButton
size="xl"
@@ -77,7 +77,7 @@
variant="outline"
class="btn-outline-gradient px-8 py-4 text-lg font-semibold rounded-xl"
>
Features entdecken
{{ $t('hero.cta.discoverFeatures') }}
</UButton>
</div>
</div>
@@ -97,8 +97,10 @@
<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>
<p class="font-semibold text-gray-900 dark:text-white text-sm">
{{ $t('hero.cards.riskAssessment') }}
</p>
<p class="text-xs text-gray-500 dark:text-gray-400">{{ $t('hero.cards.pointsOpen') }}</p>
</div>
</div>
<div class="space-y-2">
@@ -106,19 +108,19 @@
<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>
<span class="text-xs text-gray-600 dark:text-gray-300">{{ $t('hero.cards.privacyImpact') }}</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>
<span class="text-xs text-gray-600 dark:text-gray-300">{{ $t('hero.cards.performanceCheck') }}</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>
<span class="text-xs text-gray-600 dark:text-gray-300">{{ $t('hero.cards.accessDefined') }}</span>
</div>
</div>
</div>
@@ -139,10 +141,10 @@
</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>
<p class="text-xs text-gray-500 dark:text-gray-400">{{ $t('hero.cards.operatingAgreement') }}</p>
</div>
</div>
<UBadge color="primary" variant="soft" size="sm">In Bearbeitung</UBadge>
<UBadge color="primary" variant="soft" size="sm">{{ $t('hero.cards.inProgress') }}</UBadge>
</div>
<!-- Mock content -->
@@ -150,7 +152,7 @@
<!-- 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-gray-600 dark:text-gray-300 font-medium">{{ $t('hero.cards.progress') }}</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">
@@ -165,8 +167,10 @@
>
<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>
<p class="text-xs font-medium text-success-700 dark:text-success-300">
{{ $t('hero.cards.sectionsCompleted') }}
</p>
<p class="text-xs text-success-600 dark:text-success-400">{{ $t('hero.cards.completed') }}</p>
</div>
</div>
<div
@@ -174,8 +178,10 @@
>
<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>
<p class="text-xs font-medium text-primary-700 dark:text-primary-300">
{{ $t('hero.cards.commentsNew') }}
</p>
<p class="text-xs text-primary-600 dark:text-primary-400">{{ $t('hero.cards.new') }}</p>
</div>
</div>
</div>
@@ -184,7 +190,7 @@
<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
{{ $t('hero.cards.continueEditing') }}
</button>
</div>
</div>
@@ -202,8 +208,10 @@
<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>
<p class="font-semibold text-gray-900 dark:text-white text-sm">
{{ $t('hero.cards.completedTitle') }}
</p>
<p class="text-xs text-gray-500 dark:text-gray-400">{{ $t('hero.cards.lastWeek') }}</p>
</div>
</div>
<div class="space-y-2">
@@ -236,8 +244,8 @@
<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>
<p class="text-sm font-semibold text-gray-900 dark:text-white">{{ $t('hero.cards.bvCreated') }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400">{{ $t('hero.cards.readyForSignature') }}</p>
</div>
</div>
</div>
@@ -249,7 +257,7 @@
<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"
:aria-label="$t('hero.scrollDown')"
>
<UIcon name="i-lucide-chevron-down" class="w-6 h-6" />
</a>
@@ -258,6 +266,5 @@
</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.'
// No additional script needed - using $t() from i18n
</script>

View File

@@ -41,7 +41,8 @@
<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>
{{ $t('newsletter.title', { highlight: '' })
}}<span class="gradient-text">{{ $t('newsletter.titleHighlight') }}</span>
</h2>
<!-- Description -->
@@ -49,8 +50,7 @@
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.
{{ $t('newsletter.description') }}
</p>
<!-- Form -->
@@ -66,7 +66,7 @@
<UInput
v-model="formState.email"
type="email"
placeholder="Ihre E-Mail-Adresse"
:placeholder="$t('newsletter.placeholder')"
size="xl"
:disabled="isLoading || isSuccess"
:ui="{
@@ -89,10 +89,10 @@
>
<template v-if="isSuccess">
<UIcon name="i-lucide-check" class="w-5 h-5 mr-2" />
<span>Angemeldet!</span>
<span>{{ $t('newsletter.submitted') }}</span>
</template>
<template v-else>
<span>Anmelden</span>
<span>{{ $t('newsletter.submit') }}</span>
</template>
</UButton>
</div>
@@ -115,7 +115,7 @@
<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>
<span class="font-medium">{{ $t('newsletter.success') }}</span>
</div>
</div>
</Transition>
@@ -125,11 +125,13 @@
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.
<i18n-t keypath="newsletter.privacyNote" tag="span">
<template #link>
<NuxtLink to="/datenschutz" class="text-primary-600 dark:text-primary-400 hover:underline font-medium">
{{ $t('newsletter.privacyLink') }}
</NuxtLink>
</template>
</i18n-t>
</p>
<!-- Trust indicators -->
@@ -141,19 +143,19 @@
<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>
<span>{{ $t('newsletter.trust.gdpr') }}</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>
<span>{{ $t('newsletter.trust.encrypted') }}</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>
<span>{{ $t('newsletter.trust.noSpam') }}</span>
</div>
</div>
</div>
@@ -166,22 +168,20 @@
import { z } from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'
const { t } = useI18n()
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')
})
const schema = computed(() =>
z.object({
email: z.string().min(1, t('newsletter.validation.required')).email(t('newsletter.validation.invalid'))
})
)
type Schema = z.output<typeof schema>
const formState = reactive<Partial<Schema>>({
const formState = reactive<{ email: string }>({
email: ''
})
async function onSubmit(event: FormSubmitEvent<Schema>) {
async function onSubmit(event: FormSubmitEvent<{ email: string }>) {
await submitEmail(event.data.email)
}
</script>

View File

@@ -29,7 +29,7 @@
<!-- 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>
<p class="text-center text-sm text-gray-500 dark:text-gray-400 mb-8">{{ $t('stats.trustAndSecurity') }}</p>
<div class="flex flex-wrap justify-center items-center gap-8 lg:gap-12">
<div
@@ -52,22 +52,24 @@
</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 { t } = useI18n()
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' }
]
const stats = computed(() => [
{ value: 70, suffix: '%', label: t('stats.timeSaved') },
{ value: 100, suffix: '%', label: t('stats.auditProof') },
{ value: 24, suffix: '/7', label: t('stats.availability') },
{ value: 0, suffix: '', label: t('stats.mediaBreaks') }
])
const trustBadges = computed(() => [
{ icon: 'i-lucide-shield-check', label: t('stats.badges.gdpr') },
{ icon: 'i-lucide-server', label: t('stats.badges.hosting') },
{ icon: 'i-lucide-lock', label: t('stats.badges.encrypted') },
{ icon: 'i-lucide-key', label: t('stats.badges.sso') }
])
// Animated counter values
const animatedValues = ref(stats.map(() => 0))
const animatedValues = ref(stats.value.map(() => 0))
const hasAnimated = ref(false)
// Counter animation function
@@ -99,7 +101,7 @@ onMounted(() => {
entries.forEach((entry) => {
if (entry.isIntersecting && !hasAnimated.value) {
hasAnimated.value = true
stats.forEach((stat, index) => {
stats.value.forEach((stat, index) => {
setTimeout(() => {
animateCounter(index, stat.value)
}, index * 200)