Refactor SenderEditorPage for modernized UI design

Replaced inline styles with reusable CSS classes to improve maintainability, readability, and scalability. Updated the layout and styling of key components, including the action bar, title and message inputs, PDF metadata display, and buttons. Introduced a `DxAccordion` for envelope settings and redesigned the empty state and save result dialog. Added dynamic styling using CSS variables and centralized styles in `envelope-viewer.css`. Removed redundant inline styles and improved overall UI consistency.
This commit is contained in:
2026-10-02 14:59:43 +02:00
parent ae3264253d
commit 54d16eb3b8
2 changed files with 511 additions and 173 deletions

View File

@@ -34,64 +34,52 @@
@* ── Action Bar ── *@
<div class="envelope-action-bar">
<div class="envelope-action-bar__inner"
style="flex-direction: row; align-items: center; padding: 0.35rem 1.5rem; gap: 0.75rem;">
<div class="envelope-action-bar__inner sender-editor-action-inner">
@* Left: Title + meta inputs + receivers *@
<div style="flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: stretch; gap: 0.5rem;">
<div class="sender-editor-main-column">
@* ── Title & Message inputs ── *@
<div style="display: flex; align-items: flex-start; gap: 0.5rem; flex-wrap: wrap;">
<div class="sender-editor-meta-row">
@* Titel *@
<div style="display: flex; flex-direction: column; gap: 0.2rem; flex: 1 1 180px; min-width: 140px;">
<label style="font-size: 0.65rem; font-weight: 600; color: #6b7280;
text-transform: uppercase; letter-spacing: 0.05em;">
@L("Title", "Titel") <span style="color:#dc2626;">*</span>
<div class="sender-editor-input-field sender-editor-input-field--title">
<label class="sender-editor-label">
@L("Title", "Titel") <span class="sender-editor-required-asterisk">*</span>
</label>
<input type="text"
value="@_envelopeTitle"
@oninput="e => _envelopeTitle = e.Value?.ToString() ?? string.Empty"
placeholder='@L("SenderEditor_Title_Placeholder", "z.B. Arbeitsvertrag 2025")'
maxlength="120"
style="font-size: 0.78rem; font-weight: 500; color: #1f2937;
border: 1px solid #d1d5db; border-radius: 5px;
padding: 0.3rem 0.55rem; outline: none; width: 100%;
background: #fff;
@(_titleTouched && string.IsNullOrWhiteSpace(_envelopeTitle) ? "border-color:#dc2626;" : "")" />
class="sender-editor-text-input @(_titleTouched && string.IsNullOrWhiteSpace(_envelopeTitle) ? "sender-editor-text-input--invalid" : string.Empty)" />
@if (_titleTouched && string.IsNullOrWhiteSpace(_envelopeTitle))
{
<span style="font-size:0.6rem;color:#dc2626;">@L("RequiredField", "Pflichtfeld")</span>
<span class="sender-editor-required-text">@L("RequiredField", "Pflichtfeld")</span>
}
</div>
@* Nachricht *@
<div style="display: flex; flex-direction: column; gap: 0.2rem; flex: 2 1 260px; min-width: 180px;">
<label style="font-size: 0.65rem; font-weight: 600; color: #6b7280;
text-transform: uppercase; letter-spacing: 0.05em;">
@L("Message", "Nachricht") <span style="color:#6b7280;font-weight:400;">(@L("Optional", "optional"))</span>
<div class="sender-editor-input-field sender-editor-input-field--message">
<label class="sender-editor-label">
@L("Message", "Nachricht") <span class="sender-editor-optional">(@L("Optional", "optional"))</span>
</label>
<input type="text"
value="@_envelopeMessage"
@oninput="e => _envelopeMessage = e.Value?.ToString() ?? string.Empty"
placeholder='@L("SenderEditor_Message_Placeholder", "Bitte unterzeichnen Sie das beigefügte Dokument.")'
maxlength="500"
style="font-size: 0.78rem; color: #1f2937;
border: 1px solid #d1d5db; border-radius: 5px;
padding: 0.3rem 0.55rem; outline: none; width: 100%;
background: #fff;" />
class="sender-editor-text-input" />
</div>
@* PDF filename badge *@
@if (_pdfLoaded)
{
<div style="display:flex;align-items:flex-end;gap:0.4rem;padding-bottom:0.05rem;flex-shrink:0;">
<span style="font-size: 0.7rem; color: #6b7280;">@_fileName</span>
<div class="sender-editor-file-meta">
<span class="sender-editor-file-name">@_fileName</span>
@if (_signatureFields.Count > 0)
{
<span style="display: inline-flex; align-items: center; padding: 0.125rem 0.4rem;
background: #ede9fe; border-radius: 0.25rem; color: #6d28d9;
font-weight: 500; font-size: 0.7rem; white-space: nowrap;">
<span class="sender-editor-signature-count">
@_signatureFields.Count @L("SenderEditor_SignatureField", "Signaturfeld")@(_signatureFields.Count != 1 ? "er" : "")
</span>
}
@@ -99,106 +87,109 @@
}
</div>
<details style="border:1px solid #dbe5ef;border-radius:8px;background:#f9fbfd;">
<summary style="cursor:pointer;list-style:none;display:flex;align-items:center;justify-content:space-between;padding:0.55rem 0.7rem;font-size:0.74rem;font-weight:700;color:#1f2937;text-transform:uppercase;letter-spacing:0.04em;">
<span>@L("SenderEditor_EnvelopeSettings", "Envelope-Einstellungen")</span>
<span style="font-size:0.66rem;color:#64748b;font-weight:600;">@L("SenderEditor_AdvancedOptional", "Erweitert")</span>
</summary>
<div class="sender-settings-shell">
<DxAccordion ExpandMode="AccordionExpandMode.SingleOrNone" CssClass="sender-settings-accordion">
<Items>
<DxAccordionItem Text='@L("SenderEditor_EnvelopeSettings", "Envelope-Einstellungen")' Expanded="true">
<ContentTemplate>
<div class="sender-settings-body">
<div class="sender-settings-chip">@L("SenderEditor_AdvancedOptional", "Erweitert")</div>
<div style="padding:0 0.7rem 0.7rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:0.45rem;">
<div style="display:flex;flex-direction:column;gap:0.2rem;">
<label style="font-size:0.65rem;font-weight:600;color:#64748b;">@L("EnvelopeType", "Umschlagtyp")</label>
<select value="@(_selectedEnvelopeTypeId?.ToString() ?? string.Empty)"
@onchange="OnEnvelopeTypeChanged"
style="font-size:0.78rem;border:1px solid #d1d5db;border-radius:5px;padding:0.3rem 0.45rem;background:#fff;">
<option value="">@L("SenderEditor_SelectTemplate", "Vorlage auswählen")</option>
@foreach (var type in _envelopeTypes)
{
<option value="@type.Id">@type.Title</option>
}
</select>
</div>
<div class="sender-settings-grid">
<div class="sender-settings-field">
<label class="sender-settings-label">@L("EnvelopeType", "Umschlagtyp")</label>
<select value="@(_selectedEnvelopeTypeId?.ToString() ?? string.Empty)"
@onchange="OnEnvelopeTypeChanged"
class="sender-settings-select">
<option value="">@L("SenderEditor_SelectTemplate", "Vorlage auswählen")</option>
@foreach (var type in _envelopeTypes)
{
<option value="@type.Id">@type.Title</option>
}
</select>
</div>
<div style="display:flex;flex-direction:column;gap:0.2rem;">
<label style="font-size:0.65rem;font-weight:600;color:#64748b;">@L("Language", "Sprache")</label>
<select @bind="_language"
style="font-size:0.78rem;border:1px solid #d1d5db;border-radius:5px;padding:0.3rem 0.45rem;background:#fff;">
<option value="de">Deutsch (de)</option>
<option value="en">English (en)</option>
<option value="de-DE">Deutsch (de-DE)</option>
<option value="en-US">English (en-US)</option>
</select>
</div>
<div class="sender-settings-field">
<label class="sender-settings-label">@L("Language", "Sprache")</label>
<select @bind="_language" class="sender-settings-select">
<option value="de">Deutsch (de)</option>
<option value="en">English (en)</option>
<option value="de-DE">Deutsch (de-DE)</option>
<option value="en-US">English (en-US)</option>
</select>
</div>
<div style="display:flex;flex-direction:column;gap:0.2rem;">
<label style="font-size:0.65rem;font-weight:600;color:#64748b;">@L("CertificationType", "Zertifizierung")</label>
<select @bind="_certificationType"
style="font-size:0.78rem;border:1px solid #d1d5db;border-radius:5px;padding:0.3rem 0.45rem;background:#fff;">
<option value="1">@L("AdvancedElectronicSignature", "Advanced Electronic Signature")</option>
<option value="2">@L("ElectronicSignature", "Electronic Signature")</option>
<option value="3">@L("QualifiedSignature", "Qualified Signature")</option>
</select>
</div>
<div class="sender-settings-field">
<label class="sender-settings-label">@L("CertificationType", "Zertifizierung")</label>
<select @bind="_certificationType" class="sender-settings-select">
<option value="1">@L("AdvancedElectronicSignature", "Advanced Electronic Signature")</option>
<option value="2">@L("ElectronicSignature", "Electronic Signature")</option>
<option value="3">@L("QualifiedSignature", "Qualified Signature")</option>
</select>
</div>
<div style="display:flex;flex-direction:column;gap:0.3rem;justify-content:flex-end;padding-bottom:0.25rem;">
<label style="display:flex;align-items:center;gap:0.45rem;font-size:0.74rem;color:#1f2937;">
<input type="checkbox" checked="@_tfaEnabled" @onchange="OnTfaChanged" />
@L("TFAEnabled", "2FA aktiviert")
</label>
<label style="display:flex;align-items:center;gap:0.45rem;font-size:0.74rem;color:#1f2937;">
<input type="checkbox" checked="@_useAccessCode" @onchange="OnUseAccessCodeChanged" disabled="@_tfaEnabled" />
@L("UseAccessCode", "Zugriffscode verwenden")
</label>
</div>
<div class="sender-settings-toggles">
<label class="sender-settings-toggle">
<input type="checkbox" checked="@_tfaEnabled" @onchange="OnTfaChanged" />
@L("TFAEnabled", "2FA aktiviert")
</label>
<label class="sender-settings-toggle">
<input type="checkbox" checked="@_useAccessCode" @onchange="OnUseAccessCodeChanged" disabled="@_tfaEnabled" />
@L("UseAccessCode", "Zugriffscode verwenden")
</label>
</div>
<div style="display:flex;flex-direction:column;gap:0.2rem;">
<label style="font-size:0.65rem;font-weight:600;color:#64748b;">@L("FinalEmailToCreator", "Finale E-Mail an Ersteller")</label>
<select @bind="_finalEmailToCreator"
style="font-size:0.78rem;border:1px solid #d1d5db;border-radius:5px;padding:0.3rem 0.45rem;background:#fff;">
<option value="0">@L("No", "Nein")</option>
<option value="1">@L("Yes", "Ja")</option>
<option value="2">@L("YesWithAttachment", "Ja, mit Anhang")</option>
</select>
</div>
<div class="sender-settings-field">
<label class="sender-settings-label">@L("FinalEmailToCreator", "Finale E-Mail an Ersteller")</label>
<select @bind="_finalEmailToCreator" class="sender-settings-select">
<option value="0">@L("No", "Nein")</option>
<option value="1">@L("Yes", "Ja")</option>
<option value="2">@L("YesWithAttachment", "Ja, mit Anhang")</option>
</select>
</div>
<div style="display:flex;flex-direction:column;gap:0.2rem;">
<label style="font-size:0.65rem;font-weight:600;color:#64748b;">@L("FinalEmailToReceivers", "Finale E-Mail an Empfänger")</label>
<select @bind="_finalEmailToReceivers"
style="font-size:0.78rem;border:1px solid #d1d5db;border-radius:5px;padding:0.3rem 0.45rem;background:#fff;">
<option value="0">@L("No", "Nein")</option>
<option value="1">@L("Yes", "Ja")</option>
<option value="2">@L("YesWithAttachment", "Ja, mit Anhang")</option>
</select>
</div>
<div class="sender-settings-field">
<label class="sender-settings-label">@L("FinalEmailToReceivers", "Finale E-Mail an Empfänger")</label>
<select @bind="_finalEmailToReceivers" class="sender-settings-select">
<option value="0">@L("No", "Nein")</option>
<option value="1">@L("Yes", "Ja")</option>
<option value="2">@L("YesWithAttachment", "Ja, mit Anhang")</option>
</select>
</div>
<div style="display:flex;flex-direction:column;gap:0.3rem;justify-content:flex-end;padding-bottom:0.25rem;">
<label style="display:flex;align-items:center;gap:0.45rem;font-size:0.74rem;color:#1f2937;">
<input type="checkbox" checked="@_sendReminderEmails" @onchange="OnSendReminderEmailsChanged" />
@L("SendReminderEmails", "Erinnerungs-E-Mails senden")
</label>
</div>
<div class="sender-settings-toggles sender-settings-toggles--single">
<label class="sender-settings-toggle">
<input type="checkbox" checked="@_sendReminderEmails" @onchange="OnSendReminderEmailsChanged" />
@L("SendReminderEmails", "Erinnerungs-E-Mails senden")
</label>
</div>
<div style="display:flex;flex-direction:column;gap:0.2rem;">
<label style="font-size:0.65rem;font-weight:600;color:#64748b;">@L("FirstReminderDays", "Erste Erinnerung (Tage)")</label>
<InputNumber @bind-Value="_firstReminderDays" class="form-control form-control-sm" disabled="@(!_sendReminderEmails)" />
</div>
<div class="sender-settings-field">
<label class="sender-settings-label">@L("FirstReminderDays", "Erste Erinnerung (Tage)")</label>
<InputNumber @bind-Value="_firstReminderDays" class="form-control form-control-sm sender-settings-number" disabled="@(!_sendReminderEmails)" />
</div>
<div style="display:flex;flex-direction:column;gap:0.2rem;">
<label style="font-size:0.65rem;font-weight:600;color:#64748b;">@L("ReminderIntervalDays", "Erinnerungsintervall (Tage)")</label>
<InputNumber @bind-Value="_reminderIntervalDays" class="form-control form-control-sm" disabled="@(!_sendReminderEmails)" />
</div>
<div class="sender-settings-field">
<label class="sender-settings-label">@L("ReminderIntervalDays", "Erinnerungsintervall (Tage)")</label>
<InputNumber @bind-Value="_reminderIntervalDays" class="form-control form-control-sm sender-settings-number" disabled="@(!_sendReminderEmails)" />
</div>
<div style="display:flex;flex-direction:column;gap:0.2rem;">
<label style="font-size:0.65rem;font-weight:600;color:#64748b;">@L("ExpiresWhenDays", "Läuft ab nach (Tage)")</label>
<InputNumber @bind-Value="_expiresWhenDays" class="form-control form-control-sm" />
</div>
<div class="sender-settings-field">
<label class="sender-settings-label">@L("ExpiresWhenDays", "Läuft ab nach (Tage)")</label>
<InputNumber @bind-Value="_expiresWhenDays" class="form-control form-control-sm sender-settings-number" />
</div>
<div style="display:flex;flex-direction:column;gap:0.2rem;">
<label style="font-size:0.65rem;font-weight:600;color:#64748b;">@L("ExpiresWarningWhenDays", "Ablaufwarnung (Tage)")</label>
<InputNumber @bind-Value="_expiresWarningWhenDays" class="form-control form-control-sm" />
</div>
</div>
</details>
<div class="sender-settings-field">
<label class="sender-settings-label">@L("ExpiresWarningWhenDays", "Ablaufwarnung (Tage)")</label>
<InputNumber @bind-Value="_expiresWarningWhenDays" class="form-control form-control-sm sender-settings-number" />
</div>
</div>
</div>
</ContentTemplate>
</DxAccordionItem>
</Items>
</DxAccordion>
</div>
<div class="sender-receivers-panel">
<div class="sender-receivers-panel__header">
@@ -228,8 +219,7 @@
<div class="sender-receivers-list">
@foreach (var receiver in _receivers)
{
<div class="sender-receiver-chip"
style="border-left: 3px solid @receiver.Color;">
<div class="sender-receiver-chip" style="--receiver-color:@receiver.Color;">
<div class="sender-receiver-chip__body">
<div class="sender-receiver-chip__name">@receiver.FullName</div>
<div class="sender-receiver-chip__email">@receiver.Email</div>
@@ -239,11 +229,11 @@
}
</div>
<button class="pdf-toolbar__btn pdf-toolbar__btn--signature-change sender-toolbar-action-btn sender-toolbar-action-btn--compact
@(_pendingReceiverForPlacement?.Id == receiver.Id ? "pdf-toolbar__btn--signature-change-active" : "")"
@onclick="() => ActivatePlacementForReceiver(receiver)"
style="@(_pendingReceiverForPlacement?.Id == receiver.Id ? $"background:{receiver.Color};color:#fff;border-color:{receiver.Color};" : $"color:{receiver.Color};border-color:{receiver.Color};")"
title='@L("SenderEditor_PlaceSignatureField", "Signaturfeld platzieren")'>
<button class="pdf-toolbar__btn pdf-toolbar__btn--signature-change sender-toolbar-action-btn sender-toolbar-action-btn--compact sender-receiver-chip__place-btn
@(_pendingReceiverForPlacement?.Id == receiver.Id ? "sender-receiver-chip__place-btn--active" : "sender-receiver-chip__place-btn--idle")"
@onclick="() => ActivatePlacementForReceiver(receiver)"
style="--receiver-color:@receiver.Color;"
title='@L("SenderEditor_PlaceSignatureField", "Signaturfeld platzieren")'>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10z" />
</svg>
@@ -257,7 +247,7 @@
</div>
@* Right: Buttons *@
<div style="display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0;">
<div class="sender-editor-actions">
<button class="pdf-toolbar__btn pdf-toolbar__btn--reset"
@onclick="Cancel"
@@ -266,14 +256,12 @@
</button>
@* PDF Upload *@
<label class="pdf-toolbar__btn"
<label class="pdf-toolbar__btn sender-editor-upload-btn @((!_isPageReady || _isPdfUploadInProgress) ? "sender-editor-upload-btn--disabled" : string.Empty)"
title='@L("UploadPdf", "PDF hochladen")'
style="cursor: @((_isPageReady && !_isPdfUploadInProgress) ? "pointer" : "not-allowed");
opacity:@((_isPageReady && !_isPdfUploadInProgress) ? "1" : "0.6");
display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.3rem 0.75rem; font-size: 0.75rem; font-weight: 500;">
>
@if (_isPdfUploadInProgress)
{
<span class="spinner-border spinner-border-sm" role="status" style="width:0.8rem;height:0.8rem;border-width:2px;"></span>
<span class="spinner-border spinner-border-sm sender-editor-spinner" role="status"></span>
}
else
{
@@ -301,7 +289,7 @@
<InputFile OnChange="OnPdfFileSelectedAsync"
accept=".pdf"
disabled="@(!_isPageReady || _isPdfUploadInProgress)"
style="display: none;" />
class="sender-editor-hidden-input" />
</label>
@if (_pdfLoaded && _signatureFields.Count > 0)
@@ -322,8 +310,7 @@
title='@L("Save", "Speichern")'>
@if (_isSaving)
{
<span class="spinner-border spinner-border-sm me-1" role="status"
style="width:0.8rem;height:0.8rem;border-width:2px;"></span>
<span class="spinner-border spinner-border-sm me-1 sender-editor-spinner" role="status"></span>
}
else
{
@@ -338,12 +325,10 @@
<button class="pdf-toolbar__btn pdf-toolbar__btn--success"
@onclick="SendAsync"
disabled="@_isSaving"
title='@L("SendEnvelope", "Umschlag senden")'
style="background: linear-gradient(135deg,#059669,#047857); color:#fff; border-radius:6px; padding:0.3rem 0.75rem; font-size:0.75rem; font-weight:600; border:none;">
title='@L("SendEnvelope", "Umschlag senden")'>
@if (_isSaving)
{
<span class="spinner-border spinner-border-sm me-1" role="status"
style="width:0.8rem;height:0.8rem;border-width:2px;"></span>
<span class="spinner-border spinner-border-sm me-1 sender-editor-spinner" role="status"></span>
}
else
{
@@ -359,11 +344,9 @@
@* Placement mode hint bar *@
@if (_pendingReceiverForPlacement is not null)
{
<div style="background: @_pendingReceiverForPlacement.Color; color: white; font-size: 0.75rem; font-weight: 500;
padding: 0.3rem 1.5rem; text-align: center; letter-spacing: 0.01em;">
<div class="sender-editor-placement-hint" style="--placement-color:@_pendingReceiverForPlacement.Color;">
📌 @L("SenderEditor_ClickDocumentFor", "Klicken Sie auf die Stelle im Dokument für") <strong>@_pendingReceiverForPlacement.FullName</strong>.
&nbsp;<button @onclick="CancelPlacement"
style="background:none;border:none;color:white;cursor:pointer;font-size:0.75rem;text-decoration:underline;padding:0;">
&nbsp;<button @onclick="CancelPlacement" class="sender-editor-placement-cancel">
@L("Cancel", "Abbrechen")
</button>
</div>
@@ -371,30 +354,25 @@
</div>
@* ── Content ── *@
<div class="envelope-content" style="padding: 0; overflow: hidden;">
<div class="envelope-content sender-editor-content">
@if (!_pdfLoaded)
{
@* Empty state *@
<div class="d-flex justify-content-center align-items-center h-100">
<div class="text-center" style="max-width: 420px;">
<div style="width: 72px; height: 72px; background: rgba(255,255,255,0.15);
border-radius: 50%; display: flex; align-items: center;
justify-content: center; margin: 0 auto 1.25rem;">
<div class="text-center sender-editor-empty-state">
<div class="sender-editor-empty-state__icon-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" fill="white" viewBox="0 0 16 16">
<path d="M14 4.5V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h5.5L14 4.5zm-3 0A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4.5h-2z" />
</svg>
</div>
<h5 class="text-white mb-2">@L("SenderEditor_NoDocumentLoaded", "Kein Dokument geladen")</h5>
<p class="text-white mb-4" style="opacity: 0.75; font-size: 0.85rem;">
<p class="text-white mb-4 sender-editor-empty-state__description">
@L("SenderEditor_UploadPdfToPlaceFields", "Laden Sie eine PDF-Datei hoch, um Signaturfelder zu platzieren.")
</p>
<label class="btn btn-light btn-sm"
style="cursor: @((_isPageReady && !_isPdfUploadInProgress) ? "pointer" : "not-allowed");
opacity:@((_isPageReady && !_isPdfUploadInProgress) ? "1" : "0.8");
font-weight: 500;">
<label class="btn btn-light btn-sm sender-editor-empty-state__upload @((!_isPageReady || _isPdfUploadInProgress) ? "sender-editor-empty-state__upload--disabled" : string.Empty)">
@if (_isPdfUploadInProgress)
{
<span class="spinner-border spinner-border-sm me-1" role="status" style="width:0.8rem;height:0.8rem;border-width:2px;"></span>
<span class="spinner-border spinner-border-sm me-1 sender-editor-spinner" role="status"></span>
}
else
{
@@ -422,7 +400,7 @@
<InputFile OnChange="OnPdfFileSelectedAsync"
accept=".pdf"
disabled="@(!_isPageReady || _isPdfUploadInProgress)"
style="display: none;" />
class="sender-editor-hidden-input" />
</label>
</div>
</div>
@@ -546,18 +524,17 @@
<BodyContentTemplate>
@if (_saveErrorMessage is null)
{
<div style="display:flex;align-items:flex-start;gap:1rem;padding:0.5rem 0;">
<div style="flex-shrink:0;width:40px;height:40px;background:#d1fae5;border-radius:50%;
display:flex;align-items:center;justify-content:center;">
<div class="sender-editor-save-result">
<div class="sender-editor-save-result__icon sender-editor-save-result__icon--success">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#065f46" viewBox="0 0 16 16">
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z" />
</svg>
</div>
<div>
<p style="margin:0 0 0.4rem;font-weight:600;color:#1f2937;font-size:0.95rem;">
<p class="sender-editor-save-result__title">
@_saveSuccessTitle
</p>
<p style="margin:0;color:#6b7280;font-size:0.85rem;line-height:1.5;">
<p class="sender-editor-save-result__message">
@_saveSuccessBody
</p>
</div>
@@ -565,19 +542,18 @@
}
else
{
<div style="display:flex;align-items:flex-start;gap:1rem;padding:0.5rem 0;">
<div style="flex-shrink:0;width:40px;height:40px;background:#fee2e2;border-radius:50%;
display:flex;align-items:center;justify-content:center;">
<div class="sender-editor-save-result">
<div class="sender-editor-save-result__icon sender-editor-save-result__icon--error">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#991b1b" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z" />
</svg>
</div>
<div>
<p style="margin:0 0 0.4rem;font-weight:600;color:#1f2937;font-size:0.95rem;">
<p class="sender-editor-save-result__title">
@L("SenderEditor_ErrorCreatingEnvelope", "Fehler beim Erstellen des Umschlags")
</p>
<p style="margin:0;color:#6b7280;font-size:0.85rem;line-height:1.5;word-break:break-word;">
<p class="sender-editor-save-result__message sender-editor-save-result__message--break">
@_saveErrorMessage
</p>
</div>
@@ -585,30 +561,25 @@
}
</BodyContentTemplate>
<FooterContentTemplate>
<div style="display:flex;gap:0.5rem;justify-content:flex-end;width:100%;padding:0.5rem 0;">
<div class="sender-editor-save-actions">
@if (_saveErrorMessage is null)
{
<button class="btn btn-outline-secondary"
@onclick="() => _savePopupVisible = false"
style="border-radius:6px;padding:0.5rem 1.25rem;font-weight:500;">
<button class="btn btn-outline-secondary sender-editor-save-actions__secondary"
@onclick="() => _savePopupVisible = false">
@L("Close", "Schließen")
</button>
@if (_saveNavigateToDashboard)
{
<button class="btn btn-primary"
@onclick="GoToDashboard"
style="background:linear-gradient(135deg,#059669,#047857);border:none;border-radius:6px;
padding:0.5rem 1.5rem;font-weight:600;color:#fff;">
<button class="btn btn-primary sender-editor-save-actions__primary" @onclick="GoToDashboard">
@L("SenderEditor_ToOverview", "Zur Übersicht")
</button>
}
}
else
{
<button class="btn btn-outline-secondary"
@onclick="() => _savePopupVisible = false"
style="border-radius:6px;padding:0.5rem 1.25rem;font-weight:500;">
<button class="btn btn-outline-secondary sender-editor-save-actions__secondary"
@onclick="() => _savePopupVisible = false">
@L("Close", "Schließen")
</button>
}

View File

@@ -1002,6 +1002,107 @@ body.resizing {
border: 1px solid rgba(126, 34, 206, 0.12);
}
.sender-settings-shell {
border-radius: 12px;
overflow: hidden;
}
.sender-settings-accordion {
border: 1px solid #dbe5ef;
border-radius: 12px;
background: linear-gradient(135deg, #ffffff 0%, #f8fbff 100%);
}
.sender-settings-accordion .dxbl-accordion-item {
border: none;
}
.sender-settings-accordion .dxbl-accordion-item-header {
text-transform: uppercase;
letter-spacing: 0.04em;
font-size: 0.74rem;
font-weight: 700;
color: #1f2937;
padding: 0.55rem 0.7rem;
background: rgba(124, 58, 237, 0.04);
}
.sender-settings-body {
display: flex;
flex-direction: column;
gap: 0.65rem;
padding: 0.25rem 0.7rem 0.7rem;
}
.sender-settings-chip {
align-self: flex-start;
font-size: 0.66rem;
font-weight: 700;
color: #5b21b6;
background: rgba(126, 34, 206, 0.1);
border: 1px solid rgba(126, 34, 206, 0.15);
border-radius: 999px;
padding: 0.12rem 0.5rem;
}
.sender-settings-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 0.5rem;
}
.sender-settings-field {
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.sender-settings-label {
font-size: 0.65rem;
font-weight: 700;
color: #64748b;
letter-spacing: 0.01em;
}
.sender-settings-select,
.sender-settings-number {
font-size: 0.78rem;
border: 1px solid #d1d5db;
border-radius: 6px;
padding: 0.3rem 0.45rem;
background: #fff;
min-height: 32px;
color: #1f2937;
}
.sender-settings-number:focus,
.sender-settings-select:focus {
border-color: rgba(126, 34, 206, 0.45);
box-shadow: 0 0 0 2px rgba(126, 34, 206, 0.12);
outline: none;
}
.sender-settings-toggles {
display: flex;
flex-direction: column;
justify-content: flex-end;
gap: 0.3rem;
padding-bottom: 0.1rem;
}
.sender-settings-toggle {
display: inline-flex;
align-items: center;
gap: 0.45rem;
font-size: 0.74rem;
color: #1f2937;
min-height: 32px;
}
.sender-settings-toggles--single {
justify-content: center;
}
.sender-receivers-panel__header {
display: flex;
align-items: center;
@@ -1119,9 +1220,275 @@ body.resizing {
border-radius: 12px;
background: rgba(255, 255, 255, 0.88);
border: 1px solid rgba(126, 34, 206, 0.12);
border-left: 3px solid var(--receiver-color, #7c3aed);
box-shadow: 0 6px 16px rgba(15, 23, 42, 0.06);
}
.sender-receiver-chip__place-btn--idle {
color: var(--receiver-color, #7c3aed);
border-color: var(--receiver-color, #7c3aed);
}
.sender-receiver-chip__place-btn--active {
background: var(--receiver-color, #7c3aed);
color: #ffffff;
border-color: var(--receiver-color, #7c3aed);
}
.sender-editor-action-inner {
flex-direction: row;
align-items: center;
padding: 0.35rem 1.5rem;
gap: 0.75rem;
}
.sender-editor-main-column {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 0.5rem;
}
.sender-editor-meta-row {
display: flex;
align-items: flex-start;
gap: 0.5rem;
flex-wrap: wrap;
}
.sender-editor-input-field {
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.sender-editor-input-field--title {
flex: 1 1 180px;
min-width: 140px;
}
.sender-editor-input-field--message {
flex: 2 1 260px;
min-width: 180px;
}
.sender-editor-label {
font-size: 0.65rem;
font-weight: 600;
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.sender-editor-required-asterisk {
color: #dc2626;
}
.sender-editor-optional {
color: #6b7280;
font-weight: 400;
}
.sender-editor-text-input {
font-size: 0.78rem;
color: #1f2937;
border: 1px solid #d1d5db;
border-radius: 5px;
padding: 0.3rem 0.55rem;
outline: none;
width: 100%;
background: #fff;
}
.sender-editor-text-input--invalid {
border-color: #dc2626;
}
.sender-editor-required-text {
font-size: 0.6rem;
color: #dc2626;
}
.sender-editor-file-meta {
display: flex;
align-items: flex-end;
gap: 0.4rem;
padding-bottom: 0.05rem;
flex-shrink: 0;
}
.sender-editor-file-name {
font-size: 0.7rem;
color: #6b7280;
}
.sender-editor-signature-count {
display: inline-flex;
align-items: center;
padding: 0.125rem 0.4rem;
background: #ede9fe;
border-radius: 0.25rem;
color: #6d28d9;
font-weight: 500;
font-size: 0.7rem;
white-space: nowrap;
}
.sender-editor-actions {
display: flex;
align-items: center;
gap: 0.5rem;
flex-shrink: 0;
}
.sender-editor-upload-btn {
display: inline-flex;
align-items: center;
gap: 0.3rem;
padding: 0.3rem 0.75rem;
font-size: 0.75rem;
font-weight: 500;
cursor: pointer;
}
.sender-editor-upload-btn--disabled {
cursor: not-allowed;
opacity: 0.6;
}
.sender-editor-hidden-input {
display: none;
}
.sender-editor-spinner {
width: 0.8rem;
height: 0.8rem;
border-width: 2px;
}
.sender-editor-placement-hint {
background: var(--placement-color, #7c3aed);
color: #ffffff;
font-size: 0.75rem;
font-weight: 500;
padding: 0.3rem 1.5rem;
text-align: center;
letter-spacing: 0.01em;
}
.sender-editor-placement-cancel {
background: none;
border: none;
color: #ffffff;
cursor: pointer;
font-size: 0.75rem;
text-decoration: underline;
padding: 0;
}
.sender-editor-content {
padding: 0;
overflow: hidden;
}
.sender-editor-empty-state {
max-width: 420px;
}
.sender-editor-empty-state__icon-wrap {
width: 72px;
height: 72px;
background: rgba(255, 255, 255, 0.15);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 1.25rem;
}
.sender-editor-empty-state__description {
opacity: 0.75;
font-size: 0.85rem;
}
.sender-editor-empty-state__upload {
font-weight: 500;
cursor: pointer;
}
.sender-editor-empty-state__upload--disabled {
cursor: not-allowed;
opacity: 0.8;
}
.sender-editor-save-result {
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 0.5rem 0;
}
.sender-editor-save-result__icon {
flex-shrink: 0;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.sender-editor-save-result__icon--success {
background: #d1fae5;
}
.sender-editor-save-result__icon--error {
background: #fee2e2;
}
.sender-editor-save-result__title {
margin: 0 0 0.4rem;
font-weight: 600;
color: #1f2937;
font-size: 0.95rem;
}
.sender-editor-save-result__message {
margin: 0;
color: #6b7280;
font-size: 0.85rem;
line-height: 1.5;
}
.sender-editor-save-result__message--break {
word-break: break-word;
}
.sender-editor-save-actions {
display: flex;
gap: 0.5rem;
justify-content: flex-end;
width: 100%;
padding: 0.5rem 0;
}
.sender-editor-save-actions__secondary {
border-radius: 6px;
padding: 0.5rem 1.25rem;
font-weight: 500;
}
.sender-editor-save-actions__primary {
background: linear-gradient(135deg, #059669, #047857);
border: none;
border-radius: 6px;
padding: 0.5rem 1.5rem;
font-weight: 600;
color: #fff;
}
.sender-receiver-chip__body {
min-width: 0;
flex: 1;