# Page 1 Header Restyle & Label Fixes — Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Redesign l'header di pagina 1 (titolo centrato + box Tipologia/Data/Bid/Ask uniformi), rinominare colonne nelle tabelle Sottostanti ed Eventi, e fixare lo spazio nel footer branding. **Architecture:** Modifiche localizzate a 3 file esistenti. Nessuna nuova classe o interfaccia. Le nuove costanti colore/brush vengono aggiunte a `PdfTheme.cs` seguendo il pattern `=>` già usato nel file. Il nuovo `DrawTitle` in `AnagraficaSectionRenderer` è una riscrittura completa del metodo esistente. **Tech Stack:** C# / ASP.NET Core 8, Syncfusion PDF v33, Syncfusion.Drawing --- ## File map | File | Modifica | |------|----------| | `CertReports.Syncfusion/Helpers/PdfTheme.cs` | Aggiungi 6 colori + 5 brush (stile `=>`) + fix footer offset (+2pt) | | `CertReports.Syncfusion/Services/Implementations/AnagraficaSectionRenderer.cs` | Riscrivi `DrawTitle`, aggiungi `DrawInfoBox`, rinomina headers sottostanti | | `CertReports.Syncfusion/Services/Implementations/EventiSectionRenderer.cs` | Rinomina "Trigger CPN" → "Trigger Cedola" | --- ## Task 1: Nuovi colori e fix footer in PdfTheme.cs **Files:** - Modify: `CertReports.Syncfusion/Helpers/PdfTheme.cs` - [ ] **Step 1: Aggiungi nuove costanti colore** Inserisci dopo la riga `public static readonly Color TableAltRow = ...` (blocco colori, riga ~33): ```csharp // Colori box header pagina 1 public static readonly Color AccentBlueDark = Color.FromArgb(255, 13, 71, 161); // #0D47A1 public static readonly Color BoxLightBlueBg = Color.FromArgb(255, 235, 242, 251); // #EBF2FB public static readonly Color BoxGrayBg = Color.FromArgb(255, 245, 245, 245); // #F5F5F5 public static readonly Color BoxGrayAccent = Color.FromArgb(255, 136, 136, 136); // #888888 public static readonly Color BoxGrayLabel = Color.FromArgb(255, 102, 102, 102); // #666666 public static readonly Color BoxGrayValue = Color.FromArgb(255, 51, 51, 51); // #333333 ``` - [ ] **Step 2: Aggiungi i brush corrispondenti — usa il pattern `=>` come il resto del file** Inserisci dopo la riga `public static PdfPen AccentBluePen => ...` (blocco Brushes, riga ~86): ```csharp public static PdfBrush AccentBlueDarkBrush => new PdfSolidBrush(AccentBlueDark); public static PdfBrush BoxLightBlueBgBrush => new PdfSolidBrush(BoxLightBlueBg); public static PdfBrush BoxGrayBgBrush => new PdfSolidBrush(BoxGrayBg); public static PdfBrush BoxGrayAccentBrush => new PdfSolidBrush(BoxGrayAccent); public static PdfBrush BoxGrayLabelBrush => new PdfSolidBrush(BoxGrayLabel); public static PdfBrush BoxGrayValueBrush => new PdfSolidBrush(BoxGrayValue); ``` - [ ] **Step 3: Fix footer — cambia solo l'argomento `PointF` in `DrawTextWebLink` (riga ~203)** ```csharp // PRIMA: webLink.DrawTextWebLink(g, new PointF(prefixWidth, footerY)); // DOPO: webLink.DrawTextWebLink(g, new PointF(prefixWidth + 2f, footerY)); ``` > Il `DrawString` del testo prefisso (riga ~193) usa già `prefixWidth + 2f` come larghezza del `RectangleF` — questo fix allinea solo il punto di partenza del link. - [ ] **Step 4: Build** ```bash dotnet build CertReports.Syncfusion/CertReports.Syncfusion.csproj ``` Atteso: `Build succeeded` senza errori. - [ ] **Step 5: Commit** ```bash git add CertReports.Syncfusion/Helpers/PdfTheme.cs git commit -m "feat: add box header colors/brushes and fix footer branding offset" ``` --- ## Task 2: Riscrittura DrawTitle in AnagraficaSectionRenderer.cs **Files:** - Modify: `CertReports.Syncfusion/Services/Implementations/AnagraficaSectionRenderer.cs` Il metodo `DrawTitle` (righe 74-112) viene sostituito interamente. Si aggiunge il metodo privato `DrawInfoBox`. **Layout:** ``` Scheda Prodotto XS1234567890 ← centrato, AccentBlue, SectionTitleFont ───────────────────────────────────────── ← AccentBluePen [TIPOLOGIA / Cert. Bonus Cap] [DATA / 18/03] [BID / 98.50] [ASK / 99.20] ``` **Dimensioni box:** - Altezza: `28f`; Gap: `6f`; Larghezza Data: `84f`, Bid: `70f`, Ask: `70f` - `tipW` calcolato dinamicamente (vedi DrawTitle) - Bordo sinistro accent: `4f`; Padding: `6f` sx, `4f` dx - Label: `PdfTheme.Small` (6.5pt) a `y + 4f` - Valore Bid/Ask/Data: `PdfTheme.Bold` (8pt bold) a `y + 14f` - Valore Tipologia: `PdfTheme.Bold` (8pt bold) a `y + 14f` — testo più lungo, dimensione coerente con gli altri box - [ ] **Step 1: Aggiungi il metodo `DrawInfoBox` alla classe (prima di `DrawCaratteristiche`)** ```csharp private void DrawInfoBox( PdfGraphics g, float x, float y, float w, float boxH, string label, string value, PdfBrush bgBrush, PdfBrush accentBrush, PdfBrush labelBrush, PdfBrush valueBrush, PdfFont valueFont) { g.DrawRectangle(bgBrush, new RectangleF(x, y, w, boxH)); g.DrawRectangle(accentBrush, new RectangleF(x, y, 4f, boxH)); float innerX = x + 4f + 6f; float innerW = w - 4f - 6f - 4f; g.DrawString(label, PdfTheme.Small, labelBrush, new RectangleF(innerX, y + 4f, innerW, 10f)); g.DrawString(value, valueFont, valueBrush, new RectangleF(innerX, y + 14f, innerW, 14f)); } ``` > **Nota Syncfusion:** `RectangleF` non supporta named arguments — sempre forma posizionale `new RectangleF(x, y, w, h)`. - [ ] **Step 2: Sostituisci il metodo `DrawTitle` (righe 74-112) con la nuova implementazione** ```csharp private float DrawTitle(PdfGraphics g, CertificateInfo info, float w, float y) { // ── Titolo centrato ────────────────────────────────────────── g.DrawString($"Scheda Prodotto {info.Isin}", PdfTheme.SectionTitleFont, new PdfSolidBrush(PdfTheme.AccentBlue), new RectangleF(0, y, w, 20f), new PdfStringFormat(PdfTextAlignment.Center)); y += 24f; // Linea separatrice blu g.DrawLine(PdfTheme.AccentBluePen, 0, y, w, y); y += 8f; // ── Riga box: Tipologia | Data | Bid | Ask ─────────────────── const float boxH = 28f; const float gap = 6f; const float dataW = 84f; const float bidW = 70f; const float askW = 70f; bool showTip = !string.IsNullOrEmpty(info.Categoria); bool showData = !string.IsNullOrEmpty(info.LastPriceDate); bool showBidAsk = !string.IsNullOrEmpty(info.Bid) && !string.IsNullOrEmpty(info.Ask); // Calcolo dinamico larghezza Tipologia in base ai box presenti int nBoxes = (showTip ? 1 : 0) + (showData ? 1 : 0) + (showBidAsk ? 2 : 0); float totalGaps = Math.Max(0, nBoxes - 1) * gap; float fixedW = (showData ? dataW : 0f) + (showBidAsk ? bidW + askW : 0f); float tipW = showTip ? (w - totalGaps - fixedW) : 0f; float xCursor = 0f; if (showTip) { DrawInfoBox(g, xCursor, y, tipW, boxH, "TIPOLOGIA", info.Categoria, PdfTheme.BoxLightBlueBgBrush, PdfTheme.AccentBlueBrush, PdfTheme.AccentBlueBrush, PdfTheme.AccentBlueDarkBrush, PdfTheme.Bold); xCursor += tipW + gap; } if (showData) { DrawInfoBox(g, xCursor, y, dataW, boxH, "DATA", info.LastPriceDate, PdfTheme.BoxGrayBgBrush, PdfTheme.BoxGrayAccentBrush, PdfTheme.BoxGrayLabelBrush, PdfTheme.BoxGrayValueBrush, PdfTheme.Bold); xCursor += dataW + gap; } if (showBidAsk) { DrawInfoBox(g, xCursor, y, bidW, boxH, "BID", info.Bid, PdfTheme.BoxLightBlueBgBrush, PdfTheme.AccentBlueBrush, PdfTheme.AccentBlueBrush, PdfTheme.AccentBlueDarkBrush, PdfTheme.Bold); xCursor += bidW + gap; DrawInfoBox(g, xCursor, y, askW, boxH, "ASK", info.Ask, PdfTheme.BoxLightBlueBgBrush, PdfTheme.AccentBlueBrush, PdfTheme.AccentBlueBrush, PdfTheme.AccentBlueDarkBrush, PdfTheme.Bold); } y += boxH + 10f; return y; } ``` - [ ] **Step 3: Build** ```bash dotnet build CertReports.Syncfusion/CertReports.Syncfusion.csproj ``` Atteso: `Build succeeded`. - [ ] **Step 4: Verifica visiva** Avvia il progetto e apri nel browser: ``` https://localhost:{porta}/api/report/by-isin/{ISIN_VALIDO} ``` Controlla che la pagina 1 mostri: titolo centrato + linea + riga box con altezze uniformi. Con `?branding=true` verifica che "Powered by Smart Roots" abbia lo spazio corretto tra "by" e il link. - [ ] **Step 5: Commit** ```bash git add CertReports.Syncfusion/Services/Implementations/AnagraficaSectionRenderer.cs git commit -m "feat: redesign page1 header - centered title, info boxes row (Tipologia/Data/Bid/Ask)" ``` --- ## Task 3: Rinomina colonne tabella Sottostanti **Files:** - Modify: `CertReports.Syncfusion/Services/Implementations/AnagraficaSectionRenderer.cs` (metodo `DrawSottostanti`, riga ~338) - [ ] **Step 1: Aggiorna l'array `headers` in `DrawSottostanti`** ```csharp // PRIMA: string[] headers = { "Nome", "Strike", "Last", "% Perf.", "Barr.K", "Buffer K", "Trig.CPN", "Buf.CPN", "Trig.AC" }; // DOPO: string[] headers = { "Nome", "Strike", "Last", "% Perf.", "Barriera Capitale", "Buffer Capitale", "Trigger Cedola", "Buffer Cedola", "Trig.AC" }; ``` - [ ] **Step 2: Build** ```bash dotnet build CertReports.Syncfusion/CertReports.Syncfusion.csproj ``` - [ ] **Step 3: Commit** ```bash git add CertReports.Syncfusion/Services/Implementations/AnagraficaSectionRenderer.cs git commit -m "fix: rename sottostanti column headers (Barriera/Buffer/Trigger Cedola)" ``` --- ## Task 4: Rinomina colonna tabella Eventi **Files:** - Modify: `CertReports.Syncfusion/Services/Implementations/EventiSectionRenderer.cs` (riga ~45) - [ ] **Step 1: Aggiorna l'array `headers` in `EventiSectionRenderer.Render`** ```csharp // PRIMA: "Trigger CPN", "Cedola %", "Pagato", "Memoria", // DOPO: "Trigger Cedola", "Cedola %", "Pagato", "Memoria", ``` - [ ] **Step 2: Build** ```bash dotnet build CertReports.Syncfusion/CertReports.Syncfusion.csproj ``` - [ ] **Step 3: Commit** ```bash git add CertReports.Syncfusion/Services/Implementations/EventiSectionRenderer.cs git commit -m "fix: rename eventi column Trigger CPN -> Trigger Cedola" ``` --- ## Verifica finale - [ ] Avvia il server: `dotnet run --project CertReports.Syncfusion` - [ ] Apri report con un ISIN valido, verifica pagina 1: - Titolo "Scheda Prodotto {ISIN}" centrato in blu - Linea separatrice blu - Box Tipologia / Data / Bid / Ask sulla stessa riga, stessa altezza (28pt) - Box Tipologia si estende per occupare lo spazio residuo - [ ] Verifica tabella Sottostanti: header con "Barriera Capitale", "Buffer Capitale", "Trigger Cedola", "Buffer Cedola" - [ ] Verifica sezione Eventi: colonna "Trigger Cedola" (era "Trigger CPN") - [ ] Verifica footer con `?branding=true`: "Powered by Smart Roots" con spazio visibile tra "by" e il link cliccabile