mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 19:01:08 +02:00
feat(landing): add shared-landing-ui package and manadeck landing page
- Create @manacore/shared-landing-ui package with reusable components (FeatureSection, StepsSection, FAQSection, CTASection, Card atoms) - Add complete landing page for manadeck app - Refactor märchenzauber landing to use shared components (remove local CTA, FAQ, Features, HowItWorks sections) - Add German localization for manacore and memoro landing pages - Update workspace configuration and package dependencies 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
4bdb5dea85
commit
c6c4c5a552
52 changed files with 3519 additions and 381 deletions
|
|
@ -12,6 +12,7 @@
|
|||
"@astrojs/react": "^4.4.1",
|
||||
"@astrojs/tailwind": "^6.0.2",
|
||||
"@fontsource/grandstander": "^5.2.7",
|
||||
"@manacore/shared-landing-ui": "workspace:*",
|
||||
"astro": "^5.15.3",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
---
|
||||
// CTA section for landing page
|
||||
---
|
||||
|
||||
<section id="download" class="section bg-gradient-overlay relative overflow-hidden">
|
||||
<div class="container-custom relative z-10">
|
||||
<div class="text-center max-w-3xl mx-auto px-4">
|
||||
<!-- Icon -->
|
||||
<div class="text-5xl sm:text-6xl mb-4 sm:mb-6">🚀</div>
|
||||
|
||||
<!-- Heading -->
|
||||
<h2 class="font-grandstander font-bold text-2xl sm:text-3xl md:text-4xl lg:text-5xl text-text-primary mb-4 sm:mb-6 leading-tight">
|
||||
Bereit für magische Geschichten?
|
||||
</h2>
|
||||
|
||||
<!-- Description -->
|
||||
<p class="text-text-secondary text-base sm:text-lg md:text-xl mb-6 sm:mb-8 leading-relaxed">
|
||||
Lade Märchenzauber herunter und erschaffe noch heute deine erste personalisierte Geschichte.
|
||||
Starte kostenlos mit 100 Mana!
|
||||
</p>
|
||||
|
||||
<!-- CTA Button -->
|
||||
<div class="flex justify-center mb-6 sm:mb-8">
|
||||
<a href="/download" class="btn-primary inline-flex items-center justify-center gap-2 text-base sm:text-lg px-8 sm:px-10 py-4 sm:py-5 w-full sm:w-auto">
|
||||
Jetzt herunterladen
|
||||
<svg class="w-5 h-5 sm:w-6 sm:h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Trust Indicators -->
|
||||
<div class="flex flex-wrap items-center justify-center gap-4 sm:gap-6 mt-8 sm:mt-12">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 sm:w-5 sm:h-5 text-yellow-light" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M2.166 4.999A11.954 11.954 0 0010 1.944 11.954 11.954 0 0017.834 5c.11.65.166 1.32.166 2.001 0 5.225-3.34 9.67-8 11.317C5.34 16.67 2 12.225 2 7c0-.682.057-1.35.166-2.001zm11.541 3.708a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="text-text-secondary text-sm sm:text-base">100% Sicher</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 sm:w-5 sm:h-5 text-yellow-light" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10 2a1 1 0 00-1 1v1a1 1 0 002 0V3a1 1 0 00-1-1zM4 4h3a3 3 0 006 0h3a2 2 0 012 2v9a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2zm2.5 7a1.5 1.5 0 100-3 1.5 1.5 0 000 3zm2.45 4a2.5 2.5 0 10-4.9 0h4.9zM12 9a1 1 0 100 2h3a1 1 0 100-2h-3zm-1 4a1 1 0 011-1h2a1 1 0 110 2h-2a1 1 0 01-1-1z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="text-text-secondary text-sm sm:text-base">DSGVO konform</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 sm:w-5 sm:h-5 text-yellow-light" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M13 7H7v6h6V7z"></path>
|
||||
<path fill-rule="evenodd" d="M7 2a1 1 0 012 0v1h2V2a1 1 0 112 0v1h2a2 2 0 012 2v2h1a1 1 0 110 2h-1v2h1a1 1 0 110 2h-1v2a2 2 0 01-2 2h-2v1a1 1 0 11-2 0v-1H9v1a1 1 0 11-2 0v-1H5a2 2 0 01-2-2v-2H2a1 1 0 110-2h1V9H2a1 1 0 010-2h1V5a2 2 0 012-2h2V2zM5 5h10v10H5V5z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="text-text-secondary text-sm sm:text-base">Kindgerecht</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Background decoration */}
|
||||
<div class="absolute inset-0 pointer-events-none">
|
||||
<div class="absolute top-0 left-0 w-64 h-64 bg-yellow-dark/10 rounded-full blur-3xl"></div>
|
||||
<div class="absolute bottom-0 right-0 w-96 h-96 bg-yellow-light/10 rounded-full blur-3xl"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
---
|
||||
import Card from '../ui/Card.astro';
|
||||
|
||||
const faqs = [
|
||||
{
|
||||
question: 'Für welches Alter ist Märchenzauber geeignet?',
|
||||
answer: 'Märchenzauber ist für Kinder von 3-12 Jahren konzipiert. Die Geschichten werden automatisch an das Alter angepasst, sodass sowohl Kindergartenkinder als auch Grundschüler passende Inhalte erhalten.'
|
||||
},
|
||||
{
|
||||
question: 'Wie funktioniert das Mana-System?',
|
||||
answer: 'Mana sind Credits, die du für die Generierung von Geschichten verwendest. Eine Geschichte kostet etwa 30-40 Mana. Du startest mit 100 kostenlosen Mana und kannst jederzeit weitere kaufen oder ein Abo abschließen.'
|
||||
},
|
||||
{
|
||||
question: 'Kann ich die Geschichten offline lesen?',
|
||||
answer: 'Ja! Alle generierten Geschichten werden in deiner Bibliothek gespeichert und können offline gelesen werden. So hast du deine Lieblingsgeschichten immer dabei.'
|
||||
},
|
||||
{
|
||||
question: 'Sind die Inhalte sicher für Kinder?',
|
||||
answer: 'Absolut! Alle Geschichten werden automatisch auf kindgerechte Inhalte geprüft. Wir verwenden spezielle Filter und Richtlinien, um sicherzustellen, dass nur altersgerechte und positive Geschichten erstellt werden.'
|
||||
},
|
||||
{
|
||||
question: 'Kann ich mehrere Charaktere erstellen?',
|
||||
answer: 'Ja, du kannst so viele Charaktere erstellen, wie du möchtest! Jeder Charakter wird in deiner Bibliothek gespeichert und kann in verschiedenen Geschichten verwendet werden.'
|
||||
},
|
||||
{
|
||||
question: 'In welchen Sprachen ist die App verfügbar?',
|
||||
answer: 'Aktuell ist Märchenzauber auf Deutsch verfügbar. Wir arbeiten an weiteren Sprachen wie Englisch, Französisch und Spanisch, die bald verfügbar sein werden.'
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<section id="faq" class="section bg-bg-primary">
|
||||
<div class="container-custom max-w-4xl">
|
||||
<!-- Section Header -->
|
||||
<div class="text-center mb-12 md:mb-16">
|
||||
<h2 class="font-grandstander font-bold text-3xl md:text-4xl lg:text-5xl text-text-primary mb-4">
|
||||
Häufig gestellte Fragen
|
||||
</h2>
|
||||
<p class="text-text-secondary text-lg">
|
||||
Alles, was du über Märchenzauber wissen musst
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- FAQ Items -->
|
||||
<div class="space-y-4">
|
||||
{faqs.map((faq, index) => (
|
||||
<details class="group">
|
||||
<summary class="cursor-pointer list-none">
|
||||
<Card variant="hover" padding="lg">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="font-semibold text-lg text-text-primary pr-4 group-open:text-yellow-light transition-colors">
|
||||
{faq.question}
|
||||
</h3>
|
||||
<div class="flex-shrink-0 w-6 h-6 text-yellow-dark group-open:text-yellow-light transition-all duration-300 group-open:rotate-180">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-hidden max-h-0 group-open:max-h-96 transition-all duration-300">
|
||||
<p class="text-text-secondary mt-4 leading-relaxed">
|
||||
{faq.answer}
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
</summary>
|
||||
</details>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<!-- Contact CTA -->
|
||||
<div class="text-center mt-12">
|
||||
<p class="text-text-secondary mb-4">
|
||||
Noch Fragen? Wir sind für dich da!
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a href="mailto:support@maerchenzauber.app" class="btn-secondary inline-flex items-center gap-2">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
E-Mail schreiben
|
||||
</a>
|
||||
<a href="#" class="btn-secondary inline-flex items-center gap-2">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
|
||||
</svg>
|
||||
Live Chat
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
details summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
details[open] summary ~ * {
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
---
|
||||
import Card from '../ui/Card.astro';
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: '🦸♂️',
|
||||
title: 'Personalisierte Charaktere',
|
||||
description: 'Erschaffe einzigartige Helden mit eigenen Namen, Aussehen und besonderen Eigenschaften. Jeder Charakter wird liebevoll zum Leben erweckt.'
|
||||
},
|
||||
{
|
||||
icon: '✨',
|
||||
title: 'KI-generierte Geschichten',
|
||||
description: 'Unsere fortschrittliche KI erstellt maßgeschneiderte Märchen basierend auf deinen Ideen. Jede Geschichte ist einzigartig und altersgerecht.'
|
||||
},
|
||||
{
|
||||
icon: '🎨',
|
||||
title: 'Wunderschöne Illustrationen',
|
||||
description: 'Jede Seite wird mit hochwertigen, KI-generierten Bildern im 3D-Pixar-Stil illustriert. Deine Geschichte wird zum visuellen Erlebnis.'
|
||||
},
|
||||
{
|
||||
icon: '📚',
|
||||
title: 'Unbegrenzte Kreativität',
|
||||
description: 'Erstelle so viele Geschichten wie du möchtest. Von Abenteuern bis Gute-Nacht-Geschichten - deiner Fantasie sind keine Grenzen gesetzt.'
|
||||
},
|
||||
{
|
||||
icon: '👨👩👧👦',
|
||||
title: 'Familienfreundlich',
|
||||
description: 'Sichere, kindgerechte Inhalte für verschiedene Altersgruppen. Perfekt für gemeinsame Familienzeit und Vorlesestunden.'
|
||||
},
|
||||
{
|
||||
icon: '📱',
|
||||
title: 'Überall verfügbar',
|
||||
description: 'Zugriff auf deine Geschichten von jedem Gerät. Offline-Modus für unterwegs. Deine Märchenbibliothek immer dabei.'
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<section id="features" class="section bg-bg-darker">
|
||||
<div class="container-custom">
|
||||
<!-- Section Header -->
|
||||
<div class="text-center mb-12 md:mb-16 px-4">
|
||||
<h2 class="font-grandstander font-bold text-2xl sm:text-3xl md:text-4xl lg:text-5xl text-text-primary mb-4 leading-tight">
|
||||
Magische Features für kleine Geschichtenerzähler
|
||||
</h2>
|
||||
<p class="text-text-secondary text-base sm:text-lg max-w-3xl mx-auto leading-relaxed">
|
||||
Entdecke alle Möglichkeiten, die Märchenzauber bietet, um die Fantasie deines Kindes zu beflügeln.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Features Grid -->
|
||||
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6 md:gap-8 px-4">
|
||||
{features.map((feature, index) => (
|
||||
<Card variant="hover" className="group" padding="lg">
|
||||
<div class="flex flex-col items-center text-center">
|
||||
<!-- Icon -->
|
||||
<div class="text-4xl sm:text-5xl mb-4 transform group-hover:scale-110 transition-transform duration-300">
|
||||
{feature.icon}
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<h3 class="font-semibold text-lg sm:text-xl text-text-primary mb-3 group-hover:text-yellow-light transition-colors">
|
||||
{feature.title}
|
||||
</h3>
|
||||
|
||||
<!-- Description -->
|
||||
<p class="text-text-secondary text-sm sm:text-base leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<!-- Additional Feature Highlight -->
|
||||
<div class="mt-12 md:mt-16 px-4">
|
||||
<Card variant="glow" className="max-w-4xl mx-auto" padding="lg">
|
||||
<div class="flex flex-col md:flex-row items-center gap-6 md:gap-8">
|
||||
<div class="text-5xl sm:text-6xl">🌟</div>
|
||||
<div class="flex-1 text-center md:text-left">
|
||||
<h3 class="font-grandstander font-bold text-xl sm:text-2xl text-text-primary mb-2 sm:mb-3">
|
||||
Mana-Token System
|
||||
</h3>
|
||||
<p class="text-text-secondary text-sm sm:text-base leading-relaxed">
|
||||
Flexibles Kreditsystem für die Generierung von Geschichten.
|
||||
Starte kostenlos und erweitere deine Möglichkeiten mit zusätzlichen Mana-Tokens.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-10 h-10 sm:w-12 sm:h-12 bg-yellow-dark rounded-full flex items-center justify-center">
|
||||
<span class="text-white font-bold text-sm sm:text-base">M</span>
|
||||
</div>
|
||||
<div class="text-left">
|
||||
<div class="text-text-primary font-semibold text-sm sm:text-base">100 Mana</div>
|
||||
<div class="text-text-secondary text-xs sm:text-sm">Startguthaben</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
---
|
||||
import Card from '../ui/Card.astro';
|
||||
|
||||
const steps = [
|
||||
{
|
||||
number: '1',
|
||||
title: 'Charakter erstellen',
|
||||
description: 'Gib deinem Helden einen Namen und beschreibe sein Aussehen. Wähle aus drei generierten Bildern deinen Favoriten.',
|
||||
image: '/screenshots/create-character.png'
|
||||
},
|
||||
{
|
||||
number: '2',
|
||||
title: 'Geschichte beschreiben',
|
||||
description: 'Erzähle uns, wovon deine Geschichte handeln soll. Die KI verwandelt deine Idee in ein spannendes Abenteuer.',
|
||||
image: '/screenshots/create-story.png'
|
||||
},
|
||||
{
|
||||
number: '3',
|
||||
title: 'Magie erleben',
|
||||
description: 'Lehne dich zurück und genieße deine personalisierte Geschichte mit wunderschönen Illustrationen.',
|
||||
image: '/screenshots/view-story.png'
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<section id="how-it-works" class="section bg-bg-primary">
|
||||
<div class="container-custom">
|
||||
<!-- Section Header -->
|
||||
<div class="text-center mb-12 md:mb-16">
|
||||
<h2 class="font-grandstander font-bold text-3xl md:text-4xl lg:text-5xl text-text-primary mb-4">
|
||||
So einfach funktioniert's
|
||||
</h2>
|
||||
<p class="text-text-secondary text-lg max-w-3xl mx-auto">
|
||||
In nur drei Schritten zu deiner personalisierten Geschichte
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Steps -->
|
||||
<div class="space-y-16 md:space-y-24">
|
||||
{steps.map((step, index) => (
|
||||
<div class={`flex flex-col ${index % 2 === 0 ? 'lg:flex-row' : 'lg:flex-row-reverse'} gap-8 lg:gap-16 items-center`}>
|
||||
<!-- Text Content -->
|
||||
<div class="flex-1 text-center lg:text-left">
|
||||
<div class="flex items-center gap-4 mb-6 justify-center lg:justify-start">
|
||||
<div class="w-12 h-12 md:w-16 md:h-16 bg-yellow-dark rounded-full flex items-center justify-center">
|
||||
<span class="text-white font-bold text-xl md:text-2xl">{step.number}</span>
|
||||
</div>
|
||||
<h3 class="font-grandstander font-bold text-2xl md:text-3xl text-text-primary">
|
||||
{step.title}
|
||||
</h3>
|
||||
</div>
|
||||
<p class="text-text-secondary text-lg leading-relaxed">
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Screenshot -->
|
||||
<div class="flex-1">
|
||||
<Card padding="none" className="overflow-hidden">
|
||||
<div class="relative aspect-[16/9] bg-bg-darker">
|
||||
<img
|
||||
src={step.image}
|
||||
alt={step.title}
|
||||
class="w-full h-full object-cover"
|
||||
/>
|
||||
<!-- Overlay gradient for better text visibility if needed -->
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent pointer-events-none"></div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<!-- CTA -->
|
||||
<div class="text-center mt-16">
|
||||
<p class="text-text-secondary text-lg mb-6">
|
||||
Bereit, deine erste Geschichte zu erstellen?
|
||||
</p>
|
||||
<a href="#download" class="btn-primary inline-flex items-center gap-2">
|
||||
Jetzt starten
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -2,30 +2,232 @@
|
|||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Navigation from '../components/layout/Navigation.astro';
|
||||
import Footer from '../components/layout/Footer.astro';
|
||||
// Local components (app-specific)
|
||||
import Hero from '../components/sections/Hero.astro';
|
||||
import Features from '../components/sections/Features.astro';
|
||||
import HowItWorks from '../components/sections/HowItWorks.astro';
|
||||
import StoryShowcase from '../components/sections/StoryShowcase.astro';
|
||||
import CharacterGallery from '../components/sections/CharacterGallery.astro';
|
||||
import Testimonials from '../components/sections/Testimonials.astro';
|
||||
import Pricing from '../components/sections/Pricing.astro';
|
||||
import FAQ from '../components/sections/FAQ.astro';
|
||||
import CTA from '../components/sections/CTA.astro';
|
||||
// Shared components
|
||||
import FeatureSection from '@manacore/shared-landing-ui/sections/FeatureSection.astro';
|
||||
import StepsSection from '@manacore/shared-landing-ui/sections/StepsSection.astro';
|
||||
import FAQSection from '@manacore/shared-landing-ui/sections/FAQSection.astro';
|
||||
import CTASection from '@manacore/shared-landing-ui/sections/CTASection.astro';
|
||||
import Card from '@manacore/shared-landing-ui/atoms/Card.astro';
|
||||
|
||||
// Feature data
|
||||
const features = [
|
||||
{
|
||||
icon: '🦸♂️',
|
||||
title: 'Personalisierte Charaktere',
|
||||
description: 'Erschaffe einzigartige Helden mit eigenen Namen, Aussehen und besonderen Eigenschaften. Jeder Charakter wird liebevoll zum Leben erweckt.'
|
||||
},
|
||||
{
|
||||
icon: '✨',
|
||||
title: 'KI-generierte Geschichten',
|
||||
description: 'Unsere fortschrittliche KI erstellt maßgeschneiderte Märchen basierend auf deinen Ideen. Jede Geschichte ist einzigartig und altersgerecht.'
|
||||
},
|
||||
{
|
||||
icon: '🎨',
|
||||
title: 'Wunderschöne Illustrationen',
|
||||
description: 'Jede Seite wird mit hochwertigen, KI-generierten Bildern im 3D-Pixar-Stil illustriert. Deine Geschichte wird zum visuellen Erlebnis.'
|
||||
},
|
||||
{
|
||||
icon: '📚',
|
||||
title: 'Unbegrenzte Kreativität',
|
||||
description: 'Erstelle so viele Geschichten wie du möchtest. Von Abenteuern bis Gute-Nacht-Geschichten - deiner Fantasie sind keine Grenzen gesetzt.'
|
||||
},
|
||||
{
|
||||
icon: '👨👩👧👦',
|
||||
title: 'Familienfreundlich',
|
||||
description: 'Sichere, kindgerechte Inhalte für verschiedene Altersgruppen. Perfekt für gemeinsame Familienzeit und Vorlesestunden.'
|
||||
},
|
||||
{
|
||||
icon: '📱',
|
||||
title: 'Überall verfügbar',
|
||||
description: 'Zugriff auf deine Geschichten von jedem Gerät. Offline-Modus für unterwegs. Deine Märchenbibliothek immer dabei.'
|
||||
}
|
||||
];
|
||||
|
||||
// Steps data
|
||||
const steps = [
|
||||
{
|
||||
number: '1',
|
||||
title: 'Charakter erstellen',
|
||||
description: 'Gib deinem Helden einen Namen und beschreibe sein Aussehen. Wähle aus drei generierten Bildern deinen Favoriten.',
|
||||
image: '/screenshots/create-character.png'
|
||||
},
|
||||
{
|
||||
number: '2',
|
||||
title: 'Geschichte beschreiben',
|
||||
description: 'Erzähle uns, wovon deine Geschichte handeln soll. Die KI verwandelt deine Idee in ein spannendes Abenteuer.',
|
||||
image: '/screenshots/create-story.png'
|
||||
},
|
||||
{
|
||||
number: '3',
|
||||
title: 'Magie erleben',
|
||||
description: 'Lehne dich zurück und genieße deine personalisierte Geschichte mit wunderschönen Illustrationen.',
|
||||
image: '/screenshots/view-story.png'
|
||||
}
|
||||
];
|
||||
|
||||
// FAQ data
|
||||
const faqs = [
|
||||
{
|
||||
question: 'Für welches Alter ist Märchenzauber geeignet?',
|
||||
answer: 'Märchenzauber ist für Kinder von 3-12 Jahren konzipiert. Die Geschichten werden automatisch an das Alter angepasst, sodass sowohl Kindergartenkinder als auch Grundschüler passende Inhalte erhalten.'
|
||||
},
|
||||
{
|
||||
question: 'Wie funktioniert das Mana-System?',
|
||||
answer: 'Mana sind Credits, die du für die Generierung von Geschichten verwendest. Eine Geschichte kostet etwa 30-40 Mana. Du startest mit 100 kostenlosen Mana und kannst jederzeit weitere kaufen oder ein Abo abschließen.'
|
||||
},
|
||||
{
|
||||
question: 'Kann ich die Geschichten offline lesen?',
|
||||
answer: 'Ja! Alle generierten Geschichten werden in deiner Bibliothek gespeichert und können offline gelesen werden. So hast du deine Lieblingsgeschichten immer dabei.'
|
||||
},
|
||||
{
|
||||
question: 'Sind die Inhalte sicher für Kinder?',
|
||||
answer: 'Absolut! Alle Geschichten werden automatisch auf kindgerechte Inhalte geprüft. Wir verwenden spezielle Filter und Richtlinien, um sicherzustellen, dass nur altersgerechte und positive Geschichten erstellt werden.'
|
||||
},
|
||||
{
|
||||
question: 'Kann ich mehrere Charaktere erstellen?',
|
||||
answer: 'Ja, du kannst so viele Charaktere erstellen, wie du möchtest! Jeder Charakter wird in deiner Bibliothek gespeichert und kann in verschiedenen Geschichten verwendet werden.'
|
||||
},
|
||||
{
|
||||
question: 'In welchen Sprachen ist die App verfügbar?',
|
||||
answer: 'Aktuell ist Märchenzauber auf Deutsch verfügbar. Wir arbeiten an weiteren Sprachen wie Englisch, Französisch und Spanisch, die bald verfügbar sein werden.'
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<BaseLayout>
|
||||
<Navigation />
|
||||
|
||||
|
||||
<main class="pb-20 md:pb-28 lg:pb-32">
|
||||
<Hero />
|
||||
<Features />
|
||||
<HowItWorks />
|
||||
|
||||
<FeatureSection
|
||||
id="features"
|
||||
title="Magische Features für kleine Geschichtenerzähler"
|
||||
subtitle="Entdecke alle Möglichkeiten, die Märchenzauber bietet, um die Fantasie deines Kindes zu beflügeln."
|
||||
features={features}
|
||||
columns={3}
|
||||
variant="cards"
|
||||
class="bg-[var(--color-background-card)]"
|
||||
>
|
||||
<!-- Mana Token Highlight -->
|
||||
<div class="mt-12 md:mt-16 px-4" slot="highlight">
|
||||
<Card variant="glow" class="max-w-4xl mx-auto" padding="lg">
|
||||
<div class="flex flex-col md:flex-row items-center gap-6 md:gap-8">
|
||||
<div class="text-5xl sm:text-6xl">🌟</div>
|
||||
<div class="flex-1 text-center md:text-left">
|
||||
<h3 class="font-bold text-xl sm:text-2xl text-[var(--color-text-primary)] mb-2 sm:mb-3">
|
||||
Mana-Token System
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm sm:text-base leading-relaxed">
|
||||
Flexibles Kreditsystem für die Generierung von Geschichten.
|
||||
Starte kostenlos und erweitere deine Möglichkeiten mit zusätzlichen Mana-Tokens.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-10 h-10 sm:w-12 sm:h-12 bg-[var(--color-primary)] rounded-full flex items-center justify-center">
|
||||
<span class="text-white font-bold text-sm sm:text-base">M</span>
|
||||
</div>
|
||||
<div class="text-left">
|
||||
<div class="text-[var(--color-text-primary)] font-semibold text-sm sm:text-base">100 Mana</div>
|
||||
<div class="text-[var(--color-text-secondary)] text-xs sm:text-sm">Startguthaben</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</FeatureSection>
|
||||
|
||||
<StepsSection
|
||||
id="how-it-works"
|
||||
title="So einfach funktioniert's"
|
||||
subtitle="In nur drei Schritten zu deiner personalisierten Geschichte"
|
||||
steps={steps}
|
||||
showImages={true}
|
||||
alternateLayout={true}
|
||||
>
|
||||
<!-- CTA after steps -->
|
||||
<div class="text-center mt-16" slot="cta">
|
||||
<p class="text-[var(--color-text-secondary)] text-lg mb-6">
|
||||
Bereit, deine erste Geschichte zu erstellen?
|
||||
</p>
|
||||
<a href="#download" class="inline-flex items-center gap-2 px-6 py-3 bg-[var(--color-primary)] hover:bg-[var(--color-primary-hover)] text-white font-semibold rounded-lg transition-colors">
|
||||
Jetzt starten
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</StepsSection>
|
||||
|
||||
<StoryShowcase />
|
||||
<CharacterGallery />
|
||||
<Testimonials />
|
||||
<Pricing />
|
||||
<FAQ />
|
||||
<CTA />
|
||||
|
||||
<FAQSection
|
||||
id="faq"
|
||||
title="Häufig gestellte Fragen"
|
||||
subtitle="Alles, was du über Märchenzauber wissen musst"
|
||||
faqs={faqs}
|
||||
>
|
||||
<!-- Contact CTA -->
|
||||
<div class="text-center mt-12">
|
||||
<p class="text-[var(--color-text-secondary)] mb-4">
|
||||
Noch Fragen? Wir sind für dich da!
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a href="mailto:support@maerchenzauber.app" class="inline-flex items-center justify-center gap-2 px-6 py-3 border border-[var(--color-border)] hover:border-[var(--color-border-hover)] rounded-lg text-[var(--color-text-primary)] transition-colors">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
E-Mail schreiben
|
||||
</a>
|
||||
<a href="#" class="inline-flex items-center justify-center gap-2 px-6 py-3 border border-[var(--color-border)] hover:border-[var(--color-border-hover)] rounded-lg text-[var(--color-text-primary)] transition-colors">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
|
||||
</svg>
|
||||
Live Chat
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</FAQSection>
|
||||
|
||||
<CTASection
|
||||
id="download"
|
||||
title="Bereit für magische Geschichten?"
|
||||
subtitle="Lade Märchenzauber herunter und erschaffe noch heute deine erste personalisierte Geschichte. Starte kostenlos mit 100 Mana!"
|
||||
primaryCta={{ text: "Jetzt herunterladen", href: "/download" }}
|
||||
variant="highlighted"
|
||||
>
|
||||
<!-- Trust Indicators -->
|
||||
<div class="flex flex-wrap items-center justify-center gap-4 sm:gap-6 mt-8 sm:mt-12">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 sm:w-5 sm:h-5 text-[var(--color-primary)]" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M2.166 4.999A11.954 11.954 0 0010 1.944 11.954 11.954 0 0017.834 5c.11.65.166 1.32.166 2.001 0 5.225-3.34 9.67-8 11.317C5.34 16.67 2 12.225 2 7c0-.682.057-1.35.166-2.001zm11.541 3.708a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="text-[var(--color-text-secondary)] text-sm sm:text-base">100% Sicher</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 sm:w-5 sm:h-5 text-[var(--color-primary)]" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10 2a1 1 0 00-1 1v1a1 1 0 002 0V3a1 1 0 00-1-1zM4 4h3a3 3 0 006 0h3a2 2 0 012 2v9a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2zm2.5 7a1.5 1.5 0 100-3 1.5 1.5 0 000 3zm2.45 4a2.5 2.5 0 10-4.9 0h4.9zM12 9a1 1 0 100 2h3a1 1 0 100-2h-3zm-1 4a1 1 0 011-1h2a1 1 0 110 2h-2a1 1 0 01-1-1z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="text-[var(--color-text-secondary)] text-sm sm:text-base">DSGVO konform</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 sm:w-5 sm:h-5 text-[var(--color-primary)]" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M13 7H7v6h6V7z"></path>
|
||||
<path fill-rule="evenodd" d="M7 2a1 1 0 012 0v1h2V2a1 1 0 112 0v1h2a2 2 0 012 2v2h1a1 1 0 110 2h-1v2h1a1 1 0 110 2h-1v2a2 2 0 01-2 2h-2v1a1 1 0 11-2 0v-1H9v1a1 1 0 11-2 0v-1H5a2 2 0 01-2-2v-2H2a1 1 0 110-2h1V9H2a1 1 0 010-2h1V5a2 2 0 012-2h2V2zM5 5h10v10H5V5z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="text-[var(--color-text-secondary)] text-sm sm:text-base">Kindgerecht</span>
|
||||
</div>
|
||||
</div>
|
||||
</CTASection>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
|
|
|
|||
201
maerchenzauber/apps/landing/src/pages/shared-demo.astro
Normal file
201
maerchenzauber/apps/landing/src/pages/shared-demo.astro
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
---
|
||||
/**
|
||||
* Demo page showcasing shared landing UI components
|
||||
* This demonstrates how to use @manacore/shared-landing-ui in märchenzauber
|
||||
*/
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
// Import shared components
|
||||
import Button from '@manacore/shared-landing-ui/atoms/Button.astro';
|
||||
import Card from '@manacore/shared-landing-ui/atoms/Card.astro';
|
||||
import Badge from '@manacore/shared-landing-ui/atoms/Badge.astro';
|
||||
import Container from '@manacore/shared-landing-ui/atoms/Container.astro';
|
||||
import SectionHeader from '@manacore/shared-landing-ui/atoms/SectionHeader.astro';
|
||||
import HeroSection from '@manacore/shared-landing-ui/sections/HeroSection.astro';
|
||||
import FeatureSection from '@manacore/shared-landing-ui/sections/FeatureSection.astro';
|
||||
import FAQSection from '@manacore/shared-landing-ui/sections/FAQSection.astro';
|
||||
import TestimonialSection from '@manacore/shared-landing-ui/sections/TestimonialSection.astro';
|
||||
import CTASection from '@manacore/shared-landing-ui/sections/CTASection.astro';
|
||||
|
||||
// Demo data
|
||||
const features = [
|
||||
{
|
||||
icon: '🦸♂️',
|
||||
title: 'Personalisierte Charaktere',
|
||||
description: 'Erschaffe einzigartige Helden mit eigenen Namen, Aussehen und besonderen Eigenschaften.'
|
||||
},
|
||||
{
|
||||
icon: '✨',
|
||||
title: 'KI-generierte Geschichten',
|
||||
description: 'Unsere fortschrittliche KI erstellt maßgeschneiderte Märchen basierend auf deinen Ideen.'
|
||||
},
|
||||
{
|
||||
icon: '🎨',
|
||||
title: 'Wunderschöne Illustrationen',
|
||||
description: 'Jede Seite wird mit hochwertigen, KI-generierten Bildern illustriert.'
|
||||
},
|
||||
{
|
||||
icon: '📚',
|
||||
title: 'Unbegrenzte Kreativität',
|
||||
description: 'Erstelle so viele Geschichten wie du möchtest.'
|
||||
},
|
||||
{
|
||||
icon: '👨👩👧👦',
|
||||
title: 'Familienfreundlich',
|
||||
description: 'Sichere, kindgerechte Inhalte für verschiedene Altersgruppen.'
|
||||
},
|
||||
{
|
||||
icon: '📱',
|
||||
title: 'Überall verfügbar',
|
||||
description: 'Zugriff auf deine Geschichten von jedem Gerät.'
|
||||
}
|
||||
];
|
||||
|
||||
const faqs = [
|
||||
{
|
||||
question: 'Für welches Alter ist Märchenzauber geeignet?',
|
||||
answer: 'Märchenzauber ist für Kinder von 3-12 Jahren konzipiert. Die Geschichten werden automatisch an das Alter angepasst.'
|
||||
},
|
||||
{
|
||||
question: 'Wie funktioniert das Mana-System?',
|
||||
answer: 'Mana sind Credits, die du für die Generierung von Geschichten verwendest. Eine Geschichte kostet etwa 30-40 Mana.'
|
||||
},
|
||||
{
|
||||
question: 'Kann ich die Geschichten offline lesen?',
|
||||
answer: 'Ja! Alle generierten Geschichten werden in deiner Bibliothek gespeichert und können offline gelesen werden.'
|
||||
}
|
||||
];
|
||||
|
||||
const testimonials = [
|
||||
{
|
||||
name: 'Anna M.',
|
||||
role: 'Mutter von 2 Kindern',
|
||||
text: 'Meine Kinder lieben es, ihre eigenen Geschichten zu erstellen. Absolute Empfehlung!',
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
name: 'Thomas K.',
|
||||
role: 'Vater',
|
||||
text: 'Endlich eine App, die die Fantasie meiner Tochter wirklich fördert.',
|
||||
rating: 5
|
||||
},
|
||||
{
|
||||
name: 'Sarah L.',
|
||||
role: 'Grundschullehrerin',
|
||||
text: 'Ich nutze Märchenzauber im Unterricht. Die Kinder sind begeistert!',
|
||||
rating: 5
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<Layout title="Shared Components Demo - Märchenzauber">
|
||||
<!-- Hero Section using shared component -->
|
||||
<HeroSection
|
||||
title="Shared Landing UI Demo"
|
||||
subtitle="Diese Seite demonstriert die wiederverwendbaren Komponenten aus dem @manacore/shared-landing-ui Package."
|
||||
variant="centered"
|
||||
primaryCta={{
|
||||
text: 'Zurück zur Startseite',
|
||||
href: '/'
|
||||
}}
|
||||
secondaryCta={{
|
||||
text: 'Package ansehen',
|
||||
href: '#components',
|
||||
variant: 'secondary'
|
||||
}}
|
||||
/>
|
||||
|
||||
<!-- Atoms Demo -->
|
||||
<section id="components" class="py-16 bg-bg-darker">
|
||||
<Container>
|
||||
<SectionHeader
|
||||
title="Atom Components"
|
||||
subtitle="Grundlegende Bausteine für Landing Pages"
|
||||
/>
|
||||
|
||||
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<!-- Button Variants -->
|
||||
<Card variant="bordered" padding="lg">
|
||||
<h3 class="font-semibold text-lg text-text-primary mb-4">Buttons</h3>
|
||||
<div class="space-y-3">
|
||||
<Button href="#" variant="primary" fullWidth>Primary Button</Button>
|
||||
<Button href="#" variant="secondary" fullWidth>Secondary Button</Button>
|
||||
<Button href="#" variant="outline" fullWidth>Outline Button</Button>
|
||||
<Button href="#" variant="ghost" fullWidth>Ghost Button</Button>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- Badge Variants -->
|
||||
<Card variant="bordered" padding="lg">
|
||||
<h3 class="font-semibold text-lg text-text-primary mb-4">Badges</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<Badge variant="default">Default</Badge>
|
||||
<Badge variant="primary">Primary</Badge>
|
||||
<Badge variant="success">Success</Badge>
|
||||
<Badge variant="warning">Warning</Badge>
|
||||
<Badge variant="error">Error</Badge>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- Card Variants -->
|
||||
<Card variant="bordered" padding="lg">
|
||||
<h3 class="font-semibold text-lg text-text-primary mb-4">Cards</h3>
|
||||
<div class="space-y-3">
|
||||
<Card variant="default" padding="sm">
|
||||
<p class="text-sm">Default Card</p>
|
||||
</Card>
|
||||
<Card variant="hover" padding="sm">
|
||||
<p class="text-sm">Hover Card</p>
|
||||
</Card>
|
||||
<Card variant="glow" padding="sm">
|
||||
<p class="text-sm">Glow Card</p>
|
||||
</Card>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<!-- Feature Section using shared component -->
|
||||
<FeatureSection
|
||||
id="features"
|
||||
title="Feature Section Demo"
|
||||
subtitle="Alle Features werden automatisch in einem responsiven Grid angezeigt"
|
||||
features={features}
|
||||
columns={3}
|
||||
class="bg-bg-primary"
|
||||
/>
|
||||
|
||||
<!-- FAQ Section using shared component -->
|
||||
<FAQSection
|
||||
title="FAQ Section Demo"
|
||||
subtitle="Expandierbare FAQ-Elemente mit Akkordeon-Verhalten"
|
||||
faqs={faqs}
|
||||
class="bg-bg-darker"
|
||||
/>
|
||||
|
||||
<!-- Testimonial Section using shared component -->
|
||||
<TestimonialSection
|
||||
title="Testimonial Section Demo"
|
||||
subtitle="Kundenbewertungen in einem ansprechenden Grid"
|
||||
testimonials={testimonials}
|
||||
columns={3}
|
||||
class="bg-bg-primary"
|
||||
/>
|
||||
|
||||
<!-- CTA Section using shared component -->
|
||||
<CTASection
|
||||
title="Bereit für den nächsten Schritt?"
|
||||
subtitle="Nutze die shared-landing-ui Komponenten in deinem Projekt."
|
||||
primaryCta={{
|
||||
text: 'Dokumentation lesen',
|
||||
href: '#'
|
||||
}}
|
||||
secondaryCta={{
|
||||
text: 'GitHub',
|
||||
href: '#',
|
||||
variant: 'outline'
|
||||
}}
|
||||
variant="highlighted"
|
||||
/>
|
||||
</Layout>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
/* Primary colors from mobile app */
|
||||
--color-yellow-dark: #6D5B00;
|
||||
--color-yellow-light: #F8D62B;
|
||||
|
||||
|
||||
/* Background colors */
|
||||
--color-bg-primary: #181818;
|
||||
--color-bg-secondary: #333333;
|
||||
|
|
@ -15,15 +15,24 @@
|
|||
--color-bg-input: #333333;
|
||||
--color-bg-dark: #121212;
|
||||
--color-bg-darker: #1a1a1a;
|
||||
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #FFFFFF;
|
||||
--color-text-secondary: #999999;
|
||||
--color-text-muted: #666666;
|
||||
--color-text-light: #CCCCCC;
|
||||
|
||||
|
||||
/* UI elements */
|
||||
--color-border: #444444;
|
||||
|
||||
/* === Shared Landing UI Variables (aliases) === */
|
||||
--color-primary: var(--color-yellow-dark);
|
||||
--color-primary-hover: var(--color-yellow-light);
|
||||
--color-primary-glow: rgba(248, 214, 43, 0.3);
|
||||
--color-background-page: var(--color-bg-primary);
|
||||
--color-background-card: var(--color-bg-card);
|
||||
--color-background-card-hover: var(--color-bg-secondary);
|
||||
--color-border-hover: #555555;
|
||||
}
|
||||
|
||||
html {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
"@iconify-json/heroicons": "^1.2.2",
|
||||
"@iconify-json/mdi": "^1.2.3",
|
||||
"@iconify-json/tabler": "^1.2.19",
|
||||
"@manacore/shared-landing-ui": "workspace:*",
|
||||
"astro": "^5.16.0",
|
||||
"astro-icon": "^1.1.5",
|
||||
"react": "^18.3.1",
|
||||
|
|
|
|||
|
|
@ -123,6 +123,26 @@ const lang = getLangFromUrl(Astro.url);
|
|||
--grid-unit: 40px; /* 10mm ~= 40px */
|
||||
--grid-small: 10px; /* 2.5mm for finer grid lines */
|
||||
--grid-cols: 12; /* Default: Desktop 12 Spalten */
|
||||
|
||||
/* === Shared Landing UI CSS Variables === */
|
||||
/* Primary colors - ManaCore Blue */
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-hover: #2563eb;
|
||||
--color-primary-glow: rgba(59, 130, 246, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #f9fafb;
|
||||
--color-text-secondary: #d1d5db;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #081320;
|
||||
--color-background-card: #1e293b;
|
||||
--color-background-card-hover: #334155;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #334155;
|
||||
--color-border-hover: #475569;
|
||||
}
|
||||
|
||||
/* Responsive Grid Columns */
|
||||
|
|
|
|||
170
manacore/apps/landing/src/pages/de/shared-demo.astro
Normal file
170
manacore/apps/landing/src/pages/de/shared-demo.astro
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
---
|
||||
/**
|
||||
* Demo page showcasing shared landing UI components in ManaCore
|
||||
*/
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
|
||||
// Import shared components
|
||||
import Button from '@manacore/shared-landing-ui/atoms/Button.astro';
|
||||
import Card from '@manacore/shared-landing-ui/atoms/Card.astro';
|
||||
import Badge from '@manacore/shared-landing-ui/atoms/Badge.astro';
|
||||
import Container from '@manacore/shared-landing-ui/atoms/Container.astro';
|
||||
import HeroSection from '@manacore/shared-landing-ui/sections/HeroSection.astro';
|
||||
import FeatureSection from '@manacore/shared-landing-ui/sections/FeatureSection.astro';
|
||||
import FAQSection from '@manacore/shared-landing-ui/sections/FAQSection.astro';
|
||||
import PricingSection from '@manacore/shared-landing-ui/sections/PricingSection.astro';
|
||||
import CTASection from '@manacore/shared-landing-ui/sections/CTASection.astro';
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: '📊',
|
||||
title: 'Analytics Dashboard',
|
||||
description: 'Umfassende Einblicke in Team-Performance und Produktivität.'
|
||||
},
|
||||
{
|
||||
icon: '🤖',
|
||||
title: 'KI-Insights',
|
||||
description: 'Automatische Analysen und Empfehlungen durch Machine Learning.'
|
||||
},
|
||||
{
|
||||
icon: '👥',
|
||||
title: 'Team Management',
|
||||
description: 'Organisiere Teams, Rollen und Zugriffsrechte zentral.'
|
||||
},
|
||||
{
|
||||
icon: '🔗',
|
||||
title: 'Integrationen',
|
||||
description: 'Verbinde dich mit Slack, Jira, GitHub und mehr.'
|
||||
}
|
||||
];
|
||||
|
||||
const faqs = [
|
||||
{
|
||||
question: 'Was ist ManaCore?',
|
||||
answer: 'ManaCore ist eine KI-gestützte Plattform zur Messung und Verbesserung der Team-Performance.'
|
||||
},
|
||||
{
|
||||
question: 'Welche Apps sind enthalten?',
|
||||
answer: 'ManaCore umfasst Memoro (Sprachaufnahmen), ManaDeck (Teammanagement) und Märchenzauber (Kindergeschichten).'
|
||||
},
|
||||
{
|
||||
question: 'Gibt es eine kostenlose Testversion?',
|
||||
answer: 'Ja, du kannst ManaCore 14 Tage kostenlos testen - keine Kreditkarte erforderlich.'
|
||||
}
|
||||
];
|
||||
|
||||
const pricingPlans = [
|
||||
{
|
||||
name: 'Starter',
|
||||
price: '€0',
|
||||
period: 'Monat',
|
||||
features: ['1 Benutzer', '100 MB Speicher', 'Basic Analytics'],
|
||||
cta: { text: 'Kostenlos starten', href: '#' }
|
||||
},
|
||||
{
|
||||
name: 'Pro',
|
||||
price: '€29',
|
||||
period: 'Monat',
|
||||
features: ['5 Benutzer', '10 GB Speicher', 'Advanced Analytics', 'Priority Support'],
|
||||
cta: { text: 'Jetzt upgraden', href: '#' },
|
||||
highlighted: true,
|
||||
badge: 'Beliebt'
|
||||
},
|
||||
{
|
||||
name: 'Enterprise',
|
||||
price: 'Kontakt',
|
||||
features: ['Unbegrenzte Benutzer', 'Unbegrenzter Speicher', 'Custom Integrationen', 'Dedicated Support'],
|
||||
cta: { text: 'Kontakt aufnehmen', href: '#' }
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<Layout title="Shared Components Demo - ManaCore">
|
||||
<HeroSection
|
||||
title="Shared Landing UI Demo"
|
||||
subtitle="Diese Seite demonstriert die wiederverwendbaren Komponenten aus @manacore/shared-landing-ui im ManaCore-Design."
|
||||
variant="centered"
|
||||
primaryCta={{
|
||||
text: 'Zurück zur Startseite',
|
||||
href: '/de'
|
||||
}}
|
||||
secondaryCta={{
|
||||
text: 'Features ansehen',
|
||||
href: '#features',
|
||||
variant: 'secondary'
|
||||
}}
|
||||
/>
|
||||
|
||||
<section class="py-16">
|
||||
<Container>
|
||||
<h2 class="text-3xl font-bold text-center mb-8" style="color: var(--color-text-primary)">Atom Components</h2>
|
||||
|
||||
<div class="grid md:grid-cols-3 gap-6">
|
||||
<Card variant="bordered" padding="lg">
|
||||
<h3 class="font-semibold text-lg mb-4" style="color: var(--color-text-primary)">Buttons</h3>
|
||||
<div class="space-y-3">
|
||||
<Button href="#" variant="primary" fullWidth>Primary</Button>
|
||||
<Button href="#" variant="secondary" fullWidth>Secondary</Button>
|
||||
<Button href="#" variant="outline" fullWidth>Outline</Button>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card variant="bordered" padding="lg">
|
||||
<h3 class="font-semibold text-lg mb-4" style="color: var(--color-text-primary)">Badges</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<Badge variant="primary">Primary</Badge>
|
||||
<Badge variant="success">Success</Badge>
|
||||
<Badge variant="warning">Warning</Badge>
|
||||
<Badge variant="error">Error</Badge>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card variant="bordered" padding="lg">
|
||||
<h3 class="font-semibold text-lg mb-4" style="color: var(--color-text-primary)">Cards</h3>
|
||||
<div class="space-y-2">
|
||||
<Card variant="hover" padding="sm">
|
||||
<p class="text-sm" style="color: var(--color-text-secondary)">Hover Card</p>
|
||||
</Card>
|
||||
<Card variant="glow" padding="sm">
|
||||
<p class="text-sm" style="color: var(--color-text-secondary)">Glow Card</p>
|
||||
</Card>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<FeatureSection
|
||||
id="features"
|
||||
title="Feature Section"
|
||||
subtitle="Automatisch generiertes Feature-Grid"
|
||||
features={features}
|
||||
columns={4}
|
||||
/>
|
||||
|
||||
<PricingSection
|
||||
title="Pricing Section"
|
||||
subtitle="Vergleiche unsere Pläne"
|
||||
plans={pricingPlans}
|
||||
/>
|
||||
|
||||
<FAQSection
|
||||
title="FAQ Section"
|
||||
faqs={faqs}
|
||||
/>
|
||||
|
||||
<CTASection
|
||||
title="Bereit loszulegen?"
|
||||
subtitle="Starte jetzt mit ManaCore und verbessere deine Team-Performance."
|
||||
primaryCta={{
|
||||
text: 'Kostenlos testen',
|
||||
href: '#'
|
||||
}}
|
||||
secondaryCta={{
|
||||
text: 'Demo anfragen',
|
||||
href: '#',
|
||||
variant: 'outline'
|
||||
}}
|
||||
variant="highlighted"
|
||||
/>
|
||||
</Layout>
|
||||
52
manacore/apps/landing/src/styles/global.css
Normal file
52
manacore/apps/landing/src/styles/global.css
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* === Shared Landing UI CSS Variables === */
|
||||
:root {
|
||||
/* Primary colors - ManaCore Blue */
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-hover: #2563eb;
|
||||
--color-primary-glow: rgba(59, 130, 246, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #f9fafb;
|
||||
--color-text-secondary: #d1d5db;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #081320;
|
||||
--color-background-card: #1e293b;
|
||||
--color-background-card-hover: #334155;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #334155;
|
||||
--color-border-hover: #475569;
|
||||
}
|
||||
|
||||
/* Light mode overrides */
|
||||
.light {
|
||||
--color-primary: #2563eb;
|
||||
--color-primary-hover: #1d4ed8;
|
||||
--color-primary-glow: rgba(37, 99, 235, 0.3);
|
||||
|
||||
--color-text-primary: #111827;
|
||||
--color-text-secondary: #4b5563;
|
||||
--color-text-muted: #9ca3af;
|
||||
|
||||
--color-background-page: #ffffff;
|
||||
--color-background-card: #f9fafb;
|
||||
--color-background-card-hover: #f3f4f6;
|
||||
|
||||
--color-border: #e5e7eb;
|
||||
--color-border-hover: #d1d5db;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--color-background-page);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
17
manadeck/apps/landing/astro.config.mjs
Normal file
17
manadeck/apps/landing/astro.config.mjs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { defineConfig } from 'astro/config';
|
||||
import tailwind from '@astrojs/tailwind';
|
||||
import sitemap from '@astrojs/sitemap';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: 'https://manadeck.app',
|
||||
integrations: [
|
||||
tailwind(),
|
||||
sitemap()
|
||||
],
|
||||
vite: {
|
||||
ssr: {
|
||||
noExternal: ['@manacore/shared-landing-ui']
|
||||
}
|
||||
}
|
||||
});
|
||||
27
manadeck/apps/landing/package.json
Normal file
27
manadeck/apps/landing/package.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "@manadeck/landing",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
"build": "astro check && astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro",
|
||||
"type-check": "astro check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.0",
|
||||
"@astrojs/sitemap": "^3.2.1",
|
||||
"@manacore/shared-landing-ui": "workspace:*",
|
||||
"astro": "^5.16.0",
|
||||
"astro-icon": "^1.1.5",
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/tailwind": "^6.0.0",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"tailwindcss": "^3.4.17"
|
||||
}
|
||||
}
|
||||
4
manadeck/apps/landing/public/favicon.svg
Normal file
4
manadeck/apps/landing/public/favicon.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<rect width="100" height="100" rx="20" fill="#7C3AED"/>
|
||||
<text x="50" y="70" font-size="60" text-anchor="middle" fill="white">🃏</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 211 B |
4
manadeck/apps/landing/public/robots.txt
Normal file
4
manadeck/apps/landing/public/robots.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: https://manadeck.app/sitemap-index.xml
|
||||
78
manadeck/apps/landing/src/components/Footer.astro
Normal file
78
manadeck/apps/landing/src/components/Footer.astro
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
const footerLinks = {
|
||||
product: [
|
||||
{ href: '#features', label: 'Features' },
|
||||
{ href: '#pricing', label: 'Preise' },
|
||||
{ href: '#faq', label: 'FAQ' }
|
||||
],
|
||||
legal: [
|
||||
{ href: '/privacy', label: 'Datenschutz' },
|
||||
{ href: '/terms', label: 'AGB' },
|
||||
{ href: '/imprint', label: 'Impressum' }
|
||||
]
|
||||
};
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
---
|
||||
|
||||
<footer class="bg-background-card border-t border-border">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
|
||||
<!-- Brand -->
|
||||
<div class="col-span-1 md:col-span-2">
|
||||
<a href="/" class="flex items-center gap-2 mb-4">
|
||||
<span class="text-2xl">🃏</span>
|
||||
<span class="font-bold text-xl text-text-primary">ManaDeck</span>
|
||||
</a>
|
||||
<p class="text-text-secondary text-sm max-w-md">
|
||||
Dein KI-gestützter Lernpartner. Erstelle intelligente Karteikarten aus deinen Notizen
|
||||
und lerne effizienter mit Spaced Repetition.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Product Links -->
|
||||
<div>
|
||||
<h3 class="font-semibold text-text-primary mb-4">Produkt</h3>
|
||||
<ul class="space-y-2">
|
||||
{footerLinks.product.map(link => (
|
||||
<li>
|
||||
<a
|
||||
href={link.href}
|
||||
class="text-text-secondary hover:text-text-primary transition-colors text-sm"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Legal Links -->
|
||||
<div>
|
||||
<h3 class="font-semibold text-text-primary mb-4">Rechtliches</h3>
|
||||
<ul class="space-y-2">
|
||||
{footerLinks.legal.map(link => (
|
||||
<li>
|
||||
<a
|
||||
href={link.href}
|
||||
class="text-text-secondary hover:text-text-primary transition-colors text-sm"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom -->
|
||||
<div class="mt-12 pt-8 border-t border-border flex flex-col sm:flex-row justify-between items-center gap-4">
|
||||
<p class="text-text-muted text-sm">
|
||||
© {currentYear} ManaDeck. Alle Rechte vorbehalten.
|
||||
</p>
|
||||
<p class="text-text-muted text-sm">
|
||||
Made with 💜 in Germany
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
84
manadeck/apps/landing/src/components/Navigation.astro
Normal file
84
manadeck/apps/landing/src/components/Navigation.astro
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
---
|
||||
const navLinks = [
|
||||
{ href: '#features', label: 'Features' },
|
||||
{ href: '#how-it-works', label: 'So funktioniert\'s' },
|
||||
{ href: '#pricing', label: 'Preise' },
|
||||
{ href: '#faq', label: 'FAQ' }
|
||||
];
|
||||
---
|
||||
|
||||
<nav class="fixed top-0 left-0 right-0 z-50 bg-background-page/80 backdrop-blur-lg border-b border-border">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<!-- Logo -->
|
||||
<a href="/" class="flex items-center gap-2">
|
||||
<span class="text-2xl">🃏</span>
|
||||
<span class="font-bold text-xl text-text-primary">ManaDeck</span>
|
||||
</a>
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
<div class="hidden md:flex items-center gap-8">
|
||||
{navLinks.map(link => (
|
||||
<a
|
||||
href={link.href}
|
||||
class="text-text-secondary hover:text-text-primary transition-colors text-sm font-medium"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<!-- CTA Button -->
|
||||
<div class="flex items-center gap-4">
|
||||
<a
|
||||
href="#download"
|
||||
class="btn-primary text-sm px-4 py-2"
|
||||
>
|
||||
App herunterladen
|
||||
</a>
|
||||
|
||||
<!-- Mobile Menu Button -->
|
||||
<button
|
||||
type="button"
|
||||
class="md:hidden p-2 text-text-secondary hover:text-text-primary"
|
||||
aria-label="Menu"
|
||||
id="mobile-menu-button"
|
||||
>
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Menu -->
|
||||
<div class="hidden md:hidden" id="mobile-menu">
|
||||
<div class="px-4 py-4 space-y-2 bg-background-card border-t border-border">
|
||||
{navLinks.map(link => (
|
||||
<a
|
||||
href={link.href}
|
||||
class="block px-4 py-2 text-text-secondary hover:text-text-primary hover:bg-background-card-hover rounded-lg transition-colors"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<script>
|
||||
const mobileMenuButton = document.getElementById('mobile-menu-button');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
|
||||
mobileMenuButton?.addEventListener('click', () => {
|
||||
mobileMenu?.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
// Close menu when clicking a link
|
||||
mobileMenu?.querySelectorAll('a').forEach(link => {
|
||||
link.addEventListener('click', () => {
|
||||
mobileMenu?.classList.add('hidden');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
1
manadeck/apps/landing/src/env.d.ts
vendored
Normal file
1
manadeck/apps/landing/src/env.d.ts
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/// <reference types="astro/client" />
|
||||
47
manadeck/apps/landing/src/layouts/Layout.astro
Normal file
47
manadeck/apps/landing/src/layouts/Layout.astro
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
import '../styles/global.css';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
description = 'ManaDeck - Dein KI-gestützter Lernpartner für Karteikarten und effektives Lernen'
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content={description} />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:locale" content="de_DE" />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
|
||||
<title>{title}</title>
|
||||
</head>
|
||||
<body class="min-h-screen bg-background-page text-text-primary antialiased">
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
287
manadeck/apps/landing/src/pages/index.astro
Normal file
287
manadeck/apps/landing/src/pages/index.astro
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import Navigation from '../components/Navigation.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
|
||||
// Shared components
|
||||
import HeroSection from '@manacore/shared-landing-ui/sections/HeroSection.astro';
|
||||
import FeatureSection from '@manacore/shared-landing-ui/sections/FeatureSection.astro';
|
||||
import StepsSection from '@manacore/shared-landing-ui/sections/StepsSection.astro';
|
||||
import FAQSection from '@manacore/shared-landing-ui/sections/FAQSection.astro';
|
||||
import CTASection from '@manacore/shared-landing-ui/sections/CTASection.astro';
|
||||
import PricingSection from '@manacore/shared-landing-ui/sections/PricingSection.astro';
|
||||
import Card from '@manacore/shared-landing-ui/atoms/Card.astro';
|
||||
|
||||
// Feature data
|
||||
const features = [
|
||||
{
|
||||
icon: '🧠',
|
||||
title: 'KI-generierte Karteikarten',
|
||||
description: 'Lade deine Notizen, PDFs oder Texte hoch und lass die KI automatisch perfekte Karteikarten erstellen.'
|
||||
},
|
||||
{
|
||||
icon: '🔄',
|
||||
title: 'Spaced Repetition',
|
||||
description: 'Unser intelligenter Algorithmus zeigt dir Karten genau dann, wenn du sie wiederholen solltest.'
|
||||
},
|
||||
{
|
||||
icon: '📊',
|
||||
title: 'Lernstatistiken',
|
||||
description: 'Verfolge deinen Fortschritt mit detaillierten Statistiken und optimiere dein Lernen.'
|
||||
},
|
||||
{
|
||||
icon: '📱',
|
||||
title: 'Überall lernen',
|
||||
description: 'Synchronisiere deine Decks auf allen Geräten und lerne, wo immer du bist.'
|
||||
},
|
||||
{
|
||||
icon: '🎯',
|
||||
title: 'Personalisiertes Lernen',
|
||||
description: 'Die KI passt sich deinem Lernstil an und erstellt maßgeschneiderte Wiederholungspläne.'
|
||||
},
|
||||
{
|
||||
icon: '🤝',
|
||||
title: 'Decks teilen',
|
||||
description: 'Teile deine Karteikarten-Decks mit Freunden oder entdecke öffentliche Sammlungen.'
|
||||
}
|
||||
];
|
||||
|
||||
// Steps data
|
||||
const steps = [
|
||||
{
|
||||
number: '1',
|
||||
title: 'Inhalte hochladen',
|
||||
description: 'Lade deine Notizen, PDFs oder Texte hoch. ManaDeck unterstützt verschiedene Formate.',
|
||||
image: '/screenshots/upload.png'
|
||||
},
|
||||
{
|
||||
number: '2',
|
||||
title: 'KI erstellt Karten',
|
||||
description: 'Unsere KI analysiert deine Inhalte und erstellt automatisch strukturierte Karteikarten.',
|
||||
image: '/screenshots/generate.png'
|
||||
},
|
||||
{
|
||||
number: '3',
|
||||
title: 'Effizient lernen',
|
||||
description: 'Lerne mit Spaced Repetition und behalte das Gelernte langfristig im Gedächtnis.',
|
||||
image: '/screenshots/learn.png'
|
||||
}
|
||||
];
|
||||
|
||||
// Pricing data
|
||||
const pricingPlans = [
|
||||
{
|
||||
name: 'Free',
|
||||
price: '0',
|
||||
period: '/Monat',
|
||||
description: 'Perfekt zum Ausprobieren',
|
||||
features: [
|
||||
{ text: '50 Karteikarten', included: true },
|
||||
{ text: '3 Decks', included: true },
|
||||
{ text: 'Basis-KI-Generierung', included: true },
|
||||
{ text: 'Spaced Repetition', included: true },
|
||||
{ text: 'Unbegrenzte Karten', included: false },
|
||||
{ text: 'Deck-Sharing', included: false }
|
||||
],
|
||||
cta: {
|
||||
text: 'Kostenlos starten',
|
||||
href: '#download'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Pro',
|
||||
price: '9,99',
|
||||
period: '/Monat',
|
||||
description: 'Für ambitionierte Lerner',
|
||||
features: [
|
||||
{ text: 'Unbegrenzte Karteikarten', included: true },
|
||||
{ text: 'Unbegrenzte Decks', included: true },
|
||||
{ text: 'Erweiterte KI-Funktionen', included: true },
|
||||
{ text: 'Spaced Repetition', included: true },
|
||||
{ text: 'Deck-Sharing', included: true },
|
||||
{ text: 'Prioritäts-Support', included: true }
|
||||
],
|
||||
cta: {
|
||||
text: 'Pro werden',
|
||||
href: '#download'
|
||||
},
|
||||
highlighted: true,
|
||||
badge: 'Beliebt'
|
||||
},
|
||||
{
|
||||
name: 'Team',
|
||||
price: '24,99',
|
||||
period: '/Monat',
|
||||
description: 'Für Gruppen und Klassen',
|
||||
features: [
|
||||
{ text: 'Alles aus Pro', included: true },
|
||||
{ text: 'Team-Verwaltung', included: true },
|
||||
{ text: 'Gemeinsame Decks', included: true },
|
||||
{ text: 'Fortschritts-Tracking', included: true },
|
||||
{ text: 'Admin-Dashboard', included: true },
|
||||
{ text: 'Dedizierter Support', included: true }
|
||||
],
|
||||
cta: {
|
||||
text: 'Team starten',
|
||||
href: '#download'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// FAQ data
|
||||
const faqs = [
|
||||
{
|
||||
question: 'Wie funktioniert die KI-Karteikarten-Generierung?',
|
||||
answer: 'ManaDeck verwendet fortschrittliche KI-Modelle, um deine Texte zu analysieren und die wichtigsten Konzepte zu extrahieren. Daraus werden automatisch Frage-Antwort-Paare erstellt, die du als Karteikarten lernen kannst.'
|
||||
},
|
||||
{
|
||||
question: 'Was ist Spaced Repetition?',
|
||||
answer: 'Spaced Repetition ist eine wissenschaftlich bewährte Lernmethode, bei der Karten in optimalen Zeitabständen wiederholt werden. Karten, die du gut kennst, siehst du seltener, während schwierige Karten häufiger erscheinen.'
|
||||
},
|
||||
{
|
||||
question: 'Kann ich meine eigenen Karteikarten erstellen?',
|
||||
answer: 'Ja! Du kannst sowohl KI-generierte Karten nutzen als auch komplett eigene Karteikarten erstellen. Beide Varianten lassen sich beliebig kombinieren und bearbeiten.'
|
||||
},
|
||||
{
|
||||
question: 'Welche Dateiformate werden unterstützt?',
|
||||
answer: 'ManaDeck unterstützt PDF, Word-Dokumente (.docx), Textdateien (.txt) und Markdown (.md). Du kannst auch direkt Text in die App einfügen.'
|
||||
},
|
||||
{
|
||||
question: 'Sind meine Daten sicher?',
|
||||
answer: 'Ja, alle Daten werden verschlüsselt übertragen und gespeichert. Wir verkaufen keine Nutzerdaten an Dritte und sind DSGVO-konform.'
|
||||
},
|
||||
{
|
||||
question: 'Kann ich offline lernen?',
|
||||
answer: 'Ja! Du kannst deine Decks für den Offline-Modus herunterladen und überall lernen, auch ohne Internetverbindung.'
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<Layout title="ManaDeck - KI-gestützte Karteikarten für effektives Lernen">
|
||||
<Navigation />
|
||||
|
||||
<main class="pt-16">
|
||||
<HeroSection
|
||||
title="Lerne smarter, nicht härter"
|
||||
subtitle="ManaDeck verwandelt deine Notizen in intelligente Karteikarten. Mit KI-Generierung und Spaced Repetition lernst du effizienter als je zuvor."
|
||||
variant="default"
|
||||
primaryCta={{
|
||||
text: 'Jetzt kostenlos starten',
|
||||
href: '#download'
|
||||
}}
|
||||
secondaryCta={{
|
||||
text: 'Features entdecken',
|
||||
href: '#features',
|
||||
variant: 'secondary'
|
||||
}}
|
||||
trustBadges={[
|
||||
{ icon: '✓', text: 'Kostenlos testen' },
|
||||
{ icon: '🔒', text: 'DSGVO-konform' },
|
||||
{ icon: '📱', text: 'iOS & Android' }
|
||||
]}
|
||||
/>
|
||||
|
||||
<FeatureSection
|
||||
id="features"
|
||||
title="Alles was du zum Lernen brauchst"
|
||||
subtitle="ManaDeck kombiniert KI-Technologie mit bewährten Lernmethoden für maximalen Lernerfolg."
|
||||
features={features}
|
||||
columns={3}
|
||||
variant="cards"
|
||||
class="bg-[var(--color-background-card)]"
|
||||
>
|
||||
<!-- Mana System Highlight -->
|
||||
<div class="mt-12 md:mt-16 px-4" slot="highlight">
|
||||
<Card variant="glow" class="max-w-4xl mx-auto" padding="lg">
|
||||
<div class="flex flex-col md:flex-row items-center gap-6 md:gap-8">
|
||||
<div class="text-5xl sm:text-6xl">⚡</div>
|
||||
<div class="flex-1 text-center md:text-left">
|
||||
<h3 class="font-bold text-xl sm:text-2xl text-[var(--color-text-primary)] mb-2 sm:mb-3">
|
||||
Mana-System
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm sm:text-base leading-relaxed">
|
||||
Nutze Mana-Punkte für KI-Generierungen. Starte kostenlos mit 100 Mana
|
||||
und verdiene mehr durch regelmäßiges Lernen.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-10 h-10 sm:w-12 sm:h-12 bg-[var(--color-primary)] rounded-full flex items-center justify-center">
|
||||
<span class="text-white font-bold text-sm sm:text-base">M</span>
|
||||
</div>
|
||||
<div class="text-left">
|
||||
<div class="text-[var(--color-text-primary)] font-semibold text-sm sm:text-base">100 Mana</div>
|
||||
<div class="text-[var(--color-text-secondary)] text-xs sm:text-sm">zum Start</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</FeatureSection>
|
||||
|
||||
<StepsSection
|
||||
id="how-it-works"
|
||||
title="So einfach geht's"
|
||||
subtitle="In nur drei Schritten zum effektiven Lernen"
|
||||
steps={steps}
|
||||
showImages={false}
|
||||
alternateLayout={true}
|
||||
/>
|
||||
|
||||
<PricingSection
|
||||
id="pricing"
|
||||
title="Wähle deinen Plan"
|
||||
subtitle="Starte kostenlos und upgrade, wenn du bereit bist"
|
||||
plans={pricingPlans}
|
||||
class="bg-[var(--color-background-card)]"
|
||||
/>
|
||||
|
||||
<FAQSection
|
||||
id="faq"
|
||||
title="Häufig gestellte Fragen"
|
||||
subtitle="Alles was du über ManaDeck wissen musst"
|
||||
faqs={faqs}
|
||||
/>
|
||||
|
||||
<CTASection
|
||||
id="download"
|
||||
title="Bereit, smarter zu lernen?"
|
||||
subtitle="Lade ManaDeck jetzt herunter und erstelle deine ersten KI-generierten Karteikarten. Kostenlos und ohne Kreditkarte."
|
||||
primaryCta={{ text: 'App herunterladen', href: '#' }}
|
||||
variant="highlighted"
|
||||
>
|
||||
<!-- App Store Buttons -->
|
||||
<div class="flex flex-wrap items-center justify-center gap-4 mt-8">
|
||||
<a href="#" class="inline-block hover:opacity-80 transition-opacity">
|
||||
<img src="/app-store-badge.svg" alt="Download im App Store" class="h-12" />
|
||||
</a>
|
||||
<a href="#" class="inline-block hover:opacity-80 transition-opacity">
|
||||
<img src="/google-play-badge.svg" alt="Jetzt bei Google Play" class="h-12" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Trust Indicators -->
|
||||
<div class="flex flex-wrap items-center justify-center gap-4 sm:gap-6 mt-8">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-5 h-5 text-[var(--color-primary)]" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M2.166 4.999A11.954 11.954 0 0010 1.944 11.954 11.954 0 0017.834 5c.11.65.166 1.32.166 2.001 0 5.225-3.34 9.67-8 11.317C5.34 16.67 2 12.225 2 7c0-.682.057-1.35.166-2.001zm11.541 3.708a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="text-[var(--color-text-secondary)] text-sm">100% Kostenlos starten</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-5 h-5 text-[var(--color-primary)]" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="text-[var(--color-text-secondary)] text-sm">DSGVO-konform</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-5 h-5 text-[var(--color-primary)]" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M10 2a8 8 0 100 16 8 8 0 000-16zm1 11H9v-2h2v2zm0-4H9V5h2v4z"></path>
|
||||
</svg>
|
||||
<span class="text-[var(--color-text-secondary)] text-sm">Keine Kreditkarte nötig</span>
|
||||
</div>
|
||||
</div>
|
||||
</CTASection>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</Layout>
|
||||
103
manadeck/apps/landing/src/styles/global.css
Normal file
103
manadeck/apps/landing/src/styles/global.css
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* ManaDeck Theme CSS Variables */
|
||||
:root {
|
||||
/* Primary colors - ManaDeck Purple */
|
||||
--color-primary: #7C3AED;
|
||||
--color-primary-hover: #8B5CF6;
|
||||
--color-primary-glow: rgba(124, 58, 237, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #f9fafb;
|
||||
--color-text-secondary: #d1d5db;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #0f0a1a;
|
||||
--color-background-card: #1a1625;
|
||||
--color-background-card-hover: #2d2640;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #3d3555;
|
||||
--color-border-hover: #4d4570;
|
||||
}
|
||||
|
||||
/* Base styles */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', system-ui, sans-serif;
|
||||
background-color: var(--color-background-page);
|
||||
color: var(--color-text-primary);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Custom scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--color-background-card);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--color-border);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--color-border-hover);
|
||||
}
|
||||
|
||||
/* Selection */
|
||||
::selection {
|
||||
background-color: var(--color-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Focus styles */
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--color-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Gradient text */
|
||||
.text-gradient {
|
||||
background: linear-gradient(135deg, #7C3AED 0%, #A78BFA 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
/* Animation utilities */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fadeIn {
|
||||
animation: fadeIn 0.6s ease-out forwards;
|
||||
}
|
||||
|
||||
/* Button styles */
|
||||
.btn-primary {
|
||||
@apply inline-flex items-center justify-center px-6 py-3 bg-primary text-white font-semibold rounded-lg transition-all duration-200;
|
||||
@apply hover:bg-primary-hover hover:shadow-lg hover:shadow-primary-glow;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply inline-flex items-center justify-center px-6 py-3 border border-border text-text-primary font-semibold rounded-lg transition-all duration-200;
|
||||
@apply hover:border-border-hover hover:bg-background-card;
|
||||
}
|
||||
39
manadeck/apps/landing/tailwind.config.mjs
Normal file
39
manadeck/apps/landing/tailwind.config.mjs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
'./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}',
|
||||
'../../packages/shared-landing-ui/src/**/*.{astro,html,js,jsx,ts,tsx}'
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
// ManaDeck Purple Theme
|
||||
primary: {
|
||||
DEFAULT: '#7C3AED',
|
||||
hover: '#8B5CF6',
|
||||
glow: 'rgba(124, 58, 237, 0.3)'
|
||||
},
|
||||
background: {
|
||||
page: '#0f0a1a',
|
||||
card: '#1a1625',
|
||||
'card-hover': '#2d2640'
|
||||
},
|
||||
text: {
|
||||
primary: '#f9fafb',
|
||||
secondary: '#d1d5db',
|
||||
muted: '#6b7280'
|
||||
},
|
||||
border: {
|
||||
DEFAULT: '#3d3555',
|
||||
hover: '#4d4570'
|
||||
}
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif']
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/typography')
|
||||
]
|
||||
};
|
||||
9
manadeck/apps/landing/tsconfig.json
Normal file
9
manadeck/apps/landing/tsconfig.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,8 @@
|
|||
"@astrojs/rss": "^4.0.12",
|
||||
"@astrojs/sitemap": "^3.2.1",
|
||||
"@iconify-json/mdi": "^1.2.3",
|
||||
"astro": "^5.3.0",
|
||||
"@manacore/shared-landing-ui": "workspace:*",
|
||||
"astro": "^5.16.0",
|
||||
"astro-icon": "^1.1.5",
|
||||
"marked": "^16.1.1",
|
||||
"sharp": "^0.34.3",
|
||||
|
|
|
|||
150
memoro/apps/landing/src/pages/de/shared-demo.astro
Normal file
150
memoro/apps/landing/src/pages/de/shared-demo.astro
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
---
|
||||
/**
|
||||
* Demo page showcasing shared landing UI components in Memoro
|
||||
*/
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
|
||||
// Import shared components
|
||||
import Button from '@manacore/shared-landing-ui/atoms/Button.astro';
|
||||
import Card from '@manacore/shared-landing-ui/atoms/Card.astro';
|
||||
import Badge from '@manacore/shared-landing-ui/atoms/Badge.astro';
|
||||
import Container from '@manacore/shared-landing-ui/atoms/Container.astro';
|
||||
import HeroSection from '@manacore/shared-landing-ui/sections/HeroSection.astro';
|
||||
import FeatureSection from '@manacore/shared-landing-ui/sections/FeatureSection.astro';
|
||||
import FAQSection from '@manacore/shared-landing-ui/sections/FAQSection.astro';
|
||||
import CTASection from '@manacore/shared-landing-ui/sections/CTASection.astro';
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: '🎙️',
|
||||
title: 'Sprachaufnahme',
|
||||
description: 'Nimm Gespräche, Meetings und Ideen einfach per Sprache auf.'
|
||||
},
|
||||
{
|
||||
icon: '🤖',
|
||||
title: 'KI-Transkription',
|
||||
description: 'Automatische Umwandlung von Sprache in Text mit höchster Genauigkeit.'
|
||||
},
|
||||
{
|
||||
icon: '📝',
|
||||
title: 'Smart Summaries',
|
||||
description: 'KI-generierte Zusammenfassungen und Erkenntnisse aus deinen Aufnahmen.'
|
||||
},
|
||||
{
|
||||
icon: '🔒',
|
||||
title: 'Datenschutz',
|
||||
description: 'Deine Daten bleiben privat. Keine Weitergabe an Dritte.'
|
||||
},
|
||||
{
|
||||
icon: '📱',
|
||||
title: 'Cross-Platform',
|
||||
description: 'Verfügbar auf iOS, Android und Web.'
|
||||
},
|
||||
{
|
||||
icon: '🌍',
|
||||
title: '32 Sprachen',
|
||||
description: 'Unterstützung für über 32 Sprachen weltweit.'
|
||||
}
|
||||
];
|
||||
|
||||
const faqs = [
|
||||
{
|
||||
question: 'Wie funktioniert die Transkription?',
|
||||
answer: 'Memoro verwendet modernste KI-Technologie, um deine Sprachaufnahmen automatisch in Text umzuwandeln. Die Genauigkeit liegt bei über 95%.'
|
||||
},
|
||||
{
|
||||
question: 'Ist meine Privatsphäre geschützt?',
|
||||
answer: 'Ja! Alle Aufnahmen werden verschlüsselt übertragen und gespeichert. Wir verkaufen keine Daten an Dritte.'
|
||||
},
|
||||
{
|
||||
question: 'Welche Sprachen werden unterstützt?',
|
||||
answer: 'Memoro unterstützt über 32 Sprachen, darunter Deutsch, Englisch, Französisch, Spanisch, Italienisch und viele mehr.'
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Shared Components Demo - Memoro"
|
||||
description="Demonstration der shared landing UI components"
|
||||
lang="de"
|
||||
>
|
||||
<main class="bg-[var(--color-background-page)]">
|
||||
<HeroSection
|
||||
title="Shared Landing UI Demo"
|
||||
subtitle="Diese Seite zeigt die wiederverwendbaren Komponenten aus @manacore/shared-landing-ui im Memoro-Design."
|
||||
variant="centered"
|
||||
primaryCta={{
|
||||
text: 'Zurück zur Startseite',
|
||||
href: '/de'
|
||||
}}
|
||||
secondaryCta={{
|
||||
text: 'Features ansehen',
|
||||
href: '#features',
|
||||
variant: 'secondary'
|
||||
}}
|
||||
/>
|
||||
|
||||
<section class="py-16 bg-[var(--color-background-card)]">
|
||||
<Container>
|
||||
<h2 class="text-3xl font-bold text-[var(--color-text-primary)] text-center mb-8">Atom Components</h2>
|
||||
|
||||
<div class="grid md:grid-cols-3 gap-6">
|
||||
<Card variant="bordered" padding="lg">
|
||||
<h3 class="font-semibold text-lg text-[var(--color-text-primary)] mb-4">Buttons</h3>
|
||||
<div class="space-y-3">
|
||||
<Button href="#" variant="primary" fullWidth>Primary</Button>
|
||||
<Button href="#" variant="secondary" fullWidth>Secondary</Button>
|
||||
<Button href="#" variant="outline" fullWidth>Outline</Button>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card variant="bordered" padding="lg">
|
||||
<h3 class="font-semibold text-lg text-[var(--color-text-primary)] mb-4">Badges</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<Badge variant="primary">Primary</Badge>
|
||||
<Badge variant="success">Success</Badge>
|
||||
<Badge variant="warning">Warning</Badge>
|
||||
<Badge variant="error">Error</Badge>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card variant="bordered" padding="lg">
|
||||
<h3 class="font-semibold text-lg text-[var(--color-text-primary)] mb-4">Cards</h3>
|
||||
<div class="space-y-2">
|
||||
<Card variant="hover" padding="sm">
|
||||
<p class="text-sm text-[var(--color-text-secondary)]">Hover Card</p>
|
||||
</Card>
|
||||
<Card variant="glow" padding="sm">
|
||||
<p class="text-sm text-[var(--color-text-secondary)]">Glow Card</p>
|
||||
</Card>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<FeatureSection
|
||||
id="features"
|
||||
title="Feature Section"
|
||||
subtitle="Automatisch generiertes Feature-Grid"
|
||||
features={features}
|
||||
columns={3}
|
||||
/>
|
||||
|
||||
<FAQSection
|
||||
title="FAQ Section"
|
||||
faqs={faqs}
|
||||
class="bg-[var(--color-background-card)]"
|
||||
/>
|
||||
|
||||
<CTASection
|
||||
title="Bereit loszulegen?"
|
||||
subtitle="Nutze die shared components in deinem Projekt."
|
||||
primaryCta={{
|
||||
text: 'Dokumentation',
|
||||
href: '#'
|
||||
}}
|
||||
variant="highlighted"
|
||||
/>
|
||||
</main>
|
||||
</Layout>
|
||||
|
|
@ -2,6 +2,28 @@
|
|||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* === Shared Landing UI CSS Variables === */
|
||||
:root {
|
||||
/* Primary colors - Memoro Yellow/Gold */
|
||||
--color-primary: #806b00;
|
||||
--color-primary-hover: #ae9200;
|
||||
--color-primary-glow: rgba(248, 214, 43, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #ffffff;
|
||||
--color-text-secondary: #9ca3af;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #0D0C12;
|
||||
--color-background-card: #1a1a1a;
|
||||
--color-background-card-hover: #262626;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #333333;
|
||||
--color-border-hover: #404040;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@
|
|||
"manacore:dev": "turbo run dev --filter=manacore...",
|
||||
"manadeck:dev": "turbo run dev --filter=manadeck...",
|
||||
"memoro:dev": "turbo run dev --filter=memoro...",
|
||||
"dev:web": "turbo run dev --filter=@storyteller/web --filter=manacore-web --filter=web --filter=memoro-web",
|
||||
"dev:landing": "turbo run dev --filter=@storyteller/landing --filter=manacore-landing --filter=landing --filter=memoro-landing",
|
||||
"dev:mobile": "turbo run dev --filter=@storyteller/mobile --filter=manacore --filter=manadeck --filter=memoro"
|
||||
"picture:dev": "turbo run dev --filter=picture...",
|
||||
"dev:web": "turbo run dev --filter=@storyteller/web --filter=manacore-web --filter=web --filter=memoro-web --filter=@picture/web",
|
||||
"dev:landing": "turbo run dev --filter=@storyteller/landing --filter=manacore-landing --filter=landing --filter=memoro-landing --filter=@picture/landing",
|
||||
"dev:mobile": "turbo run dev --filter=@storyteller/mobile --filter=manacore --filter=manadeck --filter=memoro --filter=@picture/mobile"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.3.3",
|
||||
|
|
|
|||
326
packages/shared-landing-ui/README.md
Normal file
326
packages/shared-landing-ui/README.md
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
# @manacore/shared-landing-ui
|
||||
|
||||
Shared Astro components for landing pages across the Manacore monorepo.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pnpm add @manacore/shared-landing-ui
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Import components directly from their paths:
|
||||
|
||||
```astro
|
||||
---
|
||||
import Button from '@manacore/shared-landing-ui/atoms/Button.astro';
|
||||
import Card from '@manacore/shared-landing-ui/atoms/Card.astro';
|
||||
import HeroSection from '@manacore/shared-landing-ui/sections/HeroSection.astro';
|
||||
import FeatureSection from '@manacore/shared-landing-ui/sections/FeatureSection.astro';
|
||||
import FAQSection from '@manacore/shared-landing-ui/sections/FAQSection.astro';
|
||||
---
|
||||
```
|
||||
|
||||
## Required CSS Variables
|
||||
|
||||
The components use CSS custom properties for theming. Define these in your project's global CSS:
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Primary colors */
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-hover: #2563eb;
|
||||
--color-primary-glow: rgba(59, 130, 246, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #f9fafb;
|
||||
--color-text-secondary: #d1d5db;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #111827;
|
||||
--color-background-card: #1f2937;
|
||||
--color-background-card-hover: #374151;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #374151;
|
||||
--color-border-hover: #4b5563;
|
||||
}
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### Atoms (Basic Building Blocks)
|
||||
|
||||
- **Button** - Versatile button/link component with variants (primary, secondary, outline, ghost)
|
||||
- **Card** - Container component with variants (default, hover, glow, bordered)
|
||||
- **Badge** - Small label component with color variants
|
||||
- **Container** - Max-width wrapper with responsive padding
|
||||
- **SectionHeader** - Consistent section title and subtitle
|
||||
|
||||
### Sections (Page Sections)
|
||||
|
||||
- **HeroSection** - Hero area with title, subtitle, CTAs, and optional image
|
||||
- **FeatureSection** - Feature grid with icons and descriptions
|
||||
- **FAQSection** - Expandable FAQ accordion
|
||||
- **TestimonialSection** - Customer testimonials grid
|
||||
- **CTASection** - Call-to-action section
|
||||
- **PricingSection** - Pricing plans comparison
|
||||
|
||||
### Layouts
|
||||
|
||||
- **Footer** - Configurable footer with sections, social links, and CTAs
|
||||
|
||||
## Examples
|
||||
|
||||
### Hero Section
|
||||
|
||||
```astro
|
||||
<HeroSection
|
||||
title="Welcome to Our App"
|
||||
subtitle="The best solution for your needs"
|
||||
variant="default"
|
||||
image={{
|
||||
src: "/hero-image.jpg",
|
||||
alt: "Hero image",
|
||||
position: "right"
|
||||
}}
|
||||
primaryCta={{
|
||||
text: "Get Started",
|
||||
href: "/signup"
|
||||
}}
|
||||
secondaryCta={{
|
||||
text: "Learn More",
|
||||
href: "#features",
|
||||
variant: "secondary"
|
||||
}}
|
||||
trustBadges={[
|
||||
{ icon: "✓", text: "Free Trial" },
|
||||
{ icon: "🔒", text: "Secure" }
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
### Feature Section
|
||||
|
||||
```astro
|
||||
<FeatureSection
|
||||
id="features"
|
||||
title="Amazing Features"
|
||||
subtitle="Everything you need to succeed"
|
||||
columns={3}
|
||||
features={[
|
||||
{
|
||||
icon: "🚀",
|
||||
title: "Fast",
|
||||
description: "Lightning-fast performance"
|
||||
},
|
||||
{
|
||||
icon: "🔒",
|
||||
title: "Secure",
|
||||
description: "Enterprise-grade security"
|
||||
},
|
||||
{
|
||||
icon: "💡",
|
||||
title: "Smart",
|
||||
description: "AI-powered insights"
|
||||
}
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
### FAQ Section
|
||||
|
||||
```astro
|
||||
<FAQSection
|
||||
title="Frequently Asked Questions"
|
||||
faqs={[
|
||||
{
|
||||
question: "How does it work?",
|
||||
answer: "It's simple! Just sign up and start using our platform."
|
||||
},
|
||||
{
|
||||
question: "Is there a free trial?",
|
||||
answer: "Yes, we offer a 14-day free trial with full features."
|
||||
}
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### Slots
|
||||
|
||||
Most section components support slots for additional customization:
|
||||
|
||||
```astro
|
||||
<HeroSection title="..." subtitle="...">
|
||||
<Fragment slot="title">
|
||||
Custom <span class="text-gradient">Title</span>
|
||||
</Fragment>
|
||||
<Fragment slot="background">
|
||||
<div class="absolute inset-0 bg-gradient-to-r from-blue-500 to-purple-500 opacity-10" />
|
||||
</Fragment>
|
||||
</HeroSection>
|
||||
```
|
||||
|
||||
### Class Overrides
|
||||
|
||||
All components accept a `class` prop for additional styling:
|
||||
|
||||
```astro
|
||||
<Button class="my-custom-class">Click me</Button>
|
||||
```
|
||||
|
||||
## Pre-built Themes
|
||||
|
||||
Use one of the pre-built theme CSS files for quick setup:
|
||||
|
||||
```css
|
||||
/* In your global CSS or layout */
|
||||
@import '@manacore/shared-landing-ui/themes/memoro';
|
||||
/* OR */
|
||||
@import '@manacore/shared-landing-ui/themes/manacore';
|
||||
/* OR */
|
||||
@import '@manacore/shared-landing-ui/themes/maerchenzauber';
|
||||
/* OR */
|
||||
@import '@manacore/shared-landing-ui/themes/manadeck';
|
||||
```
|
||||
|
||||
Or import in your Astro layout:
|
||||
|
||||
```astro
|
||||
---
|
||||
import '@manacore/shared-landing-ui/themes/memoro';
|
||||
---
|
||||
```
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### Step 1: Add the package
|
||||
|
||||
```bash
|
||||
# In your landing app directory
|
||||
pnpm add @manacore/shared-landing-ui
|
||||
```
|
||||
|
||||
Or add to package.json:
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@manacore/shared-landing-ui": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Add CSS Variables
|
||||
|
||||
Either import a pre-built theme (see above) or add the CSS variables to your global styles:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--color-primary: #your-primary-color;
|
||||
--color-primary-hover: #your-primary-hover;
|
||||
--color-primary-glow: rgba(your-primary-rgb, 0.3);
|
||||
--color-text-primary: #text-color;
|
||||
--color-text-secondary: #secondary-text;
|
||||
--color-text-muted: #muted-text;
|
||||
--color-background-page: #page-bg;
|
||||
--color-background-card: #card-bg;
|
||||
--color-background-card-hover: #card-hover-bg;
|
||||
--color-border: #border-color;
|
||||
--color-border-hover: #border-hover;
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Replace Components
|
||||
|
||||
Replace your existing components with shared ones:
|
||||
|
||||
**Before (custom component):**
|
||||
```astro
|
||||
---
|
||||
import HeroSection from '../components/sections/Hero.astro';
|
||||
---
|
||||
<HeroSection />
|
||||
```
|
||||
|
||||
**After (shared component):**
|
||||
```astro
|
||||
---
|
||||
import HeroSection from '@manacore/shared-landing-ui/sections/HeroSection.astro';
|
||||
---
|
||||
<HeroSection
|
||||
title="Your Title"
|
||||
subtitle="Your subtitle"
|
||||
primaryCta={{ text: "Get Started", href: "/start" }}
|
||||
/>
|
||||
```
|
||||
|
||||
### Step 4: Migrate Data
|
||||
|
||||
Move hardcoded content to props:
|
||||
|
||||
**Before:**
|
||||
```astro
|
||||
<!-- Features hardcoded in component -->
|
||||
const features = [
|
||||
{ icon: '🚀', title: 'Fast', description: '...' }
|
||||
];
|
||||
```
|
||||
|
||||
**After:**
|
||||
```astro
|
||||
---
|
||||
// Data in page file
|
||||
const features = [
|
||||
{ icon: '🚀', title: 'Fast', description: '...' }
|
||||
];
|
||||
---
|
||||
<FeatureSection features={features} title="Features" />
|
||||
```
|
||||
|
||||
### Example Demo Pages
|
||||
|
||||
Check these demo pages for working examples:
|
||||
|
||||
- `maerchenzauber/apps/landing/src/pages/shared-demo.astro`
|
||||
- `memoro/apps/landing/src/pages/de/shared-demo.astro`
|
||||
- `manacore/apps/landing/src/pages/de/shared-demo.astro`
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Type check
|
||||
pnpm run type-check
|
||||
```
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── atoms/ # Basic UI components
|
||||
│ ├── Button.astro
|
||||
│ ├── Card.astro
|
||||
│ ├── Badge.astro
|
||||
│ ├── Container.astro
|
||||
│ └── SectionHeader.astro
|
||||
├── sections/ # Page sections
|
||||
│ ├── HeroSection.astro
|
||||
│ ├── FeatureSection.astro
|
||||
│ ├── FAQSection.astro
|
||||
│ ├── TestimonialSection.astro
|
||||
│ ├── CTASection.astro
|
||||
│ └── PricingSection.astro
|
||||
├── layouts/
|
||||
│ └── Footer.astro
|
||||
├── themes/ # Pre-built CSS themes
|
||||
│ ├── index.css # Default theme
|
||||
│ ├── memoro.css
|
||||
│ ├── manacore.css
|
||||
│ ├── maerchenzauber.css
|
||||
│ └── manadeck.css
|
||||
└── utils/
|
||||
└── index.ts # TypeScript types
|
||||
```
|
||||
39
packages/shared-landing-ui/package.json
Normal file
39
packages/shared-landing-ui/package.json
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"name": "@manacore/shared-landing-ui",
|
||||
"version": "0.1.0",
|
||||
"description": "Shared Astro landing page components for Manacore monorepo",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./atoms/*": "./src/atoms/*",
|
||||
"./sections/*": "./src/sections/*",
|
||||
"./layouts/*": "./src/layouts/*",
|
||||
"./utils": "./src/utils/index.ts",
|
||||
"./themes": "./src/themes/index.css",
|
||||
"./themes/memoro": "./src/themes/memoro.css",
|
||||
"./themes/manacore": "./src/themes/manacore.css",
|
||||
"./themes/maerchenzauber": "./src/themes/maerchenzauber.css",
|
||||
"./themes/manadeck": "./src/themes/manadeck.css"
|
||||
},
|
||||
"files": [
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"type-check": "astro check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": ">=5.0.0",
|
||||
"astro-icon": ">=1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/check": "^0.9.0",
|
||||
"astro": "^5.16.0",
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"astro",
|
||||
"landing",
|
||||
"components",
|
||||
"manacore"
|
||||
]
|
||||
}
|
||||
36
packages/shared-landing-ui/src/atoms/Badge.astro
Normal file
36
packages/shared-landing-ui/src/atoms/Badge.astro
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
/**
|
||||
* Shared Badge component for landing pages
|
||||
*/
|
||||
interface Props {
|
||||
variant?: 'default' | 'primary' | 'success' | 'warning' | 'error';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
variant = 'default',
|
||||
size = 'md',
|
||||
class: className = ''
|
||||
} = Astro.props;
|
||||
|
||||
const variants = {
|
||||
default: 'bg-[var(--color-background-card)] text-[var(--color-text-secondary)] border-[var(--color-border)]',
|
||||
primary: 'bg-[var(--color-primary)]/10 text-[var(--color-primary)] border-[var(--color-primary)]/20',
|
||||
success: 'bg-green-100 text-green-700 border-green-200',
|
||||
warning: 'bg-yellow-100 text-yellow-700 border-yellow-200',
|
||||
error: 'bg-red-100 text-red-700 border-red-200'
|
||||
};
|
||||
|
||||
const sizes = {
|
||||
sm: 'text-xs px-2 py-0.5',
|
||||
md: 'text-sm px-2.5 py-1',
|
||||
lg: 'text-base px-3 py-1.5'
|
||||
};
|
||||
|
||||
const styles = `inline-flex items-center rounded-full font-medium border ${variants[variant]} ${sizes[size]} ${className}`;
|
||||
---
|
||||
|
||||
<span class={styles}>
|
||||
<slot />
|
||||
</span>
|
||||
75
packages/shared-landing-ui/src/atoms/Button.astro
Normal file
75
packages/shared-landing-ui/src/atoms/Button.astro
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
/**
|
||||
* Shared Button component for landing pages
|
||||
* Uses CSS custom properties for theming - define these in your project:
|
||||
* --color-primary, --color-primary-hover, --color-text-primary,
|
||||
* --color-background-card, --color-border
|
||||
*/
|
||||
interface Props {
|
||||
href?: string;
|
||||
variant?: "primary" | "secondary" | "outline" | "ghost";
|
||||
size?: "sm" | "md" | "lg";
|
||||
class?: string;
|
||||
target?: string;
|
||||
rel?: string;
|
||||
download?: boolean | string;
|
||||
id?: string;
|
||||
onclick?: string;
|
||||
'aria-label'?: string;
|
||||
fullWidth?: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const {
|
||||
href,
|
||||
variant = "primary",
|
||||
size = "md",
|
||||
class: className = "",
|
||||
target,
|
||||
rel,
|
||||
download,
|
||||
id,
|
||||
onclick,
|
||||
'aria-label': ariaLabel,
|
||||
fullWidth = false,
|
||||
...rest
|
||||
} = Astro.props;
|
||||
|
||||
const variants = {
|
||||
primary:
|
||||
"bg-[var(--color-primary)] text-white hover:bg-[var(--color-primary-hover)] border-2 border-[var(--color-primary)] hover:border-[var(--color-primary-hover)]",
|
||||
secondary:
|
||||
"bg-transparent text-[var(--color-text-primary)] hover:bg-[var(--color-background-card)] border-2 border-[var(--color-border)] hover:border-[var(--color-primary)]",
|
||||
outline:
|
||||
"bg-transparent text-[var(--color-text-primary)] hover:bg-[var(--color-background-card-hover)] border-2 border-[var(--color-border)]",
|
||||
ghost:
|
||||
"bg-transparent text-[var(--color-text-primary)] hover:bg-[var(--color-background-card-hover)] border-transparent",
|
||||
};
|
||||
|
||||
const sizes = {
|
||||
sm: "text-sm px-3 py-1.5",
|
||||
md: "text-base px-4 py-2",
|
||||
lg: "text-lg px-6 py-3",
|
||||
};
|
||||
|
||||
const baseStyles =
|
||||
"inline-flex items-center justify-center rounded-lg transition-all duration-200 font-medium focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] focus:ring-offset-2 whitespace-nowrap";
|
||||
const widthStyle = fullWidth ? "w-full" : "";
|
||||
const styles = `${baseStyles} ${variants[variant]} ${sizes[size]} ${widthStyle} ${className}`;
|
||||
|
||||
const Element = href ? "a" : "button";
|
||||
---
|
||||
|
||||
<Element
|
||||
href={href}
|
||||
target={target}
|
||||
rel={rel}
|
||||
download={download}
|
||||
class={styles}
|
||||
id={id}
|
||||
onclick={onclick}
|
||||
aria-label={ariaLabel}
|
||||
{...rest}
|
||||
>
|
||||
<slot />
|
||||
</Element>
|
||||
50
packages/shared-landing-ui/src/atoms/Card.astro
Normal file
50
packages/shared-landing-ui/src/atoms/Card.astro
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
/**
|
||||
* Shared Card component for landing pages
|
||||
* Uses CSS custom properties for theming - define these in your project:
|
||||
* --color-background-card, --color-border, --color-primary
|
||||
*/
|
||||
export interface Props {
|
||||
variant?: 'default' | 'hover' | 'glow' | 'bordered';
|
||||
class?: string;
|
||||
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
||||
as?: 'div' | 'article' | 'section' | 'a';
|
||||
href?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
variant = 'default',
|
||||
class: className = '',
|
||||
padding = 'md',
|
||||
as: Element = 'div',
|
||||
href
|
||||
} = Astro.props;
|
||||
|
||||
const paddingStyles = {
|
||||
none: '',
|
||||
sm: 'p-3 sm:p-4',
|
||||
md: 'p-4 sm:p-6',
|
||||
lg: 'p-6 sm:p-8',
|
||||
xl: 'p-8 sm:p-10'
|
||||
};
|
||||
|
||||
const variantStyles = {
|
||||
default: 'bg-[var(--color-background-card)]',
|
||||
hover: 'bg-[var(--color-background-card)] hover:bg-[var(--color-background-card-hover)] hover:shadow-xl hover:scale-[1.02] transition-all duration-300',
|
||||
glow: 'bg-[var(--color-background-card)] hover:shadow-[0_0_30px_var(--color-primary-glow,rgba(59,130,246,0.3))] transition-all duration-300',
|
||||
bordered: 'bg-[var(--color-background-card)] border border-[var(--color-border)] hover:border-[var(--color-primary)] transition-colors duration-200'
|
||||
};
|
||||
|
||||
const baseStyles = 'rounded-xl shadow-lg';
|
||||
const finalClassName = `${baseStyles} ${variantStyles[variant]} ${paddingStyles[padding]} ${className}`;
|
||||
---
|
||||
|
||||
{Element === 'a' ? (
|
||||
<a href={href} class={finalClassName}>
|
||||
<slot />
|
||||
</a>
|
||||
) : (
|
||||
<Element class={finalClassName}>
|
||||
<slot />
|
||||
</Element>
|
||||
)}
|
||||
30
packages/shared-landing-ui/src/atoms/Container.astro
Normal file
30
packages/shared-landing-ui/src/atoms/Container.astro
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
/**
|
||||
* Shared Container component for consistent max-width and padding
|
||||
*/
|
||||
interface Props {
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
||||
class?: string;
|
||||
as?: 'div' | 'section' | 'article' | 'main';
|
||||
}
|
||||
|
||||
const {
|
||||
size = 'lg',
|
||||
class: className = '',
|
||||
as: Element = 'div'
|
||||
} = Astro.props;
|
||||
|
||||
const sizes = {
|
||||
sm: 'max-w-3xl',
|
||||
md: 'max-w-5xl',
|
||||
lg: 'max-w-7xl',
|
||||
xl: 'max-w-[1400px]',
|
||||
full: 'max-w-full'
|
||||
};
|
||||
|
||||
const styles = `mx-auto px-4 sm:px-6 lg:px-8 ${sizes[size]} ${className}`;
|
||||
---
|
||||
|
||||
<Element class={styles}>
|
||||
<slot />
|
||||
</Element>
|
||||
49
packages/shared-landing-ui/src/atoms/SectionHeader.astro
Normal file
49
packages/shared-landing-ui/src/atoms/SectionHeader.astro
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
/**
|
||||
* Shared Section Header component for consistent section titles
|
||||
*/
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
align?: 'left' | 'center' | 'right';
|
||||
class?: string;
|
||||
titleClass?: string;
|
||||
subtitleClass?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
align = 'center',
|
||||
class: className = '',
|
||||
titleClass = '',
|
||||
subtitleClass = ''
|
||||
} = Astro.props;
|
||||
|
||||
const alignStyles = {
|
||||
left: 'text-left',
|
||||
center: 'text-center mx-auto',
|
||||
right: 'text-right'
|
||||
};
|
||||
|
||||
const containerStyles = `mb-8 md:mb-12 ${alignStyles[align]} ${className}`;
|
||||
---
|
||||
|
||||
<div class={containerStyles}>
|
||||
<h2 class:list={[
|
||||
"text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-[var(--color-text-primary)] mb-3 md:mb-4 leading-tight",
|
||||
titleClass
|
||||
]}>
|
||||
<slot name="title">{title}</slot>
|
||||
</h2>
|
||||
{subtitle && (
|
||||
<p class:list={[
|
||||
"text-base sm:text-lg text-[var(--color-text-secondary)] max-w-3xl leading-relaxed",
|
||||
align === 'center' && 'mx-auto',
|
||||
subtitleClass
|
||||
]}>
|
||||
<slot name="subtitle">{subtitle}</slot>
|
||||
</p>
|
||||
)}
|
||||
<slot />
|
||||
</div>
|
||||
20
packages/shared-landing-ui/src/index.ts
Normal file
20
packages/shared-landing-ui/src/index.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* @manacore/shared-landing-ui
|
||||
*
|
||||
* Shared Astro components for landing pages across the Manacore monorepo.
|
||||
*
|
||||
* Usage:
|
||||
* Import components directly from their paths:
|
||||
*
|
||||
* ```astro
|
||||
* ---
|
||||
* import Button from '@manacore/shared-landing-ui/atoms/Button.astro';
|
||||
* import HeroSection from '@manacore/shared-landing-ui/sections/HeroSection.astro';
|
||||
* ---
|
||||
* ```
|
||||
*
|
||||
* Components require CSS custom properties to be defined in your project.
|
||||
* See utils/index.ts for the required variables and example themes.
|
||||
*/
|
||||
|
||||
export * from './utils/index';
|
||||
169
packages/shared-landing-ui/src/layouts/Footer.astro
Normal file
169
packages/shared-landing-ui/src/layouts/Footer.astro
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
---
|
||||
/**
|
||||
* Shared Footer component
|
||||
* Highly configurable footer for landing pages
|
||||
*/
|
||||
import Container from '../atoms/Container.astro';
|
||||
import Button from '../atoms/Button.astro';
|
||||
|
||||
interface FooterLink {
|
||||
label: string;
|
||||
href: string;
|
||||
icon?: string;
|
||||
external?: boolean;
|
||||
}
|
||||
|
||||
interface FooterSection {
|
||||
title: string;
|
||||
links: FooterLink[];
|
||||
}
|
||||
|
||||
interface SocialLink {
|
||||
platform: 'linkedin' | 'twitter' | 'facebook' | 'instagram' | 'youtube' | 'github';
|
||||
href: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
brand: {
|
||||
name: string;
|
||||
tagline?: string;
|
||||
logo?: string;
|
||||
};
|
||||
sections?: FooterSection[];
|
||||
socialLinks?: SocialLink[];
|
||||
copyright?: string;
|
||||
ctaButton?: {
|
||||
text: string;
|
||||
href: string;
|
||||
variant?: 'primary' | 'secondary';
|
||||
};
|
||||
secondaryButton?: {
|
||||
text: string;
|
||||
href: string;
|
||||
};
|
||||
class?: string;
|
||||
lang?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
brand,
|
||||
sections = [],
|
||||
socialLinks = [],
|
||||
copyright,
|
||||
ctaButton,
|
||||
secondaryButton,
|
||||
class: className = '',
|
||||
lang = 'de'
|
||||
} = Astro.props;
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
const socialIcons = {
|
||||
linkedin: `<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>`,
|
||||
twitter: `<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>`,
|
||||
facebook: `<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/>`,
|
||||
instagram: `<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/>`,
|
||||
youtube: `<path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/>`,
|
||||
github: `<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>`
|
||||
};
|
||||
|
||||
const socialHoverColors = {
|
||||
linkedin: 'hover:text-[#0077b5]',
|
||||
twitter: 'hover:text-white',
|
||||
facebook: 'hover:text-[#1877f2]',
|
||||
instagram: 'hover:text-[#E4405F]',
|
||||
youtube: 'hover:text-[#FF0000]',
|
||||
github: 'hover:text-white'
|
||||
};
|
||||
---
|
||||
|
||||
<footer class:list={["bg-[var(--color-background-page)] py-12 md:py-16", className]}>
|
||||
<Container>
|
||||
{/* Main Footer Grid */}
|
||||
{sections.length > 0 && (
|
||||
<div class:list={[
|
||||
"grid gap-8 mb-12",
|
||||
sections.length === 2 && "grid-cols-2 md:grid-cols-4",
|
||||
sections.length === 3 && "grid-cols-2 md:grid-cols-3 lg:grid-cols-4",
|
||||
sections.length >= 4 && "grid-cols-2 md:grid-cols-4 lg:grid-cols-5"
|
||||
]}>
|
||||
{sections.map((section) => (
|
||||
<div class="flex flex-col">
|
||||
<h3 class="text-xs sm:text-sm font-medium text-[var(--color-text-muted)] uppercase tracking-wider mb-4">
|
||||
{section.title}
|
||||
</h3>
|
||||
<ul class="space-y-2">
|
||||
{section.links.map((link) => (
|
||||
<li>
|
||||
<a
|
||||
href={link.href}
|
||||
class="flex items-center gap-2 px-3 py-2 bg-white/5 hover:bg-white/10 rounded-lg text-sm transition-all text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]"
|
||||
target={link.external ? "_blank" : undefined}
|
||||
rel={link.external ? "noopener noreferrer" : undefined}
|
||||
>
|
||||
{link.icon && <span class="w-4 h-4">{link.icon}</span>}
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Social Links */}
|
||||
{socialLinks.length > 0 && (
|
||||
<div class="border-t border-[var(--color-border)] pt-8 mb-8">
|
||||
<div class="flex justify-center space-x-6">
|
||||
{socialLinks.map((social) => (
|
||||
<a
|
||||
href={social.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class:list={[
|
||||
"text-[var(--color-text-muted)] transition-colors",
|
||||
socialHoverColors[social.platform]
|
||||
]}
|
||||
>
|
||||
<span class="sr-only">{social.platform}</span>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<Fragment set:html={socialIcons[social.platform]} />
|
||||
</svg>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* CTA Buttons */}
|
||||
{(ctaButton || secondaryButton) && (
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center mb-8">
|
||||
{secondaryButton && (
|
||||
<Button href={secondaryButton.href} variant="secondary" size="md">
|
||||
{secondaryButton.text}
|
||||
</Button>
|
||||
)}
|
||||
{ctaButton && (
|
||||
<Button href={ctaButton.href} variant={ctaButton.variant ?? 'primary'} size="md">
|
||||
{ctaButton.text}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Copyright */}
|
||||
<div class="text-center">
|
||||
<p class="text-[var(--color-text-muted)] text-xs sm:text-sm">
|
||||
{copyright || `© ${currentYear} ${brand.name}. All rights reserved.`}
|
||||
</p>
|
||||
{brand.tagline && (
|
||||
<p class="text-[var(--color-text-muted)] text-xs mt-1">
|
||||
{brand.tagline}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
</Container>
|
||||
</footer>
|
||||
74
packages/shared-landing-ui/src/sections/CTASection.astro
Normal file
74
packages/shared-landing-ui/src/sections/CTASection.astro
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
/**
|
||||
* Shared CTA (Call to Action) Section component
|
||||
*/
|
||||
import Container from '../atoms/Container.astro';
|
||||
import Button from '../atoms/Button.astro';
|
||||
|
||||
interface CTA {
|
||||
text: string;
|
||||
href: string;
|
||||
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
primaryCta?: CTA;
|
||||
secondaryCta?: CTA;
|
||||
variant?: 'default' | 'highlighted' | 'minimal';
|
||||
class?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
primaryCta,
|
||||
secondaryCta,
|
||||
variant = 'default',
|
||||
class: className = '',
|
||||
id
|
||||
} = Astro.props;
|
||||
|
||||
const variantStyles = {
|
||||
default: 'bg-[var(--color-background-page)]',
|
||||
highlighted: 'bg-[var(--color-primary)]/10 border-y border-[var(--color-primary)]/20',
|
||||
minimal: ''
|
||||
};
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", variantStyles[variant], className]}>
|
||||
<Container size="md">
|
||||
<div class="text-center space-y-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-[var(--color-text-primary)] leading-tight">
|
||||
<slot name="title">{title}</slot>
|
||||
</h2>
|
||||
|
||||
{subtitle && (
|
||||
<p class="text-base sm:text-lg text-[var(--color-text-secondary)] max-w-2xl mx-auto leading-relaxed">
|
||||
{subtitle}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{(primaryCta || secondaryCta) && (
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center pt-4">
|
||||
{primaryCta && (
|
||||
<Button href={primaryCta.href} variant={primaryCta.variant ?? 'primary'} size="lg">
|
||||
<slot name="primaryCtaIcon" />
|
||||
{primaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
{secondaryCta && (
|
||||
<Button href={secondaryCta.href} variant={secondaryCta.variant ?? 'secondary'} size="lg">
|
||||
<slot name="secondaryCtaIcon" />
|
||||
{secondaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<slot />
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
115
packages/shared-landing-ui/src/sections/FAQSection.astro
Normal file
115
packages/shared-landing-ui/src/sections/FAQSection.astro
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
---
|
||||
/**
|
||||
* Shared FAQ Section component
|
||||
* Expandable FAQ items with accordion behavior
|
||||
*/
|
||||
import Container from '../atoms/Container.astro';
|
||||
import SectionHeader from '../atoms/SectionHeader.astro';
|
||||
|
||||
interface FAQItem {
|
||||
question: string;
|
||||
answer: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
faqs: FAQItem[];
|
||||
class?: string;
|
||||
id?: string;
|
||||
singleExpand?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
title = 'Frequently Asked Questions',
|
||||
subtitle,
|
||||
faqs,
|
||||
class: className = '',
|
||||
id = 'faq',
|
||||
singleExpand = true
|
||||
} = Astro.props;
|
||||
|
||||
const sectionId = `faq-section-${Math.random().toString(36).substring(7)}`;
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", className]}>
|
||||
<Container size="md">
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
|
||||
<div class="max-w-3xl mx-auto space-y-4" data-faq-container={singleExpand ? sectionId : undefined}>
|
||||
{faqs.map((faq, index) => (
|
||||
<details class="group" data-faq-item={singleExpand ? sectionId : undefined}>
|
||||
<summary class="cursor-pointer list-none">
|
||||
<div class="bg-[var(--color-background-card)] rounded-xl p-5 sm:p-6 border border-[var(--color-border)] hover:bg-[var(--color-background-card-hover)] hover:border-[var(--color-border-hover,var(--color-border))] transition-all duration-200">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<h3 class="font-semibold text-base sm:text-lg text-[var(--color-text-primary)] pr-4 group-open:text-[var(--color-primary)] transition-colors text-left">
|
||||
{faq.question}
|
||||
</h3>
|
||||
<div class="flex-shrink-0 w-5 h-5 text-[var(--color-primary)] transition-transform duration-300 group-open:rotate-180">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-hidden max-h-0 group-open:max-h-[1000px] transition-all duration-300 ease-in-out">
|
||||
<div class="pt-4 text-[var(--color-text-secondary)] leading-relaxed text-sm sm:text-base prose prose-sm max-w-none">
|
||||
<Fragment set:html={faq.answer} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
</details>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<slot name="contact" />
|
||||
<slot />
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
details summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
details[open] summary ~ * {
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script define:vars={{ sectionId, singleExpand }}>
|
||||
if (singleExpand) {
|
||||
function setupFAQ() {
|
||||
const container = document.querySelector(`[data-faq-container="${sectionId}"]`);
|
||||
if (!container) return;
|
||||
|
||||
const items = container.querySelectorAll(`[data-faq-item="${sectionId}"]`);
|
||||
|
||||
items.forEach((item) => {
|
||||
item.addEventListener('toggle', (e) => {
|
||||
if (e.target.open) {
|
||||
items.forEach((otherItem) => {
|
||||
if (otherItem !== e.target && otherItem.open) {
|
||||
otherItem.open = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setupFAQ();
|
||||
document.addEventListener('astro:page-load', setupFAQ);
|
||||
}
|
||||
</script>
|
||||
95
packages/shared-landing-ui/src/sections/FeatureSection.astro
Normal file
95
packages/shared-landing-ui/src/sections/FeatureSection.astro
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
---
|
||||
/**
|
||||
* Shared Feature Section component
|
||||
* Displays features in a responsive grid
|
||||
*/
|
||||
import Container from '../atoms/Container.astro';
|
||||
import Card from '../atoms/Card.astro';
|
||||
import SectionHeader from '../atoms/SectionHeader.astro';
|
||||
|
||||
interface Feature {
|
||||
icon: string;
|
||||
title: string;
|
||||
description: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
features: Feature[];
|
||||
columns?: 2 | 3 | 4;
|
||||
variant?: 'cards' | 'simple' | 'icons-left';
|
||||
class?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
features,
|
||||
columns = 3,
|
||||
variant = 'cards',
|
||||
class: className = '',
|
||||
id
|
||||
} = Astro.props;
|
||||
|
||||
const gridCols = {
|
||||
2: 'md:grid-cols-2',
|
||||
3: 'md:grid-cols-2 lg:grid-cols-3',
|
||||
4: 'md:grid-cols-2 lg:grid-cols-4'
|
||||
};
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", className]}>
|
||||
<Container>
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
|
||||
<div class:list={["grid gap-6 md:gap-8", gridCols[columns]]}>
|
||||
{features.map((feature) => (
|
||||
variant === 'cards' ? (
|
||||
<Card variant="hover" padding="lg" as={feature.href ? 'a' : 'div'} href={feature.href}>
|
||||
<div class="flex flex-col items-center text-center h-full">
|
||||
<div class="text-4xl sm:text-5xl mb-4 transform group-hover:scale-110 transition-transform duration-300">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h3 class="font-semibold text-lg sm:text-xl text-[var(--color-text-primary)] mb-3">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm sm:text-base leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
) : variant === 'icons-left' ? (
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-shrink-0 text-3xl">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-lg text-[var(--color-text-primary)] mb-2">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div class="text-center">
|
||||
<div class="text-4xl mb-4">{feature.icon}</div>
|
||||
<h3 class="font-semibold text-lg text-[var(--color-text-primary)] mb-2">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
|
||||
<slot name="highlight" />
|
||||
<slot />
|
||||
</Container>
|
||||
</section>
|
||||
246
packages/shared-landing-ui/src/sections/HeroSection.astro
Normal file
246
packages/shared-landing-ui/src/sections/HeroSection.astro
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
---
|
||||
/**
|
||||
* Shared Hero Section component
|
||||
* Supports multiple variants: default (split), fullwidth, widescreen
|
||||
*/
|
||||
import Container from '../atoms/Container.astro';
|
||||
import Button from '../atoms/Button.astro';
|
||||
|
||||
interface CTA {
|
||||
text: string;
|
||||
href: string;
|
||||
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
interface TrustBadge {
|
||||
icon: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
variant?: 'default' | 'fullwidth' | 'centered';
|
||||
image?: {
|
||||
src: string;
|
||||
alt: string;
|
||||
position?: 'left' | 'right';
|
||||
};
|
||||
primaryCta?: CTA;
|
||||
secondaryCta?: CTA;
|
||||
microCopy?: string;
|
||||
trustBadges?: TrustBadge[];
|
||||
class?: string;
|
||||
showScrollIndicator?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
variant = 'default',
|
||||
image,
|
||||
primaryCta,
|
||||
secondaryCta,
|
||||
microCopy,
|
||||
trustBadges,
|
||||
class: className = '',
|
||||
showScrollIndicator = false
|
||||
} = Astro.props;
|
||||
|
||||
const imagePosition = image?.position ?? 'right';
|
||||
---
|
||||
|
||||
<section class:list={[
|
||||
"relative overflow-hidden",
|
||||
variant === 'default' && "py-12 md:py-20",
|
||||
variant === 'fullwidth' && "py-8 md:py-12",
|
||||
variant === 'centered' && "py-16 md:py-24 min-h-[80vh] flex items-center",
|
||||
className
|
||||
]}>
|
||||
<Container>
|
||||
{variant === 'default' && (
|
||||
<div class="grid md:grid-cols-2 gap-8 md:gap-12 items-center">
|
||||
<!-- Text Content -->
|
||||
<div class:list={[
|
||||
"text-center md:text-left space-y-6",
|
||||
imagePosition === 'left' ? 'md:order-2' : 'md:order-1'
|
||||
]}>
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold text-[var(--color-text-primary)] leading-tight">
|
||||
<slot name="title">{title}</slot>
|
||||
</h1>
|
||||
|
||||
<p class="text-base sm:text-lg md:text-xl text-[var(--color-text-secondary)] leading-relaxed max-w-xl mx-auto md:mx-0">
|
||||
{subtitle}
|
||||
</p>
|
||||
|
||||
{(primaryCta || secondaryCta) && (
|
||||
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4 justify-center md:justify-start">
|
||||
{primaryCta && (
|
||||
<Button href={primaryCta.href} variant={primaryCta.variant ?? 'primary'} size="lg">
|
||||
<slot name="primaryCtaIcon" />
|
||||
{primaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
{secondaryCta && (
|
||||
<Button href={secondaryCta.href} variant={secondaryCta.variant ?? 'secondary'} size="lg">
|
||||
<slot name="secondaryCtaIcon" />
|
||||
{secondaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{microCopy && (
|
||||
<p class="text-sm text-[var(--color-text-muted)]">{microCopy}</p>
|
||||
)}
|
||||
|
||||
{trustBadges && trustBadges.length > 0 && (
|
||||
<div class="flex flex-wrap gap-3 justify-center md:justify-start mt-6">
|
||||
{trustBadges.map((badge) => (
|
||||
<div class="inline-flex items-center gap-2 px-4 py-2 bg-white/5 rounded-full border border-white/10 backdrop-blur-sm">
|
||||
<span class="text-base">{badge.icon}</span>
|
||||
<span class="text-xs font-medium text-[var(--color-text-secondary)]">{badge.text}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<!-- Image -->
|
||||
{image && (
|
||||
<div class:list={[
|
||||
"relative",
|
||||
imagePosition === 'left' ? 'md:order-1' : 'md:order-2'
|
||||
]}>
|
||||
<div class="relative w-full aspect-square md:aspect-[4/3] overflow-hidden rounded-2xl group">
|
||||
<img
|
||||
src={image.src}
|
||||
alt={image.alt}
|
||||
class="w-full h-full object-cover shadow-2xl transform group-hover:scale-105 transition-transform duration-700"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
decoding="async"
|
||||
/>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent"></div>
|
||||
</div>
|
||||
<slot name="imageDecoration" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{variant === 'fullwidth' && image && (
|
||||
<div class="space-y-6">
|
||||
<!-- Full-width Image -->
|
||||
<div class="relative w-full aspect-[16/9] md:aspect-[21/9] overflow-hidden rounded-2xl">
|
||||
<img
|
||||
src={image.src}
|
||||
alt={image.alt}
|
||||
class="absolute inset-0 w-full h-full object-cover"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
decoding="async"
|
||||
/>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent"></div>
|
||||
|
||||
<!-- Overlay text on desktop -->
|
||||
<div class="hidden md:flex absolute inset-0 items-end justify-center pb-8">
|
||||
<div class="text-center max-w-3xl px-8 space-y-4">
|
||||
<h1 class="text-3xl md:text-5xl text-white font-bold leading-tight">
|
||||
<slot name="title">{title}</slot>
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl text-gray-200 leading-relaxed">
|
||||
{subtitle}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Text below on mobile -->
|
||||
<div class="md:hidden text-center space-y-4">
|
||||
<h1 class="text-2xl sm:text-3xl font-bold text-[var(--color-text-primary)] leading-tight">
|
||||
<slot name="title">{title}</slot>
|
||||
</h1>
|
||||
<p class="text-base text-[var(--color-text-secondary)] leading-relaxed">
|
||||
{subtitle}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- CTAs -->
|
||||
{(primaryCta || secondaryCta) && (
|
||||
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4 justify-center">
|
||||
{primaryCta && (
|
||||
<Button href={primaryCta.href} variant={primaryCta.variant ?? 'primary'} size="lg">
|
||||
<slot name="primaryCtaIcon" />
|
||||
{primaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
{secondaryCta && (
|
||||
<Button href={secondaryCta.href} variant={secondaryCta.variant ?? 'secondary'} size="lg">
|
||||
<slot name="secondaryCtaIcon" />
|
||||
{secondaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{trustBadges && trustBadges.length > 0 && (
|
||||
<div class="flex flex-wrap gap-3 justify-center">
|
||||
{trustBadges.map((badge) => (
|
||||
<div class="inline-flex items-center gap-2 px-4 py-2 bg-white/5 rounded-full border border-white/10 backdrop-blur-sm">
|
||||
<span class="text-base">{badge.icon}</span>
|
||||
<span class="text-xs font-medium text-gray-300">{badge.text}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{variant === 'centered' && (
|
||||
<div class="text-center max-w-4xl mx-auto space-y-8">
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold text-[var(--color-text-primary)] leading-tight">
|
||||
<slot name="title">{title}</slot>
|
||||
</h1>
|
||||
|
||||
<p class="text-lg md:text-xl text-[var(--color-text-secondary)] leading-relaxed max-w-2xl mx-auto">
|
||||
{subtitle}
|
||||
</p>
|
||||
|
||||
{(primaryCta || secondaryCta) && (
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
{primaryCta && (
|
||||
<Button href={primaryCta.href} variant={primaryCta.variant ?? 'primary'} size="lg">
|
||||
<slot name="primaryCtaIcon" />
|
||||
{primaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
{secondaryCta && (
|
||||
<Button href={secondaryCta.href} variant={secondaryCta.variant ?? 'secondary'} size="lg">
|
||||
<slot name="secondaryCtaIcon" />
|
||||
{secondaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{microCopy && (
|
||||
<p class="text-sm text-[var(--color-text-muted)]">{microCopy}</p>
|
||||
)}
|
||||
|
||||
<slot name="content" />
|
||||
</div>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
{showScrollIndicator && (
|
||||
<div class="absolute bottom-8 left-1/2 -translate-x-1/2 animate-bounce">
|
||||
<svg class="w-6 h-6 text-[var(--color-text-secondary)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3" />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<slot name="background" />
|
||||
</section>
|
||||
140
packages/shared-landing-ui/src/sections/PricingSection.astro
Normal file
140
packages/shared-landing-ui/src/sections/PricingSection.astro
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
---
|
||||
/**
|
||||
* Shared Pricing Section component
|
||||
*/
|
||||
import Container from '../atoms/Container.astro';
|
||||
import Card from '../atoms/Card.astro';
|
||||
import Button from '../atoms/Button.astro';
|
||||
import Badge from '../atoms/Badge.astro';
|
||||
import SectionHeader from '../atoms/SectionHeader.astro';
|
||||
|
||||
interface PricingFeature {
|
||||
text: string;
|
||||
included: boolean;
|
||||
}
|
||||
|
||||
interface PricingPlan {
|
||||
name: string;
|
||||
description?: string;
|
||||
price: string;
|
||||
period?: string;
|
||||
features: PricingFeature[] | string[];
|
||||
cta: {
|
||||
text: string;
|
||||
href: string;
|
||||
};
|
||||
highlighted?: boolean;
|
||||
badge?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
plans: PricingPlan[];
|
||||
class?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
plans,
|
||||
class: className = '',
|
||||
id = 'pricing'
|
||||
} = Astro.props;
|
||||
|
||||
// Normalize features to always have { text, included } format
|
||||
function normalizeFeatures(features: PricingFeature[] | string[]): PricingFeature[] {
|
||||
return features.map(f => typeof f === 'string' ? { text: f, included: true } : f);
|
||||
}
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", className]}>
|
||||
<Container>
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
|
||||
<div class:list={[
|
||||
"grid gap-6 md:gap-8",
|
||||
plans.length === 2 && "md:grid-cols-2 max-w-4xl mx-auto",
|
||||
plans.length === 3 && "md:grid-cols-3",
|
||||
plans.length >= 4 && "md:grid-cols-2 lg:grid-cols-4"
|
||||
]}>
|
||||
{plans.map((plan) => (
|
||||
<Card
|
||||
variant={plan.highlighted ? 'glow' : 'bordered'}
|
||||
padding="lg"
|
||||
class:list={[
|
||||
"flex flex-col relative",
|
||||
plan.highlighted && "ring-2 ring-[var(--color-primary)] scale-105"
|
||||
]}
|
||||
>
|
||||
{plan.badge && (
|
||||
<div class="absolute -top-3 left-1/2 -translate-x-1/2">
|
||||
<Badge variant="primary">{plan.badge}</Badge>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="text-center mb-6">
|
||||
<h3 class="text-xl font-bold text-[var(--color-text-primary)] mb-2">
|
||||
{plan.name}
|
||||
</h3>
|
||||
{plan.description && (
|
||||
<p class="text-sm text-[var(--color-text-secondary)]">
|
||||
{plan.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="text-center mb-6">
|
||||
<span class="text-4xl font-bold text-[var(--color-text-primary)]">
|
||||
{plan.price}
|
||||
</span>
|
||||
{plan.period && (
|
||||
<span class="text-[var(--color-text-secondary)]">
|
||||
/{plan.period}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ul class="space-y-3 mb-8 flex-1">
|
||||
{normalizeFeatures(plan.features).map((feature) => (
|
||||
<li class="flex items-start gap-3">
|
||||
<svg
|
||||
class:list={[
|
||||
"w-5 h-5 flex-shrink-0 mt-0.5",
|
||||
feature.included ? "text-green-500" : "text-[var(--color-text-muted)]"
|
||||
]}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
{feature.included ? (
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
) : (
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
)}
|
||||
</svg>
|
||||
<span class:list={[
|
||||
"text-sm",
|
||||
feature.included ? "text-[var(--color-text-primary)]" : "text-[var(--color-text-muted)] line-through"
|
||||
]}>
|
||||
{feature.text}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<Button
|
||||
href={plan.cta.href}
|
||||
variant={plan.highlighted ? 'primary' : 'secondary'}
|
||||
fullWidth
|
||||
>
|
||||
{plan.cta.text}
|
||||
</Button>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
</Container>
|
||||
</section>
|
||||
88
packages/shared-landing-ui/src/sections/StepsSection.astro
Normal file
88
packages/shared-landing-ui/src/sections/StepsSection.astro
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
/**
|
||||
* Shared Steps/How It Works Section component
|
||||
* Displays a step-by-step guide with alternating image positions
|
||||
*/
|
||||
import Container from '../atoms/Container.astro';
|
||||
import Card from '../atoms/Card.astro';
|
||||
import SectionHeader from '../atoms/SectionHeader.astro';
|
||||
|
||||
interface Step {
|
||||
number: string | number;
|
||||
title: string;
|
||||
description: string;
|
||||
image?: string;
|
||||
imageAlt?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
steps: Step[];
|
||||
showImages?: boolean;
|
||||
alternateLayout?: boolean;
|
||||
class?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
steps,
|
||||
showImages = true,
|
||||
alternateLayout = true,
|
||||
class: className = '',
|
||||
id
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", className]}>
|
||||
<Container>
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
|
||||
<div class="space-y-12 md:space-y-20">
|
||||
{steps.map((step, index) => (
|
||||
<div class:list={[
|
||||
"flex flex-col gap-8 lg:gap-12 items-center",
|
||||
alternateLayout && index % 2 === 0 ? "lg:flex-row" : "lg:flex-row-reverse"
|
||||
]}>
|
||||
<!-- Text Content -->
|
||||
<div class="flex-1 text-center lg:text-left">
|
||||
<div class="flex items-center gap-4 mb-4 justify-center lg:justify-start">
|
||||
<div class="w-12 h-12 md:w-14 md:h-14 bg-[var(--color-primary)] rounded-full flex items-center justify-center shadow-lg">
|
||||
<span class="text-white font-bold text-xl md:text-2xl">{step.number}</span>
|
||||
</div>
|
||||
<h3 class="font-bold text-xl md:text-2xl text-[var(--color-text-primary)]">
|
||||
{step.title}
|
||||
</h3>
|
||||
</div>
|
||||
<p class="text-[var(--color-text-secondary)] text-base md:text-lg leading-relaxed max-w-xl mx-auto lg:mx-0">
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Image -->
|
||||
{showImages && step.image && (
|
||||
<div class="flex-1 w-full max-w-md lg:max-w-none">
|
||||
<Card padding="none" class="overflow-hidden">
|
||||
<div class="relative aspect-video bg-[var(--color-background-card-hover)]">
|
||||
<img
|
||||
src={step.image}
|
||||
alt={step.imageAlt || step.title}
|
||||
class="w-full h-full object-cover"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent pointer-events-none"></div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<slot name="cta" />
|
||||
<slot />
|
||||
</Container>
|
||||
</section>
|
||||
121
packages/shared-landing-ui/src/sections/TestimonialSection.astro
Normal file
121
packages/shared-landing-ui/src/sections/TestimonialSection.astro
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
---
|
||||
/**
|
||||
* Shared Testimonial Section component
|
||||
* Displays customer testimonials in a grid
|
||||
*/
|
||||
import Container from '../atoms/Container.astro';
|
||||
import Card from '../atoms/Card.astro';
|
||||
import SectionHeader from '../atoms/SectionHeader.astro';
|
||||
|
||||
interface Testimonial {
|
||||
name: string;
|
||||
role?: string;
|
||||
company?: string;
|
||||
text: string;
|
||||
image?: string;
|
||||
rating?: number;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
testimonials: Testimonial[];
|
||||
columns?: 1 | 2 | 3;
|
||||
showRating?: boolean;
|
||||
class?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
testimonials,
|
||||
columns = 3,
|
||||
showRating = true,
|
||||
class: className = '',
|
||||
id
|
||||
} = Astro.props;
|
||||
|
||||
const gridCols = {
|
||||
1: 'max-w-2xl mx-auto',
|
||||
2: 'md:grid-cols-2 max-w-4xl mx-auto',
|
||||
3: 'md:grid-cols-2 lg:grid-cols-3'
|
||||
};
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", className]}>
|
||||
<Container>
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
|
||||
<div class:list={["grid gap-6 md:gap-8", gridCols[columns]]}>
|
||||
{testimonials.map((testimonial) => (
|
||||
<Card variant="bordered" padding="lg">
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- Header with avatar and info -->
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="flex-shrink-0">
|
||||
{testimonial.image ? (
|
||||
<img
|
||||
src={testimonial.image}
|
||||
alt={testimonial.name}
|
||||
class="w-12 h-12 rounded-full object-cover border-2 border-[var(--color-primary)]/20"
|
||||
width="48"
|
||||
height="48"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
) : (
|
||||
<div class="w-12 h-12 rounded-full bg-[var(--color-primary)]/20 flex items-center justify-center">
|
||||
<span class="text-xl font-semibold text-[var(--color-primary)]">
|
||||
{testimonial.name.charAt(0)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<h3 class="font-semibold text-[var(--color-text-primary)] truncate">
|
||||
{testimonial.name}
|
||||
</h3>
|
||||
{testimonial.role && (
|
||||
<p class="text-sm text-[var(--color-text-secondary)] truncate">
|
||||
{testimonial.role}
|
||||
</p>
|
||||
)}
|
||||
{testimonial.company && (
|
||||
<p class="text-sm text-[var(--color-text-muted)] truncate">
|
||||
{testimonial.company}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quote -->
|
||||
<blockquote class="flex-1 text-[var(--color-text-secondary)] italic mb-4 leading-relaxed">
|
||||
"{testimonial.text}"
|
||||
</blockquote>
|
||||
|
||||
<!-- Rating -->
|
||||
{showRating && testimonial.rating && (
|
||||
<div class="flex items-center gap-1">
|
||||
{[...Array(5)].map((_, i) => (
|
||||
<svg
|
||||
class:list={[
|
||||
"w-5 h-5",
|
||||
i < testimonial.rating ? "text-[var(--color-primary)]" : "text-[var(--color-border)]"
|
||||
]}
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
|
||||
</svg>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
</Container>
|
||||
</section>
|
||||
81
packages/shared-landing-ui/src/themes/index.css
Normal file
81
packages/shared-landing-ui/src/themes/index.css
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* Default Theme - Neutral Dark Theme
|
||||
* This is a generic dark theme that works well for any app
|
||||
* Import this file or one of the app-specific themes
|
||||
*/
|
||||
:root {
|
||||
/* Primary colors - Neutral Blue */
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-hover: #2563eb;
|
||||
--color-primary-glow: rgba(59, 130, 246, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #f9fafb;
|
||||
--color-text-secondary: #d1d5db;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #111827;
|
||||
--color-background-card: #1f2937;
|
||||
--color-background-card-hover: #374151;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #374151;
|
||||
--color-border-hover: #4b5563;
|
||||
}
|
||||
|
||||
/* Light mode support */
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--color-primary: #2563eb;
|
||||
--color-primary-hover: #1d4ed8;
|
||||
--color-primary-glow: rgba(37, 99, 235, 0.3);
|
||||
|
||||
--color-text-primary: #111827;
|
||||
--color-text-secondary: #4b5563;
|
||||
--color-text-muted: #9ca3af;
|
||||
|
||||
--color-background-page: #ffffff;
|
||||
--color-background-card: #f9fafb;
|
||||
--color-background-card-hover: #f3f4f6;
|
||||
|
||||
--color-border: #e5e7eb;
|
||||
--color-border-hover: #d1d5db;
|
||||
}
|
||||
}
|
||||
|
||||
/* Force dark mode class */
|
||||
.dark {
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-hover: #60a5fa;
|
||||
--color-primary-glow: rgba(59, 130, 246, 0.3);
|
||||
|
||||
--color-text-primary: #f9fafb;
|
||||
--color-text-secondary: #d1d5db;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
--color-background-page: #111827;
|
||||
--color-background-card: #1f2937;
|
||||
--color-background-card-hover: #374151;
|
||||
|
||||
--color-border: #374151;
|
||||
--color-border-hover: #4b5563;
|
||||
}
|
||||
|
||||
/* Force light mode class */
|
||||
.light {
|
||||
--color-primary: #2563eb;
|
||||
--color-primary-hover: #1d4ed8;
|
||||
--color-primary-glow: rgba(37, 99, 235, 0.3);
|
||||
|
||||
--color-text-primary: #111827;
|
||||
--color-text-secondary: #4b5563;
|
||||
--color-text-muted: #9ca3af;
|
||||
|
||||
--color-background-page: #ffffff;
|
||||
--color-background-card: #f9fafb;
|
||||
--color-background-card-hover: #f3f4f6;
|
||||
|
||||
--color-border: #e5e7eb;
|
||||
--color-border-hover: #d1d5db;
|
||||
}
|
||||
24
packages/shared-landing-ui/src/themes/maerchenzauber.css
Normal file
24
packages/shared-landing-ui/src/themes/maerchenzauber.css
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* Märchenzauber Theme - Golden/Yellow Dark Theme (Children's App)
|
||||
* Import this file in your landing page to use the Märchenzauber color scheme
|
||||
*/
|
||||
:root {
|
||||
/* Primary colors - Märchenzauber Gold */
|
||||
--color-primary: #6D5B00;
|
||||
--color-primary-hover: #F8D62B;
|
||||
--color-primary-glow: rgba(248, 214, 43, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #FFFFFF;
|
||||
--color-text-secondary: #999999;
|
||||
--color-text-muted: #666666;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #181818;
|
||||
--color-background-card: #2C2C2C;
|
||||
--color-background-card-hover: #333333;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #444444;
|
||||
--color-border-hover: #555555;
|
||||
}
|
||||
24
packages/shared-landing-ui/src/themes/manacore.css
Normal file
24
packages/shared-landing-ui/src/themes/manacore.css
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* ManaCore Theme - Blue Dark Theme
|
||||
* Import this file in your landing page to use the ManaCore color scheme
|
||||
*/
|
||||
:root {
|
||||
/* Primary colors - ManaCore Blue */
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-hover: #2563eb;
|
||||
--color-primary-glow: rgba(59, 130, 246, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #f9fafb;
|
||||
--color-text-secondary: #d1d5db;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #081320;
|
||||
--color-background-card: #1e293b;
|
||||
--color-background-card-hover: #334155;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #334155;
|
||||
--color-border-hover: #475569;
|
||||
}
|
||||
24
packages/shared-landing-ui/src/themes/manadeck.css
Normal file
24
packages/shared-landing-ui/src/themes/manadeck.css
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* ManaDeck Theme - Purple Dark Theme
|
||||
* Import this file in your landing page to use the ManaDeck color scheme
|
||||
*/
|
||||
:root {
|
||||
/* Primary colors - ManaDeck Purple */
|
||||
--color-primary: #7C3AED;
|
||||
--color-primary-hover: #8B5CF6;
|
||||
--color-primary-glow: rgba(124, 58, 237, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #f9fafb;
|
||||
--color-text-secondary: #d1d5db;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #0f0a1a;
|
||||
--color-background-card: #1a1625;
|
||||
--color-background-card-hover: #2d2640;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #3d3555;
|
||||
--color-border-hover: #4d4570;
|
||||
}
|
||||
24
packages/shared-landing-ui/src/themes/memoro.css
Normal file
24
packages/shared-landing-ui/src/themes/memoro.css
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* Memoro Theme - Yellow/Gold Dark Theme
|
||||
* Import this file in your landing page to use the Memoro color scheme
|
||||
*/
|
||||
:root {
|
||||
/* Primary colors - Memoro Yellow/Gold */
|
||||
--color-primary: #806b00;
|
||||
--color-primary-hover: #ae9200;
|
||||
--color-primary-glow: rgba(248, 214, 43, 0.3);
|
||||
|
||||
/* Text colors */
|
||||
--color-text-primary: #ffffff;
|
||||
--color-text-secondary: #9ca3af;
|
||||
--color-text-muted: #6b7280;
|
||||
|
||||
/* Background colors */
|
||||
--color-background-page: #0D0C12;
|
||||
--color-background-card: #1a1a1a;
|
||||
--color-background-card-hover: #262626;
|
||||
|
||||
/* Border colors */
|
||||
--color-border: #333333;
|
||||
--color-border-hover: #404040;
|
||||
}
|
||||
106
packages/shared-landing-ui/src/utils/index.ts
Normal file
106
packages/shared-landing-ui/src/utils/index.ts
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* Utility functions for shared landing UI components
|
||||
*/
|
||||
|
||||
/**
|
||||
* CSS custom properties that should be defined in your project's CSS
|
||||
* for the shared components to work correctly.
|
||||
*/
|
||||
export const requiredCssVariables = [
|
||||
'--color-primary',
|
||||
'--color-primary-hover',
|
||||
'--color-primary-glow',
|
||||
'--color-text-primary',
|
||||
'--color-text-secondary',
|
||||
'--color-text-muted',
|
||||
'--color-background-page',
|
||||
'--color-background-card',
|
||||
'--color-background-card-hover',
|
||||
'--color-border',
|
||||
'--color-border-hover',
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* Example CSS variable definitions for light theme
|
||||
*/
|
||||
export const exampleLightTheme = `
|
||||
:root {
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-hover: #2563eb;
|
||||
--color-primary-glow: rgba(59, 130, 246, 0.3);
|
||||
--color-text-primary: #111827;
|
||||
--color-text-secondary: #4b5563;
|
||||
--color-text-muted: #9ca3af;
|
||||
--color-background-page: #ffffff;
|
||||
--color-background-card: #f9fafb;
|
||||
--color-background-card-hover: #f3f4f6;
|
||||
--color-border: #e5e7eb;
|
||||
--color-border-hover: #d1d5db;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Example CSS variable definitions for dark theme
|
||||
*/
|
||||
export const exampleDarkTheme = `
|
||||
:root {
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-hover: #60a5fa;
|
||||
--color-primary-glow: rgba(59, 130, 246, 0.3);
|
||||
--color-text-primary: #f9fafb;
|
||||
--color-text-secondary: #d1d5db;
|
||||
--color-text-muted: #6b7280;
|
||||
--color-background-page: #111827;
|
||||
--color-background-card: #1f2937;
|
||||
--color-background-card-hover: #374151;
|
||||
--color-border: #374151;
|
||||
--color-border-hover: #4b5563;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Type definitions for component props (for TypeScript users)
|
||||
*/
|
||||
export interface ButtonProps {
|
||||
href?: string;
|
||||
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
fullWidth?: boolean;
|
||||
}
|
||||
|
||||
export interface CardProps {
|
||||
variant?: 'default' | 'hover' | 'glow' | 'bordered';
|
||||
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
||||
}
|
||||
|
||||
export interface Feature {
|
||||
icon: string;
|
||||
title: string;
|
||||
description: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
export interface Testimonial {
|
||||
name: string;
|
||||
role?: string;
|
||||
company?: string;
|
||||
text: string;
|
||||
image?: string;
|
||||
rating?: number;
|
||||
}
|
||||
|
||||
export interface FAQItem {
|
||||
question: string;
|
||||
answer: string;
|
||||
}
|
||||
|
||||
export interface PricingPlan {
|
||||
name: string;
|
||||
description?: string;
|
||||
price: string;
|
||||
period?: string;
|
||||
features: Array<{ text: string; included: boolean } | string>;
|
||||
cta: { text: string; href: string };
|
||||
highlighted?: boolean;
|
||||
badge?: string;
|
||||
}
|
||||
13
packages/shared-landing-ui/tsconfig.json
Normal file
13
packages/shared-landing-ui/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"moduleResolution": "bundler",
|
||||
"target": "ES2022",
|
||||
"module": "ES2022"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ packages:
|
|||
- 'manacore'
|
||||
- 'manadeck'
|
||||
- 'memoro'
|
||||
- 'picture'
|
||||
|
||||
# Sub-apps within projects
|
||||
- 'maerchenzauber/apps/*'
|
||||
|
|
@ -12,6 +13,8 @@ packages:
|
|||
- 'manadeck/apps/*'
|
||||
- 'manadeck/backend'
|
||||
- 'memoro/apps/*'
|
||||
- 'picture/apps/*'
|
||||
- 'picture/packages/*'
|
||||
|
||||
# Future shared packages
|
||||
# Shared packages
|
||||
- 'packages/*'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue