Add dynamic color support for receivers

Introduced a `Color` property to `ReceiverDraft` and `SignatureFieldDraft` models, enabling dynamic color assignment from a predefined palette (`ReceiverPalette`). Updated the UI to reflect receiver-specific colors in the sender-receiver chips, placement mode hint bar, and signature placement button.

Refactored PDF rendering logic to dynamically derive visual styles (fill, border, and text colors) from receiver colors. Added a `HexToXColor` utility for converting hex color strings to `PdfSharp.Drawing.XColor`.

Removed hardcoded visual styles and replaced them with dynamic, receiver-specific styling. Simplified receiver addition logic to automatically assign colors from the palette. These changes improve clarity and maintainability while enhancing the user experience.
This commit is contained in:
2026-07-01 23:27:38 +02:00
parent 9ecfe08e2e
commit 2c789cd4c0

View File

@@ -74,7 +74,8 @@
<div class="sender-receivers-list">
@foreach (var receiver in _receivers)
{
<div class="sender-receiver-chip">
<div class="sender-receiver-chip"
style="border-left: 3px solid @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>
@@ -87,6 +88,7 @@
<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="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" />
@@ -155,7 +157,7 @@
@* Placement mode hint bar *@
@if (_pendingReceiverForPlacement is not null)
{
<div style="background: #4F46E5; color: white; font-size: 0.75rem; font-weight: 500;
<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;">
📌 Klicken Sie auf die Stelle im Dokument für <strong>@_pendingReceiverForPlacement.FullName</strong>.
&nbsp;<button @onclick="CancelPlacement"
@@ -483,7 +485,8 @@
XPt: xPt,
YPt: yPt,
Page: page1Based,
ReceiverName: _pendingReceiverForPlacement.FullName);
ReceiverName: _pendingReceiverForPlacement.FullName,
Color: _pendingReceiverForPlacement.Color);
_signatureFields.Add(field);
_pendingReceiverForPlacement = null;
@@ -565,25 +568,6 @@
var document = PdfSharp.Pdf.IO.PdfReader.Open(
inputMs, PdfSharp.Pdf.IO.PdfDocumentOpenMode.Modify);
// Visual style — same palette as the receiver-side placeholder
var fillBrush = new PdfSharp.Drawing.XSolidBrush(PdfSharp.Drawing.XColor.FromArgb( 40, 60, 80, 160));
var borderPen = new PdfSharp.Drawing.XPen(PdfSharp.Drawing.XColor.FromArgb(200, 60, 80, 200), 1.5);
var textBrush = new PdfSharp.Drawing.XSolidBrush(PdfSharp.Drawing.XColor.FromArgb(200, 40, 60, 140));
var nameBrush = new PdfSharp.Drawing.XSolidBrush(PdfSharp.Drawing.XColor.FromArgb(255, 30, 30, 100));
var fontLabel = new PdfSharp.Drawing.XFont("Arial", 9, PdfSharp.Drawing.XFontStyleEx.Bold);
var fontName = new PdfSharp.Drawing.XFont("Arial", 7, PdfSharp.Drawing.XFontStyleEx.Regular);
var fmtCenter = new PdfSharp.Drawing.XStringFormat
{
Alignment = PdfSharp.Drawing.XStringAlignment.Center,
LineAlignment = PdfSharp.Drawing.XLineAlignment.Center,
};
var fmtBottomCenter = new PdfSharp.Drawing.XStringFormat
{
Alignment = PdfSharp.Drawing.XStringAlignment.Center,
LineAlignment = PdfSharp.Drawing.XLineAlignment.Far,
};
foreach (var field in fields)
{
int pageIndex = field.Page - 1;
@@ -592,6 +576,21 @@
var page = document.Pages[pageIndex];
using var gfx = PdfSharp.Drawing.XGraphics.FromPdfPage(page);
// Derive colours from the receiver's hex colour
var fillBrush = new PdfSharp.Drawing.XSolidBrush(HexToXColor(field.Color, alpha: 35));
var borderPen = new PdfSharp.Drawing.XPen(HexToXColor(field.Color, alpha: 210), 1.5);
var textBrush = new PdfSharp.Drawing.XSolidBrush(HexToXColor(field.Color, alpha: 200));
var nameBrush = new PdfSharp.Drawing.XSolidBrush(HexToXColor(field.Color, alpha: 230));
var fontLabel = new PdfSharp.Drawing.XFont("Arial", 9, PdfSharp.Drawing.XFontStyleEx.Bold);
var fontName = new PdfSharp.Drawing.XFont("Arial", 7, PdfSharp.Drawing.XFontStyleEx.Regular);
var fmtCenter = new PdfSharp.Drawing.XStringFormat
{
Alignment = PdfSharp.Drawing.XStringAlignment.Center,
LineAlignment = PdfSharp.Drawing.XLineAlignment.Center,
};
var rect = new PdfSharp.Drawing.XRect(field.XPt, field.YPt, SigWidthPt, SigHeightPt);
gfx.DrawRectangle(fillBrush, rect);
@@ -616,6 +615,13 @@
return outputMs.ToArray();
}
/// <summary>Converts a CSS hex colour string (e.g. "#4F46E5") to a PdfSharp XColor.</summary>
static PdfSharp.Drawing.XColor HexToXColor(string hex, int alpha)
{
var c = System.Drawing.ColorTranslator.FromHtml(hex);
return PdfSharp.Drawing.XColor.FromArgb(alpha, c.R, c.G, c.B);
}
// ── Receiver popup ──
void OpenAddReceiverPopup()
{
@@ -777,22 +783,36 @@
return Task.CompletedTask;
}
_receivers.Add(new ReceiverDraft(Guid.NewGuid(), fullName, email, phoneNumber));
_receivers.Add(new ReceiverDraft(Guid.NewGuid(), fullName, email, phoneNumber,
ReceiverPalette[_receivers.Count % ReceiverPalette.Length]));
PersistSession();
CloseAddReceiverPopup();
return Task.CompletedTask;
}
// ── Models ──
record SignatureFieldDraft(double XPt, double YPt, int Page, string ReceiverName);
record SignatureFieldDraft(double XPt, double YPt, int Page, string ReceiverName, string Color);
record NormalisedCoords(double NormX, double NormY, int PageIndex);
record ReceiverDraft(Guid Id, string FullName, string Email, string PhoneNumber);
record ReceiverDraft(Guid Id, string FullName, string Email, string PhoneNumber, string Color);
record EditorSessionData(
byte[] OriginalPdfBytes,
List<SignatureFieldDraft> Fields,
string FileName,
List<ReceiverDraft> Receivers);
// ── Receiver colour palette (cycles when > 8 receivers) ──
static readonly string[] ReceiverPalette =
[
"#4F46E5", // indigo
"#059669", // emerald
"#DC2626", // red
"#D97706", // amber
"#7C3AED", // violet
"#0891B2", // cyan
"#BE185D", // pink
"#65A30D", // lime
];
}