Files
Crumb-Core-v.1/HOME_TEMPLATE_PLAN.md

698 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🏠 Home Template System - Implementation Plan
## 🎯 Ziel
**Flexibles Home Template pro Container-Deployment:**
- Verwendet **Pico CSS** (statt Tailwind)
- **Deployment Config** (JSON) pro Container
- **Branko.de Content** als Basis
- **Multilingual** (de/en/fr)
- **Einfach austauschbar** bei neuem Container
---
## 📁 Struktur
```
compose/
deployment_config.json # Pro Container anpassbar!
app/
routers/
home.py # Home routes (/, /about, /crew, etc.)
templates/
home/
base_home.html # Base für Home (ohne Auth)
index.html # Landing Page
about.html # Mission / Wurzeln
crew.html # Character Cards
hardware.html # Hardware Info
software.html # Software Info
contact.html # Kontakt / Impressum
static/
css/
home_default.css # Standard Home Theme
home_forest.css # Wald Theme (dunkel/grün)
home_light.css # Hell Theme
data/
testimonials.de.json # Testimonials Deutsch
testimonials.en.json # English
testimonials.fr.json # Français
characters.json # Character Definitions
assets/
logo.png
hero_bg.jpg
```
---
## 🔧 1. Deployment Config
**`compose/deployment_config.json`**
```json
{
"deployment_id": "crumbforest_main",
"deployment_name": "Crumbforest Main",
"base_url": "https://branko.de",
"home": {
"enabled": true,
"theme": "forest",
"default_lang": "de",
"languages": ["de", "en", "fr"],
"hero": {
"title": "🌳 Crumbforest",
"subtitle": "Wo Fragen wachsen. Und jeder Krümel zählt.",
"cta_text": "Den Wald entdecken",
"cta_link": "#explore"
},
"mission": {
"title": "🌲 Unsere Wurzeln",
"description": "Crumbforest ist ein offenes Lern-Ökosystem mit Kindern, Maschinen und Natur.",
"values": [
{
"icon": "🦉",
"title": "Fragen",
"text": "Jedes Kind darf fragen. Wir schützen dieses Recht in jedem Terminal."
},
{
"icon": "🛠️",
"title": "Bauen",
"text": "Hands-on Lernen mit Raspberry Pi, Bash, Blockly und mehr."
},
{
"icon": "🌐",
"title": "Verbinden",
"text": "Unsere Rollen und APIs bilden ein Resonanz-Netz."
}
]
},
"sections": {
"testimonials": true,
"crew": true,
"hardware": true,
"software": true,
"contact": true
},
"navigation": [
{"label": "Home", "url": "/", "icon": "🏠"},
{"label": "Mission", "url": "/about", "icon": "🌲"},
{"label": "Crew", "url": "/crew", "icon": "🌟"},
{"label": "Hardware", "url": "/hardware", "icon": "🔧"},
{"label": "Software", "url": "/software", "icon": "💻"},
{"label": "Login", "url": "/de/login", "icon": "🔐"}
],
"footer": {
"tagline": "Made with 💚 in the Crumbforest",
"links": [
{"label": "Impressum", "url": "/impressum"},
{"label": "Datenschutz", "url": "/datenschutz"}
]
}
},
"features": {
"rag_system": true,
"diary_system": true,
"document_search": true,
"roles_web": false
}
}
```
---
## 🎨 2. Pico CSS Home Theme
**`app/static/css/home_forest.css`**
```css
/* Crumbforest Forest Theme - Dark & Green */
:root {
--pico-font-family: "Inter", system-ui, sans-serif;
/* Forest Colors */
--pico-primary: #10b981; /* Emerald */
--pico-primary-hover: #059669;
--pico-primary-focus: rgba(16, 185, 129, 0.125);
--pico-background-color: #0f172a; /* Dark Blue-Gray */
--pico-color: #e2e8f0; /* Light Gray */
/* Gradients */
--hero-gradient: linear-gradient(135deg, #064e3b 0%, #10b981 100%);
--section-accent: #1e293b;
}
/* Hero Section */
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: var(--hero-gradient);
text-align: center;
padding: 2rem;
}
.hero h1 {
font-size: 4rem;
margin-bottom: 1rem;
font-weight: 900;
}
.hero p {
font-size: 1.5rem;
margin-bottom: 2rem;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.hero .cta-button {
background: white;
color: black;
padding: 1rem 2rem;
border-radius: 2rem;
font-weight: bold;
text-decoration: none;
display: inline-block;
transition: all 0.3s;
}
.hero .cta-button:hover {
background: #fbbf24; /* Yellow */
transform: scale(1.05);
}
/* Language Switcher */
.lang-switcher {
display: flex;
gap: 1rem;
justify-content: center;
margin-top: 2rem;
}
.lang-switcher a {
background: white;
color: black;
padding: 0.5rem 1.5rem;
border-radius: 2rem;
font-weight: bold;
text-decoration: none;
}
/* Mission Section */
.mission {
padding: 4rem 2rem;
max-width: 1200px;
margin: 0 auto;
text-align: center;
}
.mission h2 {
font-size: 2.5rem;
margin-bottom: 2rem;
}
.values-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
margin-top: 2rem;
text-align: left;
}
.value-card {
background: var(--section-accent);
padding: 2rem;
border-radius: 1rem;
}
.value-card h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
/* Character Cards */
.crew-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1.5rem;
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.character-card {
background: var(--section-accent);
padding: 1.5rem;
border-radius: 1rem;
text-align: center;
cursor: pointer;
transition: all 0.3s;
border: 2px solid transparent;
}
.character-card:hover {
background: var(--pico-primary);
transform: translateY(-5px);
border-color: var(--pico-primary-hover);
}
.character-card .icon {
font-size: 3rem;
margin-bottom: 0.5rem;
}
/* Modal */
dialog {
border-radius: 1rem;
border: none;
padding: 2rem;
max-width: 600px;
background: var(--pico-background-color);
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.8);
}
/* Testimonials */
.testimonials {
background: #7c3aed; /* Purple */
padding: 4rem 2rem;
text-align: center;
}
.testimonial-slide {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
}
.testimonial-slide p {
font-size: 1.25rem;
font-style: italic;
margin-bottom: 1rem;
}
/* Responsive */
@media (max-width: 768px) {
.hero h1 {
font-size: 2.5rem;
}
.hero p {
font-size: 1.25rem;
}
.values-grid {
grid-template-columns: 1fr;
}
}
```
---
## 🧩 3. Base Home Template
**`app/templates/home/base_home.html`**
```html
<!DOCTYPE html>
<html lang="{{ lang }}" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{{ deployment.home.hero.title }}{% endblock %}</title>
<!-- SEO -->
<meta name="description" content="{% block description %}{{ deployment.home.mission.description }}{% endblock %}">
<meta name="keywords" content="Crumbforest, Kinderfragen, Lernen, Terminal, Raspberry Pi, Open Source">
<meta name="author" content="Die Crumbforest-Crew">
<meta name="robots" content="index, follow">
<!-- Open Graph -->
<meta property="og:title" content="{% block og_title %}{{ deployment.home.hero.title }}{% endblock %}">
<meta property="og:description" content="{{ deployment.home.hero.subtitle }}">
<meta property="og:url" content="{{ deployment.base_url }}">
<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
<link rel="stylesheet" href="/static/css/home_{{ deployment.home.theme }}.css">
{% block extra_css %}{% endblock %}
</head>
<body>
<!-- Navigation -->
<nav class="container-fluid">
<ul>
<li><strong>{{ deployment.home.hero.title }}</strong></li>
</ul>
<ul>
{% for nav_item in deployment.home.navigation %}
<li><a href="{{ nav_item.url }}">{{ nav_item.icon }} {{ nav_item.label }}</a></li>
{% endfor %}
</ul>
</nav>
<!-- Main Content -->
{% block content %}{% endblock %}
<!-- Footer -->
<footer class="container">
<small>
{{ deployment.home.footer.tagline }}
{% for link in deployment.home.footer.links %}
| <a href="{{ link.url }}">{{ link.label }}</a>
{% endfor %}
</small>
</footer>
{% block extra_js %}{% endblock %}
</body>
</html>
```
---
## 🏠 4. Home Index Template
**`app/templates/home/index.html`**
```html
{% extends "home/base_home.html" %}
{% block content %}
<!-- Hero Section -->
<section class="hero">
<div>
<h1>{{ deployment.home.hero.title }}</h1>
<p>{{ deployment.home.hero.subtitle }}</p>
<a href="{{ deployment.home.hero.cta_link }}" class="cta-button">
{{ deployment.home.hero.cta_text }}
</a>
<!-- Language Switcher -->
<div class="lang-switcher">
{% for lang_code in deployment.home.languages %}
<a href="?lang={{ lang_code }}">{{ lang_code.upper() }}</a>
{% endfor %}
</div>
</div>
</section>
<!-- Mission Section -->
<section id="explore" class="mission">
<h2>{{ deployment.home.mission.title }}</h2>
<p>{{ deployment.home.mission.description }}</p>
<div class="values-grid">
{% for value in deployment.home.mission.values %}
<div class="value-card">
<h3>{{ value.icon }} {{ value.title }}</h3>
<p>{{ value.text }}</p>
</div>
{% endfor %}
</div>
</section>
{% if deployment.home.sections.testimonials %}
<!-- Testimonials -->
<section class="testimonials">
<h2>💬 Stimmen aus dem Crumbforest</h2>
<div class="testimonial-slide" id="testimonial-container">
<p id="testimonial-text"></p>
<small id="testimonial-author"></small>
</div>
<div style="display: flex; justify-content: center; gap: 2rem; margin-top: 2rem;">
<button onclick="prevTestimonial()">⬅️</button>
<button onclick="nextTestimonial()">➡️</button>
</div>
</section>
{% endif %}
{% if deployment.home.sections.crew %}
<!-- Character Preview -->
<section class="container">
<h2 style="text-align: center;">🌟 Lerne die Crew kennen</h2>
<div style="text-align: center; margin: 2rem 0;">
<a href="/crew" role="button">Alle Characters entdecken</a>
</div>
</section>
{% endif %}
<!-- Access Section -->
<section class="container">
<h2 style="text-align: center;">🌐 Zugang zum Wald</h2>
<div style="display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap;">
{% if deployment.features.rag_system %}
<a href="/de/login" role="button">RAG System</a>
{% endif %}
{% if deployment.features.document_search %}
<a href="/de/login" role="button">Document Search</a>
{% endif %}
<a href="{{ deployment.base_url }}/hardware" role="button" class="outline">Hardware Info</a>
<a href="{{ deployment.base_url }}/software" role="button" class="outline">Software Info</a>
</div>
</section>
{% endblock %}
{% block extra_js %}
<script>
let testimonials = [];
let currentIndex = 0;
fetch('/static/data/testimonials.{{ lang }}.json')
.then(res => res.json())
.then(data => {
testimonials = data;
showTestimonial(0);
setInterval(nextTestimonial, 8000);
});
function showTestimonial(index) {
const t = testimonials[index];
document.getElementById('testimonial-text').textContent = `"${t.message}"`;
document.getElementById('testimonial-author').textContent = ` ${t.author}, ${t.role}`;
}
function nextTestimonial() {
currentIndex = (currentIndex + 1) % testimonials.length;
showTestimonial(currentIndex);
}
function prevTestimonial() {
currentIndex = (currentIndex - 1 + testimonials.length) % testimonials.length;
showTestimonial(currentIndex);
}
</script>
{% endblock %}
```
---
## 🦉 5. Crew Page Template
**`app/templates/home/crew.html`**
```html
{% extends "home/base_home.html" %}
{% block title %}Crew - {{ deployment.home.hero.title }}{% endblock %}
{% block content %}
<main class="container">
<hgroup>
<h1>🌟 Die Crumbforest Crew</h1>
<p>Lerne unsere Characters kennen!</p>
</hgroup>
<div class="crew-grid">
{% for character in characters %}
<div class="character-card" onclick="showCharacter('{{ character.id }}')">
<div class="icon">{{ character.icon }}</div>
<h3>{{ character.name }}</h3>
<p>{{ character.short }}</p>
</div>
<!-- Dialog for this character -->
<dialog id="dialog-{{ character.id }}">
<article>
<header>
<button aria-label="Close" rel="prev" onclick="closeCharacter('{{ character.id }}')"></button>
<h2>{{ character.icon }} {{ character.name }}</h2>
</header>
<p>{{ character.description }}</p>
</article>
</dialog>
{% endfor %}
</div>
</main>
{% endblock %}
{% block extra_js %}
<script>
function showCharacter(id) {
document.getElementById('dialog-' + id).showModal();
}
function closeCharacter(id) {
document.getElementById('dialog-' + id).close();
}
</script>
{% endblock %}
```
---
## 🔌 6. FastAPI Router
**`app/routers/home.py`**
```python
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
import json
router = APIRouter()
# Load deployment config
with open('compose/deployment_config.json') as f:
deployment_config = json.load(f)
# Load characters
with open('app/static/data/characters.json') as f:
characters_data = json.load(f)
@router.get("/", response_class=HTMLResponse)
async def home_index(req: Request, lang: str = "de"):
"""
Public home page - no auth required.
"""
req.session["lang"] = lang
return req.app.state.render(
req,
"home/index.html",
deployment=deployment_config,
lang=lang
)
@router.get("/about", response_class=HTMLResponse)
async def home_about(req: Request):
"""
About / Mission page.
"""
lang = req.session.get("lang", "de")
return req.app.state.render(
req,
"home/about.html",
deployment=deployment_config,
lang=lang
)
@router.get("/crew", response_class=HTMLResponse)
async def home_crew(req: Request):
"""
Crew / Characters page.
"""
lang = req.session.get("lang", "de")
return req.app.state.render(
req,
"home/crew.html",
deployment=deployment_config,
characters=characters_data,
lang=lang
)
@router.get("/hardware", response_class=HTMLResponse)
async def home_hardware(req: Request):
lang = req.session.get("lang", "de")
return req.app.state.render(
req,
"home/hardware.html",
deployment=deployment_config,
lang=lang
)
@router.get("/software", response_class=HTMLResponse)
async def home_software(req: Request):
lang = req.session.get("lang", "de")
return req.app.state.render(
req,
"home/software.html",
deployment=deployment_config,
lang=lang
)
```
---
## 📊 7. Implementation Steps
### Phase 1: Foundation (2-3 Stunden)
- [ ] `deployment_config.json` erstellen
- [ ] `home_forest.css` Pico Theme
- [ ] `base_home.html` Template
- [ ] `/routers/home.py` Router
### Phase 2: Content (2-3 Stunden)
- [ ] `index.html` Landing Page
- [ ] `crew.html` Character Page
- [ ] `characters.json` & `testimonials.*.json` Daten
- [ ] Branko.de Texte übernehmen
### Phase 3: Testing (1 Stunde)
- [ ] Multilingual testen (de/en/fr)
- [ ] Mobile Responsive prüfen
- [ ] Navigation Flow
- [ ] Character Modals
### Phase 4: Deployment (30 Min)
- [ ] Docker Rebuild
- [ ] Config per Container anpassbar
- [ ] Verify Home vs Admin Separation
---
## 🎨 Vorteile
**Pico CSS** - Konsistent mit dem Rest des Systems
**Deployment Config** - Neues Design = neue JSON
**Kein Auth** - Home ist öffentlich, Login für Features
**Multilingual** - de/en/fr Support
**Flexibel** - Jeder Container kann eigenes Design haben
**Characters** - Branko.de Crew integriert
---
## 🚀 Next Step?
Soll ich mit **Phase 1** starten?
- deployment_config.json
- home_forest.css (Pico-basiert)
- base_home.html
- /routers/home.py
Dann hast du ein lauffähiges Home Template! 🌲