Initial commit: Open-Source Projektplattform für Schleswig-Holstein

- Flask-App mit SQLite, Projekt-Einreichung und Bewerbungen
- Suche und Filter nach Kategorie
- Modernes UI mit Bootstrap 5 und Custom CSS
- 6 Demo-Projekte via seed_demo_data.py
- Docker und docker-compose Support

Made-with: Cursor
This commit is contained in:
2026-03-05 19:57:42 +01:00
commit 21e4d86fef
15 changed files with 968 additions and 0 deletions

46
templates/base.html Normal file
View File

@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Offene Innovation SH{% endblock %} | DigitalHub.SH</title>
<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=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<nav class="navbar navbar-expand-lg sticky-top">
<div class="container">
<a class="navbar-brand" href="{{ url_for('index') }}">Offene Innovation SH</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navCollapse" aria-controls="navCollapse" aria-expanded="false" aria-label="Navigation umschalten">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navCollapse">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('index') }}">Projekte</a>
</li>
<li class="nav-item">
<a class="nav-link btn-nav-cta" href="{{ url_for('projekt_einreichen') }}">Projekt einreichen</a>
</li>
</ul>
</div>
</div>
</nav>
<main class="main-content">
{% block content %}{% endblock %}
</main>
<footer class="footer">
<div class="container">
<p class="mb-0">Landesprogramm Offene Innovation Schleswig-Holstein</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
{% block scripts %}{% endblock %}
</body>
</html>

View File

@@ -0,0 +1,16 @@
{% extends "base.html" %}
{% block title %}Bewerbung eingegangen{% endblock %}
{% block content %}
<section class="success-section">
<div class="container">
<div class="success-card">
<div class="success-icon"></div>
<h1 class="success-title">Bewerbung erfolgreich eingereicht</h1>
<p class="success-text">Vielen Dank! Die zuständige Behörde wird sich in Kürze bei Ihnen melden.</p>
<a href="{{ url_for('index') }}" class="btn btn-primary btn-lg">Weitere Projekte ansehen</a>
</div>
</div>
</section>
{% endblock %}

63
templates/index.html Normal file
View File

@@ -0,0 +1,63 @@
{% extends "base.html" %}
{% block title %}Projekte durchsuchen{% endblock %}
{% block content %}
<section class="hero">
<div class="container">
<h1 class="hero-title">Open-Source Projekte für die Verwaltung</h1>
<p class="hero-subtitle">Finden Sie passende Projekte und bewerben Sie sich als Mitarbeitende oder reichen Sie Ihr eigenes Projekt ein.</p>
</div>
</section>
<section class="search-section">
<div class="container">
<form method="get" action="{{ url_for('index') }}" class="search-form">
<div class="row g-3 align-items-end">
<div class="col-md-6">
<label for="suche" class="form-label">Suche</label>
<input type="text" id="suche" name="suche" class="form-control form-control-lg" placeholder="Titel oder Beschreibung durchsuchen..." value="{{ suche }}">
</div>
<div class="col-md-4">
<label for="kategorie" class="form-label">Kategorie</label>
<select id="kategorie" name="kategorie" class="form-select form-select-lg">
<option value="">Alle Kategorien</option>
{% for k in kategorien %}
<option value="{{ k }}" {% if aktuelle_kategorie == k %}selected{% endif %}>{{ k }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary btn-lg w-100">Suchen</button>
</div>
</div>
</form>
</div>
</section>
<section class="projects-section">
<div class="container">
<h2 class="section-title">Verfügbare Projekte</h2>
{% if projekte %}
<div class="project-grid">
{% for projekt in projekte %}
<article class="project-card">
<span class="project-card-badge">{{ projekt.kategorie }}</span>
<h3 class="project-card-title">{{ projekt.titel }}</h3>
<p class="project-card-desc">{{ projekt.beschreibung[:180] }}{% if projekt.beschreibung|length > 180 %}…{% endif %}</p>
<div class="project-card-meta">
<span class="project-card-behoerde">{{ projekt.behoerde }}</span>
<span class="project-card-status status-{{ projekt.status }}">{{ projekt.status }}</span>
</div>
<a href="{{ url_for('projekt_detail', id=projekt.id) }}" class="project-card-link">Details & Bewerben</a>
</article>
{% endfor %}
</div>
{% else %}
<div class="empty-state">
<p>Keine Projekte gefunden. Versuchen Sie andere Suchbegriffe oder <a href="{{ url_for('projekt_einreichen') }}">reichen Sie ein Projekt ein</a>.</p>
</div>
{% endif %}
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,54 @@
{% extends "base.html" %}
{% block title %}{{ projekt.titel }}{% endblock %}
{% block content %}
<section class="detail-hero">
<div class="container">
<a href="{{ url_for('index') }}" class="back-link">&larr; Zurück zur Übersicht</a>
<span class="detail-badge">{{ projekt.kategorie }}</span>
<h1 class="detail-title">{{ projekt.titel }}</h1>
<div class="detail-meta">
<span class="detail-behoerde">{{ projekt.behoerde }}</span>
<span class="detail-status status-{{ projekt.status }}">{{ projekt.status }}</span>
</div>
</div>
</section>
<section class="detail-content">
<div class="container">
<div class="row">
<div class="col-lg-8">
<div class="detail-card">
<h2>Projektbeschreibung</h2>
<p class="detail-description">{{ projekt.beschreibung }}</p>
</div>
</div>
<div class="col-lg-4">
<div class="apply-card">
<h3>Als Mitarbeitende bewerben</h3>
<form method="post" action="{{ url_for('bewerbung_abgeben') }}">
<input type="hidden" name="projekt_id" value="{{ projekt.id }}">
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" id="name" name="name" class="form-control" required placeholder="Ihr Name">
</div>
<div class="mb-3">
<label for="email" class="form-label">E-Mail</label>
<input type="email" id="email" name="email" class="form-control" required placeholder="ihre@email.de">
</div>
<div class="mb-4">
<label for="nachricht" class="form-label">Nachricht (optional)</label>
<textarea id="nachricht" name="nachricht" class="form-control" rows="4" placeholder="Kurze Vorstellung und Motivation..."></textarea>
</div>
<button type="submit" class="btn btn-primary btn-lg w-100">Bewerbung absenden</button>
</form>
</div>
<div class="contact-info">
<p><strong>Kontakt:</strong> <a href="mailto:{{ projekt.kontakt_email }}">{{ projekt.kontakt_email }}</a></p>
</div>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,47 @@
{% extends "base.html" %}
{% block title %}Projekt einreichen{% endblock %}
{% block content %}
<section class="form-hero">
<div class="container">
<h1 class="form-hero-title">Projekt einreichen</h1>
<p class="form-hero-subtitle">Beschreiben Sie Ihre Idee für eine Open-Source-Lösung. Die Fachjury prüft eingereichte Projekte im Rahmen des Call for Concepts.</p>
</div>
</section>
<section class="form-section">
<div class="container">
<div class="form-card">
<form method="post" action="{{ url_for('projekt_einreichen') }}">
<div class="mb-4">
<label for="titel" class="form-label">Projekttitel</label>
<input type="text" id="titel" name="titel" class="form-control form-control-lg" required placeholder="Kurzer, prägnanter Titel">
</div>
<div class="mb-4">
<label for="beschreibung" class="form-label">Projektbeschreibung</label>
<textarea id="beschreibung" name="beschreibung" class="form-control" rows="6" required placeholder="Beschreiben Sie das Problem, die geplante Lösung und den Nutzen..."></textarea>
</div>
<div class="mb-4">
<label for="kategorie" class="form-label">Kategorie</label>
<select id="kategorie" name="kategorie" class="form-select form-select-lg" required>
<option value="">Bitte wählen</option>
{% for k in kategorien %}
<option value="{{ k }}">{{ k }}</option>
{% endfor %}
</select>
</div>
<div class="mb-4">
<label for="behoerde" class="form-label">Behörde / Organisation</label>
<input type="text" id="behoerde" name="behoerde" class="form-control form-control-lg" required placeholder="z.B. Stadt Kiel, Kreis Rendsburg-Eckernförde">
</div>
<div class="mb-4">
<label for="kontakt_email" class="form-label">Kontakt-E-Mail</label>
<input type="email" id="kontakt_email" name="kontakt_email" class="form-control form-control-lg" required placeholder="kontakt@behoerde.de">
</div>
<button type="submit" class="btn btn-primary btn-lg">Projekt einreichen</button>
</form>
</div>
</div>
</section>
{% endblock %}