added more page content
This commit is contained in:
@@ -0,0 +1,327 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
import {
|
||||||
|
ArrowLeft,
|
||||||
|
ArrowRight,
|
||||||
|
CheckCircle2,
|
||||||
|
HelpCircle,
|
||||||
|
ShieldCheck,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
import {
|
||||||
|
getMarketingFeature,
|
||||||
|
marketingFeatures,
|
||||||
|
} from "@/lib/marketing/features";
|
||||||
|
|
||||||
|
type FeaturePageProps = {
|
||||||
|
params: Promise<{
|
||||||
|
slug: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const dynamicParams = false;
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return marketingFeatures.map((feature) => ({
|
||||||
|
slug: feature.slug,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: FeaturePageProps): Promise<Metadata> {
|
||||||
|
const { slug } = await params;
|
||||||
|
const feature = getMarketingFeature(slug);
|
||||||
|
|
||||||
|
if (!feature) {
|
||||||
|
return {
|
||||||
|
title: "Feature nicht gefunden",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: feature.seoTitle,
|
||||||
|
description: feature.seoDescription,
|
||||||
|
openGraph: {
|
||||||
|
title: feature.seoTitle,
|
||||||
|
description: feature.seoDescription,
|
||||||
|
type: "website",
|
||||||
|
locale: "de_DE",
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: "/og-image.png",
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: "Ein Kind spielt mit bunten Holzklötzen.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
title: feature.seoTitle,
|
||||||
|
description: feature.seoDescription,
|
||||||
|
images: ["/og-image.png"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function FeaturePage({ params }: FeaturePageProps) {
|
||||||
|
const { slug } = await params;
|
||||||
|
const feature = getMarketingFeature(slug);
|
||||||
|
|
||||||
|
if (!feature) {
|
||||||
|
notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Icon = feature.icon;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-[#f8faf8] text-slate-950">
|
||||||
|
<header className="border-b border-slate-200 bg-white/95">
|
||||||
|
<div className="mx-auto flex h-20 w-full max-w-7xl items-center justify-between px-5 sm:px-6">
|
||||||
|
<Link href="/" className="flex items-center gap-3 text-slate-950">
|
||||||
|
<span className="flex h-9 w-9 items-center justify-center rounded-lg bg-slate-950 text-white">
|
||||||
|
<ShieldCheck className="h-5 w-5" />
|
||||||
|
</span>
|
||||||
|
<span className="text-base font-semibold tracking-tight">
|
||||||
|
Kita-Planer
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<nav className="flex items-center gap-2">
|
||||||
|
<Button asChild variant="ghost">
|
||||||
|
<Link href="/login">Login</Link>
|
||||||
|
</Button>
|
||||||
|
<Button asChild>
|
||||||
|
<Link href="/#kontakt">Demo anfragen</Link>
|
||||||
|
</Button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section className="bg-slate-950 px-5 py-20 text-white sm:px-6 lg:py-24">
|
||||||
|
<div className="mx-auto grid w-full max-w-7xl gap-12 lg:grid-cols-[0.95fr_1.05fr] lg:items-center">
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
variant="ghost"
|
||||||
|
className="-ml-3 mb-8 text-slate-300 hover:bg-white/10 hover:text-white"
|
||||||
|
>
|
||||||
|
<Link href="/">
|
||||||
|
<ArrowLeft className="h-4 w-4" />
|
||||||
|
Zur Startseite
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Badge className="mb-6 border-white/15 bg-white/10 text-white hover:bg-white/10">
|
||||||
|
{feature.eyebrow}
|
||||||
|
</Badge>
|
||||||
|
<h1 className="max-w-4xl text-balance text-4xl font-semibold leading-tight sm:text-5xl lg:text-6xl">
|
||||||
|
{feature.heroTitle}
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 max-w-2xl text-lg leading-8 text-slate-300">
|
||||||
|
{feature.heroDescription}
|
||||||
|
</p>
|
||||||
|
<div className="mt-9 flex flex-col gap-3 sm:flex-row">
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
size="lg"
|
||||||
|
className="h-12 bg-white px-6 text-slate-950 hover:bg-white/90"
|
||||||
|
>
|
||||||
|
<Link href="/#kontakt">
|
||||||
|
Demo anfragen
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
size="lg"
|
||||||
|
variant="outline"
|
||||||
|
className="h-12 border-white/35 bg-white/10 px-6 text-white hover:bg-white/20 hover:text-white"
|
||||||
|
>
|
||||||
|
<Link href="/register">Kita registrieren</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="rounded-lg border border-white/10 bg-white/[0.06] p-6 shadow-2xl shadow-slate-950/30">
|
||||||
|
<div
|
||||||
|
className={`mb-6 flex h-14 w-14 items-center justify-center rounded-lg ring-1 ${feature.accent}`}
|
||||||
|
>
|
||||||
|
<Icon className="h-7 w-7" />
|
||||||
|
</div>
|
||||||
|
<p className="text-sm font-semibold uppercase tracking-wide text-emerald-200">
|
||||||
|
In einem Satz
|
||||||
|
</p>
|
||||||
|
<p className="mt-4 text-2xl font-semibold leading-snug">
|
||||||
|
{feature.description}
|
||||||
|
</p>
|
||||||
|
<div className="mt-8 grid gap-3 text-sm text-slate-300">
|
||||||
|
{feature.benefits.slice(0, 3).map((benefit) => (
|
||||||
|
<div key={benefit.title} className="flex items-start gap-2">
|
||||||
|
<CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0 text-emerald-300" />
|
||||||
|
<span>{benefit.title}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mx-auto grid w-full max-w-7xl gap-6 px-5 py-20 sm:px-6 lg:grid-cols-2">
|
||||||
|
<Card className="border-slate-200 bg-white">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-2xl tracking-tight">
|
||||||
|
{feature.problemTitle}
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription className="text-base leading-7 text-slate-600">
|
||||||
|
{feature.problemText}
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-slate-200 bg-white">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-2xl tracking-tight">
|
||||||
|
{feature.solutionTitle}
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription className="text-base leading-7 text-slate-600">
|
||||||
|
{feature.solutionText}
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="px-5 pb-20 sm:px-6">
|
||||||
|
<div className="mx-auto w-full max-w-7xl">
|
||||||
|
<div className="mb-10 max-w-3xl">
|
||||||
|
<p className="mb-3 text-sm font-semibold uppercase tracking-wide text-emerald-700">
|
||||||
|
Was das konkret bringt
|
||||||
|
</p>
|
||||||
|
<h2 className="text-balance text-3xl font-semibold leading-tight sm:text-4xl">
|
||||||
|
Weniger Abstimmungslast, mehr Klarheit im Kita-Alltag.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-5 md:grid-cols-2">
|
||||||
|
{feature.benefits.map((benefit) => (
|
||||||
|
<Card key={benefit.title} className="border-slate-200 bg-white">
|
||||||
|
<CardHeader>
|
||||||
|
<div className="mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-emerald-50 text-emerald-700 ring-1 ring-emerald-100">
|
||||||
|
<CheckCircle2 className="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<CardTitle className="text-xl tracking-tight">
|
||||||
|
{benefit.title}
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription className="text-sm leading-6 text-slate-600">
|
||||||
|
{benefit.text}
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="bg-slate-950 px-5 py-18 text-white sm:px-6">
|
||||||
|
<div className="mx-auto flex w-full max-w-7xl flex-col gap-5 lg:flex-row lg:items-center lg:justify-between">
|
||||||
|
<div className="max-w-3xl">
|
||||||
|
<Badge className="mb-5 border-emerald-300/20 bg-emerald-300/10 text-emerald-100 hover:bg-emerald-300/10">
|
||||||
|
Vertrauen & Datenschutz
|
||||||
|
</Badge>
|
||||||
|
<h2 className="text-3xl font-semibold tracking-tight">
|
||||||
|
{feature.trustTitle}
|
||||||
|
</h2>
|
||||||
|
<p className="mt-4 text-base leading-7 text-slate-300">
|
||||||
|
{feature.trustText}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
size="lg"
|
||||||
|
className="h-12 bg-white px-6 text-slate-950 hover:bg-white/90 lg:shrink-0"
|
||||||
|
>
|
||||||
|
<Link href="/datenschutz">Datenschutz ansehen</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mx-auto w-full max-w-7xl px-5 py-20 sm:px-6">
|
||||||
|
<div className="mb-10 max-w-3xl">
|
||||||
|
<p className="mb-3 text-sm font-semibold uppercase tracking-wide text-emerald-700">
|
||||||
|
Fragen aus dem Vorstand
|
||||||
|
</p>
|
||||||
|
<h2 className="text-balance text-3xl font-semibold leading-tight sm:text-4xl">
|
||||||
|
Kurz beantwortet.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-4 lg:grid-cols-3">
|
||||||
|
{feature.faqs.map((faq) => (
|
||||||
|
<Card key={faq.question} className="border-slate-200 bg-white">
|
||||||
|
<CardHeader>
|
||||||
|
<div className="mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-slate-100 text-slate-700">
|
||||||
|
<HelpCircle className="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<CardTitle className="text-lg leading-snug">
|
||||||
|
{faq.question}
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription className="text-sm leading-6 text-slate-600">
|
||||||
|
{faq.answer}
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="px-5 pb-20 sm:px-6">
|
||||||
|
<div className="mx-auto flex w-full max-w-7xl flex-col gap-6 rounded-lg border border-slate-200 bg-white p-8 shadow-sm sm:p-10 md:flex-row md:items-center md:justify-between">
|
||||||
|
<div className="max-w-2xl">
|
||||||
|
<h2 className="text-2xl font-semibold tracking-tight">
|
||||||
|
Wollt ihr {feature.shortTitle} im echten Kita-Alltag sehen?
|
||||||
|
</h2>
|
||||||
|
<p className="mt-3 text-sm leading-6 text-slate-600">
|
||||||
|
Schreibt uns kurz, wie ihr heute organisiert seid. Wir zeigen
|
||||||
|
euch, wie Kita-Planer zu eurem Elternverein passen kann.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button asChild size="lg">
|
||||||
|
<Link href="/#kontakt">
|
||||||
|
Demo anfragen
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer className="border-t border-slate-200 bg-white">
|
||||||
|
<div className="mx-auto flex w-full max-w-7xl flex-col gap-4 px-5 py-8 text-sm text-slate-500 sm:flex-row sm:items-center sm:justify-between sm:px-6">
|
||||||
|
<span>© {new Date().getFullYear()} Kita-Planer</span>
|
||||||
|
<nav className="flex gap-5">
|
||||||
|
<Link href="/impressum" className="hover:text-slate-950">
|
||||||
|
Impressum
|
||||||
|
</Link>
|
||||||
|
<Link href="/datenschutz" className="hover:text-slate-950">
|
||||||
|
Datenschutz
|
||||||
|
</Link>
|
||||||
|
<Link href="/#kontakt" className="hover:text-slate-950">
|
||||||
|
Kontakt
|
||||||
|
</Link>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
+12
-46
@@ -3,19 +3,14 @@ import Link from "next/link";
|
|||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
ArrowRight,
|
ArrowRight,
|
||||||
CalendarDays,
|
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
DatabaseZap,
|
DatabaseZap,
|
||||||
Fingerprint,
|
Fingerprint,
|
||||||
LockKeyhole,
|
LockKeyhole,
|
||||||
Mail,
|
Mail,
|
||||||
Megaphone,
|
|
||||||
MessageSquareText,
|
MessageSquareText,
|
||||||
ShieldAlert,
|
|
||||||
ShieldCheck,
|
ShieldCheck,
|
||||||
Stethoscope,
|
|
||||||
Trash2,
|
Trash2,
|
||||||
UsersRound,
|
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
import { auth } from "@/auth";
|
import { auth } from "@/auth";
|
||||||
@@ -28,6 +23,7 @@ import {
|
|||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
|
import { marketingFeatures } from "@/lib/marketing/features";
|
||||||
import { ContactForm } from "./contact-form";
|
import { ContactForm } from "./contact-form";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
@@ -61,46 +57,6 @@ export const metadata: Metadata = {
|
|||||||
const heroImage =
|
const heroImage =
|
||||||
"https://images.unsplash.com/photo-1503454537195-1dcabb73ffb9?auto=format&fit=crop&w=2400&q=86";
|
"https://images.unsplash.com/photo-1503454537195-1dcabb73ffb9?auto=format&fit=crop&w=2400&q=86";
|
||||||
|
|
||||||
const features = [
|
|
||||||
{
|
|
||||||
icon: ShieldAlert,
|
|
||||||
title: "Fairer Notdienst-Planer",
|
|
||||||
description:
|
|
||||||
"Automatische Generierung, gerechte Verteilung und 1-Klick-Alarmierung, wenn morgens Ersatz gebraucht wird.",
|
|
||||||
accent: "bg-red-50 text-red-700 ring-red-100",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: CalendarDays,
|
|
||||||
title: "Smarter Kalender",
|
|
||||||
description:
|
|
||||||
"Feste, Termine, Raumbuchungen und digitale Mitbring-Listen in einem verbindlichen Kalender für alle Familien.",
|
|
||||||
accent: "bg-sky-50 text-sky-700 ring-sky-100",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: UsersRound,
|
|
||||||
title: "Sicheres Adressbuch",
|
|
||||||
description:
|
|
||||||
"Haushaltsbasiert, DSGVO-konform und mit strengem Opt-In: Kontaktdaten werden nur sichtbar, wenn Eltern zustimmen.",
|
|
||||||
accent: "bg-emerald-50 text-emerald-700 ring-emerald-100",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: Stethoscope,
|
|
||||||
title: "Digitale Krankmeldung",
|
|
||||||
description:
|
|
||||||
"Ein Klick statt Dauerläuten am Morgen. Eltern melden Kinder digital ab, ErzieherInnen sehen auf dem Tablet sofort den Überblick für den Morgenkreis.",
|
|
||||||
accent: "bg-amber-50 text-amber-700 ring-amber-100",
|
|
||||||
badge: "Neu",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: Megaphone,
|
|
||||||
title: "Schwarzes Brett",
|
|
||||||
description:
|
|
||||||
"Der WhatsApp-Killer für Vorstände: offizielle Ankündigungen mit Dateianhängen, Lesebestätigung und optionalem E-Mail-Push.",
|
|
||||||
accent: "bg-indigo-50 text-indigo-700 ring-indigo-100",
|
|
||||||
badge: "Neu",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const privacyPoints = [
|
const privacyPoints = [
|
||||||
{
|
{
|
||||||
icon: DatabaseZap,
|
icon: DatabaseZap,
|
||||||
@@ -246,7 +202,7 @@ export default async function LandingPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-5 md:grid-cols-2 xl:grid-cols-6">
|
<div className="grid gap-5 md:grid-cols-2 xl:grid-cols-6">
|
||||||
{features.map((feature, index) => {
|
{marketingFeatures.map((feature, index) => {
|
||||||
const Icon = feature.icon;
|
const Icon = feature.icon;
|
||||||
const isWide = index > 2;
|
const isWide = index > 2;
|
||||||
return (
|
return (
|
||||||
@@ -276,6 +232,16 @@ export default async function LandingPage() {
|
|||||||
<CardDescription className="mt-3 text-sm leading-6 text-slate-600">
|
<CardDescription className="mt-3 text-sm leading-6 text-slate-600">
|
||||||
{feature.description}
|
{feature.description}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
variant="link"
|
||||||
|
className="mt-4 h-auto p-0 text-slate-950"
|
||||||
|
>
|
||||||
|
<Link href={`/features/${feature.slug}`}>
|
||||||
|
Mehr erfahren
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ export default function robots(): MetadataRoute.Robots {
|
|||||||
return {
|
return {
|
||||||
rules: {
|
rules: {
|
||||||
userAgent: "*",
|
userAgent: "*",
|
||||||
allow: ["/", "/impressum", "/datenschutz"],
|
allow: ["/", "/features/", "/impressum", "/datenschutz"],
|
||||||
disallow: [
|
disallow: [
|
||||||
"/api/",
|
"/api/",
|
||||||
"/dashboard/",
|
"/dashboard/",
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { MetadataRoute } from "next";
|
import type { MetadataRoute } from "next";
|
||||||
|
|
||||||
|
import { marketingFeatures } from "@/lib/marketing/features";
|
||||||
|
|
||||||
function getSiteUrl() {
|
function getSiteUrl() {
|
||||||
return process.env.NEXT_PUBLIC_SITE_URL ?? "https://mein-kitaplaner.de";
|
return process.env.NEXT_PUBLIC_SITE_URL ?? "https://mein-kitaplaner.de";
|
||||||
}
|
}
|
||||||
@@ -27,5 +29,11 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
|||||||
changeFrequency: "yearly",
|
changeFrequency: "yearly",
|
||||||
priority: 0.2,
|
priority: 0.2,
|
||||||
},
|
},
|
||||||
|
...marketingFeatures.map((feature) => ({
|
||||||
|
url: `${siteUrl}/features/${feature.slug}`,
|
||||||
|
lastModified,
|
||||||
|
changeFrequency: "monthly" as const,
|
||||||
|
priority: 0.8,
|
||||||
|
})),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import Script from "next/script";
|
import Script from "next/script";
|
||||||
|
|
||||||
|
import { marketingFeatureSlugs } from "@/lib/marketing/features";
|
||||||
|
|
||||||
const publicAnalyticsPaths = new Set([
|
const publicAnalyticsPaths = new Set([
|
||||||
"/",
|
"/",
|
||||||
"/impressum",
|
"/impressum",
|
||||||
"/datenschutz",
|
"/datenschutz",
|
||||||
"/login",
|
"/login",
|
||||||
"/register",
|
"/register",
|
||||||
|
...marketingFeatureSlugs.map((slug) => `/features/${slug}`),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export function UmamiAnalytics() {
|
export function UmamiAnalytics() {
|
||||||
|
|||||||
@@ -0,0 +1,350 @@
|
|||||||
|
import type { LucideIcon } from "lucide-react";
|
||||||
|
import {
|
||||||
|
CalendarDays,
|
||||||
|
Megaphone,
|
||||||
|
ShieldAlert,
|
||||||
|
Stethoscope,
|
||||||
|
UsersRound,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
export type MarketingFeature = {
|
||||||
|
slug: string;
|
||||||
|
icon: LucideIcon;
|
||||||
|
title: string;
|
||||||
|
shortTitle: string;
|
||||||
|
description: string;
|
||||||
|
accent: string;
|
||||||
|
badge?: string;
|
||||||
|
eyebrow: string;
|
||||||
|
heroTitle: string;
|
||||||
|
heroDescription: string;
|
||||||
|
seoTitle: string;
|
||||||
|
seoDescription: string;
|
||||||
|
problemTitle: string;
|
||||||
|
problemText: string;
|
||||||
|
solutionTitle: string;
|
||||||
|
solutionText: string;
|
||||||
|
benefits: {
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
}[];
|
||||||
|
trustTitle: string;
|
||||||
|
trustText: string;
|
||||||
|
faqs: {
|
||||||
|
question: string;
|
||||||
|
answer: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const marketingFeatures: MarketingFeature[] = [
|
||||||
|
{
|
||||||
|
slug: "notdienst-planer",
|
||||||
|
icon: ShieldAlert,
|
||||||
|
title: "Fairer Notdienst-Planer",
|
||||||
|
shortTitle: "Notdienst-Planer",
|
||||||
|
description:
|
||||||
|
"Automatische Generierung, gerechte Verteilung und 1-Klick-Alarmierung, wenn morgens Ersatz gebraucht wird.",
|
||||||
|
accent: "bg-red-50 text-red-700 ring-red-100",
|
||||||
|
eyebrow: "Notdienst ohne Excel-Lotterie",
|
||||||
|
heroTitle: "Faire Notdienstplanung für Elterninitiativen.",
|
||||||
|
heroDescription:
|
||||||
|
"Eltern tragen ihre Verfügbarkeiten ein, Vorstände behalten den Überblick und der Monatsplan entsteht nachvollziehbar statt in endlosen Chatverläufen.",
|
||||||
|
seoTitle: "Notdienst-Planer für Kita-Elternvereine",
|
||||||
|
seoDescription:
|
||||||
|
"Plant Notdienste fair, digital und nachvollziehbar: Verfügbarkeiten erfassen, Mindesttage berücksichtigen und Ersatz schneller finden.",
|
||||||
|
problemTitle: "Wenn morgens plötzlich Ersatz gebraucht wird",
|
||||||
|
problemText:
|
||||||
|
"In vielen Elterninitiativen hängt der Notdienst an Tabellen, Bauchgefühl und der Hoffnung, dass irgendwer im Chat rechtzeitig reagiert. Das ist für Vorstände anstrengend und für Eltern oft schwer nachvollziehbar.",
|
||||||
|
solutionTitle: "Verfügbarkeiten einsammeln, Plan erzeugen, reagieren",
|
||||||
|
solutionText:
|
||||||
|
"Kita-Planer bündelt die Verfügbarkeiten der Familien, berücksichtigt Mindesttage pro Kind und unterstützt Koordinatoren dabei, den Monatsplan zu erstellen und bei Ausfällen schneller Ersatz zu finden.",
|
||||||
|
benefits: [
|
||||||
|
{
|
||||||
|
title: "Verfügbarkeiten pro Familie",
|
||||||
|
text: "Eltern geben digital an, an welchen Tagen sie unterstützen können. Der Vorstand arbeitet mit strukturierten Daten statt verstreuten Nachrichten.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Nachvollziehbare Verteilung",
|
||||||
|
text: "Mindesttage pro Kind und aktive Kinder werden berücksichtigt, damit die Planung transparent und fairer erklärbar bleibt.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Planung für Koordinatoren",
|
||||||
|
text: "Koordinatoren sehen den Zielmonat, können Pläne erzeugen und bei Bedarf manuell nachsteuern.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Schneller reagieren",
|
||||||
|
text: "Wenn morgens Ersatz nötig ist, hilft eine strukturierte Übersicht deutlich mehr als ein hektischer Chat.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trustTitle: "Gemacht für sensible Kita-Abläufe",
|
||||||
|
trustText:
|
||||||
|
"Notdienst-Daten bleiben im geschützten Kita-Kontext und sind an Rollenrechte sowie die jeweilige Kita-Zugehörigkeit gebunden.",
|
||||||
|
faqs: [
|
||||||
|
{
|
||||||
|
question: "Können Eltern selbst eintragen, wann sie verfügbar sind?",
|
||||||
|
answer:
|
||||||
|
"Ja. Eltern können ihre möglichen Notdiensttage für den Zielmonat digital hinterlegen.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Kann der Vorstand den Plan noch anpassen?",
|
||||||
|
answer:
|
||||||
|
"Ja. Koordinatoren und Admins behalten die Übersicht und können bei Bedarf manuell nachsteuern.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Ersetzt das alle Abstimmungen im Notfall?",
|
||||||
|
answer:
|
||||||
|
"Nein, aber es schafft eine deutlich bessere Grundlage, um schnell passende Familien zu finden.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "kita-kalender",
|
||||||
|
icon: CalendarDays,
|
||||||
|
title: "Smarter Kalender",
|
||||||
|
shortTitle: "Kita-Kalender",
|
||||||
|
description:
|
||||||
|
"Feste, Termine, Raumbuchungen und digitale Mitbring-Listen in einem verbindlichen Kalender für alle Familien.",
|
||||||
|
accent: "bg-sky-50 text-sky-700 ring-sky-100",
|
||||||
|
eyebrow: "Termine, Dienste und Mitbringlisten",
|
||||||
|
heroTitle: "Ein Kita-Kalender, den Eltern wirklich nutzen.",
|
||||||
|
heroDescription:
|
||||||
|
"Alle wichtigen Termine, Dienstzuordnungen und Mitbringlisten an einem Ort, damit niemand nach der richtigen Nachricht im Chat suchen muss.",
|
||||||
|
seoTitle: "Kita-Kalender für Elternvereine",
|
||||||
|
seoDescription:
|
||||||
|
"Ein gemeinsamer Kalender für Elterninitiativen: Termine, Anfragen, Dienste und Mitbringlisten übersichtlich organisieren.",
|
||||||
|
problemTitle: "Termine verschwinden zu schnell",
|
||||||
|
problemText:
|
||||||
|
"Elternabende, Feste, Schließtage, Dienste und Mitbringlisten landen oft in unterschiedlichen Kanälen. Wer später nachschaut, findet nicht mehr sicher die aktuelle Information.",
|
||||||
|
solutionTitle: "Ein verbindlicher Ort für den Kita-Alltag",
|
||||||
|
solutionText:
|
||||||
|
"Kita-Planer zeigt bestätigte Termine, eigene Anfragen, Dienstzuordnungen und Mitbringlisten gemeinsam. Admins können Anfragen prüfen und offizielle Termine sauber veröffentlichen.",
|
||||||
|
benefits: [
|
||||||
|
{
|
||||||
|
title: "Termine im Überblick",
|
||||||
|
text: "Feste, Schließtage, Elternabende und andere Ereignisse werden zentral sichtbar.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Anfragen statt Nebenabsprachen",
|
||||||
|
text: "Eltern können Terminwünsche einreichen, die von Verantwortlichen geprüft werden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Mitbringlisten direkt am Termin",
|
||||||
|
text: "Was gebraucht wird, steht dort, wo Eltern es erwarten: am passenden Termin.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Dienste sichtbar machen",
|
||||||
|
text: "Geplante Dienste werden im Kontext der kommenden Termine und Aufgaben angezeigt.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trustTitle: "Verbindlichkeit statt Chat-Suche",
|
||||||
|
trustText:
|
||||||
|
"Der Kalender ist Teil des geschützten Kita-Bereichs und zeigt Informationen rollen- und mandantenbezogen an.",
|
||||||
|
faqs: [
|
||||||
|
{
|
||||||
|
question: "Können Eltern eigene Termine vorschlagen?",
|
||||||
|
answer:
|
||||||
|
"Ja. Terminanfragen können eingereicht und von berechtigten Personen geprüft werden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Sind Mitbringlisten enthalten?",
|
||||||
|
answer:
|
||||||
|
"Ja. Termine können mit digitalen Mitbringlisten verbunden werden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Wer sieht welche Termine?",
|
||||||
|
answer:
|
||||||
|
"Termine werden innerhalb der jeweiligen Kita angezeigt; Admins und Koordinatoren haben zusätzliche Prüf- und Verwaltungsfunktionen.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "eltern-adressbuch",
|
||||||
|
icon: UsersRound,
|
||||||
|
title: "Sicheres Adressbuch",
|
||||||
|
shortTitle: "Eltern-Adressbuch",
|
||||||
|
description:
|
||||||
|
"Haushaltsbasiert, DSGVO-konform gedacht und mit strengem Opt-In: Kontaktdaten werden nur sichtbar, wenn Eltern zustimmen.",
|
||||||
|
accent: "bg-emerald-50 text-emerald-700 ring-emerald-100",
|
||||||
|
eyebrow: "Kontakte nur mit Zustimmung",
|
||||||
|
heroTitle: "Ein Eltern-Adressbuch mit klarer Freigabe.",
|
||||||
|
heroDescription:
|
||||||
|
"Kontaktdaten werden nicht einfach herumgereicht, sondern nur sichtbar, wenn Eltern aktiv zustimmen.",
|
||||||
|
seoTitle: "Sicheres Eltern-Adressbuch für Kitas",
|
||||||
|
seoDescription:
|
||||||
|
"Ein digitales Kita-Adressbuch mit Opt-in, Haushalten und freigegebenen Kontaktdaten für Elternvereine und Elterninitiativen.",
|
||||||
|
problemTitle: "Kontaktlisten sind praktisch, aber sensibel",
|
||||||
|
problemText:
|
||||||
|
"Spielverabredungen und schnelle Rückfragen brauchen Kontaktdaten. Gleichzeitig möchten Eltern selbst entscheiden, welche Daten sichtbar sind.",
|
||||||
|
solutionTitle: "Haushalte, Kinder und Freigaben sauber trennen",
|
||||||
|
solutionText:
|
||||||
|
"Kita-Planer zeigt Familien und Kontaktdaten nur, wenn mindestens ein Elternteil aktiv zugestimmt hat. Nicht freigegebene Daten bleiben verborgen.",
|
||||||
|
benefits: [
|
||||||
|
{
|
||||||
|
title: "Opt-in statt Rundmail",
|
||||||
|
text: "Eltern geben bewusst frei, ob ihre Kontaktdaten im internen Adressbuch erscheinen.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Haushalte im Blick",
|
||||||
|
text: "Familien, Kinder und Elternteile werden gemeinsam verständlich dargestellt.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Nur freigegebene Daten",
|
||||||
|
text: "E-Mail und Telefonnummer werden nur dort angezeigt, wo eine Freigabe vorliegt.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Hilfreich für Dienste",
|
||||||
|
text: "Zugeordnete Elternaufgaben und Familieninformationen können im passenden Kontext sichtbar werden.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trustTitle: "Datenschutz ist Teil der Funktion",
|
||||||
|
trustText:
|
||||||
|
"Das Adressbuch ist bewusst als Opt-in-Funktion gestaltet. Es ersetzt lose Listen durch kontrollierte Sichtbarkeit.",
|
||||||
|
faqs: [
|
||||||
|
{
|
||||||
|
question: "Sind alle Eltern automatisch sichtbar?",
|
||||||
|
answer:
|
||||||
|
"Nein. Kontaktdaten erscheinen nur nach aktiver Freigabe.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Kann eine Familie teilweise sichtbar sein?",
|
||||||
|
answer:
|
||||||
|
"Ja. Sichtbarkeit hängt an den freigegebenen Elternteilen und deren Daten.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Ist das eine Rechtsberatung zur DSGVO?",
|
||||||
|
answer:
|
||||||
|
"Nein. Kita-Planer ist datensparsam gedacht, ersetzt aber keine rechtliche Prüfung eurer konkreten Prozesse.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "krankmeldung",
|
||||||
|
icon: Stethoscope,
|
||||||
|
title: "Digitale Krankmeldung",
|
||||||
|
shortTitle: "Krankmeldung",
|
||||||
|
description:
|
||||||
|
"Ein Klick statt Dauerläuten am Morgen. Eltern melden Kinder digital ab, ErzieherInnen sehen sofort den Überblick.",
|
||||||
|
accent: "bg-amber-50 text-amber-700 ring-amber-100",
|
||||||
|
badge: "Neu",
|
||||||
|
eyebrow: "Abwesenheiten ohne Telefonkette",
|
||||||
|
heroTitle: "Krankmeldungen digital und morgens sofort sichtbar.",
|
||||||
|
heroDescription:
|
||||||
|
"Eltern melden Abwesenheiten digital, das Team sieht den Tagesüberblick und der Morgen startet mit weniger Telefonchaos.",
|
||||||
|
seoTitle: "Digitale Krankmeldung für Kitas",
|
||||||
|
seoDescription:
|
||||||
|
"Eltern melden Kinder digital krank oder abwesend. Kita-Teams behalten den Tagesüberblick ohne Telefonchaos am Morgen.",
|
||||||
|
problemTitle: "Der Morgen beginnt oft mit Dauerläuten",
|
||||||
|
problemText:
|
||||||
|
"Wenn mehrere Kinder fehlen, sammeln sich Telefonate, Chatnachrichten und Zurufe genau dann, wenn das Team eigentlich den Tag vorbereiten muss.",
|
||||||
|
solutionTitle: "Abwesenheiten dort erfassen, wo sie gebraucht werden",
|
||||||
|
solutionText:
|
||||||
|
"Kita-Planer bündelt digitale Abwesenheitsmeldungen je Kita und zeigt sie im Dashboard, damit Team und Vorstand schneller den Überblick haben.",
|
||||||
|
benefits: [
|
||||||
|
{
|
||||||
|
title: "Eltern melden digital",
|
||||||
|
text: "Abwesenheiten können strukturiert mit Zeitraum und Grund hinterlegt werden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Tagesüberblick fürs Team",
|
||||||
|
text: "ErzieherInnen sehen, welche Kinder fehlen, ohne Telefonnotizen zusammenzutragen.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Weniger Missverständnisse",
|
||||||
|
text: "Zeiträume und Hinweise sind dokumentiert, statt in einzelnen Chatnachrichten zu verschwinden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Passt zum Familienprofil",
|
||||||
|
text: "Abwesenheiten sind mit den Kindern und der jeweiligen Kita-Zugehörigkeit verbunden.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trustTitle: "Sensible Informationen geschützt behandeln",
|
||||||
|
trustText:
|
||||||
|
"Abwesenheiten sind personenbezogene Informationen. Kita-Planer behandelt sie innerhalb des geschützten Kita-Bereichs und nicht als öffentliche Nachricht.",
|
||||||
|
faqs: [
|
||||||
|
{
|
||||||
|
question: "Können Eltern mehrere Tage eintragen?",
|
||||||
|
answer:
|
||||||
|
"Ja. Abwesenheiten können für einen Zeitraum erfasst werden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Sieht das Kita-Team die Meldungen sofort?",
|
||||||
|
answer:
|
||||||
|
"Die Meldungen werden im System sichtbar und können im Dashboard ausgewertet werden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Ersetzt das jede telefonische Rückfrage?",
|
||||||
|
answer:
|
||||||
|
"Nicht jede. Bei besonderen Situationen kann weiterhin persönlich nachgefragt werden.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "schwarzes-brett",
|
||||||
|
icon: Megaphone,
|
||||||
|
title: "Schwarzes Brett",
|
||||||
|
shortTitle: "Schwarzes Brett",
|
||||||
|
description:
|
||||||
|
"Offizielle Ankündigungen mit Dateianhängen, Lesebestätigung und optionalem E-Mail-Push statt verstreuter Chatposts.",
|
||||||
|
accent: "bg-indigo-50 text-indigo-700 ring-indigo-100",
|
||||||
|
badge: "Neu",
|
||||||
|
eyebrow: "Verbindliche Kita-Kommunikation",
|
||||||
|
heroTitle: "Ein digitales Schwarzes Brett für offizielle Nachrichten.",
|
||||||
|
heroDescription:
|
||||||
|
"Vorstände veröffentlichen Ankündigungen, hängen Dokumente an und erreichen Eltern über einen klaren Kanal statt über mehrere Chatgruppen.",
|
||||||
|
seoTitle: "Digitales Schwarzes Brett für Kitas",
|
||||||
|
seoDescription:
|
||||||
|
"Offizielle Ankündigungen für Elternvereine: Nachrichten, Anhänge, Lesestatus und optionaler E-Mail-Push in einem geschützten System.",
|
||||||
|
problemTitle: "Wichtige Infos gehen im Chat unter",
|
||||||
|
problemText:
|
||||||
|
"Zwischen Fotos, Rückfragen und spontanen Abstimmungen verlieren offizielle Ankündigungen schnell ihre Sichtbarkeit.",
|
||||||
|
solutionTitle: "Ein Kanal für das, was verbindlich sein soll",
|
||||||
|
solutionText:
|
||||||
|
"Kita-Planer trennt offizielle Nachrichten vom Chatrauschen. Ankündigungen können Anhänge enthalten und sind für die passende Kita geschützt abrufbar.",
|
||||||
|
benefits: [
|
||||||
|
{
|
||||||
|
title: "Offizielle Ankündigungen",
|
||||||
|
text: "Vorstände und Admins veröffentlichen zentrale Nachrichten an Eltern oder Team.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Geschützte Anhänge",
|
||||||
|
text: "PDF, JPG und PNG werden nicht öffentlich ausgeliefert, sondern nach Session und Kita geprüft.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Lesestatus im Blick",
|
||||||
|
text: "Das System kann sichtbar machen, welche Ankündigungen für Nutzer noch ungelesen sind.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Optional per E-Mail",
|
||||||
|
text: "Wichtige Meldungen können zusätzlich per E-Mail angestoßen werden.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
trustTitle: "Nicht öffentlich, nicht im Chat verloren",
|
||||||
|
trustText:
|
||||||
|
"Anhänge und Ankündigungen bleiben an Login, Rolle und Kita-Kontext gebunden. Das ist ruhiger und kontrollierter als öffentliche Links.",
|
||||||
|
faqs: [
|
||||||
|
{
|
||||||
|
question: "Welche Dateitypen sind möglich?",
|
||||||
|
answer:
|
||||||
|
"Aktuell sind PDF, JPG und PNG vorgesehen.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Sind Anhänge öffentlich erreichbar?",
|
||||||
|
answer:
|
||||||
|
"Nein. Anhänge werden nur nach Session- und Kita-Prüfung ausgeliefert.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Kann eine Ankündigung per E-Mail versendet werden?",
|
||||||
|
answer:
|
||||||
|
"Ja. Für wichtige Meldungen ist optional ein E-Mail-Push vorgesehen.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const marketingFeatureSlugs = marketingFeatures.map(
|
||||||
|
(feature) => feature.slug,
|
||||||
|
);
|
||||||
|
|
||||||
|
export function getMarketingFeature(slug: string) {
|
||||||
|
return marketingFeatures.find((feature) => feature.slug === slug);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user