hugin/static/css-framework/.opencode/skills/references/components.md
2026-10-27 08:33:21 +01:00

14 KiB
Raw Blame History

Komponenten-Referenz

Vollständige Dokumentation aller opt-in Klassen aus components.css.


Navigation

Top Navigation (.topnav)

Sticky Navigationsleiste mit Branding, Links und optionalem User-Dropdown.

<nav class="topnav">
  <div class="topnav-inner">
    <a class="topnav-brand" href="/">Brand</a>

    <ul class="topnav-links">
      <li><a href="/" class="active">Dashboard</a></li>
      <li>
        <button data-action="nav-dropdown">
          Mehr <svg class="nav-chevron"><!-- Chevron SVG --></svg>
        </button>
        <div class="topnav-dropdown">
          <a href="/settings">Einstellungen</a>
          <a href="/profile">Profil</a>
        </div>
      </li>
    </ul>

    <div class="topnav-end">
      <!-- Buttons, User-Dropdown, Theme-Toggle -->
    </div>

    <button class="topnav-burger" aria-label="Menü öffnen">☰</button>
  </div>
  <div class="topnav-mobile">
    <!-- Mobile Links -->
  </div>
</nav>

Modifier: .topnav-static — nicht sticky

Sidebar (.sidebar)

Feste Seitenleiste für App-Layouts. Wird mit .with-sidebar kombiniert.

<!-- Vor dem with-sidebar-Container -->
<div class="mobile-topbar">
  <button id="sidebar-toggle" aria-label="Menü öffnen">☰</button>
  <span>App Name</span>
</div>
<div id="sidebar-backdrop" class="sidebar-backdrop"></div>

<div class="with-sidebar">
  <aside class="sidebar">
    <div class="sidebar-header">
      <a href="/" class="sidebar-brand">Brand</a>
    </div>

    <nav class="sidebar-nav">
      <div class="sidebar-section">Hauptmenü</div>
      <a href="/" class="active">
        <svg><!-- Icon --></svg>
        Dashboard
        <span class="nav-count">4</span>
      </a>

      <details class="sidebar-group">
        <summary><svg><!-- Icon --></svg> Gruppe</summary>
        <div class="sidebar-group-items">
          <a href="/unterseite">Unterseite</a>
        </div>
      </details>
    </nav>

    <div class="sidebar-footer">
      <a href="/profil" class="sidebar-user">
        <div class="avatar avatar-sm">AM</div>
        <div class="sidebar-user-info">
          <div class="sidebar-user-name">Anna Müller</div>
          <div class="sidebar-user-role">Admin</div>
        </div>
      </a>
    </div>
  </aside>

  <main class="stack stack-lg">
    <!-- Seiteninhalt -->
  </main>
</div>
<!-- Einfach -->
<footer class="footer">
  <div class="footer-inner">
    <a class="footer-brand" href="/">Brand</a>
    <ul class="footer-links">
      <li><a href="/impressum">Impressum</a></li>
      <li><a href="/datenschutz">Datenschutz</a></li>
    </ul>
    <p class="footer-copy">© 2025 Acme GmbH</p>
  </div>
</footer>

<!-- Mehrspaltig -->
<footer class="footer footer-full">
  <div class="footer-inner">
    <div class="footer-col">
      <p class="footer-col-title">Produkt</p>
      <a href="/features">Features</a>
      <a href="/pricing">Preise</a>
    </div>
    <div class="footer-col">
      <p class="footer-col-title">Rechtliches</p>
      <a href="/impressum">Impressum</a>
    </div>
  </div>
  <div class="footer-bottom">
    <span>© 2025 Acme GmbH</span>
    <ul class="footer-social">
      <li><a href="https://github.com/..."><svg><!-- GitHub Icon --></svg></a></li>
    </ul>
  </div>
</footer>

Breadcrumbs (.breadcrumbs)

<nav class="breadcrumbs" aria-label="Breadcrumb">
  <ol>
    <li><a href="/dashboard">Dashboard</a></li>
    <li><a href="/projekte">Projekte</a></li>
    <li><span aria-current="page">Einstellungen</span></li>
  </ol>
</nav>

Horizontaler Navigationspfad. Auf schmalen Viewports horizontal scrollbar.


Buttons (.btn)

Alle Buttons benötigen .btn als Basisklasse plus eine Variante.

<!-- Varianten -->
<button class="btn btn-primary">Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-ghost">Ghost</button>
<button class="btn btn-danger">Danger</button>
<button class="btn btn-success">Success</button>

<!-- Größen (Standardgröße ist keine Größenklasse = medium) -->
<button class="btn btn-primary btn-xs">XSmall</button>
<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary btn-lg">Large</button>
<button class="btn btn-primary btn-xl">XLarge</button>

<!-- Modifiers -->
<button class="btn btn-primary btn-full">Volle Breite</button>
<button class="btn btn-ghost btn-icon"><svg><!-- Icon --></svg></button>

<!-- Als Link -->
<a href="/ziel" class="btn btn-primary">Link-Button</a>

<!-- Disabled -->
<button class="btn btn-primary" disabled>Gesperrt</button>

<!-- Button Group -->
<div class="button-group" role="group">
  <button class="btn btn-secondary">Liste</button>
  <button class="btn btn-secondary">Board</button>
  <button class="btn btn-secondary">Kalender</button>
</div>

<!-- Segmented Control (Radio-Basis, kein JS) -->
<div class="segmented" role="radiogroup">
  <label class="segmented-option" for="r-tag">
    <input class="segmented-input" type="radio" name="range" id="r-tag">
    <span class="segmented-button">Tag</span>
  </label>
  <label class="segmented-option" for="r-woche">
    <input class="segmented-input" type="radio" name="range" id="r-woche" checked>
    <span class="segmented-button">Woche</span>
  </label>
  <label class="segmented-option" for="r-monat">
    <input class="segmented-input" type="radio" name="range" id="r-monat">
    <span class="segmented-button">Monat</span>
  </label>
</div>

Badges (.badge)

<span class="badge badge-default">Standard</span>
<span class="badge badge-primary">Primär</span>
<span class="badge badge-success">Erfolg</span>
<span class="badge badge-warning">Warnung</span>
<span class="badge badge-danger">Fehler</span>
<span class="badge badge-info">Info</span>
<span class="badge badge-outline">Outline</span>

<!-- Mit Dot-Indikator -->
<span class="badge badge-success badge-dot">Live</span>

Cards (.card)

<div class="card">
  <div class="card-header">
    <h3>Titel</h3>
    <span class="badge badge-success">Aktiv</span>
  </div>
  <div class="card-body">
    Inhalt der Karte
  </div>
  <div class="card-footer">
    <button class="btn btn-ghost btn-sm">Abbrechen</button>
    <button class="btn btn-primary btn-sm">Aktion</button>
  </div>
</div>

Varianten: .card-flat, .card-raised, .card-ghost Hover-Effekt: .card.card-hover

Image Card:

<div class="card">
  <div class="card-media">
    <img src="..." alt="...">
  </div>
  <div class="card-body">
    <h3>Titel</h3>
    <p>Beschreibung</p>
  </div>
</div>

Formulare

Basis-Eingabeelemente (input, select, textarea) werden classless gestylt. Opt-in Klassen für Gruppierung und Zustände:

<div class="form-group">
  <label for="email">E-Mail</label>
  <input type="email" id="email" name="email">
  <span class="form-hint">Wird für Login genutzt.</span>
</div>

<!-- Fehler-State -->
<div class="form-group">
  <label for="pwd">Passwort</label>
  <input type="password" id="pwd" class="error">
  <span class="form-error">Mindestens 8 Zeichen.</span>
</div>

<!-- Mehrere Felder nebeneinander -->
<div class="form-row">
  <div class="form-group">
    <label for="vorname">Vorname</label>
    <input type="text" id="vorname">
  </div>
  <div class="form-group">
    <label for="nachname">Nachname</label>
    <input type="text" id="nachname">
  </div>
</div>

<!-- Input mit Prefix/Suffix -->
<div class="input-group">
  <span class="input-group-prefix">https://</span>
  <input type="text" placeholder="beispiel.de">
</div>
<div class="input-group">
  <input type="text" placeholder="Betrag">
  <span class="input-group-suffix">EUR</span>
</div>

Tabellen

Classless gestylt — kein Wrapper nötig für einfache Tabellen:

<table>
  <thead>
    <tr><th>Name</th><th>Status</th><th>Datum</th></tr>
  </thead>
  <tbody>
    <tr><td>Anna Müller</td><td><span class="badge badge-success">Aktiv</span></td><td>2025-01-15</td></tr>
  </tbody>
</table>

<!-- Mit Rahmen und horizontalem Scroll (z.B. auf Mobile) -->
<div class="table-wrap">
  <table>...</table>
</div>

<!-- Modifier -->
<table class="table-striped">...</table>
<table class="table-compact">...</table>

Alerts

<div class="alert alert-info">
  <svg class="alert-icon"><!-- Icon --></svg>
  <div class="alert-content">
    <p class="alert-title">Hinweis</p>
    <p>Deine Änderungen werden gespeichert.</p>
  </div>
</div>

Varianten: alert-info, alert-success, alert-warning, alert-danger


Modals

<!-- Struktur -->
<div class="modal-backdrop" id="mein-modal"
     data-action="modal-backdrop">
  <div class="modal">
    <div class="modal-header">
      <h3>Titel</h3>
      <button class="btn btn-ghost btn-icon btn-sm"
              data-action="modal-close" data-target="mein-modal">✕</button>
    </div>
    <div class="modal-body">Inhalt</div>
    <div class="modal-footer">
      <button class="btn btn-ghost" data-action="modal-close" data-target="mein-modal">Abbrechen</button>
      <button class="btn btn-primary">Bestätigen</button>
    </div>
  </div>
</div>

<button data-action="modal-open" data-target="mein-modal">Modal öffnen</button>

Größen: .modal-sm, .modal-lg, .modal-xl


Tabs

<div class="tabs">
  <ul class="tab-list" role="tablist">
    <li>
      <button class="active" role="tab"
              data-action="tab" data-target="panel-1">Tab 1</button>
    </li>
    <li>
      <button role="tab"
              data-action="tab" data-target="panel-2">Tab 2</button>
    </li>
  </ul>
  <div id="panel-1" class="tab-panel active">Inhalt Tab 1</div>
  <div id="panel-2" class="tab-panel">Inhalt Tab 2</div>
</div>

Dropdowns

<div class="dropdown" id="dd-aktionen">
  <button class="btn btn-secondary" data-action="dropdown" data-target="dd-aktionen">
    Aktionen
  </button>
  <div class="dropdown-menu">
    <div class="dropdown-label">Aktionen</div>
    <button class="dropdown-item">Bearbeiten</button>
    <div class="dropdown-divider"></div>
    <button class="dropdown-item danger">Löschen</button>
  </div>
</div>

Positionierung: .dropdown-menu-left, .dropdown-menu-top Breite: .dropdown-wide

Spezielle Item-Typen:

<!-- Mit Beschreibung -->
<button class="dropdown-item dropdown-item-rich">
  <div class="dropdown-item-title">Projekt</div>
  <div class="dropdown-item-desc">Neue Projektmappe erstellen</div>
</button>

<!-- Checkbox/Filter -->
<button class="dropdown-item dropdown-item-check checked"
        data-action="toggle-class" data-class="checked">
  Aktiv
</button>

<!-- User-Header -->
<div class="dropdown-header">
  <div class="avatar">AM</div>
  <div>
    <div class="dropdown-header-name">Anna Müller</div>
    <div class="dropdown-header-sub">anna@beispiel.de</div>
  </div>
</div>

Pagination

<ul class="pagination">
  <li class="disabled"><a>←</a></li>
  <li><a class="active" href="?page=1">1</a></li>
  <li><a href="?page=2">2</a></li>
  <li><a href="?page=3">3</a></li>
  <li><a href="?page=2">→</a></li>
</ul>

Feedback & Status-Komponenten

Spinner

<div class="spinner spinner-sm"></div>
<div class="spinner"></div>          <!-- default -->
<div class="spinner spinner-lg"></div>

Fortschrittsbalken

<div class="progress">
  <div class="progress-bar" data-progress="75"></div>
</div>
<div class="progress">
  <div class="progress-bar success" data-progress="100"></div>
</div>

Skeleton (Lade-Platzhalter)

<div class="skeleton skeleton-line is-short"></div>
<div class="skeleton skeleton-title"></div>
<div class="skeleton skeleton-block"></div>

KPI / Stat

<div class="stat">
  <span class="stat-label">Umsatz</span>
  <span class="stat-value">€ 48.291</span>
  <span class="stat-change up">↑ +12.4%</span>
</div>

<!-- Trend-basierte Einfärbung des Hauptwerts -->
<div class="stat" data-trend="positive">
  <span class="stat-label">Saldo</span>
  <span class="stat-value">+ € 1.240</span>
</div>
<div class="stat" data-trend="negative">
  <span class="stat-label">Saldo</span>
  <span class="stat-value">− € 320</span>
</div>

Avatar

<div class="avatar">AM</div>
<div class="avatar avatar-sm">AM</div>
<div class="avatar avatar-lg"><img src="..." alt="Profilbild"></div>

<!-- Avatar Group -->
<div class="avatar-group">
  <div class="avatar avatar-sm">AM</div>
  <div class="avatar avatar-sm">BS</div>
  <div class="avatar avatar-sm">CK</div>
</div>

Empty State

<div class="empty">
  <svg class="empty-icon"><!-- Illustration/Icon --></svg>
  <p class="empty-title">Keine Einträge</p>
  <p class="empty-description">Erstelle deinen ersten Eintrag, um loszulegen.</p>
  <button class="btn btn-primary btn-sm">Erstellen</button>
</div>

Toasts

<div class="toast-container" id="toast-container"></div>

<!-- Aus einem Button heraus -->
<button class="btn" data-action="toast" data-message="Gespeichert!" data-type="success">Speichern</button>

<!-- Nach einer HTMX-Antwort: Server setzt HX-Trigger, eigenes Skript (als Datei) reagiert -->
<!-- Response-Header: HX-Trigger: {"toast": {"message": "Gespeichert!", "type": "success"}} -->
<!-- static/js/app.js: document.body.addEventListener('toast', e => showToast(e.detail.message, e.detail.type)); -->

Divider mit Label

<div class="divider">oder</div>

Filter-Leiste

<!-- Flex-Row, auf Mobile gestapelt (< 40rem) -->
<div class="filter-bar">
  <div class="form-group">
    <label>Monat</label>
    <input type="month">
  </div>
  <div class="form-group">
    <label>Typ</label>
    <select>
      <option>Alle</option>
      <option>Einnahme</option>
    </select>
  </div>
  <button class="btn btn-secondary btn-sm">Filtern</button>
</div>