🌿 Füllhorn UI Components

Solarpunk Design System

touch_app Buttons

Button Varianten

.btn-primary (Fern) | .btn-secondary (Outline) | .btn-accent (Amber) | .btn-ghost

Danger & Disabled

Icon Buttons

label Chips

Unit Chips (einfacher Toggle)

g kg ml l Stück Packung
.chip-unit – Active: Fern BG, White Text

Category Chips (mit Ring-Dot, dynamische Farben)

Gemüse Obst Fleisch Fisch Milchprodukte Backwaren
.chip-category[data-color="..."] – Farbe aus DB, Ring-Dot zeigt Selection

Item Type Chips (Artikel-Typ)

Frisch eingekauft TK-Ware gekauft Selbst eingemacht

Quick Filter Chips (für Dashboard)

Kühlschrank Gefriertruhe Keller

edit Inputs

Entnommene anzeigen

inventory_2 Item Cards (Unified)

Standard Card (Vorrat-Ansicht)

Mangold
500 g · Selbst eingefr.
place Gefriertruhe Gemüse
MHD
30.11.25
Joghurt
4 Stk · Frisch
place Kühlschrank Milchprodukte
Ablauf
in 5 Tagen
Milch
1 L · Frisch
place Kühlschrank Milchprodukte
Ablauf
Morgen

Card mit Action-Button (Dashboard-Ansicht)

Milch
1 L · Frisch
place Kühlschrank Milchprodukte
Ablauf
in 2 Tagen
Hackfleisch (TK)
500 g · TK gekauft
place Gefriertruhe Fleisch
Ablauf
Abgelaufen

Item-Type Badges

Frisch TK gekauft Eingefr. Selbst eingefr. Eingemacht
.type-badge.fresh (Leaf) | .type-badge.frozen (Info-Blau) | .type-badge.homemade (Terracotta)
Card-Struktur: Zeile 1: Name | Zeile 2: Menge · Type-Badge | Zeile 3: 📍Lagerort + Kategorie-Tag
Modifiers: .status-warning | .status-critical | .with-action (für Dashboard)

dashboard Dashboard Components

Alert Section (mit Unified Cards)

Bald abgelaufen (3)

Milch
1 L · Frisch
place Kühlschrank Milchprodukte
Ablauf
in 2 Tagen
Joghurt
1 Stk · Frisch
place Kühlschrank Milchprodukte
Ablauf
Morgen
Dashboard verwendet dieselbe .item-card Komponente mit .with-action Modifier

Statistics Card

bar_chart

Vorrats-Statistik

24
Artikel
6
Ablauf
3
Entn.

Summary Box (Wizard)

Zusammenfassung:
Mangold • 500.0 g • Selbst eingefroren • Gemüse Datum: 30.11.2025 • Eingefroren: 30.11.2025

settings Admin Components

drag_indicator Gemüse
drag_indicator Obst
drag_indicator Fleisch

expand_less Bottom Sheet

Mangold
scale
Menge
500 g
place
Lagerort
Gefriertruhe
event
Haltbar bis
30.11.2025
notes
Notizen
blanchiert

smartphone Fullscreen Demo

Bald abgelaufen (2)

Milch
1 L · Frisch
place Kühlschrank Milch
Ablauf
in 2 Tagen
Joghurt
1 Stk · Frisch
place Kühlschrank Milch
Ablauf
Morgen
bar_chart

Vorrats-Statistik

8
Artikel
2
Ablauf
0
Entn.
label

Schnellfilter

Kühlschrank Keller Gefriertruhe

code CSS Integration

Tailwind Config (tailwind.config.js)

module.exports = {
  theme: {
    extend: {
      colors: {
        // Solarpunk Primary - Greens
        'fern': {
          DEFAULT: '#4A7C59',
          dark: '#3D6A4A',
          light: '#5A8C69',
        },
        'moss': '#5C7F5C',
        'leaf': '#7CB342',
        'sage': {
          DEFAULT: '#9CAF88',
          light: '#B8C9A8',
        },
        // Solarpunk Secondary - Earth & Gold
        'amber': {
          DEFAULT: '#E6A832',
          dark: '#D49A28',
          light: '#F0BC52',
        },
        'honey': '#DAA520',
        'terracotta': '#C17F59',
        // Solarpunk Neutrals
        'cream': '#FAF7F0',
        'oat': '#F5F0E6',
        'parchment': '#EDE8DB',
        'stone': {
          DEFAULT: '#A39E93',
          dark: '#7D796F',
        },
        // Status (override defaults)
        'status-ok': '#7CB342',
        'status-warning': '#E6A832',
        'status-critical': '#E07A5F',
      },
      fontFamily: {
        'display': ['Cormorant Garamond', 'Georgia', 'serif'],
        'body': ['Nunito', 'system-ui', 'sans-serif'],
      },
      borderRadius: {
        'sp-sm': '8px',
        'sp-md': '12px',
        'sp-lg': '16px',
        'sp-xl': '20px',
      },
    },
  },
}

NiceGUI Custom CSS (static/solarpunk.css)

/* ========================================
   FÜLLHORN SOLARPUNK THEME
   NiceGUI / Quasar Override
   ======================================== */

@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600;700&family=Nunito:wght@400;500;600;700&display=swap');

:root {
  /* Primary - Greens */
  --fern: #4A7C59;
  --fern-dark: #3D6A4A;
  --moss: #5C7F5C;
  --leaf: #7CB342;
  --sage: #9CAF88;
  --sage-light: #B8C9A8;
  
  /* Secondary - Earth & Gold */
  --amber: #E6A832;
  --honey: #DAA520;
  --terracotta: #C17F59;
  
  /* Neutrals */
  --cream: #FAF7F0;
  --oat: #F5F0E6;
  --parchment: #EDE8DB;
  --stone: #A39E93;
  --charcoal: #3D3D3D;
  
  /* Status */
  --status-ok: #7CB342;
  --status-warning: #E6A832;
  --status-critical: #E07A5F;
  
  /* Quasar Primary Override */
  --q-primary: #4A7C59;
  --q-secondary: #E6A832;
  --q-positive: #7CB342;
  --q-negative: #E07A5F;
  --q-warning: #E6A832;
}

/* Base */
body {
  font-family: 'Nunito', system-ui, sans-serif;
  background: var(--cream) !important;
}

/* Typography */
.text-h4, .text-h5, .text-h6 {
  font-family: 'Cormorant Garamond', Georgia, serif !important;
  color: var(--fern) !important;
}

/* Cards */
.q-card {
  background: white !important;
  border-radius: 12px !important;
  box-shadow: 0 2px 8px rgba(74, 124, 89, 0.1) !important;
}

/* Buttons */
.q-btn--standard.bg-primary {
  background: var(--fern) !important;
}
.q-btn--standard.bg-primary:hover {
  background: var(--fern-dark) !important;
}
.q-btn--outline.text-primary {
  color: var(--fern) !important;
  border-color: var(--fern) !important;
}
.q-btn--standard.bg-secondary,
.q-btn--standard.bg-positive {
  background: var(--amber) !important;
}
.q-btn--standard.bg-negative {
  background: var(--status-critical) !important;
}

/* Inputs */
.q-field--outlined .q-field__control {
  border-radius: 12px !important;
}
.q-field--outlined .q-field__control:before {
  border-color: var(--sage-light) !important;
}
.q-field--outlined.q-field--focused .q-field__control:after {
  border-color: var(--fern) !important;
}

/* Bottom Navigation */
.q-footer, .bottom-nav {
  background: white !important;
  border-top: 1px solid var(--sage-light) !important;
}
.q-tab--active {
  color: var(--fern) !important;
}

/* Item Cards - Status Border */
.item-card {
  border-left: 4px solid var(--status-ok);
  border-radius: 12px;
  background: white;
}
.item-card.status-warning {
  border-left-color: var(--status-warning);
}
.item-card.status-critical {
  border-left-color: var(--status-critical);
}

/* Chips Base */
.solarpunk-chip {
  min-height: 44px;
  padding: 10px 20px;
  border-radius: 9999px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s ease;
}

/* Unit Chips */
.chip-unit {
  background: var(--oat);
  color: var(--charcoal);
  border: 2px solid var(--sage-light);
}
.chip-unit:hover {
  border-color: var(--sage);
}
.chip-unit.active {
  background: var(--fern);
  color: white;
  border-color: var(--fern);
}

/* Ring-Dot for Category/Type Chips */
.ring-dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid currentColor;
  background: white;
  flex-shrink: 0;
}
.ring-dot.filled {
  background: radial-gradient(circle, currentColor 35%, white 35%);
}
.chip-category.active .ring-dot,
.chip-type.active .ring-dot {
  border-color: white;
  background: radial-gradient(circle, white 35%, transparent 35%);
}

Farb-Mapping: Alt → Solarpunk

Bisherig (Tailwind) Solarpunk Hex
primary / blue-* fern #4A7C59
secondary amber #E6A832
green-500 (OK) leaf / status-ok #7CB342
orange-500 / yellow-500 status-warning #E6A832
red-500 status-critical #E07A5F
gray-100 / gray-200 cream / oat #FAF7F0
gray-500 / gray-600 stone #A39E93
border-gray-200 sage-light #B8C9A8

integration_instructions NiceGUI Beispiele

Button (Python)

# Primary Button
ui.button('Speichern', icon='save').classes(
    'bg-fern text-white rounded-sp-md'
)

# Secondary Button
ui.button('Zurück', icon='arrow_back').props(
    'flat no-caps'
).classes('text-fern')

# Accent/CTA Button
ui.button('Weiter', icon='arrow_forward').classes(
    'bg-amber text-white rounded-sp-md'
)

# Danger Button
ui.button('Löschen', icon='delete').classes(
    'bg-status-critical text-white'
)

Chip Components (Python)

# Unit Chip (simplified)
def unit_chip(label: str, selected: bool = False):
    classes = 'chip-unit active' if selected else 'chip-unit'
    return ui.element('span').classes(classes).text(label)

# Category Chip (with ring-dot)
def category_chip(name: str, color: str, selected: bool = False):
    with ui.element('span').classes(
        f'solarpunk-chip chip-category {"active" if selected else ""}'
    ).style(f'--chip-color: {color}'):
        ui.element('span').classes(
            f'ring-dot {"filled" if selected else ""}'
        ).style(f'border-color: {color}')
        ui.label(name)

Item Card (Python)

def item_card(item: Item):
    # Status based on days until expiry
    status = 'status-critical' if item.days_left < 3 else \
             'status-warning' if item.days_left < 7 else ''
    
    with ui.card().classes(f'item-card {status} w-full mb-2'):
        with ui.row().classes('items-start gap-3'):
            # Status dot
            ui.element('span').classes(
                'w-3 h-3 rounded-full mt-1'
            ).style(f'background: var(--{status or "status-ok"})')
            
            # Content
            with ui.column().classes('flex-1 gap-1'):
                ui.label(item.name).classes('font-semibold')
                ui.label(f'{item.quantity} {item.unit}').classes(
                    'text-sm text-stone'
                )
                with ui.row().classes('items-center gap-1'):
                    ui.icon('place', size='16px').classes('text-terracotta')
                    ui.label(item.location).classes('text-xs text-stone')
            
            # Expiry
            with ui.column().classes('text-right'):
                ui.label('Ablauf:').classes('text-xs text-stone')
                ui.label(item.expiry_text).classes(
                    f'font-semibold text-{status or "status-ok"}'
                )