UI redesign step 6 (admin lists + modals): Stitch styles

Card-rendering helpers (list-item, admin-card, prozentsaetze-list,
tarif-provision-controls) now match the Stitch design:
- Compact bordered cards with white surface and soft cool-grey
  outlines instead of the previous grey-on-grey blocks.
- Card headers get a primary-tinted surface band; provider sub-
  panels show a clear title bar plus a tight content area.
- Action buttons inside list rows use the same outlined / blue /
  red-outlined trio as the admin tables.

Admin form-section input controls keep their compact h-30ish style
and now also override the legacy global green CTAs to a Stitch
primary-blue pill so "Hinzufügen" buttons match the rest of the
chrome. The Tarifoptionen admin sub-page swaps its inline-styled
search bar and "Neue Tarifoption" CTA for the same Tailwind
components used across the new tabs.

Shared modal scaffolding:
- New `.app-modal` / `.app-modal-card` / `.app-modal-{header,body,
  form,field,checkbox,footer}` + `.app-modal-btn-{primary,secondary}`
  classes produce a consistent dialog shell.
- Userverwaltung, VO-Bearbeiten, Tarif-Bearbeiten and Schaltung
  löschen migrated to the shared markup. Each dialog gets a Material
  icon in the header, label-caps form fields, focus ring on inputs
  and a primary / outlined button pair in the footer.
- The Add-/Edit-Tarifoption dialog and the large Schaltung-bearbeiten
  dialog still use their legacy inline styles; those will be folded
  in once the rest stabilises.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kerimatilganandClaude Opus 4.7 committed 2026-05-15 20:25:05 +02:00
1 parent 7da168e213
commit 968cb183f2
1 file changed
+375 -97
+375 -97
View File
@@ -649,11 +649,113 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 10px; gap: 16px;
margin-bottom: 5px; padding: 10px 14px;
background: white; background: #ffffff;
border-radius: 4px; border: 1px solid #c3c6d7;
border: 1px solid #ddd; border-radius: 6px;
font-size: 13px;
color: #0b1c30;
}
.list-item strong {
color: #0b1c30;
font-weight: 600;
}
.list-item small {
color: #434655;
font-size: 12px;
}
.list-item button {
background: #ffffff;
color: #434655;
padding: 4px 10px;
border: 1px solid #c3c6d7;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
font-family: inherit;
}
.list-item button:hover {
background: #dce9ff;
color: #0b1c30;
border-color: #2563eb;
}
.list-item button.btn-danger {
background: #ffffff;
color: #ba1a1a;
border-color: #ffdad6;
}
.list-item button.btn-danger:hover {
background: #ffdad6;
border-color: #ba1a1a;
}
.list-item button.btn-success {
background: #2563eb;
color: #ffffff;
border-color: #2563eb;
}
.list-item button.btn-success:hover {
background: #004ac6;
}
/* Provider cards used by MA-Prozentsätze / MA-Provisionen / Provisionsregeln */
.admin-card {
background: #ffffff;
border: 1px solid #c3c6d7;
border-radius: 8px;
overflow: hidden;
}
.admin-card-header {
padding: 12px 16px;
background: #eff4ff;
border-bottom: 1px solid #c3c6d7;
}
.admin-card-header h4 {
margin: 0;
font-size: 14px;
font-weight: 600;
color: #0b1c30;
}
.admin-card-content {
padding: 12px 16px;
color: #0b1c30;
display: flex;
flex-direction: column;
gap: 8px;
}
.prozentsaetze-list {
display: flex;
flex-direction: column;
gap: 6px;
}
.tarif-provision-controls .form-row {
margin-bottom: 0;
align-items: center;
}
.tarif-provision-controls label {
color: #434655;
font-size: 12px;
font-weight: 500;
}
.tarif-provision-controls input[type=number] {
padding: 6px 10px;
border: 1px solid #c3c6d7;
border-radius: 6px;
font-size: 13px;
}
.tarif-provision-controls button.btn-success {
background: #2563eb;
color: #ffffff;
padding: 6px 12px;
border: none;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
}
.tarif-provision-controls button.btn-success:hover {
background: #004ac6;
} }
.table-container { .table-container {
@@ -754,6 +856,137 @@
Only keep the document-item rule at line ~574 — that one is Only keep the document-item rule at line ~574 — that one is
still used by other places (file upload preview list). */ still used by other places (file upload preview list). */
/* Shared app-modal scaffolding (Stitch style). Pair `display:none`
with `display:flex` in JS to toggle. */
.app-modal {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.app-modal-card {
background: #ffffff;
border: 1px solid rgba(195, 198, 215, 0.3);
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
width: 100%;
max-height: 85vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.app-modal-header {
padding: 16px 24px;
border-bottom: 1px solid #c3c6d7;
display: flex;
align-items: center;
justify-content: space-between;
}
.app-modal-header h3 {
font-size: 18px;
font-weight: 600;
color: #0b1c30;
}
.app-modal-body {
padding: 24px;
overflow-y: auto;
color: #0b1c30;
}
.app-modal-form {
display: flex;
flex-direction: column;
gap: 16px;
}
.app-modal-field {
display: flex;
flex-direction: column;
gap: 4px;
}
.app-modal-field > span {
font-size: 11px;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
color: #434655;
}
.app-modal-field input[type=text],
.app-modal-field input[type=number],
.app-modal-field input[type=password],
.app-modal-field input[type=date],
.app-modal-field select,
.app-modal-field textarea {
padding: 8px 12px;
border: 1px solid #c3c6d7;
border-radius: 8px;
font-size: 14px;
font-family: inherit;
color: #0b1c30;
background: #ffffff;
width: 100%;
}
.app-modal-field input:focus,
.app-modal-field select:focus,
.app-modal-field textarea:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
}
.app-modal-checkbox {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: #0b1c30;
cursor: pointer;
}
.app-modal-checkbox input[type=checkbox] {
width: 16px;
height: 16px;
accent-color: #2563eb;
cursor: pointer;
}
.app-modal-footer {
padding: 16px 24px;
border-top: 1px solid #c3c6d7;
background: rgba(239, 244, 255, 0.5);
display: flex;
justify-content: flex-end;
gap: 8px;
}
.app-modal-btn-primary {
background: #2563eb;
color: #ffffff;
padding: 8px 16px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
font-family: inherit;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.app-modal-btn-primary:hover {
background: #004ac6;
}
.app-modal-btn-secondary {
background: #ffffff;
color: #0b1c30;
padding: 8px 16px;
border: 1px solid #c3c6d7;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
font-family: inherit;
}
.app-modal-btn-secondary:hover {
background: #eff4ff;
}
@keyframes fadeIn { @keyframes fadeIn {
from { opacity: 0; } from { opacity: 0; }
to { opacity: 1; } to { opacity: 1; }
@@ -1425,25 +1658,32 @@
</div> </div>
<div class="admin-form-section"> <div class="admin-form-section">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;"> <div class="flex justify-between items-center">
<div> <div>
<h4>Tarifoptionen verwalten</h4> <h4 style="margin:0;">Tarifoptionen verwalten</h4>
<p style="margin: 0; color: #6c757d; font-size: 14px;">Erstellen und verwalten Sie Zusatzoptionen für Tarife</p> <p style="margin:4px 0 0 0; color:#434655; font-size:13px;">Erstellen und verwalten Sie Zusatzoptionen für Tarife</p>
</div> </div>
<button onclick="openAddTarifoptionModal()" style="background: #28a745; color: white; border: none; padding: 12px 24px; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500; display: flex; align-items: center; gap: 8px;"> <button onclick="openAddTarifoptionModal()"
<span style="font-size: 16px;">+</span> class="bg-primary-container text-on-primary hover:bg-primary transition-colors rounded-lg px-md py-sm text-body-sm flex items-center gap-xs shadow-sm">
<span class="material-symbols-outlined text-[18px]">add</span>
Neue Tarifoption Neue Tarifoption
</button> </button>
</div> </div>
</div> </div>
<div class="admin-content-section"> <div class="admin-content-section">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;"> <div class="flex justify-between items-center" style="margin-bottom:16px;">
<h4>Bestehende Tarifoptionen</h4> <h4 style="margin:0;">Bestehende Tarifoptionen</h4>
<div style="display: flex; gap: 15px; align-items: center;"> <div class="flex items-center gap-sm">
<input type="text" id="tarifoptionSearch" placeholder="Nach Tarif oder Option suchen..." style="padding: 8px 12px; border: 2px solid #e1e5e9; border-radius: 6px; width: 250px; font-size: 14px;" oninput="filterTarifoptionenAdmin()"> <input type="text" id="tarifoptionSearch" placeholder="Nach Tarif oder Option suchen…"
<button onclick="clearTarifoptionSearch()" style="background: #6c757d; color: white; border: none; padding: 8px 12px; border-radius: 6px; cursor: pointer; font-size: 13px;">Löschen</button> oninput="filterTarifoptionenAdmin()"
<div id="tarifoptionSearchCounter" style="font-size: 13px; color: #6c757d; min-width: 120px;"></div> class="bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm text-body-sm text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary"
style="width:250px;">
<button onclick="clearTarifoptionSearch()"
class="bg-surface-container-high text-on-surface border border-outline-variant hover:bg-surface-variant transition-colors rounded h-8 px-md text-body-sm">
Zurücksetzen
</button>
<div id="tarifoptionSearchCounter" class="text-body-sm text-on-surface-variant" style="min-width:120px;"></div>
</div> </div>
</div> </div>
<div class="table-container"> <div class="table-container">
@@ -1594,60 +1834,78 @@
</div> </div>
<!-- Modal: Benutzer anlegen / bearbeiten --> <!-- Modal: Benutzer anlegen / bearbeiten -->
<div id="userModal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.5); z-index:1000;"> <div id="userModal" class="app-modal" style="display:none;">
<div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); background:white; border-radius:8px; width:90%; max-width:500px; padding:24px; box-shadow:0 10px 30px rgba(0,0,0,0.2);"> <div class="app-modal-card" style="max-width:480px;">
<h3 id="userModalTitle" style="margin-top:0;">Neuer Benutzer</h3> <div class="app-modal-header">
<input type="hidden" id="userModalUuid"> <div class="flex items-center gap-sm">
<div class="form-group" style="margin-bottom:14px;"> <span class="material-symbols-outlined text-primary">person</span>
<label for="userModalUsername">Username</label> <h3 id="userModalTitle" style="margin:0;">Neuer Benutzer</h3>
<input type="text" id="userModalUsername" style="width:100%; padding:8px; border:1px solid #ccc; border-radius:4px;"> </div>
<button onclick="closeUserModal()" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
<span class="material-symbols-outlined">close</span>
</button>
</div> </div>
<div class="form-group" style="margin-bottom:14px;"> <div class="app-modal-body app-modal-form">
<label for="userModalDisplay">Anzeigename</label> <input type="hidden" id="userModalUuid">
<input type="text" id="userModalDisplay" style="width:100%; padding:8px; border:1px solid #ccc; border-radius:4px;"> <label class="app-modal-field">
</div> <span>Username</span>
<div class="form-group" style="margin-bottom:14px;"> <input type="text" id="userModalUsername">
<label for="userModalPassword">Passwort <span id="userModalPasswordHint" style="color:#666; font-size:12px;">(min. 8 Zeichen)</span></label> </label>
<input type="password" id="userModalPassword" autocomplete="new-password" style="width:100%; padding:8px; border:1px solid #ccc; border-radius:4px;"> <label class="app-modal-field">
<small id="userModalPasswordEditHint" style="color:#666; display:none;">Leer lassen, um Passwort unverändert zu lassen</small> <span>Anzeigename</span>
</div> <input type="text" id="userModalDisplay">
<div class="form-group" style="margin-bottom:18px;"> </label>
<label style="display:flex; align-items:center; gap:8px; cursor:pointer;"> <label class="app-modal-field">
<input type="checkbox" id="userModalIsAdmin"> Administrator <span>Passwort <span id="userModalPasswordHint" style="font-weight:400; letter-spacing:normal; text-transform:none; font-size:12px;">(min. 8 Zeichen)</span></span>
<input type="password" id="userModalPassword" autocomplete="new-password">
<small id="userModalPasswordEditHint" style="display:none; color:#434655; font-size:12px;">Leer lassen, um Passwort unverändert zu lassen</small>
</label>
<label class="app-modal-checkbox">
<input type="checkbox" id="userModalIsAdmin">
<span>Administrator</span>
</label> </label>
</div> </div>
<div style="text-align:right;"> <div class="app-modal-footer">
<button type="button" onclick="closeUserModal()" style="margin-right:8px;">Abbrechen</button> <button type="button" onclick="closeUserModal()" class="app-modal-btn-secondary">Abbrechen</button>
<button type="button" class="btn-success" onclick="saveUserFromModal()">Speichern</button> <button type="button" onclick="saveUserFromModal()" class="app-modal-btn-primary">Speichern</button>
</div> </div>
</div> </div>
</div> </div>
<!-- Modal: VO bearbeiten --> <!-- Modal: VO bearbeiten -->
<div id="voEditModal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.5); z-index:1000;"> <div id="voEditModal" class="app-modal" style="display:none;">
<div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); background:white; border-radius:8px; width:90%; max-width:480px; padding:24px; box-shadow:0 10px 30px rgba(0,0,0,0.2);"> <div class="app-modal-card" style="max-width:480px;">
<h3 style="margin-top:0;">VO bearbeiten</h3> <div class="app-modal-header">
<input type="hidden" id="voEditId"> <div class="flex items-center gap-sm">
<div class="form-group" style="margin-bottom:12px;"> <span class="material-symbols-outlined text-primary">badge</span>
<label>Anbieter</label> <h3 style="margin:0;">VO bearbeiten</h3>
<input type="text" id="voEditAnbieter" readonly style="width:100%; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f5f5f5;"> </div>
<button onclick="closeVoEditModal()" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
<span class="material-symbols-outlined">close</span>
</button>
</div> </div>
<div class="form-group" style="margin-bottom:12px;"> <div class="app-modal-body app-modal-form">
<label for="voEditNummer">VO-Nummer</label> <input type="hidden" id="voEditId">
<input type="text" id="voEditNummer" style="width:100%; padding:8px; border:1px solid #ccc; border-radius:4px;"> <label class="app-modal-field">
</div> <span>Anbieter</span>
<div class="form-group" style="margin-bottom:12px;"> <input type="text" id="voEditAnbieter" readonly style="background:#eff4ff; color:#434655;">
<label for="voEditBezeichnung">Bezeichnung</label> </label>
<input type="text" id="voEditBezeichnung" placeholder="z.B. Fachhandel (leer = keine)" style="width:100%; padding:8px; border:1px solid #ccc; border-radius:4px;"> <label class="app-modal-field">
</div> <span>VO-Nummer</span>
<div class="form-group" style="margin-bottom:18px;"> <input type="text" id="voEditNummer">
<label style="display:flex; align-items:center; gap:8px; cursor:pointer;"> </label>
<input type="checkbox" id="voEditAktiv"> Aktiv <label class="app-modal-field">
<span>Bezeichnung</span>
<input type="text" id="voEditBezeichnung" placeholder="z.B. Fachhandel (leer = keine)">
</label>
<label class="app-modal-checkbox">
<input type="checkbox" id="voEditAktiv">
<span>Aktiv</span>
</label> </label>
</div> </div>
<div style="text-align:right;"> <div class="app-modal-footer">
<button type="button" onclick="closeVoEditModal()" style="margin-right:8px;">Abbrechen</button> <button type="button" onclick="closeVoEditModal()" class="app-modal-btn-secondary">Abbrechen</button>
<button type="button" class="btn-success" onclick="saveVoFromModal()">Speichern</button> <button type="button" onclick="saveVoFromModal()" class="app-modal-btn-primary">Speichern</button>
</div> </div>
</div> </div>
</div> </div>
@@ -1744,35 +2002,45 @@
</div> </div>
<!-- Edit Tariff Modal --> <!-- Edit Tariff Modal -->
<div id="editTariffModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000;"> <div id="editTariffModal" class="app-modal" style="display:none;">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 30px; border-radius: 8px; width: 600px; max-width: 90%; max-height: 90vh; overflow-y: auto;"> <div class="app-modal-card" style="max-width:600px;">
<h3>Tarif bearbeiten</h3> <div class="app-modal-header">
<form id="editTariffForm"> <div class="flex items-center gap-sm">
<input type="hidden" id="editTariffId"> <span class="material-symbols-outlined text-primary">receipt_long</span>
<div class="form-group"> <h3 style="margin:0;">Tarif bearbeiten</h3>
<label>Tarif-Name:</label>
<input type="text" id="editTariffName" required>
</div> </div>
<div class="form-group"> <button onclick="closeModal('editTariffModal')" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
<label>VO:</label> <span class="material-symbols-outlined">close</span>
<select id="editTariffVo"> </button>
<option value="">VO wählen...</option> </div>
</select> <form id="editTariffForm" class="contents">
</div> <div class="app-modal-body app-modal-form">
<div class="form-group"> <input type="hidden" id="editTariffId">
<label>Shop-Provision (€):</label> <label class="app-modal-field">
<input type="number" id="editTariffProvisionBetrag" step="0.01" min="0" placeholder="Betrag in Euro"> <span>Tarif-Name</span>
</div> <input type="text" id="editTariffName" required>
<div class="form-group"> </label>
<label>Tarifoptionen (Anbieter-weit):</label> <label class="app-modal-field">
<div id="editTariffOptionenContainer" style="border:1px solid #ddd; border-radius:6px; padding:10px; max-height:200px; overflow-y:auto; background:#fafafa;"> <span>VO</span>
<small style="color:#666;">Keine Tarifoptionen für diesen Anbieter vorhanden</small> <select id="editTariffVo">
<option value="">VO wählen…</option>
</select>
</label>
<label class="app-modal-field">
<span>Shop-Provision (€)</span>
<input type="number" id="editTariffProvisionBetrag" step="0.01" min="0" placeholder="Betrag in Euro">
</label>
<div class="app-modal-field">
<span>Tarifoptionen (Anbieter-weit)</span>
<div id="editTariffOptionenContainer"
style="border:1px solid #c3c6d7; border-radius:8px; padding:12px; max-height:200px; overflow-y:auto; background:#eff4ff; display:flex; flex-direction:column; gap:6px;">
<small style="color:#434655;">Keine Tarifoptionen für diesen Anbieter vorhanden</small>
</div>
</div> </div>
</div> </div>
<div class="app-modal-footer">
<div style="display: flex; gap: 10px; margin-top: 20px;"> <button type="button" onclick="closeModal('editTariffModal')" class="app-modal-btn-secondary">Abbrechen</button>
<button type="submit" class="btn-success">Speichern</button> <button type="submit" class="app-modal-btn-primary">Speichern</button>
<button type="button" onclick="closeModal('editTariffModal')">Abbrechen</button>
</div> </div>
</form> </form>
</div> </div>
@@ -1867,20 +2135,30 @@
</div> </div>
<!-- Delete Schaltung Modal --> <!-- Delete Schaltung Modal -->
<div id="deleteSchaltungModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000;"> <div id="deleteSchaltungModal" class="app-modal" style="display:none;">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 30px; border-radius: 8px; width: 500px; max-width: 90%;"> <div class="app-modal-card" style="max-width:500px;">
<h3>Schaltung löschen</h3> <div class="app-modal-header">
<p>Sind Sie sicher, dass Sie diese Schaltung löschen möchten?</p> <div class="flex items-center gap-sm">
<p><strong id="deleteSchaltungInfo"></strong></p> <span class="material-symbols-outlined text-error">warning</span>
<div class="form-group" style="margin-top: 20px;"> <h3 style="margin:0;">Schaltung löschen</h3>
<label>Grund für die Löschung <span class="required">*</span></label> </div>
<textarea id="deleteReason" rows="3" placeholder="Bitte geben Sie den Grund für die Löschung ein..." required style="resize: vertical;"></textarea> <button onclick="closeModal('deleteSchaltungModal')" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
<span class="material-symbols-outlined">close</span>
</button>
</div> </div>
<div style="display: flex; gap: 10px; margin-top: 20px;"> <div class="app-modal-body app-modal-form">
<button onclick="confirmDeleteSchaltung()" class="btn-danger">Löschen</button> <p style="color:#434655;">Sind Sie sicher, dass Sie diese Schaltung löschen möchten?</p>
<button onclick="closeModal('deleteSchaltungModal')">Abbrechen</button> <div style="padding:10px 14px; background:#eff4ff; border:1px solid #c3c6d7; border-radius:8px; color:#0b1c30; font-weight:600;" id="deleteSchaltungInfo"></div>
<label class="app-modal-field">
<span>Grund für die Löschung *</span>
<textarea id="deleteReason" rows="3" placeholder="Bitte geben Sie den Grund für die Löschung ein…" required style="resize: vertical;"></textarea>
</label>
<input type="hidden" id="deleteSchaltungId">
</div>
<div class="app-modal-footer">
<button type="button" onclick="closeModal('deleteSchaltungModal')" class="app-modal-btn-secondary">Abbrechen</button>
<button type="button" onclick="confirmDeleteSchaltung()" class="app-modal-btn-primary" style="background:#ba1a1a;">Löschen</button>
</div> </div>
<input type="hidden" id="deleteSchaltungId">
</div> </div>
</div> </div>