diff --git a/EnvelopeGenerator.ReceiverUIBlazor/Pages/Index.razor b/EnvelopeGenerator.ReceiverUIBlazor/Pages/Index.razor index 3f307da7..3228d138 100644 --- a/EnvelopeGenerator.ReceiverUIBlazor/Pages/Index.razor +++ b/EnvelopeGenerator.ReceiverUIBlazor/Pages/Index.razor @@ -84,6 +84,7 @@ private ElementReference OverlayRef; private string? PdfBase64; + private string? OriginalPdfBase64; private int PageIndex; private int PageCount; private double ViewportWidthPx = 800; @@ -143,6 +144,7 @@ using var ms = new MemoryStream(); await stream.CopyToAsync(ms); PdfBase64 = Convert.ToBase64String(ms.ToArray()); + OriginalPdfBase64 = PdfBase64; // Show the canvas before we start rendering await InvokeAsync(StateHasChanged); @@ -186,13 +188,28 @@ } } - private void Reset() + private async Task Reset() { - PdfBase64 = null; - PageIndex = 0; - PageCount = 0; - ViewportHeightPx = 0; + ErrorMessage = null; CloseOverlays(); + ShowSignaturePadModal = false; + OverlayXpx = 20; + OverlayYpx = 20; + OverlayWidthPx = 200; + OverlayHeightPx = 80; + TextValue = "Text"; + + if (string.IsNullOrWhiteSpace(OriginalPdfBase64)) + { + return; + } + + PdfBase64 = OriginalPdfBase64; + PageIndex = 0; + + var result = await JS.InvokeAsync("pdfInterop.loadPdf", PdfBase64); + PageCount = result.Pages; + await RenderPage(); } private void CloseOverlays() diff --git a/EnvelopeGenerator.ReceiverUIBlazor/wwwroot/css/app.css b/EnvelopeGenerator.ReceiverUIBlazor/wwwroot/css/app.css index b6892527..12714836 100644 --- a/EnvelopeGenerator.ReceiverUIBlazor/wwwroot/css/app.css +++ b/EnvelopeGenerator.ReceiverUIBlazor/wwwroot/css/app.css @@ -1,114 +1,143 @@ +:root { + --bg: #f6f7fb; + --bg-strong: #eef2fb; + --text: #0f172a; + --muted: #475569; + --border: #e2e8f0; + --shadow: 0 20px 60px rgba(15, 23, 42, 0.08); + --card: #ffffff; + --accent: #2563eb; + --accent-strong: #1d4ed8; + --accent-soft: #e8efff; + --danger: #dc2626; +} + body { margin: 0; - font-family: "Segoe UI", Arial, sans-serif; - background: #0f172a; - color: #e2e8f0; + font-family: "Manrope", "Segoe UI", system-ui, -apple-system, sans-serif; + background: radial-gradient(120% 120% at 10% 20%, #ffffff 0%, #f3f6ff 45%, #eef2fb 80%); + color: var(--text); + line-height: 1.5; } .main-layout { min-height: 100vh; - background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0b1220 100%); } .top-bar { display: flex; align-items: center; - padding: 12px 20px; - background: rgba(255, 255, 255, 0.04); - border-bottom: 1px solid rgba(226, 232, 240, 0.08); + padding: 14px 24px; + background: var(--card); + border-bottom: 1px solid var(--border); + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.05); } .top-bar .brand { - font-weight: 700; - letter-spacing: 0.5px; + font-weight: 800; + letter-spacing: 0.4px; } .content { - padding: 24px 32px; + padding: 28px 32px 40px; + max-width: 1200px; + margin: 0 auto; + display: flex; + flex-direction: column; + gap: 16px; + align-items: center; } h1 { - margin-top: 0; - margin-bottom: 8px; - letter-spacing: 0.3px; + margin: 0 0 10px; + letter-spacing: 0.2px; } .controls { display: flex; - gap: 8px; + gap: 10px; flex-wrap: wrap; align-items: center; - margin-bottom: 12px; + margin-bottom: 14px; + justify-content: center; } .btn { - background: #22d3ee; - color: #0f172a; + background: linear-gradient(135deg, var(--accent) 0%, var(--accent-strong) 100%); + color: #ffffff; border: none; padding: 10px 14px; - border-radius: 8px; - font-weight: 600; + border-radius: 10px; + font-weight: 700; cursor: pointer; - transition: transform 120ms ease, box-shadow 120ms ease; + transition: transform 120ms ease, box-shadow 120ms ease, filter 120ms ease; + box-shadow: 0 12px 28px rgba(37, 99, 235, 0.22); } .btn:hover:not(:disabled) { transform: translateY(-1px); - box-shadow: 0 8px 18px rgba(34, 211, 238, 0.25); + filter: brightness(1.02); } .btn:disabled { - opacity: 0.4; + opacity: 0.45; cursor: not-allowed; + box-shadow: none; } .btn.secondary { - background: rgba(226, 232, 240, 0.12); - color: #e2e8f0; - border: 1px solid rgba(226, 232, 240, 0.2); + background: var(--accent-soft); + color: var(--accent-strong); + border: 1px solid var(--border); + box-shadow: none; } .drop-hint { - padding: 24px; - border: 1px dashed rgba(226, 232, 240, 0.3); - border-radius: 12px; + padding: 26px; + border: 1px dashed var(--border); + border-radius: 14px; text-align: center; - color: rgba(226, 232, 240, 0.8); + color: var(--muted); + background: #ffffff; + width: min(1100px, 100%); + margin: 0 auto; } .error-banner { - margin-top: 8px; - padding: 10px 12px; - border-radius: 8px; - background: rgba(239, 68, 68, 0.12); - border: 1px solid rgba(239, 68, 68, 0.3); - color: #fecdd3; + margin-top: 10px; + padding: 12px 14px; + border-radius: 10px; + background: #fff1f2; + border: 1px solid #fecdd3; + color: #b91c1c; } .document-shell { position: relative; - margin-top: 12px; - border-radius: 12px; + margin-top: 14px; + border-radius: 14px; overflow: hidden; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35); - background: #0b1220; - border: 1px solid rgba(226, 232, 240, 0.08); + box-shadow: var(--shadow); + background: var(--card); + border: 1px solid var(--border); + margin-left: auto; + margin-right: auto; } canvas { display: block; width: 100%; height: auto; - background: #111827; + background: #ffffff; } .overlay { position: absolute; - border: 2px solid #22d3ee; - border-radius: 8px; - padding: 6px; - background: rgba(15, 23, 42, 0.9); - box-shadow: 0 10px 24px rgba(0, 0, 0, 0.35); + border: 1px dashed var(--accent); + border-radius: 10px; + padding: 8px; + background: rgba(255, 255, 255, 0.96); + box-shadow: 0 12px 30px rgba(37, 99, 235, 0.15); user-select: none; touch-action: none; } @@ -121,36 +150,39 @@ canvas { .overlay-controls { position: absolute; - top: -36px; + top: -44px; right: 0; display: flex; - gap: 4px; + gap: 6px; } .overlay-btn { - background: #0f172a; - color: #22d3ee; - border: 1px solid rgba(34, 211, 238, 0.4); - border-radius: 6px; - padding: 4px 8px; + background: #ffffff; + color: var(--accent-strong); + border: 1px solid var(--accent); + border-radius: 8px; + padding: 6px 10px; cursor: pointer; + box-shadow: 0 6px 16px rgba(37, 99, 235, 0.15); } .overlay-input { - border: none; - background: transparent; - color: #e2e8f0; + border: 1px solid var(--border); + background: #ffffff; + color: var(--text); font-size: 18px; - padding: 4px; - min-width: 160px; + padding: 6px 8px; + min-width: 180px; + border-radius: 8px; outline: none; } .paging { - margin-top: 12px; + margin-top: 14px; display: flex; gap: 10px; align-items: center; + color: var(--muted); } .modal-backdrop { @@ -159,7 +191,8 @@ canvas { left: 0; right: 0; bottom: 0; - background: rgba(0, 0, 0, 0.65); + background: rgba(15, 23, 42, 0.35); + backdrop-filter: blur(3px); display: flex; align-items: center; justify-content: center; @@ -167,25 +200,26 @@ canvas { } .modal { - background: #0f172a; - border: 1px solid rgba(226, 232, 240, 0.08); - border-radius: 12px; - padding: 16px; + background: var(--card); + border: 1px solid var(--border); + border-radius: 14px; + padding: 18px; min-width: 760px; - box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45); + box-shadow: var(--shadow); } .modal-row { display: flex; align-items: center; - gap: 10px; - margin-top: 10px; + gap: 12px; + margin-top: 12px; + color: var(--muted); } .modal canvas { - background: #0b1220; - border: 1px solid rgba(226, 232, 240, 0.1); - border-radius: 8px; + background: #ffffff; + border: 1px solid var(--border); + border-radius: 10px; } .spacer { diff --git a/EnvelopeGenerator.ReceiverUIBlazor/wwwroot/js/pdfInterop.js b/EnvelopeGenerator.ReceiverUIBlazor/wwwroot/js/pdfInterop.js index 6f8c60c0..6d0ea97f 100644 --- a/EnvelopeGenerator.ReceiverUIBlazor/wwwroot/js/pdfInterop.js +++ b/EnvelopeGenerator.ReceiverUIBlazor/wwwroot/js/pdfInterop.js @@ -175,7 +175,7 @@ x, y: y - 14 * scaleY, size: 14 * scaleX, - color: PDFLib.rgb(0.07, 0.54, 0.26), + color: PDFLib.rgb(0.11, 0.25, 0.56), }); } @@ -209,7 +209,7 @@ x, y, size: fontSize * scaleX, - color: PDFLib.rgb(0.9, 0.9, 0.9), + color: PDFLib.rgb(0.2, 0.23, 0.28), }); const updatedBase64 = await pdfDoc.saveAsBase64({ dataUri: false }); @@ -225,7 +225,7 @@ const ctx = canvas.getContext('2d'); ctx.lineWidth = 2; ctx.lineCap = 'round'; - ctx.strokeStyle = '#22d3ee'; + ctx.strokeStyle = '#1c3d8f'; const padState = { drawing: false,