Files
shiftcraft/app/pages/index.vue
Clanker 36e0946ee4 feat: complete ShiftCraft — AI-powered shift scheduling SaaS
Complete implementation including:
- Landing page with hero, features, how-it-works, pricing
- Employee management (CRUD with soft delete)
- AI constraint parser (Anthropic Claude API)
- German labor law templates (ArbZG §3, §5, §9)
- HiGHS ILP solver for optimal fair schedules
- Schedule calendar result view (employee × date grid)
- Shift framework configuration (periods + shifts)
- Subscription tiers: Free / Pro / Business
- PocketBase setup script with collection creation + seed data
- .env.example with all required variables documented

Pages: employees, constraints (list/new/templates), schedules (list/new/[id]),
       settings (organization/shifts/billing), dashboard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 07:47:31 +02:00

273 lines
14 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="min-h-screen bg-white">
<!-- Navigation -->
<nav class="fixed top-0 w-full z-50 bg-white/80 backdrop-blur-xl border-b border-gray-100">
<div class="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between">
<div class="flex items-center gap-2">
<div class="w-8 h-8 rounded-xl bg-gradient-to-br from-indigo-500 to-violet-600 flex items-center justify-center">
<span class="text-white font-bold text-sm">S</span>
</div>
<span class="font-bold text-gray-900 text-lg">ShiftCraft</span>
</div>
<div class="hidden md:flex items-center gap-8">
<a href="#features" class="text-gray-600 hover:text-gray-900 text-sm font-medium transition-colors">Features</a>
<a href="#how-it-works" class="text-gray-600 hover:text-gray-900 text-sm font-medium transition-colors">So funktioniert's</a>
<a href="#pricing" class="text-gray-600 hover:text-gray-900 text-sm font-medium transition-colors">Preise</a>
</div>
<div class="flex items-center gap-3">
<NuxtLink to="/login" class="text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors">Anmelden</NuxtLink>
<NuxtLink to="/register">
<UButton color="primary" size="sm">Kostenlos starten</UButton>
</NuxtLink>
</div>
</div>
</nav>
<!-- Hero -->
<section class="pt-32 pb-20 px-6 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-indigo-50 via-violet-50 to-emerald-50 -z-10" />
<div class="absolute top-20 right-0 w-96 h-96 bg-violet-200 rounded-full filter blur-3xl opacity-30 -z-10" />
<div class="absolute bottom-0 left-20 w-64 h-64 bg-indigo-200 rounded-full filter blur-3xl opacity-30 -z-10" />
<div class="max-w-4xl mx-auto text-center">
<div class="inline-flex items-center gap-2 px-4 py-1.5 bg-indigo-50 text-indigo-700 rounded-full text-sm font-medium mb-8 border border-indigo-100">
<span class="w-1.5 h-1.5 rounded-full bg-indigo-500 animate-pulse" />
Schichtplanung neu gedacht
</div>
<h1 class="text-5xl md:text-7xl font-extrabold text-gray-900 leading-tight mb-6">
Schichtplanung,<br>
<span class="bg-gradient-to-r from-indigo-600 to-violet-600 bg-clip-text text-transparent">
die Ihre Sprache<br>spricht
</span>
</h1>
<p class="text-xl text-gray-600 max-w-2xl mx-auto mb-10 leading-relaxed">
Einfach Ihre Wünsche und Regeln eingeben — wie in einer E-Mail.
ShiftCraft erstellt automatisch den optimalen, fairen Schichtplan.
</p>
<div class="flex flex-col sm:flex-row gap-4 justify-center mb-16">
<NuxtLink to="/register">
<UButton color="primary" size="xl" trailing-icon="i-lucide-arrow-right" class="shadow-lg shadow-indigo-200">
Kostenlos starten
</UButton>
</NuxtLink>
<a href="#how-it-works">
<UButton color="neutral" variant="outline" size="xl">
Demo ansehen
</UButton>
</a>
</div>
<!-- Mock UI Preview -->
<div class="relative max-w-3xl mx-auto">
<div class="bg-white rounded-3xl shadow-2xl border border-gray-100 overflow-hidden">
<div class="bg-gray-50 px-6 py-4 border-b border-gray-100 flex items-center gap-2">
<div class="w-3 h-3 rounded-full bg-red-400" />
<div class="w-3 h-3 rounded-full bg-yellow-400" />
<div class="w-3 h-3 rounded-full bg-green-400" />
<span class="ml-4 text-xs text-gray-400 font-medium">ShiftCraft — Neue Bedingung</span>
</div>
<div class="p-6 text-left">
<div class="mb-4">
<label class="text-xs font-medium text-gray-500 uppercase tracking-wide mb-2 block">Bedingung eingeben</label>
<div class="w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-gray-700 text-sm min-h-[80px]">
Sabine mag keine Nachtschichten und sollte maximal 4 Tage am Stück arbeiten. Tom darf nicht mehr als 3 Nachtschichten hintereinander machen.
</div>
</div>
<div class="space-y-2">
<div v-for="preview in constraintPreviews" :key="preview.text" class="bg-indigo-50 border border-indigo-100 rounded-xl p-3 flex items-start gap-3">
<UIcon name="i-lucide-check-circle" class="text-indigo-600 mt-0.5 w-4 h-4 shrink-0" />
<div>
<p class="text-sm font-medium text-indigo-900">{{ preview.text }}</p>
<p class="text-xs text-indigo-500">{{ preview.meta }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="absolute -bottom-4 -right-4 w-32 h-32 bg-violet-100 rounded-full -z-10" />
<div class="absolute -top-4 -left-4 w-24 h-24 bg-emerald-100 rounded-full -z-10" />
</div>
</div>
</section>
<!-- Features -->
<section id="features" class="py-24 px-6">
<div class="max-w-6xl mx-auto">
<div class="text-center mb-16">
<h2 class="text-4xl font-bold text-gray-900 mb-4">Alles was Sie brauchen</h2>
<p class="text-xl text-gray-600 max-w-2xl mx-auto">Keine komplizierte Software mehr. Einfach eingeben, was Sie wollen.</p>
</div>
<div class="grid md:grid-cols-3 gap-8">
<div v-for="feature in features" :key="feature.title" class="bg-white rounded-2xl border border-gray-100 shadow-sm p-8 hover:shadow-md transition-shadow">
<div class="w-12 h-12 rounded-2xl flex items-center justify-center text-2xl mb-6" :class="feature.bgColor">
{{ feature.icon }}
</div>
<h3 class="text-xl font-bold text-gray-900 mb-3">{{ feature.title }}</h3>
<p class="text-gray-600 leading-relaxed">{{ feature.description }}</p>
</div>
</div>
</div>
</section>
<!-- How it works -->
<section id="how-it-works" class="py-24 px-6 bg-gradient-to-br from-gray-50 to-indigo-50/30">
<div class="max-w-5xl mx-auto">
<div class="text-center mb-16">
<h2 class="text-4xl font-bold text-gray-900 mb-4">So einfach geht's</h2>
<p class="text-xl text-gray-600">In drei Schritten zum perfekten Schichtplan</p>
</div>
<div class="grid md:grid-cols-3 gap-8">
<div v-for="(step, i) in steps" :key="step.title" class="text-center relative">
<div class="w-20 h-20 rounded-3xl bg-white shadow-lg border border-gray-100 flex items-center justify-center text-4xl mx-auto mb-6 relative">
{{ step.icon }}
<span class="absolute -top-2 -right-2 w-7 h-7 rounded-full bg-indigo-600 text-white text-xs font-bold flex items-center justify-center">{{ i + 1 }}</span>
</div>
<h3 class="text-xl font-bold text-gray-900 mb-3">{{ step.title }}</h3>
<p class="text-gray-600 leading-relaxed">{{ step.description }}</p>
</div>
</div>
</div>
</section>
<!-- Legal highlight -->
<section class="py-24 px-6">
<div class="max-w-6xl mx-auto">
<div class="bg-gradient-to-r from-indigo-600 to-violet-700 rounded-3xl p-12 text-white">
<div class="grid md:grid-cols-2 gap-12 items-center">
<div>
<div class="inline-flex items-center gap-2 px-4 py-1.5 bg-white/20 rounded-full text-sm font-medium mb-6">
Rechtlich abgesichert
</div>
<h2 class="text-3xl font-bold mb-4">Gesetzliche Vorgaben inklusive</h2>
<p class="text-indigo-100 text-lg leading-relaxed mb-6">
Alle relevanten Vorschriften aus dem Arbeitszeitgesetz sind bereits als Vorlagen hinterlegt.
Einfach aktivieren fertig.
</p>
<ul class="space-y-3">
<li v-for="rule in legalRules" :key="rule" class="flex items-center gap-3">
<span class="text-emerald-300"></span>
<span class="text-indigo-100">{{ rule }}</span>
</li>
</ul>
</div>
<div class="space-y-3">
<div v-for="template in legalTemplates" :key="template.label" class="bg-white/10 backdrop-blur rounded-2xl p-4 border border-white/20">
<div class="flex items-center justify-between mb-1">
<span class="font-medium">{{ template.label }}</span>
<span class="text-xs bg-red-400/30 text-red-200 px-2 py-0.5 rounded-full">Pflicht</span>
</div>
<p class="text-sm text-indigo-200">{{ template.description }}</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Pricing -->
<section id="pricing" class="py-24 px-6 bg-gray-50">
<div class="max-w-6xl mx-auto">
<div class="text-center mb-16">
<h2 class="text-4xl font-bold text-gray-900 mb-4">Einfache Preise</h2>
<p class="text-xl text-gray-600">Kein verstecktes Kleingedrucktes. Starten Sie kostenlos.</p>
</div>
<div class="grid md:grid-cols-3 gap-8">
<div
v-for="(tier, key) in PLAN_LIMITS"
:key="key"
class="bg-white rounded-2xl border border-gray-100 shadow-sm p-8 relative"
:class="key === 'pro' ? 'ring-2 ring-indigo-500 shadow-xl shadow-indigo-100' : ''"
>
<div v-if="key === 'pro'" class="absolute -top-4 left-1/2 -translate-x-1/2 px-4 py-1 bg-indigo-600 text-white text-sm font-medium rounded-full whitespace-nowrap">
Beliebteste Wahl
</div>
<h3 class="text-2xl font-bold text-gray-900 mb-2">{{ tier.name }}</h3>
<p class="text-gray-500 mb-6 text-sm">{{ tier.description }}</p>
<div class="mb-8">
<span class="text-5xl font-extrabold text-gray-900">{{ tier.price_eur_month }}</span>
<span class="text-gray-500 ml-2">/Monat</span>
</div>
<ul class="space-y-3 mb-8">
<li v-for="f in tier.features" :key="f" class="flex items-center gap-3 text-gray-600 text-sm">
<UIcon name="i-lucide-check" class="text-emerald-500 w-4 h-4 shrink-0" />
{{ f }}
</li>
</ul>
<NuxtLink :to="tier.price_eur_month === 0 ? '/register' : '/register'">
<UButton
:color="key === 'pro' ? 'primary' : 'neutral'"
:variant="key === 'pro' ? 'solid' : 'outline'"
class="w-full justify-center"
size="lg"
>
{{ tier.price_eur_month === 0 ? 'Kostenlos starten' : 'Jetzt upgraden' }}
</UButton>
</NuxtLink>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer class="py-12 px-6 border-t border-gray-100">
<div class="max-w-6xl mx-auto flex flex-col md:flex-row items-center justify-between gap-4">
<div class="flex items-center gap-2">
<div class="w-7 h-7 rounded-lg bg-gradient-to-br from-indigo-500 to-violet-600 flex items-center justify-center">
<span class="text-white font-bold text-xs">S</span>
</div>
<span class="font-bold text-gray-900">ShiftCraft</span>
</div>
<p class="text-gray-500 text-sm">© 2025 ShiftCraft. Alle Rechte vorbehalten.</p>
<div class="flex gap-6">
<a href="#" class="text-gray-500 hover:text-gray-700 text-sm transition-colors">Datenschutz</a>
<a href="#" class="text-gray-500 hover:text-gray-700 text-sm transition-colors">Impressum</a>
<a href="#" class="text-gray-500 hover:text-gray-700 text-sm transition-colors">Kontakt</a>
</div>
</div>
</footer>
</div>
</template>
<script setup lang="ts">
import { PLAN_LIMITS } from '~/app/utils/planLimits'
definePageMeta({ layout: false })
const constraintPreviews = [
{ text: 'Sabine bevorzugt keine Nachtschichten', meta: 'Soft-Bedingung · Gewicht 65' },
{ text: 'Max. 4 aufeinanderfolgende Schichten (Sabine)', meta: 'Harte Bedingung' },
{ text: 'Max. 3 Nachtschichten am Stück (Tom)', meta: 'Harte Bedingung' },
]
const features = [
{ icon: '💬', title: 'Einfach eingeben', description: 'Keine komplizierten Formulare. Schreiben Sie einfach, was Sie wollen — wie in einer Nachricht.', bgColor: 'bg-indigo-50' },
{ icon: '⚡', title: 'Automatisch optimiert', description: 'Unser intelligentes System erstellt den bestmöglichen, fairen Plan in Sekunden — nicht Stunden.', bgColor: 'bg-violet-50' },
{ icon: '⚖️', title: 'Rechtlich sicher', description: 'Gesetzliche Vorlagen für Deutschland, Österreich und die Schweiz sind bereits eingebaut.', bgColor: 'bg-emerald-50' },
{ icon: '🤝', title: 'Mitarbeiterwünsche', description: 'Individuelle Präferenzen werden berücksichtigt — für mehr Zufriedenheit im Team.', bgColor: 'bg-amber-50' },
{ icon: '📊', title: 'Faire Verteilung', description: 'Automatisch faire Verteilung von Nacht-, Wochenend- und Feiertagsschichten.', bgColor: 'bg-pink-50' },
{ icon: '📤', title: 'Export & Teilen', description: 'Den fertigen Plan als PDF oder Excel exportieren und direkt teilen.', bgColor: 'bg-cyan-50' },
]
const steps = [
{ icon: '🗓️', title: 'Rahmen festlegen', description: 'Definieren Sie Ihre Schichtzeiten und wie viele Mitarbeiter pro Schicht benötigt werden.' },
{ icon: '✏️', title: 'Regeln eingeben', description: 'Schreiben Sie Ihre Wünsche und Regeln in normaler Sprache — so einfach wie eine E-Mail.' },
{ icon: '✨', title: 'Plan erhalten', description: 'ShiftCraft berechnet automatisch den optimalen, fairen Schichtplan für Ihr Team.' },
]
const legalRules = [
'Max. 10 Stunden Arbeitszeit pro Tag',
'Min. 11 Stunden Ruhezeit zwischen Schichten',
'Max. 48 Stunden Arbeitszeit pro Woche',
'Keine Frühschicht nach Nachtschicht',
]
const legalTemplates = [
{ label: 'Max. 10 Stunden/Tag', description: 'Arbeitszeitgesetz §3 — Pflicht für alle Unternehmen' },
{ label: 'Min. 11h Ruhezeit', description: 'Arbeitszeitgesetz §5 — Zwischen zwei Schichten' },
{ label: 'Max. 6 Tage am Stück', description: 'Arbeitszeitgesetz §9 — Sonntagsruhe' },
]
</script>