Files
SmartReports/docs/superpowers/plans/2026-03-20-page1-header-restyle.md

11 KiB

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"

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):

    // 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):

    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)

    // 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

    dotnet build CertReports.Syncfusion/CertReports.Syncfusion.csproj
    

    Atteso: Build succeeded senza errori.

  • Step 5: Commit

    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)

    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

    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

    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

    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

    // 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

    dotnet build CertReports.Syncfusion/CertReports.Syncfusion.csproj
    
  • Step 3: Commit

    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

    // PRIMA:
    "Trigger CPN", "Cedola %", "Pagato", "Memoria",
    
    // DOPO:
    "Trigger Cedola", "Cedola %", "Pagato", "Memoria",
    
  • Step 2: Build

    dotnet build CertReports.Syncfusion/CertReports.Syncfusion.csproj
    
  • Step 3: Commit

    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