diff --git a/app/Livewire/Registro.php b/app/Livewire/Registro.php
index 66b32f3..b1d771e 100644
--- a/app/Livewire/Registro.php
+++ b/app/Livewire/Registro.php
@@ -48,6 +48,10 @@ class Registro extends Component
public bool $showDeleteConfirm = false;
public ?int $deleteId = null;
+ // ─── Modal modulo S-13 ──────────────────────────────────────
+ public bool $showS13Modal = false;
+ public string $s13Anno = '';
+
protected $queryString = [
'search' => ['except' => ''],
'filtroAnno' => ['except' => ''],
@@ -176,10 +180,28 @@ class Registro extends Component
// ─── Modulo S-13 ────────────────────────────────────────────
+ /**
+ * Chiede quale anno di servizio stampare. L'anno del filtro è solo la
+ * proposta iniziale: il modulo finisce in archivio e viene firmato, quindi
+ * la scelta va confermata invece di essere ereditata da uno stato della
+ * pagina che l'utente può non avere presente.
+ */
+ public function openS13(): void
+ {
+ abort_if(!auth()->user()->can('settings.manage'), 403);
+
+ $this->s13Anno = $this->filtroAnno !== ''
+ ? $this->filtroAnno
+ : (string) AnnoTeocratico::corrente()->id;
+
+ $this->resetValidation();
+ $this->showS13Modal = true;
+ }
+
/**
* Modulo ufficiale S-13-I ("Registrazione delle assegnazioni del
- * territorio") compilato con le assegnazioni dell'anno di servizio
- * selezionato nei filtri.
+ * territorio") compilato con le assegnazioni dell'anno di servizio scelto
+ * nella modale.
*
* Solo amministratore, come il resto del CRUD di questa pagina: il modulo
* espone in un unico file l'anagrafica completa di chi ha avuto quale
@@ -190,12 +212,17 @@ class Registro extends Component
{
abort_if(!auth()->user()->can('settings.manage'), 403);
- // Il modulo è per definizione relativo a un singolo anno di servizio:
- // con "Tutti gli anni" selezionato si ripiega sull'anno corrente.
- $anno = $this->filtroAnno
- ? AnnoTeocratico::find($this->filtroAnno)
- : null;
- $anno ??= AnnoTeocratico::corrente();
+ $this->validate(
+ ['s13Anno' => 'required|exists:anni_teocratici,id'],
+ [
+ 's13Anno.required' => "Seleziona l'anno di servizio da stampare.",
+ 's13Anno.exists' => "L'anno di servizio selezionato non esiste.",
+ ]
+ );
+
+ $anno = AnnoTeocratico::findOrFail($this->s13Anno);
+
+ $this->showS13Modal = false;
$pdf = Pdf::loadView('pdf.registro-s13', [
'annoLabel' => $anno->label,
diff --git a/resources/views/livewire/registro.blade.php b/resources/views/livewire/registro.blade.php
index 99d8e89..419898c 100644
--- a/resources/views/livewire/registro.blade.php
+++ b/resources/views/livewire/registro.blade.php
@@ -3,14 +3,11 @@
+ @endif
+ @endcan
+
{{-- ─── Modal Crea / Modifica (solo admin) ────────────────── --}}
@can('settings.manage')
@if($showModal)
diff --git a/resources/views/pdf/registro-s13.blade.php b/resources/views/pdf/registro-s13.blade.php
index 10a4a60..c8cd593 100644
--- a/resources/views/pdf/registro-s13.blade.php
+++ b/resources/views/pdf/registro-s13.blade.php
@@ -18,20 +18,39 @@
--}}
@php
/**
- * Il nome del proclamatore deve stare su una riga in una cella larga
- * ~35mm. DejaVu Sans ha larghezza media ~0.52em per carattere, quindi a
- * 8pt entrano circa 23 caratteri: sotto quella soglia si scala il corpo
- * invece di mandare a capo, che sfonderebbe l'altezza fissa della riga.
+ * Il nome del proclamatore deve stare su una riga: le righe hanno altezza
+ * fissa e la cella è nowrap, quindi mandare a capo sfonderebbe la griglia.
+ * Invece di andare a capo si scala il corpo.
+ *
+ * Larghezza utile della cella ~34.8mm (due colonne meno il padding).
+ * DejaVu Sans occupa in media 0.52em per carattere, cioè ~0.1835mm per
+ * carattere per punto di corpo: da lì il corpo massimo che entra.
+ *
+ * Sotto i 4.5pt il testo non sarebbe più leggibile, quindi oltre i 42
+ * caratteri si tronca — l'ellissi rende visibile l'accorciamento, mentre
+ * un nome che deborda corromperebbe la griglia in silenzio.
*/
- $nomeFontSize = static function (string $nome): string {
+ $LARGHEZZA_CELLA_MM = 34.8;
+ $MM_PER_CARATTERE_PER_PUNTO = 0.1835;
+ $CORPO_MAX_PT = 8.0;
+ $CORPO_MIN_PT = 4.5;
+
+ $maxCaratteri = (int) floor($LARGHEZZA_CELLA_MM / ($CORPO_MIN_PT * $MM_PER_CARATTERE_PER_PUNTO));
+
+ $nomeTroncato = static fn (string $nome): string => mb_strlen($nome) > $maxCaratteri
+ ? mb_substr($nome, 0, $maxCaratteri - 1) . '…'
+ : $nome;
+
+ $nomeFontSize = static function (string $nome) use ($LARGHEZZA_CELLA_MM, $MM_PER_CARATTERE_PER_PUNTO, $CORPO_MAX_PT, $CORPO_MIN_PT): string {
$len = mb_strlen($nome);
- return match (true) {
- $len <= 23 => '8pt',
- $len <= 27 => '7pt',
- $len <= 32 => '6.2pt',
- default => '5.5pt',
- };
+ if ($len === 0) {
+ return $CORPO_MAX_PT . 'pt';
+ }
+
+ $pt = $LARGHEZZA_CELLA_MM / ($len * $MM_PER_CARATTERE_PER_PUNTO);
+
+ return round(max($CORPO_MIN_PT, min($CORPO_MAX_PT, $pt)), 1) . 'pt';
};
$ultimaPagina = $pagine->count() - 1;
@@ -42,11 +61,22 @@
S-13 — Registrazione delle assegnazioni del territorio
@@ -142,7 +175,8 @@