8 Commits
129 changed files with 2650 additions and 1742 deletions
+4 -5
View File
@@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Círculo azul e letra 'i' informativa centrada em (24, 24) --> <circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="2"/>
<circle cx="24" cy="24" r="18" fill="#0288d1"/> <circle cx="12" cy="7.5" r="1.2" fill="currentColor"/>
<circle cx="24" cy="15" r="2.5" fill="#ffffff"/> <line x1="12" y1="11" x2="12" y2="16.5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="24" y1="21" x2="24" y2="33" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 362 B

After

Width:  |  Height:  |  Size: 338 B

+1 -1
View File
@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M 8 5 L 15 12 L 8 19" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M 9 5 L 16 12 L 9 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 224 B

+3 -11
View File
@@ -1,12 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <path d="M 16.5 6.5 L 9.5 13.5 C 8.1 14.9 8.1 17.1 9.5 18.5 C 10.9 19.9 13.1 19.9 14.5 18.5 L 20 13 C 22.2 10.8 22.2 7.2 20 5 C 17.8 2.8 14.2 2.8 12 5 L 6.5 10.5 C 3.7 13.3 3.7 17.7 6.5 20.5 C 9.3 23.3 13.7 23.3 16.5 20.5 L 20 17"
<path d="M 10 4 L 34 4 L 42 12 L 42 44 L 10 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 34 4 L 34 12 L 42 12 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2"/>
<!-- Linhas de texto representativas -->
<line x1="16" y1="20" x2="36" y2="20" stroke="#90caf9" stroke-width="2" stroke-linecap="round"/>
<line x1="16" y1="26" x2="36" y2="26" stroke="#90caf9" stroke-width="2" stroke-linecap="round"/>
<line x1="16" y1="32" x2="30" y2="32" stroke="#90caf9" stroke-width="2" stroke-linecap="round"/>
<!-- Clipe de papel metálico prendendo a folha -->
<path d="M 12 2 C 8 2 6 5 6 9 L 6 25 C 6 29 9 32 14 32 C 18 32 21 29 21 25 L 21 11 C 21 8 19 6 16 6 C 13 6 12 8 12 11 L 12 24"
fill="none" stroke="#455a64" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 976 B

After

Width:  |  Height:  |  Size: 433 B

+5 -12
View File
@@ -1,13 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha traseira (3) --> <path d="M 3.5 7.5 H 16.5 V 20.5 H 3.5 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 16 4 L 38 4 L 44 10 L 44 32 L 16 32 Z" fill="#e1f5fe" stroke="#4fc3f7" stroke-width="2" stroke-linejoin="round"/> <path d="M 7.5 4.5 H 20.5 V 17.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<!-- Folha do meio (2) --> <line x1="7" y1="11.5" x2="13" y2="11.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<path d="M 10 10 L 32 10 L 38 16 L 38 38 L 10 38 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/> <line x1="7" y1="15.5" x2="11" y2="15.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<!-- Folha frontal (1) -->
<path d="M 4 16 L 26 16 L 32 22 L 32 44 L 4 44 Z" fill="#ffffff" stroke="#01579b" stroke-width="2.2" stroke-linejoin="round"/>
<!-- Dobra folha frontal -->
<path d="M 26 16 L 26 22 L 32 22 Z" fill="#e1f5fe" stroke="#01579b" stroke-width="1.8"/>
<!-- Checkmark de execução/lote concluído -->
<circle cx="34" cy="34" r="10" fill="#00c853"/>
<path d="M 29 34 L 33 38 L 39 30" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 920 B

After

Width:  |  Height:  |  Size: 543 B

+6 -10
View File
@@ -1,11 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Pasta de arquivos de certificados --> <rect x="3" y="4" width="18" height="16" rx="2.5" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M 4 10 L 16 10 L 20 14 L 44 14 L 44 40 L 4 40 Z" fill="#e1f5fe" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/> <circle cx="12" cy="10" r="2.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
<!-- Aba superior da pasta --> <path d="M 10.5 12.2 L 9.5 17 L 12 15.5 L 14.5 17 L 13.5 12.2" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linejoin="round"/>
<path d="M 4 18 L 44 18" stroke="#0288d1" stroke-width="2"/> <line x1="6" y1="7" x2="8" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<!-- Cadeado de segurança dourado/azul --> <line x1="16" y1="7" x2="18" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<rect x="26" y="24" width="14" height="12" rx="3" fill="#0288d1"/>
<!-- Arco do cadeado -->
<path d="M 29 24 L 29 20 C 29 17 31 15 33 15 C 35 15 37 17 37 20 L 37 24" fill="none" stroke="#01579b" stroke-width="2.5"/>
<circle cx="33" cy="30" r="1.8" fill="#ffffff"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 625 B

+3 -3
View File
@@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<circle cx="24" cy="24" r="20" fill="#10b981"/> <circle cx="12" cy="12" r="9" fill="#10b981"/>
<path d="M 14 24 L 21 31 L 34 17" fill="none" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M 8 12 L 11 15 L 16 9" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 269 B

+1 -1
View File
@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M 6 6 L 18 18 M 18 6 L 6 18" fill="none" stroke="#64748b" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M 6 6 L 18 18 M 18 6 L 6 18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 228 B

After

Width:  |  Height:  |  Size: 231 B

+5 -11
View File
@@ -1,12 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha secundária --> <path d="M 13 3.5 H 5 C 4.4 3.5 4 3.9 4 4.5 V 20.5 C 4 21.1 4.4 21.5 5 21.5 H 17 C 17.6 21.5 18 21.1 18 20.5 V 13"
<path d="M 6 10 L 26 10 L 32 16 L 32 40 L 6 40 Z" fill="#ffffff" stroke="#1976d2" stroke-width="2.2" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<!-- Folha primária --> <path d="M 12 18 C 14 18 16 17 18 15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<path d="M 16 4 L 36 4 L 42 10 L 42 34 L 16 34 Z" fill="#e3f2fd" stroke="#0288d1" stroke-width="2.2" stroke-linejoin="round"/> <path d="M 18.5 3.5 L 21 6 L 14 13 L 11.5 13.5 L 12 11 Z" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linejoin="round"/>
<path d="M 36 4 L 36 10 L 42 10 Z" fill="#bbdefb" stroke="#0288d1" stroke-width="1.8"/>
<!-- Ícone de dois usuários / parceiros de assinatura -->
<circle cx="16" cy="24" r="4" fill="#0d47a1"/>
<path d="M 10 36 C 10 31 13 30 16 30 C 19 30 22 31 22 36 Z" fill="#0d47a1"/>
<circle cx="26" cy="22" r="3.5" fill="#0288d1"/>
<path d="M 21 34 C 21 30 24 29 26 29 C 29 29 32 30 32 34 Z" fill="#0288d1"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 815 B

After

Width:  |  Height:  |  Size: 546 B

+4 -4
View File
@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<circle cx="24" cy="24" r="20" fill="#ef4444"/> <circle cx="12" cy="12" r="9" fill="#ef4444"/>
<line x1="16" y1="16" x2="32" y2="32" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round"/> <line x1="8.5" y1="8.5" x2="15.5" y2="15.5" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/>
<line x1="32" y1="16" x2="16" y2="32" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round"/> <line x1="15.5" y1="8.5" x2="8.5" y2="15.5" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 343 B

After

Width:  |  Height:  |  Size: 350 B

+5 -7
View File
@@ -1,8 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Porta de saída / batente --> <path d="M 10 3.5 H 5.5 C 4.4 3.5 3.5 4.4 3.5 5.5 V 18.5 C 3.5 19.6 4.4 20.5 5.5 20.5 H 10"
<path d="M 24 8 L 12 8 C 9.8 8 8 9.8 8 12 L 8 36 C 8 38.2 9.8 40 12 40 L 24 40" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
fill="none" stroke="#546e7a" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/> <line x1="8.5" y1="12" x2="20.5" y2="12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/>
<!-- Seta vermelha apontando para fora --> <polyline points="16.5 8, 20.5 12, 16.5 16" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="18" y1="24" x2="40" y2="24" stroke="#d32f2f" stroke-width="3.2" stroke-linecap="round"/>
<polyline points="32 16, 40 24, 32 32" fill="none" stroke="#d32f2f" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 598 B

After

Width:  |  Height:  |  Size: 537 B

+6 -12
View File
@@ -1,13 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<!-- Dobra de canto --> <path d="M 14 3.5 V 8.5 H 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/> <line x1="8" y1="13" x2="15" y2="13" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<!-- Linhas de texto representativas --> <line x1="8" y1="17" x2="13" y2="17" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<line x1="14" y1="20" x2="34" y2="20" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<line x1="14" y1="26" x2="34" y2="26" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<!-- Caneta / Pena de assinatura eletrônica -->
<path d="M 16 38 L 30 24 L 35 29 L 21 43 L 14 44 Z" fill="#0288d1"/>
<path d="M 30 24 L 34 20 L 39 25 L 35 29 Z" fill="#01579b"/>
<circle cx="16" cy="42" r="1.5" fill="#ffffff"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 626 B

+5 -12
View File
@@ -1,13 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Janela de terminal / console --> <rect x="2.5" y="3.5" width="19" height="17" rx="3" fill="none" stroke="currentColor" stroke-width="2"/>
<rect x="4" y="6" width="40" height="36" rx="6" fill="#1e293b" stroke="#334155" stroke-width="2"/> <path d="M 6.5 8.5 L 9.5 11 L 6.5 13.5" fill="none" stroke="#0288d1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<!-- Barra de título do terminal com botões --> <line x1="11.5" y1="13.5" x2="16.5" y2="13.5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<circle cx="10" cy="12" r="2" fill="#ef4444"/> <line x1="6.5" y1="16.5" x2="14" y2="16.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.6"/>
<circle cx="16" cy="12" r="2" fill="#f59e0b"/>
<circle cx="22" cy="12" r="2" fill="#10b981"/>
<!-- Linha divisória -->
<line x1="4" y1="18" x2="44" y2="18" stroke="#334155" stroke-width="1.5"/>
<!-- Texto e prompt de código </> -->
<path d="M 12 24 L 18 29 L 12 34" fill="none" stroke="#38bdf8" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="22" y1="34" x2="32" y2="34" stroke="#94a3b8" stroke-width="2.5" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 811 B

After

Width:  |  Height:  |  Size: 572 B

+5 -10
View File
@@ -1,11 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
<path d="M 8 4 L 30 4 L 38 12 L 38 34 L 8 34 Z" fill="#ffffff" stroke="#00838f" stroke-width="2.5" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 30 4 L 30 12 L 38 12 Z" fill="#b2dfdb" stroke="#00838f" stroke-width="2"/> <circle cx="14" cy="15" r="4.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
<!-- Linhas no documento --> <polyline points="14 12.5, 14 15, 16 15" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round"/>
<line x1="14" y1="18" x2="30" y2="18" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<line x1="14" y1="24" x2="24" y2="24" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<!-- Selo LTV com fita de proteção permanente -->
<circle cx="32" cy="32" r="12" fill="#e0f2f1" stroke="#00897b" stroke-width="2.5"/>
<text x="32" y="36.5" font-family="Segoe UI, Arial, sans-serif" font-size="9" font-weight="bold" fill="#00695c" text-anchor="middle">LTV</text>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 861 B

After

Width:  |  Height:  |  Size: 507 B

+2 -5
View File
@@ -1,6 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Lua crescente ciano/índigo perfeitamente centrada em (24, 24) --> <path d="M 12 3 A 9 9 0 1 0 21 12 A 7.5 7.5 0 0 1 12 3 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 24 8 A 16 16 0 1 0 40 24 A 14 14 0 0 1 24 8 Z" fill="#38bdf8"/>
<circle cx="34" cy="14" r="1.8" fill="#818cf8"/>
<circle cx="38" cy="22" r="1.2" fill="#818cf8"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 344 B

After

Width:  |  Height:  |  Size: 251 B

+6 -12
View File
@@ -1,13 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#d32f2f" stroke-width="2.5" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<!-- Dobra de canto --> <path d="M 14 3.5 V 8.5 H 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#ffcdd2" stroke="#d32f2f" stroke-width="2" stroke-linejoin="round"/> <rect x="7" y="12" width="10" height="6" rx="1.5" fill="#ef4444"/>
<!-- Linhas de texto representativas --> <path d="M 9 14 H 10.5 C 11 14 11.5 14.3 11.5 14.8 C 11.5 15.3 11 15.6 10.5 15.6 H 9 V 17 M 9 15.6 H 10.5" stroke="#ffffff" stroke-width="1" stroke-linecap="round" fill="none"/>
<line x1="13" y1="18" x2="27" y2="18" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
<line x1="13" y1="22" x2="35" y2="22" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
<line x1="13" y1="26" x2="35" y2="26" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
<!-- Etiqueta vermelha com sigla PDF perfeitamente centralizada -->
<rect x="11" y="31" width="28" height="11" rx="3" fill="#d32f2f"/>
<text x="25" y="36.5" font-family="'Segoe UI', Arial, sans-serif" font-size="8.5px" font-weight="bold" fill="#ffffff" text-anchor="middle" dominant-baseline="central">PDF</text>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 665 B

+3 -3
View File
@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M 20 4 L 20 9 L 15 9" fill="none" stroke="#0284c7" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M 19 4 L 19 9 L 14 9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 4 20 L 4 15 L 9 15" fill="none" stroke="#0284c7" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M 5 20 L 5 15 L 10 15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 5.8 9 A 7 7 0 0 1 18.5 7.5 L 20 9 M 4 15 L 5.5 16.5 A 7 7 0 0 0 18.2 15" fill="none" stroke="#0284c7" stroke-width="2.2" stroke-linecap="round"/> <path d="M 6.3 8.7 A 8 8 0 0 1 18.5 7.5 L 19 9 M 5 15 L 5.5 16.5 A 8 8 0 0 0 17.7 15.3" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 510 B

After

Width:  |  Height:  |  Size: 524 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M 12 2.5 L 4.5 5.5 V 11 C 4.5 16 8 20 12 21.5 C 16 20 19.5 16 19.5 11 V 5.5 Z"
fill="none" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/>
<rect x="8.5" y="11" width="7" height="5.5" rx="1.2" fill="#0288d1"/>
<path d="M 10 11 V 8.5 C 10 7.4 10.9 6.5 12 6.5 C 13.1 6.5 14 7.4 14 8.5 V 11" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round"/>
<circle cx="12" cy="13.5" r="0.8" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 541 B

+4 -10
View File
@@ -1,11 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Fita pendente do selo --> <circle cx="12" cy="10" r="7.5" fill="none" stroke="#f59e0b" stroke-width="2"/>
<polygon points="18,30 24,44 30,30" fill="#f59e0b"/> <circle cx="12" cy="10" r="4.5" fill="none" stroke="#f59e0b" stroke-width="1.2" stroke-dasharray="2 1.5"/>
<polygon points="12,30 16,42 20,30" fill="#d97706"/> <path d="M 9.5 15.5 L 7 21.5 L 12 19 L 17 21.5 L 14.5 15.5" fill="none" stroke="#d97706" stroke-width="1.8" stroke-linejoin="round"/>
<polygon points="28,30 32,42 36,30" fill="#d97706"/>
<!-- Medalha / Selo circular -->
<circle cx="24" cy="20" r="16" fill="#d97706" stroke="#fbbf24" stroke-width="2.5"/>
<circle cx="24" cy="20" r="13" fill="none" stroke="#fbbf24" stroke-width="1.2" stroke-dasharray="2,2"/>
<!-- Estrela de 5 pontas central -->
<polygon points="24,9 26.5,16.5 34,16.5 28,21 30.5,28.5 24,24 17.5,28.5 20,21 14,16.5 21.5,16.5" fill="#ffffff"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 671 B

After

Width:  |  Height:  |  Size: 418 B

+4 -3
View File
@@ -1,4 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Engrenagem corporativa simétrica centrada em (24, 24) --> <circle cx="12" cy="12" r="3" fill="none" stroke="currentColor" stroke-width="2"/>
<path fill="#0288d1" fill-rule="evenodd" d="M 21.5 5 L 26.5 5 L 27.2 10.2 C 29 10.9 30.7 11.9 32.2 13.1 L 36.6 10.6 L 40.1 14.1 L 37.6 18.5 C 38.8 20 39.8 21.7 40.5 23.5 L 45.7 24.2 L 45.7 29.2 L 40.5 29.9 C 39.8 31.7 38.8 33.4 37.6 34.9 L 40.1 39.3 L 36.6 42.8 L 32.2 40.3 C 30.7 41.5 29 42.5 27.2 43.2 L 26.5 48.4 L 21.5 48.4 L 20.8 43.2 C 19 42.5 17.3 41.5 15.8 40.3 L 11.4 42.8 L 7.9 39.3 L 10.4 34.9 C 9.2 33.4 8.2 31.7 7.5 29.9 L 2.3 29.2 L 2.3 24.2 L 7.5 23.5 C 8.2 21.7 9.2 20 10.4 18.5 L 7.9 14.1 L 11.4 10.6 L 15.8 13.1 C 17.3 11.9 19 10.9 20.8 10.2 Z M 24 17.5 A 6.5 6.5 0 1 0 24 30.5 A 6.5 6.5 0 1 0 24 17.5 Z"/> <path d="M 10.7 2.5 L 13.3 2.5 L 13.7 4.8 C 14.4 5.1 15.1 5.5 15.8 6.1 L 17.9 5.2 L 19.8 7.1 L 18.9 9.2 C 19.4 9.9 19.8 10.6 20.1 11.3 L 22.5 11.7 L 22.5 14.3 L 20.1 14.7 C 19.8 15.4 19.4 16.1 18.9 16.8 L 19.8 18.9 L 17.9 20.8 L 15.8 19.9 C 15.1 20.5 14.4 20.9 13.7 21.2 L 13.3 23.5 L 10.7 23.5 L 10.3 21.2 C 9.6 20.9 8.9 20.5 8.2 19.9 L 6.1 20.8 L 4.2 18.9 L 5.1 16.8 C 4.6 16.1 4.2 15.4 3.9 14.7 L 1.5 14.3 L 1.5 11.7 L 3.9 11.3 C 4.2 10.6 4.6 9.9 5.1 9.2 L 4.2 7.1 L 6.1 5.2 L 8.2 6.1 C 8.9 5.5 9.6 5.1 10.3 4.8 Z"
fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 784 B

After

Width:  |  Height:  |  Size: 784 B

+4 -5
View File
@@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Escudo CyberShield --> <path d="M 12 2.5 L 4 5.5 V 11.5 C 4 16.5 7.5 21 12 22.5 C 16.5 21 20 16.5 20 11.5 V 5.5 Z"
<path d="M 24 4 L 8 11 L 8 24 C 8 34.5 15 42.5 24 45 C 33 42.5 40 34.5 40 24 L 40 11 Z" fill="#0284c7" stroke="#38bdf8" stroke-width="2.5" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<!-- Chave de segurança criptográfica no centro --> <path d="M 8.5 11.5 L 11 14 L 15.5 9.5" fill="none" stroke="#0288d1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 24 14 C 20.7 14 18 16.7 18 20 C 18 22.4 19.5 24.5 22 25.4 L 22 34 L 26 34 L 26 30 L 28 30 L 28 27 L 26 27 L 26 25.4 C 28.5 24.5 30 22.4 30 20 C 30 16.7 27.3 14 24 14 Z M 24 18 C 25.1 18 26 18.9 26 20 C 26 21.1 25.1 22 24 22 C 22.9 22 22 21.1 22 20 C 22 18.9 22.9 18 24 18 Z" fill="#ffffff"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 649 B

After

Width:  |  Height:  |  Size: 408 B

+3 -3
View File
@@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<polygon points="24,4 29.5,16.5 43,17.5 32.5,26.5 35.8,40 24,32.5 12.2,40 15.5,26.5 5,17.5 18.5,16.5" <polygon points="12,2.5 14.8,8.2 21.1,9.1 16.5,13.6 17.6,19.9 12,16.9 6.4,19.9 7.5,13.6 2.9,9.1 9.2,8.2"
fill="#f59e0b" stroke="#d97706" stroke-width="2" stroke-linejoin="round"/> fill="#f59e0b" stroke="#d97706" stroke-width="1.2" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 287 B

+10 -14
View File
@@ -1,15 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Núcleo solar brilhante --> <circle cx="12" cy="12" r="4.5" fill="none" stroke="currentColor" stroke-width="2"/>
<circle cx="24" cy="24" r="10" fill="#f59e0b"/> <line x1="12" y1="2" x2="12" y2="4.5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<!-- Raios solares --> <line x1="12" y1="19.5" x2="12" y2="22" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<g stroke="#f59e0b" stroke-width="3" stroke-linecap="round"> <line x1="2" y1="12" x2="4.5" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="24" y1="4" x2="24" y2="9"/> <line x1="19.5" y1="12" x2="22" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="24" y1="39" x2="24" y2="44"/> <line x1="4.9" y1="4.9" x2="6.7" y2="6.7" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="4" y1="24" x2="9" y2="24"/> <line x1="17.3" y1="17.3" x2="19.1" y2="19.1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="39" y1="24" x2="44" y2="24"/> <line x1="4.9" y1="19.1" x2="6.7" y2="17.3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="9.8" y1="9.8" x2="13.3" y2="13.3"/> <line x1="17.3" y1="6.7" x2="19.1" y2="4.9" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="34.7" y1="34.7" x2="38.2" y2="38.2"/>
<line x1="9.8" y1="38.2" x2="13.3" y2="34.7"/>
<line x1="34.7" y1="13.3" x2="38.2" y2="9.8"/>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 647 B

After

Width:  |  Height:  |  Size: 1.0 KiB

+4 -12
View File
@@ -1,13 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M 8 4 L 30 4 L 38 12 L 38 34 L 8 34 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/> <polyline points="12 7, 12 12, 16 14" fill="none" stroke="#0288d1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 30 4 L 30 12 L 38 12 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2"/> <line x1="12" y1="1" x2="12" y2="3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<!-- Linhas no documento -->
<line x1="14" y1="18" x2="30" y2="18" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<line x1="14" y1="24" x2="24" y2="24" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<!-- Relógio de precisão temporal TSA -->
<circle cx="32" cy="32" r="12" fill="#e1f5fe" stroke="#0288d1" stroke-width="2.5"/>
<circle cx="32" cy="32" r="2" fill="#01579b"/>
<line x1="32" y1="24" x2="32" y2="32" stroke="#01579b" stroke-width="2.5" stroke-linecap="round"/>
<line x1="32" y1="32" x2="38" y2="32" stroke="#01579b" stroke-width="2.5" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 413 B

+4 -7
View File
@@ -1,8 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Monitor de computador --> <path d="M 3 6.5 C 3 5 4.5 4 6 4 C 8.5 4 11 5.5 12 7 C 13 5.5 15.5 4 18 4 C 19.5 4 21 5 21 6.5 V 18 C 21 19 19.5 19.5 18 19.5 C 15.5 19.5 13 18 12 17 C 11 18 8.5 19.5 6 19.5 C 4.5 19.5 3 19 3 18 Z"
<rect x="4" y="6" width="40" height="28" rx="4" fill="#ffffff" stroke="#0288d1" stroke-width="2.5"/> fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/>
<!-- Base do monitor --> <line x1="12" y1="7" x2="12" y2="17" stroke="currentColor" stroke-width="1.8"/>
<path d="M 16 34 L 12 42 L 36 42 L 32 34" fill="none" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/>
<!-- Ícone de play/vídeo tutorial central -->
<polygon points="20,14 32,20 20,26" fill="#0288d1"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 461 B

+5 -9
View File
@@ -1,10 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Círculo de relógio base --> <circle cx="10" cy="10" r="7.5" fill="none" stroke="currentColor" stroke-width="2"/>
<circle cx="24" cy="24" r="20" fill="#f1f8e9" stroke="#558b2f" stroke-width="2.5"/> <polyline points="10 6, 10 10, 13 11" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<!-- Ponteiros do relógio --> <circle cx="16.5" cy="16.5" r="5" fill="none" stroke="#10b981" stroke-width="2"/>
<line x1="24" y1="12" x2="24" y2="24" stroke="#33691e" stroke-width="2" stroke-linecap="round"/> <polyline points="14.8 16.5, 16 17.7, 18.5 15.2" fill="none" stroke="#10b981" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="24" y1="24" x2="32" y2="24" stroke="#33691e" stroke-width="2" stroke-linecap="round"/>
<!-- Checkmark verde de validação de tempo -->
<circle cx="34" cy="34" r="10" fill="#2e7d32"/>
<path d="M 29 34 L 33 38 L 39 30" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 528 B

+5 -10
View File
@@ -1,11 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <path d="M 5 3.5 H 13 L 18 8.5 V 13" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/> <path d="M 5 3.5 V 20.5 H 10" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2"/> <circle cx="15.5" cy="16.5" r="5" fill="none" stroke="#10b981" stroke-width="2"/>
<!-- Linhas no documento --> <polyline points="13.8 16.5, 15 17.7, 17.5 15.2" fill="none" stroke="#10b981" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="14" y1="20" x2="34" y2="20" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<line x1="14" y1="26" x2="28" y2="26" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<!-- Emblema de validação com Checkmark verde -->
<circle cx="30" cy="34" r="11" fill="#e8f5e9" stroke="#2e7d32" stroke-width="2.5"/>
<path d="M 24 34 L 28 38 L 36 29" fill="none" stroke="#2e7d32" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 848 B

After

Width:  |  Height:  |  Size: 548 B

+7 -12
View File
@@ -1,13 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<!-- Dobra de canto --> <path d="M 14 3.5 V 8.5 H 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/> <path d="M 8.5 13 L 6.5 15 L 8.5 17" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
<!-- Linhas de texto representativas --> <path d="M 15.5 13 L 17.5 15 L 15.5 17" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="13" y1="18" x2="27" y2="18" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/> <line x1="13" y1="12.5" x2="11" y2="17.5" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round"/>
<line x1="13" y1="22" x2="35" y2="22" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
<line x1="13" y1="26" x2="35" y2="26" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
<!-- Etiqueta azul com sigla XML perfeitamente centralizada -->
<rect x="11" y="31" width="28" height="11" rx="3" fill="#0288d1"/>
<text x="25" y="36.5" font-family="'Segoe UI', Arial, sans-serif" font-size="8px" font-weight="bold" fill="#ffffff" text-anchor="middle" dominant-baseline="central">&lt;XML&gt;</text>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 796 B

+4 -1
View File
@@ -1,3 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M 4 9 L 4 4 L 9 4 M 15 4 L 20 4 L 20 9 M 20 15 L 20 20 L 15 20 M 9 20 L 4 20 L 4 15" fill="none" stroke="#0284c7" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M 4 8 L 4 4 L 8 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 16 4 L 20 4 L 20 8" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 4 16 L 4 20 L 8 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 16 20 L 20 20 L 20 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 284 B

After

Width:  |  Height:  |  Size: 623 B

+3 -3
View File
@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<circle cx="10" cy="10" r="7" fill="none" stroke="#0284c7" stroke-width="2.2"/> <circle cx="10.5" cy="10.5" r="6.5" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M 15 15 L 21 21" fill="none" stroke="#0284c7" stroke-width="2.5" stroke-linecap="round"/> <path d="M 15.5 15.5 L 20.5 20.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M 10 7 L 10 13 M 7 10 L 13 10" fill="none" stroke="#0284c7" stroke-width="2" stroke-linecap="round"/> <path d="M 10.5 7.5 L 10.5 13.5 M 7.5 10.5 L 13.5 10.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 387 B

After

Width:  |  Height:  |  Size: 428 B

+3 -3
View File
@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<circle cx="10" cy="10" r="7" fill="none" stroke="#0284c7" stroke-width="2.2"/> <circle cx="10.5" cy="10.5" r="6.5" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M 15 15 L 21 21" fill="none" stroke="#0284c7" stroke-width="2.5" stroke-linecap="round"/> <path d="M 15.5 15.5 L 20.5 20.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M 7 10 L 13 10" fill="none" stroke="#0284c7" stroke-width="2" stroke-linecap="round"/> <path d="M 7.5 10.5 L 13.5 10.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 372 B

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

+106
View File
@@ -0,0 +1,106 @@
# Sistema de Ícones — CyberCore Signer
Este documento estabelece as especificações de design, gramática visual, convenções de código e diretrizes de renderização do sistema de ícones do **CyberCore Signer**.
---
## 1. Gramática Visual e Grid Base
O sistema de ícones do CyberCore Signer foi projetado para oferecer clareza, consistência corporativa e alta fidelidade tanto no **Modo Claro** quanto no **Modo Escuro**, além de suporte a telas com alta densidade de pixels (HiDPI / Retina).
| Parâmetro | Especificação | Descrição |
| :--- | :--- | :--- |
| **ViewBox Canônico** | `0 0 24 24` | Todos os ícones são desenhados em um canvas quadrado padronizado de 24×24 pixels. |
| **Safe Area** | `2px` em todas as bordas | Os grafismos principais ficam contidos na área útil de `20×20px` (coordenadas de `2` a `22`). |
| **Stroke (Espessura)** | `1.75px` a `2.0px` | Traços consistentes entre todos os glifos vetoriais, proporcionando peso uniforme. |
| **Cantos e Terminações** | `round` | `stroke-linecap="round"` e `stroke-linejoin="round"` para um visual moderno e suave. |
| **Texto Embutido** | **Nenhum** (`Proibido`) | Ícones não devem incorporar elementos `<text>`. Toda semântica é transmitida por formas puras e labels da interface. |
---
## 2. Paleta de Cores e Tintas Semânticas
Os ícones utilizam `currentColor` como tinta principal, permitindo repintura dinâmica e herança das cores dos tokens do tema ativo:
| Papel | Token / Cor Modo Claro | Token / Cor Modo Escuro | Uso |
| :--- | :--- | :--- | :--- |
| **Tinta Principal (`currentColor`)** | `#1E293B` (`-fx-color-text`) | `#F1F5F9` (`-fx-color-text`) | Linhas de contorno, silhuetas e glifos primários. |
| **Acento Primário** | `#0288D1` (`-fx-color-primary`) | `#38BDF8` (`-fx-color-primary`) | Elementos de destaque, dobras de documentos, escudos. |
| **Sucesso** | `#10B981` (`-fx-color-success`) | `#34D399` (`-fx-color-success`) | Confirmações, validações concluídas (`check`, `validate`). |
| **Alerta / Atenção** | `#F59E0B` (`-fx-color-warning`) | `#FBBF24` (`-fx-color-warning`) | Avisos de validade próxima, selos e certificações (`seal`). |
| **Erro / Perigo** | `#EF4444` (`-fx-color-error`) | `#F87171` (`-fx-color-error`) | Ações destrutivas, falhas de assinatura (`error`, `exit`). |
| **Atenuado / Muted** | `#64748B` (`-fx-color-text-muted`) | `#94A3B8` (`-fx-color-text-muted`) | Guias internas, linhas secundárias, fechar (`close`). |
---
## 3. Escala de Tamanhos Padronizados
Para manter a consistência da interface, os ícones devem ser consumidos exclusivamente através dos 5 tamanhos canônicos definidos na fachada `Icons`:
```
16px 20px 24px 32px 40px
[ Micro ] [ Pequeno ] [ Padrão ] [ Médio ] [ Grande ]
```
- **`SIZE_16` (16×16 px):** Badges de status de certificado, botões auxiliares pequenos de janelas de diálogo (ex.: fechar, atualizar).
- **`SIZE_20` (20×20 px):** Menus secundários, botões de ação secundária, itens compactos em listas.
- **`SIZE_24` (24×24 px):** Tamanho padrão de componentes, botões de barra lateral do Hub, campos com ícone prefixado.
- **`SIZE_32` (32×32 px):** Cabeçalhos de diálogos de aprovação CCSP, títulos de assistentes.
- **`SIZE_40` (40×40 px):** Cartões e botões do painel principal (Hub de Ações Rápidas).
---
## 4. Catálogo dos Ícones Vetoriais
| Arquivo SVG | Glifo / Nome | Propósito e Uso na Aplicação |
| :--- | :--- | :--- |
| `pdf.svg` | `Icons.pdf()` | Assinatura de documentos PDF e fluxos PAdES. |
| `xml.svg` | `Icons.xml()` | Assinatura de documentos XML e notas fiscais (XMLDSig). |
| `file.svg` | `Icons.file()` | Assinatura de arquivos e digests genéricos. |
| `attached.svg` | `Icons.attached()` | Assinatura atachada / envelopada (CAdES Attached). |
| `batch.svg` | `Icons.batch()` | Assinatura de múltiplos documentos em lote. |
| `co-sign.svg` | `Icons.coSign()` | Adição de co-assinatura em documento já assinado. |
| `timestamp.svg` | `Icons.timestamp()` | Aplicação de carimbo do tempo (TSA). |
| `ltv.svg` | `Icons.ltv()` | Assinatura com validação de longo prazo (LTV). |
| `validate.svg` | `Icons.validate()` | Validador de integridade e assinaturas digitais. |
| `validate-timestamp.svg` | `Icons.validateTimestamp()` | Validador específico de carimbos de tempo. |
| `seal.svg` | `Icons.seal()` | Gerenciamento e aplicação de selos visuais. |
| `seal-icp-brasil.svg` | `Icons.sealIcpBrasil()` | Selo vetorial oficial padrão ICP-Brasil. |
| `cert.svg` | `Icons.certificates()` | Gerenciamento e seleção de certificados A1 e A3. |
| `shield.svg` | `Icons.shield()` | Segurança, proteção e integridade do agente. |
| `settings.svg` | `Icons.settings()` | Painel de configurações e preferências locais. |
| `logs.svg` | `Icons.logs()` | Visualizador de registros de auditoria e logs locais. |
| `tutorial.svg` | `Icons.tutorial()` | Guia interativo e tutorial de primeiros passos. |
| `about.svg` | `Icons.about()` | Diálogo sobre o CyberCore Signer, versão e licença. |
| `exit.svg` | `Icons.exit()` | Confirmação e encerramento do agente desktop. |
| `refresh.svg` | `Icons.refresh()` | Atualizar lista de certificados e recarregar dados. |
| `sun.svg` | `Icons.sun()` | Alternador para Modo Claro. |
| `moon.svg` | `Icons.moon()` | Alternador para Modo Escuro. |
| `arrow-right.svg` | `Icons.arrowRight()` | Navegação para próximo passo ou expansão. |
| `close.svg` | `Icons.close()` | Fechar diálogo, dispensar notificação ou cancelar. |
| `check.svg` | `Icons.check()` | Operação concluída com sucesso ou item selecionado. |
| `error.svg` | `Icons.error()` | Alerta de falha, cancelamento ou erro de hardware. |
| `star.svg` | `Icons.star()` | Certificado padrão ou favorito selecionado. |
| `zoom-in.svg` | `Icons.zoomIn()` | Aumentar zoom na visualização de documento ou selo. |
| `zoom-out.svg` | `Icons.zoomOut()` | Reduzir zoom na visualização de documento ou selo. |
| `zoom-fit.svg` | `Icons.zoomFit()` | Ajustar visualização à tela ou página inteira. |
---
## 5. Implementação Técnica
### Fachada `Icons`
A classe `br.com.cybercore.signer.ui.components.Icons` centraliza a instanciação:
```java
// Tamanho padrão (24px) com cor do tema ativo:
Node icon = Icons.settings();
// Tamanho específico:
Node refresh = Icons.refresh(Icons.SIZE_16);
// Tinta customizada:
Node custom = Icons.of("pdf", Icons.SIZE_40, Color.web("#0288D1"));
```
### Repintura Dinâmica
Ao registrar alteração de tema em `ThemeManager`, os nós de ícone baseados em `currentColor` recebem automaticamente o listener e atualizam suas cores em tempo real sem necessidade de recriar a janela.
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

+79
View File
@@ -0,0 +1,79 @@
# UI Troubleshooting & Resolução de Estilos (JavaFX CSS)
Este documento registra a investigação da causa raiz de problemas visuais na interface gráfica do CyberCore Signer, em especial a falha de renderização de textos escuros sobre fundo escuro no tema escuro.
---
## 1. O Problema: Texto Preto sobre Fundo Escuro (Contraste ~1.1:1)
### Sintoma
No tema escuro (`ThemeManager.AppTheme.DARK` / `.theme-dark`), determinados textos nos diálogos `ExitConfirmationDialog` (texto explicativo da ação), `PdfSignDialog` (nome e metadados do documento PDF selecionado, dica de arraste do selo visual) e `PdfCertificateSignDialog` (opção de memorização segura de PIN) eram renderizados com a cor preta (`#000000`) sobre um fundo escuro (`#090d16` ou `#111827`).
O contraste medido entre o texto e o fundo situava-se em aproximadamente **1.1:1 a 1.2:1**, violando completamente as diretrizes de acessibilidade WCAG AA (mínimo de 4.5:1 para texto normal) e tornando o texto praticamente invisível.
---
## 2. Investigação Técnica e Causa Raiz
### 2.1 Lookups Inexistentes no CSS
Ao inspecionar o código-fonte Java dessas telas, verificou-se o uso de estilos inline via `setStyle(...)`:
```java
subtitle.setStyle("-fx-text-fill: -fx-text-secondary; -fx-font-size: 12px;");
lblDocName.setStyle("-fx-font-weight: bold; -fx-font-size: 12.5px; -fx-text-fill: -fx-text-primary;");
lblDocMeta.setStyle("-fx-font-size: 11px; -fx-text-fill: -fx-text-secondary;");
previewBox.setStyle("-fx-background-color: -fx-bg-primary; -fx-border-color: -fx-border-light; ...");
chkRememberPin.setStyle("-fx-font-size: 11.5px; -fx-text-fill: -fx-text-primary;");
```
Os tokens `-fx-text-primary`, `-fx-text-secondary`, `-fx-bg-primary`, `-fx-border-light` e `-fx-accent` **não estavam declarados** no arquivo de folha de estilos `theme.css`.
### 2.2 Por que o JavaFX rebaixa para preto (`#000000`)?
No motor de estilização do JavaFX (`com.sun.javafx.css` / Modena):
1. Quando uma declaração inline em `setStyle(...)` utiliza uma cor de lookup (`-fx-text-fill: <variavel>`), o analisador CSS do JavaFX tenta resolver essa variável percorrendo os ancestrais do nó até o `.root` da cena.
2. Caso a variável **não seja encontrada**, o `StyleConverter` do JavaFX não lança exceção em tempo de execução. Em vez disso, seu mecanismo de tolerância a falhas adota o valor fallback padrão da especificação base de controles: **`Color.BLACK` (`rgba(0, 0, 0, 1.0)`)**.
3. Em um tema claro, o fundo é branco ou cinza claro (`#ffffff` / `#f1f5f9`), de modo que o texto preto parece ter funcionado por pura coincidência de luminância.
4. No tema escuro, no entanto, o fundo da aplicação é escuro (`#090d16` a `#111827`), fazendo com que o fallback para `#000000` destrua o contraste da interface.
### 2.3 Problemas Adicionais com `setStyle(...)`
- **Prioridade Forçada:** `setStyle(...)` tem especificidade de estilo inline (prioridade máxima), sobrescrevendo quaisquer regras de temas `.theme-light` e `.theme-dark` que tentem ajustar o elemento.
- **Acoplamento:** Espalha lógica visual e regras de cor pelo código Java, dificultando testes de regressão automatizados e auditorias de contraste.
---
## 3. Diretrizes e Solução Adotada
### 3.1 Definição Completa de Tokens e Aliases no `theme.css`
Todos os tokens semânticos e seus aliases de compatibilidade são declarados formalmente nos blocos canônicos de tokens:
```css
.theme-light {
-fx-text-primary: -fx-color-text;
-fx-text-secondary: -fx-color-text-muted;
-fx-bg-primary: -fx-color-surface;
-fx-border-light: -fx-color-border-subtle;
-fx-accent: -fx-color-primary;
}
.theme-dark {
-fx-text-primary: -fx-color-text;
-fx-text-secondary: -fx-color-text-muted;
-fx-bg-primary: -fx-color-surface;
-fx-border-light: -fx-color-border;
-fx-accent: -fx-color-primary;
}
```
### 3.2 Eliminação de Cores Inline
É terminantemente proibido utilizar `setStyle(...)` com propriedades que afetem cores:
- Proibidos em `setStyle`: `-fx-text-fill`, `-fx-background-color`, `-fx-border-color`, `-fx-fill`, `-fx-stroke` ou códigos `#hex`.
- Permitidos em `setStyle` exclusivamente quando estritamente necessário: geometria e layout (`-fx-min-width`, `-fx-pref-width`, `-fx-padding`).
Toda estilização cromática deve ser feita atribuindo classes semânticas:
- `.text-primary`: Texto principal com alta luminância no escuro e baixa no claro.
- `.text-secondary`, `.text-muted`: Texto secundário / auxiliar com contraste garantido >= 4.5:1.
- `.text-accent`: Destaque com a cor primária da marca.
- `.surface-box`, `.toolbar-box`: Caixas de superfície neutra e barras de ferramentas.
### 3.3 Testes Automatizados de Guarda-Corpo
O projeto mantém testes unitários automatizados em `DesignTokenGuardrailTest` e `CssColorAndContrastGuardrailTest` que:
1. Fazem varredura estática de todo o código Java da UI para reprovar qualquer `setStyle` que declare cor ou hexadecimal.
2. Validam matematicamente a fórmula de luminância relativa WCAG 2.1 para cada par texto/fundo nos dois temas, garantindo conformidade rigorosa.
@@ -95,6 +95,10 @@ public class CyberCoreDesktopApplication extends Application {
developmentMode = devMode; developmentMode = devMode;
} }
public static boolean isDevelopmentMode() {
return developmentMode;
}
public static MainAppView getMainAppView() { public static MainAppView getMainAppView() {
return mainAppView; return mainAppView;
} }
@@ -224,7 +228,7 @@ public class CyberCoreDesktopApplication extends Application {
ScrollPane scrollPane = new ScrollPane(settingsView); ScrollPane scrollPane = new ScrollPane(settingsView);
scrollPane.setFitToWidth(true); scrollPane.setFitToWidth(true);
scrollPane.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); scrollPane.getStyleClass().add("scroll-transparent");
VBox.setVgrow(scrollPane, Priority.ALWAYS); VBox.setVgrow(scrollPane, Priority.ALWAYS);
Button btnClose = new Button(" Fechar", SvgIcons.closeIcon(13)); Button btnClose = new Button(" Fechar", SvgIcons.closeIcon(13));
@@ -39,14 +39,15 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import br.com.cybercore.signer.ui.CyberCoreDesktopApplication;
import br.com.cybercore.signer.ui.theme.ThemeManager;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* Gerenciador centralizado de recursos visuais (ícones e imagens). * Gerenciador centralizado de recursos visuais (ícones e imagens).
* Permite que o usuário customize ou substitua facilmente qualquer ícone ou imagem (SVG/PNG) * Centraliza o carregamento de recursos do classpath em produção e permite
* do CyberCore Signer simplesmente colocando os arquivos na pasta 'assets/' * substituição via pasta externa 'assets/' exclusivamente em modo de desenvolvimento.
* na raiz do projeto ou no diretório ~/.cybercore/assets/.
*/ */
public final class AssetManager { public final class AssetManager {
@@ -54,9 +55,33 @@ public final class AssetManager {
private static final String[] RASTER_EXTENSIONS = {".png", ".jpg", ".jpeg"}; private static final String[] RASTER_EXTENSIONS = {".png", ".jpg", ".jpeg"};
private static volatile Boolean externalOverridesOverride = null;
private AssetManager() { private AssetManager() {
} }
/**
* Define explicitamente se o carregamento de assets externos está habilitado (útil para testes).
*/
public static void setExternalOverridesEnabled(Boolean enabled) {
externalOverridesOverride = enabled;
}
/**
* Indica se o carregamento de assets externos (./assets ou ~/.cybercore/assets) é permitido.
* Em ambiente de produção, este método retorna false por padrão para garantir
* integridade e isolamento estrito de recursos empacotados.
*/
public static boolean isExternalOverridesAllowed() {
if (externalOverridesOverride != null) {
return externalOverridesOverride;
}
if (CyberCoreDesktopApplication.isDevelopmentMode()) {
return true;
}
return Boolean.getBoolean("cybercore.dev") || Boolean.getBoolean("cybercore.assets.external");
}
/** /**
* Retorna o caminho do diretório externo prioritário de assets. * Retorna o caminho do diretório externo prioritário de assets.
*/ */
@@ -81,31 +106,33 @@ public final class AssetManager {
String cleanName = cleanBaseName(baseName); String cleanName = cleanBaseName(baseName);
// 1. Procura no diretório local ./assets/{category}/ if (isExternalOverridesAllowed()) {
Path localDir = Path.of("assets", category); // 1. Procura no diretório local ./assets/{category}/
for (String ext : RASTER_EXTENSIONS) { Path localDir = Path.of("assets", category);
Path file = localDir.resolve(cleanName + ext); for (String ext : RASTER_EXTENSIONS) {
if (Files.isRegularFile(file)) { Path file = localDir.resolve(cleanName + ext);
try (InputStream in = new FileInputStream(file.toFile())) { if (Files.isRegularFile(file)) {
logger.debug("Carregando imagem bitmap do diretório local: {}", file); try (InputStream in = new FileInputStream(file.toFile())) {
return Optional.of(new Image(in, width, height, true, true)); logger.debug("Carregando imagem bitmap do diretório local: {}", file);
} catch (Exception e) { return Optional.of(new Image(in, width, height, true, true));
logger.warn("Falha ao ler imagem customizada {}: {}", file, e.getMessage()); } catch (Exception e) {
logger.warn("Falha ao ler imagem customizada {}: {}", file, e.getMessage());
}
} }
} }
}
// 2. Procura em ~/.cybercore/assets/{category}/ // 2. Procura em ~/.cybercore/assets/{category}/
String userHome = System.getProperty("user.home", "."); String userHome = System.getProperty("user.home", ".");
Path userDir = Path.of(userHome, ".cybercore", "assets", category); Path userDir = Path.of(userHome, ".cybercore", "assets", category);
for (String ext : RASTER_EXTENSIONS) { for (String ext : RASTER_EXTENSIONS) {
Path file = userDir.resolve(cleanName + ext); Path file = userDir.resolve(cleanName + ext);
if (Files.isRegularFile(file)) { if (Files.isRegularFile(file)) {
try (InputStream in = new FileInputStream(file.toFile())) { try (InputStream in = new FileInputStream(file.toFile())) {
logger.debug("Carregando imagem bitmap de ~/.cybercore: {}", file); logger.debug("Carregando imagem bitmap de ~/.cybercore: {}", file);
return Optional.of(new Image(in, width, height, true, true)); return Optional.of(new Image(in, width, height, true, true));
} catch (Exception e) { } catch (Exception e) {
logger.warn("Falha ao ler imagem do usuário {}: {}", file, e.getMessage()); logger.warn("Falha ao ler imagem do usuário {}: {}", file, e.getMessage());
}
} }
} }
} }
@@ -130,20 +157,29 @@ public final class AssetManager {
* Retorna um Node de ícone customizado (prioritariamente SVG, com fallback para PNG ou supplier vetorial). * Retorna um Node de ícone customizado (prioritariamente SVG, com fallback para PNG ou supplier vetorial).
*/ */
public static Node getIconOrDefault(String iconName, double size, Supplier<Node> fallbackSupplier) { public static Node getIconOrDefault(String iconName, double size, Supplier<Node> fallbackSupplier) {
return getIconOrDefault(iconName, size, null, fallbackSupplier);
}
/**
* Retorna um Node de ícone customizado com suporte a repintura ou tinta explícita.
*/
public static Node getIconOrDefault(String iconName, double size, Color tint, Supplier<Node> fallbackSupplier) {
if (iconName != null && !iconName.isBlank()) { if (iconName != null && !iconName.isBlank()) {
String cleanName = cleanBaseName(iconName); String cleanName = cleanBaseName(iconName);
// 1. Prioridade para SVG em ./assets/icons/ if (isExternalOverridesAllowed()) {
Optional<Node> localSvg = loadSvgIconFromPath(Path.of("assets", "icons", cleanName + ".svg"), size); // 1. Prioridade para SVG em ./assets/icons/
if (localSvg.isPresent()) { Optional<Node> localSvg = loadSvgIconFromPath(Path.of("assets", "icons", cleanName + ".svg"), size, tint);
return localSvg.get(); if (localSvg.isPresent()) {
} return localSvg.get();
}
// 2. Procura SVG em ~/.cybercore/assets/icons/ // 2. Procura SVG em ~/.cybercore/assets/icons/
String userHome = System.getProperty("user.home", "."); String userHome = System.getProperty("user.home", ".");
Optional<Node> userSvg = loadSvgIconFromPath(Path.of(userHome, ".cybercore", "assets", "icons", cleanName + ".svg"), size); Optional<Node> userSvg = loadSvgIconFromPath(Path.of(userHome, ".cybercore", "assets", "icons", cleanName + ".svg"), size, tint);
if (userSvg.isPresent()) { if (userSvg.isPresent()) {
return userSvg.get(); return userSvg.get();
}
} }
// 3. Procura SVG no Classpath interno // 3. Procura SVG no Classpath interno
@@ -151,7 +187,7 @@ public final class AssetManager {
InputStream resStream = AssetManager.class.getResourceAsStream(resSvgPath); InputStream resStream = AssetManager.class.getResourceAsStream(resSvgPath);
if (resStream != null) { if (resStream != null) {
try (resStream) { try (resStream) {
Node node = parseSvgToNode(resStream, size, size); Node node = parseSvgToNode(resStream, size, size, tint);
if (node != null) { if (node != null) {
return node; return node;
} }
@@ -180,32 +216,34 @@ public final class AssetManager {
if (imageName != null && !imageName.isBlank()) { if (imageName != null && !imageName.isBlank()) {
String cleanName = cleanBaseName(imageName); String cleanName = cleanBaseName(imageName);
// 1. Prioridade para SVG em ./assets/images/ if (isExternalOverridesAllowed()) {
Path localSvg = Path.of("assets", "images", cleanName + ".svg"); // 1. Prioridade para SVG em ./assets/images/
if (Files.isRegularFile(localSvg)) { Path localSvg = Path.of("assets", "images", cleanName + ".svg");
try (InputStream in = new FileInputStream(localSvg.toFile())) { if (Files.isRegularFile(localSvg)) {
Node node = parseSvgToNode(in, width, height); try (InputStream in = new FileInputStream(localSvg.toFile())) {
if (node != null) { Node node = parseSvgToNode(in, width, height, null);
logger.debug("Carregada imagem SVG local: {}", localSvg); if (node != null) {
return node; logger.debug("Carregada imagem SVG local: {}", localSvg);
return node;
}
} catch (Exception e) {
logger.warn("Falha ao ler imagem SVG local {}: {}", localSvg, e.getMessage());
} }
} catch (Exception e) {
logger.warn("Falha ao ler imagem SVG local {}: {}", localSvg, e.getMessage());
} }
}
// 2. Procura SVG em ~/.cybercore/assets/images/ // 2. Procura SVG em ~/.cybercore/assets/images/
String userHome = System.getProperty("user.home", "."); String userHome = System.getProperty("user.home", ".");
Path userSvg = Path.of(userHome, ".cybercore", "assets", "images", cleanName + ".svg"); Path userSvg = Path.of(userHome, ".cybercore", "assets", "images", cleanName + ".svg");
if (Files.isRegularFile(userSvg)) { if (Files.isRegularFile(userSvg)) {
try (InputStream in = new FileInputStream(userSvg.toFile())) { try (InputStream in = new FileInputStream(userSvg.toFile())) {
Node node = parseSvgToNode(in, width, height); Node node = parseSvgToNode(in, width, height, null);
if (node != null) { if (node != null) {
logger.debug("Carregada imagem SVG do usuário: {}", userSvg); logger.debug("Carregada imagem SVG do usuário: {}", userSvg);
return node; return node;
}
} catch (Exception e) {
logger.warn("Falha ao ler imagem SVG do usuário {}: {}", userSvg, e.getMessage());
} }
} catch (Exception e) {
logger.warn("Falha ao ler imagem SVG do usuário {}: {}", userSvg, e.getMessage());
} }
} }
@@ -214,7 +252,7 @@ public final class AssetManager {
InputStream resStream = AssetManager.class.getResourceAsStream(resPath); InputStream resStream = AssetManager.class.getResourceAsStream(resPath);
if (resStream != null) { if (resStream != null) {
try (resStream) { try (resStream) {
Node node = parseSvgToNode(resStream, width, height); Node node = parseSvgToNode(resStream, width, height, null);
if (node != null) { if (node != null) {
return node; return node;
} }
@@ -244,6 +282,59 @@ public final class AssetManager {
return getImageOrDefault("app-logo", width, height, fallbackSupplier); return getImageOrDefault("app-logo", width, height, fallbackSupplier);
} }
private static final int[] ICON_SIZES = {16, 24, 32, 48, 64, 128, 256};
/**
* Retorna a lista de imagens multi-resolução do ícone da aplicação
* para configuração do Stage JavaFX principal (16, 24, 32, 48, 64, 128, 256 px).
*/
public static List<Image> getApplicationIcons() {
List<Image> icons = new ArrayList<>();
for (int size : ICON_SIZES) {
String path = "/assets/images/app-icon-" + size + ".png";
InputStream in = AssetManager.class.getResourceAsStream(path);
if (in != null) {
try (in) {
icons.add(new Image(in));
} catch (Exception e) {
logger.debug("Falha ao carregar ícone {}: {}", path, e.getMessage());
}
} else {
InputStream fallback = AssetManager.class.getResourceAsStream("/assets/images/app-icon.png");
if (fallback != null) {
try (fallback) {
icons.add(new Image(fallback, size, size, true, true));
} catch (Exception ignored) {
}
}
}
}
return icons;
}
/**
* Carrega a imagem da bandeja do sistema nativa (AWT TrayIcon) em alta fidelidade.
*/
public static java.awt.Image getTrayIconImage() {
String[] preferredPaths = {
"/assets/images/app-icon-32.png",
"/assets/images/app-icon-16.png",
"/assets/images/app-icon.png"
};
for (String path : preferredPaths) {
InputStream in = AssetManager.class.getResourceAsStream(path);
if (in != null) {
try (in) {
return javax.imageio.ImageIO.read(in);
} catch (Exception e) {
logger.debug("Falha ao ler recurso AWT {}: {}", path, e.getMessage());
}
}
}
return null;
}
private static String cleanBaseName(String name) { private static String cleanBaseName(String name) {
String clean = name; String clean = name;
int dotIdx = clean.lastIndexOf('.'); int dotIdx = clean.lastIndexOf('.');
@@ -253,10 +344,10 @@ public final class AssetManager {
return clean; return clean;
} }
private static Optional<Node> loadSvgIconFromPath(Path path, double size) { private static Optional<Node> loadSvgIconFromPath(Path path, double size, Color tint) {
if (Files.isRegularFile(path)) { if (Files.isRegularFile(path)) {
try (InputStream in = new FileInputStream(path.toFile())) { try (InputStream in = new FileInputStream(path.toFile())) {
Node node = parseSvgToNode(in, size, size); Node node = parseSvgToNode(in, size, size, tint);
if (node != null) { if (node != null) {
logger.debug("Carregado ícone SVG customizado de: {}", path); logger.debug("Carregado ícone SVG customizado de: {}", path);
return Optional.of(node); return Optional.of(node);
@@ -272,13 +363,18 @@ public final class AssetManager {
* Parser analítico de SVG para nós gráficos JavaFX com suporte a dimensões quadradas. * Parser analítico de SVG para nós gráficos JavaFX com suporte a dimensões quadradas.
*/ */
public static Node parseSvgToNode(InputStream in, double targetSize) { public static Node parseSvgToNode(InputStream in, double targetSize) {
return parseSvgToNode(in, targetSize, targetSize); return parseSvgToNode(in, targetSize, targetSize, null);
}
public static Node parseSvgToNode(InputStream in, double targetSize, Color tint) {
return parseSvgToNode(in, targetSize, targetSize, tint);
} }
/**
* Parser analítico completo de SVG para nós gráficos JavaFX com dimensões proporcionais e suporte a defs/gradientes.
*/
public static Node parseSvgToNode(InputStream in, double targetWidth, double targetHeight) { public static Node parseSvgToNode(InputStream in, double targetWidth, double targetHeight) {
return parseSvgToNode(in, targetWidth, targetHeight, null);
}
public static Node parseSvgToNode(InputStream in, double targetWidth, double targetHeight, Color tint) {
try { try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(false); dbf.setNamespaceAware(false);
@@ -326,8 +422,14 @@ public final class AssetManager {
Map<String, Paint> defsMap = new HashMap<>(); Map<String, Paint> defsMap = new HashMap<>();
parseDefs(svg, defsMap); parseDefs(svg, defsMap);
Color effectiveCurrentColor = (tint != null) ? tint :
(ThemeManager.isDark() ? Color.web("#F1F5F9") : Color.web("#1E293B"));
List<Shape> dynamicStrokeShapes = new ArrayList<>();
List<Shape> dynamicFillShapes = new ArrayList<>();
RenderContext ctx = new RenderContext(defsMap, effectiveCurrentColor, dynamicStrokeShapes, dynamicFillShapes);
Group contentGroup = new Group(); Group contentGroup = new Group();
renderChildren(svg, contentGroup, defsMap); renderChildren(svg, contentGroup, ctx);
double scaleX = targetWidth / vbWidth; double scaleX = targetWidth / vbWidth;
double scaleY = targetHeight / vbHeight; double scaleY = targetHeight / vbHeight;
@@ -348,9 +450,24 @@ public final class AssetManager {
); );
Pane container = new Pane(contentGroup); Pane container = new Pane(contentGroup);
container.getStyleClass().add("cyber-icon");
container.setPrefSize(targetWidth, targetHeight); container.setPrefSize(targetWidth, targetHeight);
container.setMaxSize(targetWidth, targetHeight); container.setMaxSize(targetWidth, targetHeight);
container.setMinSize(targetWidth, targetHeight); container.setMinSize(targetWidth, targetHeight);
// Se for dinâmico (sem tint fixo) e contiver elementos currentColor, atualiza com a mudança de tema
if (tint == null && (!dynamicStrokeShapes.isEmpty() || !dynamicFillShapes.isEmpty())) {
ThemeManager.addListener(theme -> {
Color c = (theme == ThemeManager.AppTheme.DARK) ? Color.web("#F1F5F9") : Color.web("#1E293B");
for (Shape s : dynamicStrokeShapes) {
s.setStroke(c);
}
for (Shape s : dynamicFillShapes) {
s.setFill(c);
}
});
}
return container; return container;
} catch (Exception e) { } catch (Exception e) {
@@ -444,7 +561,14 @@ public final class AssetManager {
} }
} }
private static void renderChildren(Element parent, Group targetGroup, Map<String, Paint> defsMap) { private record RenderContext(
Map<String, Paint> defsMap,
Color currentColor,
List<Shape> dynamicStrokeShapes,
List<Shape> dynamicFillShapes
) {}
private static void renderChildren(Element parent, Group targetGroup, RenderContext ctx) {
NodeList children = parent.getChildNodes(); NodeList children = parent.getChildNodes();
for (int i = 0; i < children.getLength(); i++) { for (int i = 0; i < children.getLength(); i++) {
org.w3c.dom.Node n = children.item(i); org.w3c.dom.Node n = children.item(i);
@@ -452,7 +576,7 @@ public final class AssetManager {
if ("defs".equalsIgnoreCase(el.getTagName())) { if ("defs".equalsIgnoreCase(el.getTagName())) {
continue; continue;
} }
Node jfxNode = createElementNode(el, defsMap); Node jfxNode = createElementNode(el, ctx);
if (jfxNode != null) { if (jfxNode != null) {
targetGroup.getChildren().add(jfxNode); targetGroup.getChildren().add(jfxNode);
} }
@@ -460,7 +584,7 @@ public final class AssetManager {
} }
} }
private static Node createElementNode(Element el, Map<String, Paint> defsMap) { private static Node createElementNode(Element el, RenderContext ctx) {
String tagName = el.getTagName().toLowerCase(); String tagName = el.getTagName().toLowerCase();
Shape shape = null; Shape shape = null;
@@ -527,7 +651,7 @@ public final class AssetManager {
Map<String, String> inlineStyle = el.hasAttribute("style") ? parseStyleAttribute(el.getAttribute("style")) : Map.of(); Map<String, String> inlineStyle = el.hasAttribute("style") ? parseStyleAttribute(el.getAttribute("style")) : Map.of();
String fillVal = inlineStyle.getOrDefault("fill", el.hasAttribute("fill") ? el.getAttribute("fill") : null); String fillVal = inlineStyle.getOrDefault("fill", el.hasAttribute("fill") ? el.getAttribute("fill") : null);
if (fillVal != null) { if (fillVal != null) {
t.setFill(parsePaint(fillVal, defsMap, Color.BLACK)); t.setFill(parsePaint(fillVal, ctx, Color.BLACK));
} }
String anchor = inlineStyle.getOrDefault("text-anchor", el.getAttribute("text-anchor")); String anchor = inlineStyle.getOrDefault("text-anchor", el.getAttribute("text-anchor"));
@@ -555,9 +679,9 @@ public final class AssetManager {
} }
case "g" -> { case "g" -> {
Group g = new Group(); Group g = new Group();
renderChildren(el, g, defsMap); renderChildren(el, g, ctx);
if (el.hasAttribute("stroke")) { if (el.hasAttribute("stroke")) {
Paint strokePaint = parsePaint(el.getAttribute("stroke"), defsMap, null); Paint strokePaint = parsePaint(el.getAttribute("stroke"), ctx, null);
double sw = parseDouble(el.getAttribute("stroke-width"), 1.0); double sw = parseDouble(el.getAttribute("stroke-width"), 1.0);
for (Node child : g.getChildren()) { for (Node child : g.getChildren()) {
if (child instanceof Shape s) { if (child instanceof Shape s) {
@@ -572,7 +696,8 @@ public final class AssetManager {
} }
if (shape != null) { if (shape != null) {
applyShapeStyles(el, shape, defsMap); shape.getStyleClass().add("cyber-icon-glyph");
applyShapeStyles(el, shape, ctx);
applyElementTransform(el, shape); applyElementTransform(el, shape);
return shape; return shape;
} }
@@ -597,19 +722,25 @@ public final class AssetManager {
return styleMap; return styleMap;
} }
private static void applyShapeStyles(Element el, Shape shape, Map<String, Paint> defsMap) { private static void applyShapeStyles(Element el, Shape shape, RenderContext ctx) {
Map<String, String> inlineStyle = el.hasAttribute("style") ? parseStyleAttribute(el.getAttribute("style")) : Map.of(); Map<String, String> inlineStyle = el.hasAttribute("style") ? parseStyleAttribute(el.getAttribute("style")) : Map.of();
String fillVal = inlineStyle.getOrDefault("fill", el.hasAttribute("fill") ? el.getAttribute("fill") : null); String fillVal = inlineStyle.getOrDefault("fill", el.hasAttribute("fill") ? el.getAttribute("fill") : null);
if (fillVal != null) { if (fillVal != null) {
shape.setFill(parsePaint(fillVal, defsMap, Color.TRANSPARENT)); if ("currentColor".equalsIgnoreCase(fillVal.trim()) && ctx != null) {
ctx.dynamicFillShapes().add(shape);
}
shape.setFill(parsePaint(fillVal, ctx, Color.TRANSPARENT));
} else if (shape instanceof Line) { } else if (shape instanceof Line) {
shape.setFill(Color.TRANSPARENT); shape.setFill(Color.TRANSPARENT);
} }
String strokeVal = inlineStyle.getOrDefault("stroke", el.hasAttribute("stroke") ? el.getAttribute("stroke") : null); String strokeVal = inlineStyle.getOrDefault("stroke", el.hasAttribute("stroke") ? el.getAttribute("stroke") : null);
if (strokeVal != null) { if (strokeVal != null) {
shape.setStroke(parsePaint(strokeVal, defsMap, Color.TRANSPARENT)); if ("currentColor".equalsIgnoreCase(strokeVal.trim()) && ctx != null) {
ctx.dynamicStrokeShapes().add(shape);
}
shape.setStroke(parsePaint(strokeVal, ctx, Color.TRANSPARENT));
} }
String strokeWidthVal = inlineStyle.getOrDefault("stroke-width", el.hasAttribute("stroke-width") ? el.getAttribute("stroke-width") : null); String strokeWidthVal = inlineStyle.getOrDefault("stroke-width", el.hasAttribute("stroke-width") ? el.getAttribute("stroke-width") : null);
@@ -629,20 +760,20 @@ public final class AssetManager {
} }
} }
private static Paint parsePaint(String str, Map<String, Paint> defsMap, Paint fallback) { private static Paint parsePaint(String str, RenderContext ctx, Paint fallback) {
if (str == null || str.isBlank() || "none".equalsIgnoreCase(str)) { if (str == null || str.isBlank() || "none".equalsIgnoreCase(str)) {
return Color.TRANSPARENT; return Color.TRANSPARENT;
} }
String trimmed = str.trim(); String trimmed = str.trim();
if (trimmed.startsWith("url(#") && trimmed.endsWith(")")) { if (trimmed.startsWith("url(#") && trimmed.endsWith(")")) {
String id = trimmed.substring(5, trimmed.length() - 1).trim(); String id = trimmed.substring(5, trimmed.length() - 1).trim();
Paint defPaint = defsMap.get(id); Paint defPaint = ctx != null && ctx.defsMap() != null ? ctx.defsMap().get(id) : null;
if (defPaint != null) { if (defPaint != null) {
return defPaint; return defPaint;
} }
return Color.web("#0288d1"); return Color.web("#0288d1");
} }
return parseColor(trimmed, fallback instanceof Color ? (Color) fallback : Color.BLACK); return parseColor(trimmed, fallback instanceof Color ? (Color) fallback : Color.BLACK, ctx);
} }
private static void parsePoints(String ptsStr, java.util.List<Double> pointsList) { private static void parsePoints(String ptsStr, java.util.List<Double> pointsList) {
@@ -658,12 +789,19 @@ public final class AssetManager {
} }
private static Color parseColor(String str, Color fallback) { private static Color parseColor(String str, Color fallback) {
return parseColor(str, fallback, null);
}
private static Color parseColor(String str, Color fallback, RenderContext ctx) {
if (str == null || str.isBlank() || "none".equalsIgnoreCase(str)) { if (str == null || str.isBlank() || "none".equalsIgnoreCase(str)) {
return Color.TRANSPARENT; return Color.TRANSPARENT;
} }
String trimmed = str.trim(); String trimmed = str.trim();
if ("currentColor".equalsIgnoreCase(trimmed)) { if ("currentColor".equalsIgnoreCase(trimmed)) {
return Color.web("#0288d1"); if (ctx != null && ctx.currentColor() != null) {
return ctx.currentColor();
}
return ThemeManager.isDark() ? Color.web("#F1F5F9") : Color.web("#1E293B");
} }
try { try {
return Color.web(trimmed); return Color.web(trimmed);
@@ -3,6 +3,7 @@ package br.com.cybercore.signer.ui.components;
import br.com.cybercore.signer.core.domain.CertificateStatus; import br.com.cybercore.signer.core.domain.CertificateStatus;
import br.com.cybercore.signer.core.domain.CertificateType; import br.com.cybercore.signer.core.domain.CertificateType;
import br.com.cybercore.signer.core.domain.ManagedCertificate; import br.com.cybercore.signer.core.domain.ManagedCertificate;
import javafx.scene.Node;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@@ -34,24 +35,31 @@ public final class CertificateCardNode extends VBox {
setCursor(javafx.scene.Cursor.HAND); setCursor(javafx.scene.Cursor.HAND);
setSpacing(8); setSpacing(8);
// Linha 1: Nome do Titular e Badge A1/A3 // Linha 1: Ícone + Nome do Titular e Badge A1/A3
HBox topRow = new HBox(10); HBox topRow = new HBox(10);
topRow.setAlignment(Pos.CENTER_LEFT); topRow.setAlignment(Pos.CENTER_LEFT);
Node certIcon = Icons.certificates(Icons.SIZE_20);
String rawName = certificate.commonName() != null ? certificate.commonName() : certificate.alias(); String rawName = certificate.commonName() != null ? certificate.commonName() : certificate.alias();
String cleanTitle = rawName != null && rawName.contains(":") ? rawName.split(":")[0].trim() : (rawName != null ? rawName.trim() : "Certificado Digital"); String cleanTitle = rawName != null && rawName.contains(":") ? rawName.split(":")[0].trim() : (rawName != null ? rawName.trim() : "Certificado Digital");
Label titleLabel = new Label(cleanTitle); Label titleLabel = new Label(cleanTitle);
titleLabel.getStyleClass().add("cert-title"); titleLabel.getStyleClass().add("cert-title");
HBox.setHgrow(titleLabel, Priority.ALWAYS); HBox.setHgrow(titleLabel, Priority.ALWAYS);
Label badgeLabel = new Label("[" + certificate.type().getCode() + "]"); HBox titleBox = new HBox(8, certIcon, titleLabel);
titleBox.setAlignment(Pos.CENTER_LEFT);
HBox.setHgrow(titleBox, Priority.ALWAYS);
String badgeText = certificate.type() == CertificateType.A1 ? "A1 • SOFTWARE" : "A3 • TOKEN";
Label badgeLabel = new Label(badgeText);
if (certificate.type() == CertificateType.A1) { if (certificate.type() == CertificateType.A1) {
badgeLabel.getStyleClass().add("cert-badge-a1"); badgeLabel.getStyleClass().add("cert-badge-a1");
} else { } else {
badgeLabel.getStyleClass().add("cert-badge-a3"); badgeLabel.getStyleClass().add("cert-badge-a3");
} }
topRow.getChildren().addAll(titleLabel, badgeLabel); topRow.getChildren().addAll(titleBox, badgeLabel);
// Linha 2: Documento (CPF / CNPJ) e Emissor // Linha 2: Documento (CPF / CNPJ) e Emissor
HBox midRow = new HBox(12); HBox midRow = new HBox(12);
@@ -0,0 +1,165 @@
package br.com.cybercore.signer.ui.components;
import br.com.cybercore.signer.ui.assets.AssetManager;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import java.util.function.Supplier;
/**
* Fachada centralizada e moderna para obtenção de ícones vetoriais padronizados no CyberCore Signer.
* <p>
* Segue a gramática visual estipulada em {@code docs/icon-system.md}:
* grid canônico de 24x24 px, safe area de 2px, stroke 1.75-2.0px, sem textos embutidos
* e repintura dinâmica orientada a temas (currentColor).
*/
public final class Icons {
/** Tamanho micro (16x16 px) para badges, tags e botões compactos. */
public static final int SIZE_16 = 16;
/** Tamanho pequeno (20x20 px) para botões auxiliares e itens compactos. */
public static final int SIZE_20 = 20;
/** Tamanho padrão canônico (24x24 px) para botões de diálogo e barra lateral. */
public static final int SIZE_24 = 24;
/** Tamanho médio (32x32 px) para cabeçalhos e diálogos de aprovação CCSP. */
public static final int SIZE_32 = 32;
/** Tamanho grande (40x40 px) para cards e botões do painel principal (Hub). */
public static final int SIZE_40 = 40;
private Icons() {
}
/**
* Retorna um ícone vetorial pelo nome no tamanho especificado, com repintura dinâmica de tema.
*/
public static Node of(String name, int size) {
return of(name, size, null, null);
}
/**
* Retorna um ícone vetorial pelo nome no tamanho especificado, aplicando uma tinta (tint) fixa.
*/
public static Node of(String name, int size, Color tint) {
return of(name, size, tint, null);
}
/**
* Retorna um ícone vetorial com fallback customizado.
*/
public static Node of(String name, int size, Color tint, Supplier<Node> fallbackSupplier) {
return AssetManager.getIconOrDefault(name, size, tint, fallbackSupplier);
}
// ==========================================
// MÉTODOS DE CONVENIÊNCIA POR SEMÂNTICA VISUAL
// ==========================================
public static Node pdf() { return pdf(SIZE_24); }
public static Node pdf(int size) { return of("pdf", size); }
public static Node pdf(int size, Color tint) { return of("pdf", size, tint); }
public static Node xml() { return xml(SIZE_24); }
public static Node xml(int size) { return of("xml", size); }
public static Node file() { return file(SIZE_24); }
public static Node file(int size) { return of("file", size); }
public static Node attached() { return attached(SIZE_24); }
public static Node attached(int size) { return of("attached", size); }
public static Node batch() { return batch(SIZE_24); }
public static Node batch(int size) { return of("batch", size); }
public static Node coSign() { return coSign(SIZE_24); }
public static Node coSign(int size) { return of("co-sign", size); }
public static Node timestamp() { return timestamp(SIZE_24); }
public static Node timestamp(int size) { return of("timestamp", size); }
public static Node ltv() { return ltv(SIZE_24); }
public static Node ltv(int size) { return of("ltv", size); }
public static Node validate() { return validate(SIZE_24); }
public static Node validate(int size) { return of("validate", size); }
public static Node validateTimestamp() { return validateTimestamp(SIZE_24); }
public static Node validateTimestamp(int size) { return of("validate-timestamp", size); }
public static Node seal() { return seal(SIZE_24); }
public static Node seal(int size) { return of("seal", size); }
public static Node sealIcpBrasil() { return sealIcpBrasil(SIZE_24); }
public static Node sealIcpBrasil(int size) { return of("seal-icp-brasil", size); }
public static Node certificates() { return certificates(SIZE_24); }
public static Node certificates(int size) { return of("cert", size); }
public static Node shield() { return shield(SIZE_24); }
public static Node shield(int size) { return of("shield", size); }
public static Node settings() { return settings(SIZE_24); }
public static Node settings(int size) { return of("settings", size); }
public static Node logs() { return logs(SIZE_24); }
public static Node logs(int size) { return of("logs", size); }
public static Node tutorial() { return tutorial(SIZE_24); }
public static Node tutorial(int size) { return of("tutorial", size); }
public static Node about() { return about(SIZE_24); }
public static Node about(int size) { return of("about", size); }
public static Node exit() { return exit(SIZE_24); }
public static Node exit(int size) { return of("exit", size); }
public static Node refresh() { return refresh(SIZE_16); }
public static Node refresh(int size) { return of("refresh", size); }
public static Node sun() { return sun(SIZE_16); }
public static Node sun(int size) { return of("sun", size); }
public static Node moon() { return moon(SIZE_16); }
public static Node moon(int size) { return of("moon", size); }
public static Node arrowRight() { return arrowRight(SIZE_16); }
public static Node arrowRight(int size) { return of("arrow-right", size); }
public static Node close() { return close(SIZE_16); }
public static Node close(int size) { return of("close", size); }
public static Node check() { return check(SIZE_16); }
public static Node check(int size) { return of("check", size); }
public static Node error() { return error(SIZE_16); }
public static Node error(int size) { return of("error", size); }
public static Node star() { return star(SIZE_16); }
public static Node star(int size) { return of("star", size); }
public static Node zoomIn() { return zoomIn(SIZE_16); }
public static Node zoomIn(int size) { return of("zoom-in", size); }
public static Node zoomOut() { return zoomOut(SIZE_16); }
public static Node zoomOut(int size) { return of("zoom-out", size); }
public static Node zoomFit() { return zoomFit(SIZE_16); }
public static Node zoomFit(int size) { return of("zoom-fit", size); }
/**
* Logotipo institucional principal do CyberCore Signer.
*/
public static Node appLogo(double width, double height) {
return AssetManager.getLogoOrDefault(width, height, () -> SvgIcons.buildAppCrystalLogo(Math.min(width, height)));
}
/**
* Logotipo de cristal CyberCore.
*/
public static Node appCrystal(double size) {
return SvgIcons.createAppCrystalLogo(size);
}
}
@@ -19,7 +19,7 @@ import javafx.scene.text.FontWeight;
import javafx.scene.text.Text; import javafx.scene.text.Text;
/** /**
* Fábrica de ícones e grafismos vetoriais SVG nítidos e escaláveis para a interface Serpro do CyberCore Signer. * Fábrica de ícones e grafismos vetoriais SVG nítidos e escaláveis para a interface do CyberCore Signer.
* Integra-se ao AssetManager para carregar dinamicamente arquivos .svg ou .png da pasta 'assets/icons/'. * Integra-se ao AssetManager para carregar dinamicamente arquivos .svg ou .png da pasta 'assets/icons/'.
*/ */
public final class SvgIcons { public final class SvgIcons {
@@ -189,9 +189,15 @@ public class SystemTrayManager {
} }
/** /**
* Gera dinamicamente um ícone vetorial de 32x32 com o padrão de cores CyberCore (#38bdf8). * Obtém o ícone oficial da marca CyberCore em alta resolução para a bandeja do sistema,
* com fallback vetorial dinâmico caso o recurso não esteja disponível.
*/ */
private Image createTrayIconImage() { private Image createTrayIconImage() {
Image trayAsset = br.com.cybercore.signer.ui.assets.AssetManager.getTrayIconImage();
if (trayAsset != null) {
return trayAsset;
}
int size = 32; int size = 32;
BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics(); Graphics2D g = image.createGraphics();
@@ -69,15 +69,14 @@ public class ApplicationApprovalDialog {
Label originTitle = new Label("ORIGEM WEB (URL)"); Label originTitle = new Label("ORIGEM WEB (URL)");
originTitle.getStyleClass().add("dialog-field-title"); originTitle.getStyleClass().add("dialog-field-title");
Label originValue = new Label(origin != null ? origin : "Origem desconhecida"); Label originValue = new Label(origin != null ? origin : "Origem desconhecida");
originValue.setStyle("-fx-text-fill: -fx-accent; -fx-font-size: 13px; -fx-font-family: monospace;"); originValue.getStyleClass().addAll("text-accent", "text-mono");
originRow.getChildren().addAll(originTitle, originValue); originRow.getChildren().addAll(originTitle, originValue);
VBox idRow = new VBox(2); VBox idRow = new VBox(2);
Label idTitle = new Label("IDENTIFICADOR DA APLICAÇÃO"); Label idTitle = new Label("IDENTIFICADOR DA APLICAÇÃO");
idTitle.getStyleClass().add("dialog-field-title"); idTitle.getStyleClass().add("dialog-field-title");
Label idValue = new Label(applicationId); Label idValue = new Label(applicationId);
idValue.getStyleClass().add("dialog-field-value"); idValue.getStyleClass().addAll("dialog-field-value", "text-mono", "text-small");
idValue.setStyle("-fx-font-size: 12px; -fx-font-family: monospace;");
idRow.getChildren().addAll(idTitle, idValue); idRow.getChildren().addAll(idTitle, idValue);
detailsBox.getChildren().addAll(appRow, originRow, idRow); detailsBox.getChildren().addAll(appRow, originRow, idRow);
@@ -88,21 +87,21 @@ public class ApplicationApprovalDialog {
"instalados e solicitar assinaturas. Nenhuma assinatura será realizada sem a sua confirmação explícita na tela." "instalados e solicitar assinaturas. Nenhuma assinatura será realizada sem a sua confirmação explícita na tela."
); );
secWarning.setWrapText(true); secWarning.setWrapText(true);
secWarning.setStyle("-fx-text-fill: -fx-text-secondary; -fx-font-size: 11px; -fx-line-spacing: 2px;"); secWarning.getStyleClass().addAll("text-muted", "text-small");
// Botões de Ação // Botões de Ação
HBox actionsRow = new HBox(12); HBox actionsRow = new HBox(12);
actionsRow.setAlignment(Pos.CENTER_RIGHT); actionsRow.setAlignment(Pos.CENTER_RIGHT);
Button btnReject = new Button("Recusar Acesso"); Button btnReject = new Button("Recusar Acesso");
btnReject.getStyleClass().add("btn-secondary"); btnReject.getStyleClass().addAll("btn-danger-outline", "btn-dialog");
btnReject.setOnAction(e -> { btnReject.setOnAction(e -> {
approvalFuture.complete(false); approvalFuture.complete(false);
stage.close(); stage.close();
}); });
Button btnAuthorize = new Button("Autorizar Conexão"); Button btnAuthorize = new Button("Autorizar Conexão");
btnAuthorize.getStyleClass().add("btn-primary"); btnAuthorize.getStyleClass().addAll("btn-primary", "btn-dialog");
btnAuthorize.setDefaultButton(true); btnAuthorize.setDefaultButton(true);
btnAuthorize.setOnAction(e -> { btnAuthorize.setOnAction(e -> {
approvalFuture.complete(true); approvalFuture.complete(true);
@@ -74,8 +74,7 @@ public class CertificateDetailsDialog {
// Nome do Titular em destaque // Nome do Titular em destaque
VBox titleBox = new VBox(4); VBox titleBox = new VBox(4);
Label nameLabel = new Label(cert.commonName() != null ? cert.commonName() : cert.alias()); Label nameLabel = new Label(cert.commonName() != null ? cert.commonName() : cert.alias());
nameLabel.getStyleClass().add("cert-title"); nameLabel.getStyleClass().addAll("dialog-header-title", "text-bold");
nameLabel.setStyle("-fx-font-size: 16px; -fx-font-weight: bold;");
String docInfo = ""; String docInfo = "";
if (cert.cpf() != null) { if (cert.cpf() != null) {
@@ -121,7 +120,7 @@ public class CertificateDetailsDialog {
ScrollPane scroll = new ScrollPane(detailsBox); ScrollPane scroll = new ScrollPane(detailsBox);
scroll.setFitToWidth(true); scroll.setFitToWidth(true);
scroll.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); scroll.getStyleClass().add("scroll-transparent");
VBox.setVgrow(scroll, Priority.ALWAYS); VBox.setVgrow(scroll, Priority.ALWAYS);
// Botões de Ação // Botões de Ação
@@ -129,7 +128,7 @@ public class CertificateDetailsDialog {
actionsRow.setAlignment(Pos.CENTER_RIGHT); actionsRow.setAlignment(Pos.CENTER_RIGHT);
Button btnClose = new Button(" Fechar", SvgIcons.closeIcon(13)); Button btnClose = new Button(" Fechar", SvgIcons.closeIcon(13));
btnClose.getStyleClass().addAll("btn-secondary", "btn-dialog"); btnClose.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnClose.setPrefWidth(110); btnClose.setPrefWidth(110);
btnClose.setMinWidth(110); btnClose.setMinWidth(110);
btnClose.setOnAction(e -> stage.close()); btnClose.setOnAction(e -> stage.close());
@@ -86,7 +86,7 @@ public final class CertificatesManagerDialog {
// Container com Scroll // Container com Scroll
ScrollPane scroll = new ScrollPane(certificatesContainer); ScrollPane scroll = new ScrollPane(certificatesContainer);
scroll.setFitToWidth(true); scroll.setFitToWidth(true);
scroll.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); scroll.getStyleClass().add("scroll-transparent");
VBox.setVgrow(scroll, Priority.ALWAYS); VBox.setVgrow(scroll, Priority.ALWAYS);
refreshList(); refreshList();
@@ -69,7 +69,7 @@ public final class DiagnosticsView extends VBox {
// Container de Itens // Container de Itens
ScrollPane scrollPane = new ScrollPane(itemsContainer); ScrollPane scrollPane = new ScrollPane(itemsContainer);
scrollPane.setFitToWidth(true); scrollPane.setFitToWidth(true);
scrollPane.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); scrollPane.getStyleClass().add("scroll-transparent");
VBox.setVgrow(scrollPane, Priority.ALWAYS); VBox.setVgrow(scrollPane, Priority.ALWAYS);
getChildren().addAll(headerBox, actionsRow, scrollPane); getChildren().addAll(headerBox, actionsRow, scrollPane);
@@ -54,13 +54,13 @@ public final class ExitConfirmationDialog {
VBox titleBox = new VBox(4); VBox titleBox = new VBox(4);
Label title = new Label("Como você deseja proceder?"); Label title = new Label("Como você deseja proceder?");
title.setStyle("-fx-font-size: 15px; -fx-font-weight: bold;"); title.getStyleClass().addAll("dialog-header-title", "text-bold");
Label subtitle = new Label( Label subtitle = new Label(
"Você pode manter o CyberCore Signer ativo na bandeja do sistema\n" + "Você pode manter o CyberCore Signer ativo na bandeja do sistema\n" +
"para atender assinaturas de aplicações web, ou encerrá-lo por completo." "para atender assinaturas de aplicações web, ou encerrá-lo por completo."
); );
subtitle.setStyle("-fx-text-fill: -fx-text-secondary; -fx-font-size: 12px;"); subtitle.getStyleClass().addAll("dialog-subtitle", "text-muted");
titleBox.getChildren().addAll(title, subtitle); titleBox.getChildren().addAll(title, subtitle);
header.getChildren().addAll(SvgIcons.cyberShieldLogo(38), titleBox); header.getChildren().addAll(SvgIcons.cyberShieldLogo(38), titleBox);
@@ -70,7 +70,7 @@ public final class ExitConfirmationDialog {
actionsRow.setAlignment(Pos.CENTER_RIGHT); actionsRow.setAlignment(Pos.CENTER_RIGHT);
Button btnCancel = new Button("Cancelar"); Button btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().addAll("btn-cancel", "btn-dialog"); btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setOnAction(e -> { btnCancel.setOnAction(e -> {
chosenAction = ExitChoice.CANCEL; chosenAction = ExitChoice.CANCEL;
stage.close(); stage.close();
@@ -80,7 +80,7 @@ public final class ExitConfirmationDialog {
HBox.setHgrow(spacer, Priority.ALWAYS); HBox.setHgrow(spacer, Priority.ALWAYS);
Button btnExit = new Button("Encerrar Definitivamente"); Button btnExit = new Button("Encerrar Definitivamente");
btnExit.getStyleClass().addAll("btn-danger", "btn-dialog"); btnExit.getStyleClass().addAll("btn-danger-outline", "btn-dialog");
btnExit.setOnAction(e -> { btnExit.setOnAction(e -> {
chosenAction = ExitChoice.EXIT_COMPLETELY; chosenAction = ExitChoice.EXIT_COMPLETELY;
stage.close(); stage.close();
@@ -104,6 +104,10 @@ public final class ExitConfirmationDialog {
stage.setOnCloseRequest(e -> chosenAction = ExitChoice.CANCEL); stage.setOnCloseRequest(e -> chosenAction = ExitChoice.CANCEL);
} }
public Stage getStage() {
return stage;
}
public ExitChoice showAndGetChoice() { public ExitChoice showAndGetChoice() {
stage.showAndWait(); stage.showAndWait();
return chosenAction; return chosenAction;
@@ -1,6 +1,7 @@
package br.com.cybercore.signer.ui.view; package br.com.cybercore.signer.ui.view;
import br.com.cybercore.signer.ui.CyberCoreUiConstants; import br.com.cybercore.signer.ui.CyberCoreUiConstants;
import br.com.cybercore.signer.ui.components.Icons;
import br.com.cybercore.signer.ui.components.SvgIcons; import br.com.cybercore.signer.ui.components.SvgIcons;
import br.com.cybercore.signer.ui.theme.ThemeManager; import br.com.cybercore.signer.ui.theme.ThemeManager;
import javafx.geometry.Insets; import javafx.geometry.Insets;
@@ -9,6 +10,7 @@ import javafx.scene.Node;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
@@ -57,7 +59,7 @@ public final class MainAppView {
} }
private void initLayout() { private void initLayout() {
root.getStyleClass().addAll("cyber-root", "serpro-root"); root.getStyleClass().add("cyber-root");
root.setAlignment(Pos.TOP_CENTER); root.setAlignment(Pos.TOP_CENTER);
// 1. Barra Superior Moderna com Identidade CyberCore, Status do Agente e Alternador de Tema // 1. Barra Superior Moderna com Identidade CyberCore, Status do Agente e Alternador de Tema
@@ -69,37 +71,44 @@ public final class MainAppView {
mainContent.setAlignment(Pos.CENTER); mainContent.setAlignment(Pos.CENTER);
VBox.setVgrow(mainContent, Priority.ALWAYS); VBox.setVgrow(mainContent, Priority.ALWAYS);
// --- Hub Central de Ações (Grid 3 colunas x 2 linhas) --- // --- Hub Central de Ações (Grid 3 colunas x 2 linhas responsivo) ---
GridPane actionGrid = new GridPane(); GridPane actionGrid = new GridPane();
actionGrid.setHgap(12); actionGrid.setHgap(12);
actionGrid.setVgap(12); actionGrid.setVgap(12);
actionGrid.setAlignment(Pos.CENTER); actionGrid.setAlignment(Pos.CENTER);
HBox.setHgrow(actionGrid, Priority.ALWAYS); HBox.setHgrow(actionGrid, Priority.ALWAYS);
for (int i = 0; i < 3; i++) {
ColumnConstraints col = new ColumnConstraints();
col.setHgrow(Priority.ALWAYS);
col.setPercentWidth(33.33);
actionGrid.getColumnConstraints().add(col);
}
// Linha 0: Operações de Assinatura // Linha 0: Operações de Assinatura
actionGrid.add(createActionButton(SvgIcons.pdfIcon(), "Assinar\nPDF", () -> trigger(onSignPdf)), 0, 0); actionGrid.add(createActionButton(Icons.pdf(Icons.SIZE_40), "Assinar\nPDF", () -> trigger(onSignPdf)), 0, 0);
actionGrid.add(createActionButton(SvgIcons.xmlIcon(), "Assinar\nXML", () -> trigger(onSignXml)), 1, 0); actionGrid.add(createActionButton(Icons.xml(Icons.SIZE_40), "Assinar\nXML", () -> trigger(onSignXml)), 1, 0);
actionGrid.add(createActionButton(SvgIcons.attachedIcon(), "Assinatura\nAtachada", () -> trigger(onAttachedSign)), 2, 0); actionGrid.add(createActionButton(Icons.attached(Icons.SIZE_40), "Assinatura\nAtachada", () -> trigger(onAttachedSign)), 2, 0);
// Linha 1: Identidade Visual, Auditoria e Saída // Linha 1: Identidade Visual, Auditoria e Saída
actionGrid.add(createActionButton(SvgIcons.sealIcon(), "Gerenciar\nSelos", () -> trigger(onManageSeals)), 0, 1); actionGrid.add(createActionButton(Icons.seal(Icons.SIZE_40), "Gerenciar\nSelos", () -> trigger(onManageSeals)), 0, 1);
actionGrid.add(createActionButton(SvgIcons.validateIcon(), "Validar\nAssinatura", () -> trigger(onValidateSignature)), 1, 1); actionGrid.add(createActionButton(Icons.validate(Icons.SIZE_40), "Validar\nAssinatura", () -> trigger(onValidateSignature)), 1, 1);
actionGrid.add(createActionButton(SvgIcons.exitIcon(), "Sair do\nAgente", () -> trigger(onExit)), 2, 1); actionGrid.add(createActionButton(Icons.exit(Icons.SIZE_40), "Sair do\nAgente", () -> trigger(onExit)), 2, 1);
// --- Painel Lateral Direito (Ferramentas, Certificados e Diagnóstico) --- // --- Painel Lateral Direito (Ferramentas, Certificados e Diagnóstico) ---
VBox sideColumn = new VBox(10); VBox sideColumn = new VBox(10);
sideColumn.getStyleClass().add("cyber-side-column"); sideColumn.getStyleClass().add("cyber-side-column");
sideColumn.setPrefWidth(195); sideColumn.setPrefWidth(210);
sideColumn.setMinWidth(190); sideColumn.setMinWidth(180);
sideColumn.setMaxWidth(210); sideColumn.setMaxWidth(230);
sideColumn.setAlignment(Pos.TOP_CENTER); sideColumn.setAlignment(Pos.TOP_CENTER);
sideColumn.getChildren().addAll( sideColumn.getChildren().addAll(
createSideButton(SvgIcons.logsIcon(), "Logs", () -> trigger(onLogs)), createSideButton(Icons.logs(Icons.SIZE_24), "Logs", () -> trigger(onLogs)),
createSideButton(SvgIcons.settingsIcon(), "Configurações", () -> trigger(onSettings)), createSideButton(Icons.settings(Icons.SIZE_24), "Configurações", () -> trigger(onSettings)),
createSideButton(SvgIcons.tutorialIcon(), "Tutorial", () -> trigger(onTutorial)), createSideButton(Icons.tutorial(Icons.SIZE_24), "Tutorial", () -> trigger(onTutorial)),
createSideButton(SvgIcons.certificatesIcon(), "Certificados", () -> trigger(onCertificates)), createSideButton(Icons.certificates(Icons.SIZE_24), "Certificados", () -> trigger(onCertificates)),
createSideButton(SvgIcons.aboutIcon(), "Sobre", () -> trigger(onAbout)) createSideButton(Icons.about(Icons.SIZE_24), "Sobre", () -> trigger(onAbout))
); );
// Espaçador elástico e Rodapé de status local // Espaçador elástico e Rodapé de status local
@@ -112,13 +121,13 @@ public final class MainAppView {
HBox brandFooter = new HBox(6); HBox brandFooter = new HBox(6);
brandFooter.setAlignment(Pos.CENTER); brandFooter.setAlignment(Pos.CENTER);
Node smallLogo = SvgIcons.cyberShieldLogo(16); Node smallLogo = Icons.shield(Icons.SIZE_16);
Label lblBrandFoot = new Label("CyberCore"); Label lblBrandFoot = new Label("CyberCore");
lblBrandFoot.setStyle("-fx-font-weight: bold; -fx-font-size: 11.5px;"); lblBrandFoot.getStyleClass().addAll("cyber-version-label", "text-bold");
brandFooter.getChildren().addAll(smallLogo, lblBrandFoot); brandFooter.getChildren().addAll(smallLogo, lblBrandFoot);
Label lblVersion = new Label("v" + CyberCoreUiConstants.APP_VERSION); Label lblVersion = new Label("v" + CyberCoreUiConstants.APP_VERSION);
lblVersion.getStyleClass().addAll("cyber-version-label", "serpro-version-label"); lblVersion.getStyleClass().add("cyber-version-label");
footerBox.getChildren().addAll(brandFooter, lblVersion); footerBox.getChildren().addAll(brandFooter, lblVersion);
sideColumn.getChildren().add(footerBox); sideColumn.getChildren().add(footerBox);
@@ -146,6 +155,7 @@ public final class MainAppView {
ThemeManager.addListener(theme -> updateThemeToggleButton()); ThemeManager.addListener(theme -> updateThemeToggleButton());
stage.setTitle(CyberCoreUiConstants.APP_NAME); stage.setTitle(CyberCoreUiConstants.APP_NAME);
stage.getIcons().addAll(br.com.cybercore.signer.ui.assets.AssetManager.getApplicationIcons());
stage.setScene(scene); stage.setScene(scene);
if (Boolean.getBoolean("cybercore.diag.plain-stage")) { if (Boolean.getBoolean("cybercore.diag.plain-stage")) {
@@ -174,15 +184,13 @@ public final class MainAppView {
brandRow.setAlignment(Pos.CENTER_LEFT); brandRow.setAlignment(Pos.CENTER_LEFT);
Label lblAssinador = new Label("ASSINADOR"); Label lblAssinador = new Label("ASSINADOR");
lblAssinador.getStyleClass().addAll("cyber-brand-title", "serpro-header-title"); lblAssinador.getStyleClass().addAll("cyber-brand-title", "cyber-brand-prefix");
lblAssinador.setStyle("-fx-font-weight: 300; -fx-opacity: 0.85;");
Label lblSep = new Label("|"); Label lblSep = new Label("|");
lblSep.setStyle("-fx-font-size: 16px; -fx-opacity: 0.4;"); lblSep.getStyleClass().add("cyber-brand-separator");
Label lblBrand = new Label("CyberCore"); Label lblBrand = new Label("CyberCore");
lblBrand.getStyleClass().addAll("cyber-brand-title", "serpro-header-brand"); lblBrand.getStyleClass().addAll("cyber-brand-title", "text-bold");
lblBrand.setStyle("-fx-font-weight: bold;");
brandRow.getChildren().addAll(lblAssinador, lblSep, lblBrand); brandRow.getChildren().addAll(lblAssinador, lblSep, lblBrand);
@@ -217,7 +225,7 @@ public final class MainAppView {
HBox content = new HBox(8); HBox content = new HBox(8);
content.setAlignment(Pos.CENTER); content.setAlignment(Pos.CENTER);
Node icon = dark ? SvgIcons.sunIcon(15) : SvgIcons.moonIcon(15); Node icon = dark ? Icons.sun(16) : Icons.moon(16);
StackPane iconBox = new StackPane(icon); StackPane iconBox = new StackPane(icon);
iconBox.setPrefSize(18, 18); iconBox.setPrefSize(18, 18);
iconBox.setMinSize(18, 18); iconBox.setMinSize(18, 18);
@@ -225,7 +233,7 @@ public final class MainAppView {
iconBox.setAlignment(Pos.CENTER); iconBox.setAlignment(Pos.CENTER);
Label label = new Label(dark ? "Modo Claro" : "Modo Escuro"); Label label = new Label(dark ? "Modo Claro" : "Modo Escuro");
label.setStyle("-fx-font-size: 11.5px; -fx-font-weight: bold;"); label.getStyleClass().add("text-bold");
content.getChildren().addAll(iconBox, label); content.getChildren().addAll(iconBox, label);
themeToggleBtn.setGraphic(content); themeToggleBtn.setGraphic(content);
@@ -233,17 +241,16 @@ public final class MainAppView {
private Button createActionButton(Node icon, String text, Runnable onAction) { private Button createActionButton(Node icon, String text, Runnable onAction) {
Button btn = new Button(); Button btn = new Button();
btn.getStyleClass().addAll("cyber-action-card", "serpro-action-btn"); btn.getStyleClass().add("cyber-action-card");
btn.setPrefWidth(162); btn.setMaxWidth(Double.MAX_VALUE);
btn.setMinWidth(158); btn.setPrefHeight(72);
btn.setPrefHeight(68);
btn.setMinHeight(68); btn.setMinHeight(68);
HBox content = new HBox(12); HBox content = new HBox(12);
content.setAlignment(Pos.CENTER_LEFT); content.setAlignment(Pos.CENTER_LEFT);
Label lbl = new Label(text); Label lbl = new Label(text);
lbl.getStyleClass().addAll("cyber-action-text", "serpro-action-text"); lbl.getStyleClass().add("cyber-action-text");
lbl.setWrapText(true); lbl.setWrapText(true);
lbl.setAlignment(Pos.CENTER_LEFT); lbl.setAlignment(Pos.CENTER_LEFT);
HBox.setHgrow(lbl, Priority.ALWAYS); HBox.setHgrow(lbl, Priority.ALWAYS);
@@ -268,7 +275,7 @@ public final class MainAppView {
private Button createSideButton(Node icon, String text, Runnable onAction) { private Button createSideButton(Node icon, String text, Runnable onAction) {
Button btn = new Button(); Button btn = new Button();
btn.getStyleClass().addAll("cyber-side-card", "serpro-side-btn"); btn.getStyleClass().add("cyber-side-card");
btn.setPrefHeight(42); btn.setPrefHeight(42);
btn.setMinHeight(42); btn.setMinHeight(42);
btn.setMaxWidth(Double.MAX_VALUE); btn.setMaxWidth(Double.MAX_VALUE);
@@ -277,7 +284,7 @@ public final class MainAppView {
content.setAlignment(Pos.CENTER_LEFT); content.setAlignment(Pos.CENTER_LEFT);
Label lbl = new Label(text); Label lbl = new Label(text);
lbl.getStyleClass().addAll("cyber-side-text", "serpro-side-text"); lbl.getStyleClass().add("cyber-side-text");
lbl.setWrapText(false); lbl.setWrapText(false);
lbl.setAlignment(Pos.CENTER_LEFT); lbl.setAlignment(Pos.CENTER_LEFT);
HBox.setHgrow(lbl, Priority.ALWAYS); HBox.setHgrow(lbl, Priority.ALWAYS);
@@ -83,7 +83,7 @@ public final class MainDashboardView extends VBox {
certsContainer.setPadding(new Insets(4, 0, 4, 0)); certsContainer.setPadding(new Insets(4, 0, 4, 0));
ScrollPane scrollPane = new ScrollPane(certsContainer); ScrollPane scrollPane = new ScrollPane(certsContainer);
scrollPane.setFitToWidth(true); scrollPane.setFitToWidth(true);
scrollPane.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); scrollPane.getStyleClass().add("scroll-transparent");
VBox.setVgrow(scrollPane, Priority.ALWAYS); VBox.setVgrow(scrollPane, Priority.ALWAYS);
getChildren().addAll(statusBox, certsHeader, scrollPane); getChildren().addAll(statusBox, certsHeader, scrollPane);
@@ -167,15 +167,15 @@ public final class PdfCertificateSignDialog {
summaryGrid.setVgap(6); summaryGrid.setVgap(6);
Label lblDocTitle = new Label("Arquivo:"); Label lblDocTitle = new Label("Arquivo:");
lblDocTitle.setStyle("-fx-font-weight: bold; -fx-text-fill: -fx-text-secondary; -fx-font-size: 11.5px;"); lblDocTitle.getStyleClass().addAll("form-label-muted", "text-bold");
Label lblDocValue = new Label(sourcePdfFile.getName() + " (" + (sourcePdfFile.length() / 1024) + " KB)"); Label lblDocValue = new Label(sourcePdfFile.getName() + " (" + (sourcePdfFile.length() / 1024) + " KB)");
lblDocValue.setStyle("-fx-font-weight: bold; -fx-text-fill: -fx-text-primary; -fx-font-size: 11.5px;"); lblDocValue.getStyleClass().addAll("form-label", "text-bold");
lblDocValue.setWrapText(true); lblDocValue.setWrapText(true);
Label lblSealTitle = new Label("Selo Visual:"); Label lblSealTitle = new Label("Selo Visual:");
lblSealTitle.setStyle("-fx-font-weight: bold; -fx-text-fill: -fx-text-secondary; -fx-font-size: 11.5px;"); lblSealTitle.getStyleClass().addAll("form-label-muted", "text-bold");
Label lblSealValue = new Label(sealSummaryText); Label lblSealValue = new Label(sealSummaryText);
lblSealValue.setStyle("-fx-text-fill: #0284c7; -fx-font-weight: bold; -fx-font-size: 11.5px;"); lblSealValue.getStyleClass().addAll("text-primary", "text-bold");
lblSealValue.setWrapText(true); lblSealValue.setWrapText(true);
summaryGrid.add(lblDocTitle, 0, 0); summaryGrid.add(lblDocTitle, 0, 0);
@@ -237,13 +237,12 @@ public final class PdfCertificateSignDialog {
} }
}); });
// Banner informativo para certificados da Loja do Windows (sem PIN)
windowsStoreBox = new HBox(8); windowsStoreBox = new HBox(8);
windowsStoreBox.setAlignment(Pos.CENTER_LEFT); windowsStoreBox.setAlignment(Pos.CENTER_LEFT);
windowsStoreBox.setPadding(new Insets(10, 12, 10, 12)); windowsStoreBox.setPadding(new Insets(10, 12, 10, 12));
windowsStoreBox.setStyle("-fx-background-color: #ecfdf5; -fx-border-color: #a7f3d0; -fx-border-radius: 6px; -fx-background-radius: 6px;"); windowsStoreBox.getStyleClass().add("status-badge-valid");
Label lblWinNotice = new Label("✓ Certificado instalado no computador — Gerenciado nativamente pelo Windows (PIN não necessário)"); Label lblWinNotice = new Label("✓ Certificado instalado no computador — Gerenciado nativamente pelo Windows (PIN não necessário)");
lblWinNotice.setStyle("-fx-text-fill: #065f46; -fx-font-weight: bold; -fx-font-size: 11.5px;"); lblWinNotice.getStyleClass().addAll("text-success", "text-bold");
lblWinNotice.setWrapText(true); lblWinNotice.setWrapText(true);
HBox.setHgrow(lblWinNotice, Priority.ALWAYS); HBox.setHgrow(lblWinNotice, Priority.ALWAYS);
windowsStoreBox.getChildren().add(lblWinNotice); windowsStoreBox.getChildren().add(lblWinNotice);
@@ -260,7 +259,6 @@ public final class PdfCertificateSignDialog {
btnClearRememberedPin = new Button("Alterar PIN"); btnClearRememberedPin = new Button("Alterar PIN");
btnClearRememberedPin.getStyleClass().addAll("btn-secondary", "btn-compact"); btnClearRememberedPin.getStyleClass().addAll("btn-secondary", "btn-compact");
btnClearRememberedPin.setStyle("-fx-font-size: 11px;");
btnClearRememberedPin.setVisible(false); btnClearRememberedPin.setVisible(false);
btnClearRememberedPin.setOnAction(e -> { btnClearRememberedPin.setOnAction(e -> {
ManagedCertificate sel = certCombo.getValue(); ManagedCertificate sel = certCombo.getValue();
@@ -271,20 +269,20 @@ public final class PdfCertificateSignDialog {
}); });
lblPinNotice = new Label(); lblPinNotice = new Label();
lblPinNotice.setStyle("-fx-font-size: 11.5px;"); lblPinNotice.getStyleClass().addAll("dialog-subtitle", "text-muted");
lblPinNotice.setWrapText(true); lblPinNotice.setWrapText(true);
HBox.setHgrow(lblPinNotice, Priority.ALWAYS); HBox.setHgrow(lblPinNotice, Priority.ALWAYS);
pinRow.getChildren().addAll(lblPinTitle, pinField, btnClearRememberedPin, lblPinNotice); pinRow.getChildren().addAll(lblPinTitle, pinField, btnClearRememberedPin, lblPinNotice);
chkRememberPin = new CheckBox("Lembrar PIN/senha com segurança neste computador"); chkRememberPin = new CheckBox("Lembrar PIN/senha com segurança neste computador");
chkRememberPin.setStyle("-fx-font-size: 11.5px; -fx-text-fill: -fx-text-primary;"); chkRememberPin.getStyleClass().addAll("text-primary", "text-small");
chkRememberPin.setSelected(true); chkRememberPin.setSelected(true);
VBox tipBox = new VBox(2); VBox tipBox = new VBox(2);
tipBox.setPadding(new Insets(8, 10, 8, 10)); tipBox.setPadding(new Insets(8, 10, 8, 10));
tipBox.setStyle("-fx-background-color: -fx-bg-primary; -fx-border-color: -fx-border-light; -fx-border-radius: 6px; -fx-background-radius: 6px;"); tipBox.getStyleClass().add("dialog-box");
Label lblTip = new Label("🔒 Segurança: O PIN é criptografado localmente com AES-256-GCM vinculado à máquina e nunca é transmitido na rede."); Label lblTip = new Label("🔒 Segurança: O PIN é criptografado localmente com AES-256-GCM vinculado à máquina e nunca é transmitido na rede.");
lblTip.setStyle("-fx-font-size: 11px; -fx-text-fill: -fx-text-secondary;"); lblTip.getStyleClass().add("text-muted");
lblTip.setWrapText(true); lblTip.setWrapText(true);
lblTip.setMaxWidth(Double.MAX_VALUE); lblTip.setMaxWidth(Double.MAX_VALUE);
tipBox.getChildren().add(lblTip); tipBox.getChildren().add(lblTip);
@@ -301,11 +299,11 @@ public final class PdfCertificateSignDialog {
progressIndicator.setVisible(false); progressIndicator.setVisible(false);
lblStatus = new Label(); lblStatus = new Label();
lblStatus.setStyle("-fx-font-size: 12px;"); lblStatus.getStyleClass().addAll("text-muted", "text-small");
HBox.setHgrow(lblStatus, Priority.ALWAYS); HBox.setHgrow(lblStatus, Priority.ALWAYS);
btnCancel = new Button("Cancelar"); btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().addAll("btn-secondary", "btn-dialog"); btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setMinWidth(110); btnCancel.setMinWidth(110);
btnCancel.setOnAction(e -> stage.close()); btnCancel.setOnAction(e -> stage.close());
@@ -381,7 +379,7 @@ public final class PdfCertificateSignDialog {
chkRememberPin.setManaged(false); chkRememberPin.setManaged(false);
btnClearRememberedPin.setVisible(true); btnClearRememberedPin.setVisible(true);
lblPinNotice.setText("✓ PIN lembrado com segurança neste computador"); lblPinNotice.setText("✓ PIN lembrado com segurança neste computador");
lblPinNotice.setStyle("-fx-text-fill: #10b981; -fx-font-weight: bold; -fx-font-size: 11.5px;"); lblPinNotice.getStyleClass().setAll("label", "text-success", "text-bold");
} else { } else {
pinField.clear(); pinField.clear();
pinField.setDisable(false); pinField.setDisable(false);
@@ -390,7 +388,7 @@ public final class PdfCertificateSignDialog {
btnClearRememberedPin.setVisible(false); btnClearRememberedPin.setVisible(false);
boolean isA3 = cert.type() == CertificateType.A3; boolean isA3 = cert.type() == CertificateType.A3;
lblPinNotice.setText(isA3 ? "Requer PIN do token" : "Requer senha do certificado"); lblPinNotice.setText(isA3 ? "Requer PIN do token" : "Requer senha do certificado");
lblPinNotice.setStyle("-fx-text-fill: -fx-text-secondary; -fx-font-size: 11.5px;"); lblPinNotice.getStyleClass().setAll("label", "text-muted");
} }
} }
@@ -469,7 +467,7 @@ public final class PdfCertificateSignDialog {
setFormDisabled(true); setFormDisabled(true);
progressIndicator.setVisible(true); progressIndicator.setVisible(true);
lblStatus.setText("Assinando documento PDF com envelope PAdES..."); lblStatus.setText("Assinando documento PDF com envelope PAdES...");
lblStatus.setStyle("-fx-text-fill: -fx-accent;"); lblStatus.getStyleClass().setAll("text-accent", "text-bold");
Task<File> signTask = new Task<>() { Task<File> signTask = new Task<>() {
@Override @Override
@@ -483,7 +481,7 @@ public final class PdfCertificateSignDialog {
setFormDisabled(false); setFormDisabled(false);
progressIndicator.setVisible(false); progressIndicator.setVisible(false);
lblStatus.setText("✓ Documento assinado com sucesso!"); lblStatus.setText("✓ Documento assinado com sucesso!");
lblStatus.setStyle("-fx-text-fill: #10b981; -fx-font-weight: bold;"); lblStatus.getStyleClass().setAll("label", "text-success", "text-bold");
// Salva o PIN de forma segura se solicitado pelo usuário // Salva o PIN de forma segura se solicitado pelo usuário
if (!isWindowsStore && chkRememberPin.isSelected() && enteredPin != null && enteredPin.length > 0) { if (!isWindowsStore && chkRememberPin.isSelected() && enteredPin != null && enteredPin.length > 0) {
@@ -508,7 +506,7 @@ public final class PdfCertificateSignDialog {
} }
lblStatus.setText("✕ Falha na assinatura"); lblStatus.setText("✕ Falha na assinatura");
lblStatus.setStyle("-fx-text-fill: #ef4444; -fx-font-weight: bold;"); lblStatus.getStyleClass().setAll("label", "text-danger", "text-bold");
showAlert(Alert.AlertType.ERROR, "Erro na Assinatura do PDF", showAlert(Alert.AlertType.ERROR, "Erro na Assinatura do PDF",
"Não foi possível concluir a assinatura digital:\n" + (ex != null ? ex.getMessage() : "Erro desconhecido")); "Não foi possível concluir a assinatura digital:\n" + (ex != null ? ex.getMessage() : "Erro desconhecido"));
@@ -587,4 +585,8 @@ public final class PdfCertificateSignDialog {
stage.show(); stage.show();
stage.toFront(); stage.toFront();
} }
public Stage getStage() {
return stage;
}
} }
@@ -228,9 +228,9 @@ public final class PdfSignDialog {
VBox docDetails = new VBox(2); VBox docDetails = new VBox(2);
lblDocName = new Label("Nenhum arquivo selecionado"); lblDocName = new Label("Nenhum arquivo selecionado");
lblDocName.setStyle("-fx-font-weight: bold; -fx-font-size: 12.5px; -fx-text-fill: -fx-text-primary;"); lblDocName.getStyleClass().addAll("text-primary", "text-bold");
lblDocMeta = new Label("Selecione um arquivo PDF para pré-visualização"); lblDocMeta = new Label("Selecione um arquivo PDF para pré-visualização");
lblDocMeta.setStyle("-fx-font-size: 11px; -fx-text-fill: -fx-text-secondary;"); lblDocMeta.getStyleClass().addAll("text-muted", "text-small");
docDetails.getChildren().addAll(lblDocName, lblDocMeta); docDetails.getChildren().addAll(lblDocName, lblDocMeta);
Region docSpacer = new Region(); Region docSpacer = new Region();
@@ -252,7 +252,7 @@ public final class PdfSignDialog {
leftScroll.setPrefWidth(330); leftScroll.setPrefWidth(330);
leftScroll.setMinWidth(310); leftScroll.setMinWidth(310);
leftScroll.setMaxWidth(360); leftScroll.setMaxWidth(360);
leftScroll.setStyle("-fx-background-color: transparent; -fx-background: transparent; -fx-border-color: transparent;"); leftScroll.getStyleClass().add("scroll-transparent");
VBox sealSection = buildSealOptionsSection(); VBox sealSection = buildSealOptionsSection();
leftScroll.setContent(sealSection); leftScroll.setContent(sealSection);
@@ -269,14 +269,14 @@ public final class PdfSignDialog {
footer.setPadding(new Insets(6, 0, 0, 0)); footer.setPadding(new Insets(6, 0, 0, 0));
btnCancel = new Button("Cancelar"); btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().addAll("btn-secondary", "btn-dialog"); btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setMinWidth(110); btnCancel.setMinWidth(110);
btnCancel.setOnAction(e -> stage.close()); btnCancel.setOnAction(e -> stage.close());
HBox btnNextContent = new HBox(8); HBox btnNextContent = new HBox(8);
btnNextContent.setAlignment(Pos.CENTER); btnNextContent.setAlignment(Pos.CENTER);
Label lblBtnNextText = new Label("Avançar"); Label lblBtnNextText = new Label("Avançar");
lblBtnNextText.setStyle("-fx-font-weight: bold; -fx-font-size: 12px; -fx-text-fill: #ffffff;"); lblBtnNextText.getStyleClass().add("text-bold");
btnNextContent.getChildren().addAll(lblBtnNextText, SvgIcons.arrowRightIcon(12)); btnNextContent.getChildren().addAll(lblBtnNextText, SvgIcons.arrowRightIcon(12));
btnNextToCert = new Button(); btnNextToCert = new Button();
@@ -325,11 +325,10 @@ public final class PdfSignDialog {
HBox themeHeader = new HBox(8); HBox themeHeader = new HBox(8);
themeHeader.setAlignment(Pos.CENTER_LEFT); themeHeader.setAlignment(Pos.CENTER_LEFT);
Label lblDefaultBadge = new Label("★ PADRÃO"); Label lblDefaultBadge = new Label("★ PADRÃO");
lblDefaultBadge.setStyle("-fx-background-color: #0284c7; -fx-text-fill: #ffffff; -fx-padding: 2px 6px; -fx-background-radius: 4px; -fx-font-weight: bold; -fx-font-size: 10px;"); lblDefaultBadge.getStyleClass().add("badge-primary");
lblSealThemeName = new Label(); lblSealThemeName = new Label();
lblSealThemeName.getStyleClass().add("cert-title"); lblSealThemeName.getStyleClass().addAll("cert-title", "text-bold");
lblSealThemeName.setStyle("-fx-font-size: 12.5px; -fx-font-weight: bold;");
themeHeader.getChildren().addAll(lblDefaultBadge, lblSealThemeName); themeHeader.getChildren().addAll(lblDefaultBadge, lblSealThemeName);
lblSealThemeDesc = new Label(); lblSealThemeDesc = new Label();
@@ -349,7 +348,7 @@ public final class PdfSignDialog {
// Preview em miniatura do SVG // Preview em miniatura do SVG
VBox previewBox = new VBox(4); VBox previewBox = new VBox(4);
previewBox.setAlignment(Pos.CENTER); previewBox.setAlignment(Pos.CENTER);
previewBox.setStyle("-fx-background-color: -fx-bg-primary; -fx-border-color: -fx-border-light; -fx-border-radius: 6px; -fx-padding: 8px;"); previewBox.getStyleClass().add("surface-box");
sealPreviewImageView = new ImageView(); sealPreviewImageView = new ImageView();
sealPreviewImageView.setPreserveRatio(true); sealPreviewImageView.setPreserveRatio(true);
sealPreviewImageView.setFitWidth(260); sealPreviewImageView.setFitWidth(260);
@@ -391,9 +390,9 @@ public final class PdfSignDialog {
// Dica amigável de posicionamento livre // Dica amigável de posicionamento livre
VBox dragTipBox = new VBox(2); VBox dragTipBox = new VBox(2);
dragTipBox.setPadding(new Insets(8, 10, 8, 10)); dragTipBox.setPadding(new Insets(8, 10, 8, 10));
dragTipBox.setStyle("-fx-background-color: -fx-bg-primary; -fx-border-color: -fx-border-light; -fx-border-radius: 6px; -fx-background-radius: 6px;"); dragTipBox.getStyleClass().add("surface-box");
Label lblDragTip = new Label("💡 Arraste o selo livremente sobre a folha para posicioná-lo onde desejar."); Label lblDragTip = new Label("💡 Arraste o selo livremente sobre a folha para posicioná-lo onde desejar.");
lblDragTip.setStyle("-fx-font-size: 11px; -fx-text-fill: -fx-text-secondary;"); lblDragTip.getStyleClass().addAll("text-muted", "text-small");
lblDragTip.setWrapText(true); lblDragTip.setWrapText(true);
dragTipBox.getChildren().add(lblDragTip); dragTipBox.getChildren().add(lblDragTip);
@@ -458,7 +457,7 @@ public final class PdfSignDialog {
// Grupo de Zoom da Folha // Grupo de Zoom da Folha
HBox zoomBox = new HBox(5); HBox zoomBox = new HBox(5);
zoomBox.setAlignment(Pos.CENTER_LEFT); zoomBox.setAlignment(Pos.CENTER_LEFT);
zoomBox.setStyle("-fx-background-color: -fx-bg-primary; -fx-border-color: -fx-border-light; -fx-border-radius: 6px; -fx-padding: 2px 6px;"); zoomBox.getStyleClass().add("toolbar-box");
btnZoomOut = new Button(); btnZoomOut = new Button();
btnZoomOut.setGraphic(SvgIcons.zoomOutIcon(13)); btnZoomOut.setGraphic(SvgIcons.zoomOutIcon(13));
@@ -486,7 +485,7 @@ public final class PdfSignDialog {
// Grupo de Tamanho do Selo // Grupo de Tamanho do Selo
HBox resizeToolBox = new HBox(6); HBox resizeToolBox = new HBox(6);
resizeToolBox.setAlignment(Pos.CENTER_LEFT); resizeToolBox.setAlignment(Pos.CENTER_LEFT);
resizeToolBox.setStyle("-fx-background-color: -fx-bg-primary; -fx-border-color: -fx-border-light; -fx-border-radius: 6px; -fx-padding: 2px 6px;"); resizeToolBox.getStyleClass().add("toolbar-box");
btnToggleResize = new Button(" Redimensionar", SvgIcons.zoomFitIcon(13)); btnToggleResize = new Button(" Redimensionar", SvgIcons.zoomFitIcon(13));
btnToggleResize.getStyleClass().addAll("btn-secondary", "btn-compact"); btnToggleResize.getStyleClass().addAll("btn-secondary", "btn-compact");
@@ -508,7 +507,7 @@ public final class PdfSignDialog {
HBox.setHgrow(tbSpacer, Priority.ALWAYS); HBox.setHgrow(tbSpacer, Priority.ALWAYS);
lblPositionFeedback = new Label("Clique na folha para posicionar"); lblPositionFeedback = new Label("Clique na folha para posicionar");
lblPositionFeedback.setStyle("-fx-font-size: 11.5px; -fx-text-fill: -fx-accent; -fx-font-weight: bold;"); lblPositionFeedback.getStyleClass().addAll("text-accent", "text-bold");
toolbar.getChildren().addAll(pageNavBox, zoomBox, resizeToolBox, tbSpacer, lblPositionFeedback); toolbar.getChildren().addAll(pageNavBox, zoomBox, resizeToolBox, tbSpacer, lblPositionFeedback);
@@ -517,7 +516,7 @@ public final class PdfSignDialog {
sheetScroll.setFitToWidth(false); sheetScroll.setFitToWidth(false);
sheetScroll.setFitToHeight(false); sheetScroll.setFitToHeight(false);
sheetScroll.setPannable(false); sheetScroll.setPannable(false);
sheetScroll.setStyle("-fx-background-color: transparent; -fx-background: transparent; -fx-border-color: transparent;"); sheetScroll.getStyleClass().add("scroll-transparent");
VBox.setVgrow(sheetScroll, Priority.ALWAYS); VBox.setVgrow(sheetScroll, Priority.ALWAYS);
// Permite atalho de Zoom com Ctrl + Rolagem do Mouse // Permite atalho de Zoom com Ctrl + Rolagem do Mouse
@@ -538,7 +537,7 @@ public final class PdfSignDialog {
pageSheetContainer = new StackPane(); pageSheetContainer = new StackPane();
pageSheetContainer.setAlignment(Pos.TOP_LEFT); pageSheetContainer.setAlignment(Pos.TOP_LEFT);
pageSheetContainer.setStyle("-fx-background-color: #ffffff; -fx-border-color: #94a3b8; -fx-border-width: 1px;"); pageSheetContainer.getStyleClass().add("preview-box");
DropShadow sheetShadow = new DropShadow(16, 0, 4, Color.rgb(0, 0, 0, 0.30)); DropShadow sheetShadow = new DropShadow(16, 0, 4, Color.rgb(0, 0, 0, 0.30));
pageSheetContainer.setEffect(sheetShadow); pageSheetContainer.setEffect(sheetShadow);
updateContainerZoomDimensions(); updateContainerZoomDimensions();
@@ -684,11 +683,11 @@ public final class PdfSignDialog {
if (btnToggleResize != null) { if (btnToggleResize != null) {
if (isResizeModeActive) { if (isResizeModeActive) {
btnToggleResize.setText("✓ Concluir"); btnToggleResize.setText("✓ Concluir");
btnToggleResize.setStyle("-fx-background-color: #0284c7; -fx-text-fill: white; -fx-font-weight: bold;"); btnToggleResize.getStyleClass().setAll("btn-primary");
lblPositionFeedback.setText("👉 Puxe a alça azul no canto do selo para ajustar o tamanho"); lblPositionFeedback.setText("👉 Puxe a alça azul no canto do selo para ajustar o tamanho");
} else { } else {
btnToggleResize.setText("📏 Redimensionar"); btnToggleResize.setText("📏 Redimensionar");
btnToggleResize.setStyle(""); btnToggleResize.getStyleClass().setAll("btn-secondary");
updateFeedbackLabel(); updateFeedbackLabel();
} }
} }
@@ -1250,4 +1249,8 @@ public final class PdfSignDialog {
return label; return label;
} }
} }
public Stage getStage() {
return stage;
}
} }
@@ -135,7 +135,7 @@ public final class SealDesignerDialog {
ScrollPane scrollForm = new ScrollPane(formPane); ScrollPane scrollForm = new ScrollPane(formPane);
scrollForm.setFitToWidth(true); scrollForm.setFitToWidth(true);
VBox.setVgrow(scrollForm, Priority.ALWAYS); VBox.setVgrow(scrollForm, Priority.ALWAYS);
scrollForm.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); scrollForm.getStyleClass().add("scroll-transparent");
HBox.setHgrow(scrollForm, Priority.ALWAYS); HBox.setHgrow(scrollForm, Priority.ALWAYS);
// 1. Identificação do Selo e Campos Adicionais // 1. Identificação do Selo e Campos Adicionais
@@ -276,7 +276,7 @@ public final class SealDesignerDialog {
logoBtnRow.setAlignment(Pos.CENTER_LEFT); logoBtnRow.setAlignment(Pos.CENTER_LEFT);
lblLogoStatus = new Label("Nenhum logotipo carregado (usando emblema vetorial)"); lblLogoStatus = new Label("Nenhum logotipo carregado (usando emblema vetorial)");
lblLogoStatus.setStyle("-fx-font-size: 11px; -fx-text-fill: #64748b;"); lblLogoStatus.getStyleClass().add("text-muted");
Label lblFallbackIcon = new Label("Emblema Vetorial Alternativo (caso sem logo própria):"); Label lblFallbackIcon = new Label("Emblema Vetorial Alternativo (caso sem logo própria):");
lblFallbackIcon.getStyleClass().add("form-label"); lblFallbackIcon.getStyleClass().add("form-label");
@@ -341,7 +341,7 @@ public final class SealDesignerDialog {
lblPreviewTitle.getStyleClass().add("dialog-field-title"); lblPreviewTitle.getStyleClass().add("dialog-field-title");
Label lblPreviewNotice = new Label("O selo sempre exibe o nome completo do signatário com destaque e máxima legibilidade."); Label lblPreviewNotice = new Label("O selo sempre exibe o nome completo do signatário com destaque e máxima legibilidade.");
lblPreviewNotice.setStyle("-fx-font-size: 11px; -fx-text-fill: #94a3b8;"); lblPreviewNotice.getStyleClass().add("text-muted");
lblPreviewNotice.setWrapText(true); lblPreviewNotice.setWrapText(true);
previewImageView = new ImageView(); previewImageView = new ImageView();
@@ -351,7 +351,7 @@ public final class SealDesignerDialog {
HBox previewContainer = new HBox(previewImageView); HBox previewContainer = new HBox(previewImageView);
previewContainer.setAlignment(Pos.CENTER); previewContainer.setAlignment(Pos.CENTER);
previewContainer.setPadding(new Insets(16, 8, 16, 8)); previewContainer.setPadding(new Insets(16, 8, 16, 8));
previewContainer.setStyle("-fx-background-color: #090d16; -fx-background-radius: 8px; -fx-border-color: #334155; -fx-border-radius: 8px;"); previewContainer.getStyleClass().add("preview-box");
VBox previewContentBox = new VBox(10); VBox previewContentBox = new VBox(10);
previewContentBox.setAlignment(Pos.CENTER); previewContentBox.setAlignment(Pos.CENTER);
@@ -442,7 +442,7 @@ public final class SealDesignerDialog {
byte[] bytes = Files.readAllBytes(file.toPath()); byte[] bytes = Files.readAllBytes(file.toPath());
customLogoBase64 = Base64.getEncoder().encodeToString(bytes); customLogoBase64 = Base64.getEncoder().encodeToString(bytes);
lblLogoStatus.setText("✓ Imagem carregada: " + file.getName()); lblLogoStatus.setText("✓ Imagem carregada: " + file.getName());
lblLogoStatus.setStyle("-fx-font-size: 11px; -fx-text-fill: #16a34a; -fx-font-weight: bold;"); lblLogoStatus.getStyleClass().setAll("label", "text-success", "text-bold");
btnClearLogo.setDisable(false); btnClearLogo.setDisable(false);
updatePreview(); updatePreview();
} catch (Exception ex) { } catch (Exception ex) {
@@ -454,7 +454,7 @@ public final class SealDesignerDialog {
private void handleClearLogo() { private void handleClearLogo() {
customLogoBase64 = null; customLogoBase64 = null;
lblLogoStatus.setText("Nenhum logotipo carregado (usando emblema vetorial)"); lblLogoStatus.setText("Nenhum logotipo carregado (usando emblema vetorial)");
lblLogoStatus.setStyle("-fx-font-size: 11px; -fx-text-fill: #64748b;"); lblLogoStatus.getStyleClass().setAll("label", "text-muted");
btnClearLogo.setDisable(true); btnClearLogo.setDisable(true);
updatePreview(); updatePreview();
} }
@@ -524,12 +524,12 @@ public final class SealDesignerDialog {
if (theme.customLogoBase64() != null && !theme.customLogoBase64().isBlank()) { if (theme.customLogoBase64() != null && !theme.customLogoBase64().isBlank()) {
this.customLogoBase64 = theme.customLogoBase64(); this.customLogoBase64 = theme.customLogoBase64();
lblLogoStatus.setText("✓ Logotipo carregado com sucesso!"); lblLogoStatus.setText("✓ Logotipo carregado com sucesso!");
lblLogoStatus.setStyle("-fx-font-size: 11px; -fx-text-fill: #16a34a; -fx-font-weight: bold;"); lblLogoStatus.getStyleClass().setAll("label", "text-success", "text-bold");
btnClearLogo.setDisable(false); btnClearLogo.setDisable(false);
} else { } else {
this.customLogoBase64 = null; this.customLogoBase64 = null;
lblLogoStatus.setText("Nenhum logotipo carregado (usando emblema vetorial)"); lblLogoStatus.setText("Nenhum logotipo carregado (usando emblema vetorial)");
lblLogoStatus.setStyle("-fx-font-size: 11px; -fx-text-fill: #64748b;"); lblLogoStatus.getStyleClass().setAll("label", "text-muted");
btnClearLogo.setDisable(true); btnClearLogo.setDisable(true);
} }
@@ -118,7 +118,7 @@ public final class SealManagementDialog {
listViewSeals = new ListView<>(); listViewSeals = new ListView<>();
VBox.setVgrow(listViewSeals, Priority.ALWAYS); VBox.setVgrow(listViewSeals, Priority.ALWAYS);
listViewSeals.setStyle("-fx-background-color: transparent; -fx-background-radius: 6px;"); listViewSeals.getStyleClass().add("cyber-scroll-pane");
listViewSeals.setCellFactory(lv -> new SealListCell()); listViewSeals.setCellFactory(lv -> new SealListCell());
listViewSeals.getSelectionModel().selectedItemProperty().addListener((obs, oldV, newV) -> onThemeSelected(newV)); listViewSeals.getSelectionModel().selectedItemProperty().addListener((obs, oldV, newV) -> onThemeSelected(newV));
@@ -153,10 +153,10 @@ public final class SealManagementDialog {
lblPreviewHeader.getStyleClass().add("dialog-field-title"); lblPreviewHeader.getStyleClass().add("dialog-field-title");
lblSelectedName = new Label("Selecione um selo para visualizar"); lblSelectedName = new Label("Selecione um selo para visualizar");
lblSelectedName.setStyle("-fx-font-weight: bold; -fx-font-size: 14px;"); lblSelectedName.getStyleClass().add("dialog-header-title");
lblSelectedDesc = new Label(""); lblSelectedDesc = new Label("");
lblSelectedDesc.setStyle("-fx-font-size: 11.5px; -fx-text-fill: #64748b;"); lblSelectedDesc.getStyleClass().add("text-muted");
lblSelectedDesc.setWrapText(true); lblSelectedDesc.setWrapText(true);
previewImageView = new ImageView(); previewImageView = new ImageView();
@@ -166,14 +166,14 @@ public final class SealManagementDialog {
HBox previewContainer = new HBox(previewImageView); HBox previewContainer = new HBox(previewImageView);
previewContainer.setAlignment(Pos.CENTER); previewContainer.setAlignment(Pos.CENTER);
previewContainer.setPadding(new Insets(14, 10, 14, 10)); previewContainer.setPadding(new Insets(14, 10, 14, 10));
previewContainer.setStyle("-fx-background-color: #090d16; -fx-background-radius: 8px; -fx-border-color: #334155; -fx-border-radius: 8px;"); previewContainer.getStyleClass().add("preview-box");
VBox.setVgrow(previewContainer, Priority.ALWAYS); VBox.setVgrow(previewContainer, Priority.ALWAYS);
lblActiveBadge = new Label(""); lblActiveBadge = new Label("");
lblActiveBadge.setStyle("-fx-font-weight: bold; -fx-font-size: 12px;"); lblActiveBadge.getStyleClass().add("text-bold");
lblFeedback = new Label(""); lblFeedback = new Label("");
lblFeedback.setStyle("-fx-font-size: 12px; -fx-font-weight: bold; -fx-text-fill: #16a34a;"); lblFeedback.getStyleClass().addAll("text-success", "text-bold");
// Botões de Ação do Selo Selecionado // Botões de Ação do Selo Selecionado
VBox sealActions = new VBox(8); VBox sealActions = new VBox(8);
@@ -271,16 +271,14 @@ public final class SealManagementDialog {
boolean isDefault = theme.id().equalsIgnoreCase(currentDefaultThemeId); boolean isDefault = theme.id().equalsIgnoreCase(currentDefaultThemeId);
if (isDefault) { if (isDefault) {
lblActiveBadge.setText("★ ESTE É O SELO PADRÃO ATIVO PARA TODAS AS ASSINATURAS"); lblActiveBadge.setText("★ ESTE É O SELO PADRÃO ATIVO PARA TODAS AS ASSINATURAS");
lblActiveBadge.setStyle("-fx-text-fill: #38bdf8; -fx-font-weight: bold; -fx-font-size: 11.5px;"); lblActiveBadge.getStyleClass().setAll("label", "text-primary", "text-bold");
btnSetDefault.setText("★ Selo Padrão Ativo no Sistema"); btnSetDefault.setText("★ Selo Padrão Ativo no Sistema");
btnSetDefault.setDisable(true); btnSetDefault.setDisable(true);
btnSetDefault.setStyle("-fx-opacity: 0.95; -fx-background-color: #0369a1; -fx-text-fill: #ffffff; -fx-font-weight: bold;");
} else { } else {
lblActiveBadge.setText("Selo disponível para uso."); lblActiveBadge.setText("Selo disponível para uso.");
lblActiveBadge.setStyle("-fx-text-fill: #94a3b8; -fx-font-size: 11.5px;"); lblActiveBadge.getStyleClass().setAll("label", "text-muted");
btnSetDefault.setText("✔ Definir como Selo Padrão Ativo"); btnSetDefault.setText("✔ Definir como Selo Padrão Ativo");
btnSetDefault.setDisable(false); btnSetDefault.setDisable(false);
btnSetDefault.setStyle("");
} }
btnEditClone.setDisable(false); btnEditClone.setDisable(false);
@@ -460,14 +458,14 @@ public final class SealManagementDialog {
VBox textBox = new VBox(2); VBox textBox = new VBox(2);
Label lblName = new Label(item.name()); Label lblName = new Label(item.name());
lblName.setStyle("-fx-font-weight: bold; -fx-font-size: 12.5px;"); lblName.getStyleClass().add("cert-title");
lblName.maxWidthProperty().bind(listViewSeals.widthProperty().subtract(120)); lblName.maxWidthProperty().bind(listViewSeals.widthProperty().subtract(120));
lblName.setWrapText(true); lblName.setWrapText(true);
String desc = (item.description() != null && !item.description().isBlank()) String desc = (item.description() != null && !item.description().isBlank())
? item.description() : "Identidade visual de assinatura"; ? item.description() : "Identidade visual de assinatura";
Label lblDesc = new Label(desc); Label lblDesc = new Label(desc);
lblDesc.setStyle("-fx-font-size: 11px; -fx-text-fill: #64748b;"); lblDesc.getStyleClass().add("cert-detail");
lblDesc.maxWidthProperty().bind(listViewSeals.widthProperty().subtract(120)); lblDesc.maxWidthProperty().bind(listViewSeals.widthProperty().subtract(120));
lblDesc.setWrapText(true); lblDesc.setWrapText(true);
@@ -480,14 +478,12 @@ public final class SealManagementDialog {
boolean isDefault = item.id().equalsIgnoreCase(currentDefaultThemeId); boolean isDefault = item.id().equalsIgnoreCase(currentDefaultThemeId);
if (isDefault) { if (isDefault) {
Label badgeDefault = new Label("★ PADRÃO"); Label badgeDefault = new Label("★ PADRÃO");
badgeDefault.setStyle("-fx-background-color: #0284c7; -fx-text-fill: #ffffff; -fx-font-size: 9.5px; -fx-font-weight: bold; -fx-padding: 2px 6px; -fx-background-radius: 4px;"); badgeDefault.getStyleClass().add("badge-primary");
badgesBox.getChildren().add(badgeDefault); badgesBox.getChildren().add(badgeDefault);
} }
Label badgeType = new Label(item.isCustom() ? "Personalizado" : "Sistema"); Label badgeType = new Label(item.isCustom() ? "Personalizado" : "Sistema");
badgeType.setStyle(item.isCustom() badgeType.getStyleClass().add(item.isCustom() ? "cert-badge-a3" : "cert-badge-a1");
? "-fx-background-color: #fef3c7; -fx-text-fill: #b45309; -fx-font-size: 9.5px; -fx-padding: 2px 6px; -fx-background-radius: 4px;"
: "-fx-background-color: #e0f2fe; -fx-text-fill: #0369a1; -fx-font-size: 9.5px; -fx-padding: 2px 6px; -fx-background-radius: 4px;");
badgesBox.getChildren().add(badgeType); badgesBox.getChildren().add(badgeType);
card.getChildren().addAll(textBox, badgesBox); card.getChildren().addAll(textBox, badgesBox);
@@ -53,7 +53,7 @@ public final class SettingsView extends VBox {
Label subtitleLabel = new Label("Parâmetros de segurança local, identidade visual dos selos e aplicações autorizadas."); Label subtitleLabel = new Label("Parâmetros de segurança local, identidade visual dos selos e aplicações autorizadas.");
subtitleLabel.getStyleClass().add("brand-subtitle"); subtitleLabel.getStyleClass().add("brand-subtitle");
saveFeedbackLabel.setStyle("-fx-text-fill: #10b981; -fx-font-size: 11.5px; -fx-font-weight: bold;"); saveFeedbackLabel.getStyleClass().addAll("text-success", "text-bold");
headerBox.getChildren().addAll(titleLabel, subtitleLabel, saveFeedbackLabel); headerBox.getChildren().addAll(titleLabel, subtitleLabel, saveFeedbackLabel);
@@ -126,10 +126,9 @@ public final class SettingsView extends VBox {
Button btnClearPins = new Button("Limpar PINs Salvos (Sessão e Computador)"); Button btnClearPins = new Button("Limpar PINs Salvos (Sessão e Computador)");
btnClearPins.getStyleClass().add("btn-secondary"); btnClearPins.getStyleClass().add("btn-secondary");
btnClearPins.setStyle("-fx-padding: 6px 14px; -fx-font-size: 12px;");
Label pinStatusLabel = new Label(); Label pinStatusLabel = new Label();
pinStatusLabel.setStyle("-fx-text-fill: #34d399; -fx-font-size: 12px;"); pinStatusLabel.getStyleClass().add("text-success");
btnClearPins.setOnAction(e -> { btnClearPins.setOnAction(e -> {
PinSessionManager.getInstance().clearAll(); PinSessionManager.getInstance().clearAll();
@@ -152,12 +151,11 @@ public final class SettingsView extends VBox {
sealHeaderRow.setAlignment(Pos.CENTER_LEFT); sealHeaderRow.setAlignment(Pos.CENTER_LEFT);
Label lblSealsDesc = new Label("Gerencie os temas e identidades gráficas instaladas para assinaturas PDF:"); Label lblSealsDesc = new Label("Gerencie os temas e identidades gráficas instaladas para assinaturas PDF:");
lblSealsDesc.setStyle("-fx-text-fill: #94a3b8; -fx-font-size: 12px;"); lblSealsDesc.getStyleClass().add("text-muted");
HBox.setHgrow(lblSealsDesc, Priority.ALWAYS); HBox.setHgrow(lblSealsDesc, Priority.ALWAYS);
Button btnCreateSeal = new Button("🎨 Criar ou Instalar Selo..."); Button btnCreateSeal = new Button("🎨 Criar ou Instalar Selo...");
btnCreateSeal.getStyleClass().add("btn-primary"); btnCreateSeal.getStyleClass().add("btn-primary");
btnCreateSeal.setStyle("-fx-padding: 6px 14px; -fx-font-size: 12px;");
btnCreateSeal.setOnAction(e -> openSealDesigner()); btnCreateSeal.setOnAction(e -> openSealDesigner());
sealHeaderRow.getChildren().addAll(lblSealsDesc, btnCreateSeal); sealHeaderRow.getChildren().addAll(lblSealsDesc, btnCreateSeal);
@@ -176,7 +174,7 @@ public final class SettingsView extends VBox {
ScrollPane scrollApps = new ScrollPane(appsContainer); ScrollPane scrollApps = new ScrollPane(appsContainer);
scrollApps.setFitToWidth(true); scrollApps.setFitToWidth(true);
scrollApps.setPrefHeight(150); scrollApps.setPrefHeight(150);
scrollApps.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); scrollApps.getStyleClass().add("cyber-scroll-pane");
appsBox.getChildren().addAll(appsTitle, scrollApps); appsBox.getChildren().addAll(appsTitle, scrollApps);
@@ -222,12 +220,11 @@ public final class SettingsView extends VBox {
if (isDefault) { if (isDefault) {
Label badgeDefault = new Label("★ PADRÃO"); Label badgeDefault = new Label("★ PADRÃO");
badgeDefault.setStyle("-fx-background-color: #0284c7; -fx-text-fill: #ffffff; -fx-padding: 3px 8px; -fx-background-radius: 4px; -fx-font-weight: bold; -fx-font-size: 11px;"); badgeDefault.getStyleClass().add("badge-primary");
item.getChildren().add(badgeDefault); item.getChildren().add(badgeDefault);
} else { } else {
Button btnSetDefault = new Button("★ Definir Padrão"); Button btnSetDefault = new Button("★ Definir Padrão");
btnSetDefault.getStyleClass().addAll("btn-secondary", "btn-compact"); btnSetDefault.getStyleClass().addAll("btn-secondary", "btn-compact");
btnSetDefault.setStyle("-fx-padding: 3px 8px; -fx-font-size: 11px;");
btnSetDefault.setOnAction(e -> { btnSetDefault.setOnAction(e -> {
AgentConfiguration current = configService.getConfig(); AgentConfiguration current = configService.getConfig();
configService.updateConfig(new AgentConfiguration( configService.updateConfig(new AgentConfiguration(
@@ -247,8 +244,7 @@ public final class SettingsView extends VBox {
if (theme.isCustom()) { if (theme.isCustom()) {
Button btnDelete = new Button("Excluir"); Button btnDelete = new Button("Excluir");
btnDelete.getStyleClass().add("btn-secondary"); btnDelete.getStyleClass().add("btn-danger-sm");
btnDelete.setStyle("-fx-padding: 3px 8px; -fx-font-size: 11px; -fx-text-fill: #f87171;");
btnDelete.setOnAction(e -> { btnDelete.setOnAction(e -> {
try { try {
PdfSealThemeRegistry.uninstallCustomTheme(theme.id()); PdfSealThemeRegistry.uninstallCustomTheme(theme.id());
@@ -310,8 +306,7 @@ public final class SettingsView extends VBox {
statusLabel.getStyleClass().add(app.enabled() ? "diagnostic-value-ok" : "diagnostic-value-warn"); statusLabel.getStyleClass().add(app.enabled() ? "diagnostic-value-ok" : "diagnostic-value-warn");
Button btnRevoke = new Button("Revogar"); Button btnRevoke = new Button("Revogar");
btnRevoke.getStyleClass().add("btn-secondary"); btnRevoke.getStyleClass().add("btn-danger-sm");
btnRevoke.setStyle("-fx-padding: 4px 10px; -fx-font-size: 11px; -fx-text-fill: #f87171;");
btnRevoke.setOnAction(e -> { btnRevoke.setOnAction(e -> {
if (onRevokeApplication != null) { if (onRevokeApplication != null) {
onRevokeApplication.accept(app.applicationId()); onRevokeApplication.accept(app.applicationId());
@@ -174,14 +174,13 @@ public class SignaturePromptDialog {
if (isWindowsStore) { if (isWindowsStore) {
VBox winBox = new VBox(6); VBox winBox = new VBox(6);
Label winTitle = new Label("🔐 Autenticação nativa pelo Windows / Driver do Token"); Label winTitle = new Label("🔐 Autenticação nativa pelo Windows / Driver do Token");
winTitle.setStyle("-fx-text-fill: -fx-accent; -fx-font-weight: bold; -fx-font-size: 13px;"); winTitle.getStyleClass().addAll("text-accent", "text-bold");
Label winDesc = new Label( Label winDesc = new Label(
"O PIN deste dispositivo é gerenciado diretamente pelo driver nativo (SafeSign / Windows Security). " + "O PIN deste dispositivo é gerenciado diretamente pelo driver nativo (SafeSign / Windows Security). " +
"Caso o token ainda não esteja autenticado, a janela segura do driver será aberta automaticamente." "Caso o token ainda não esteja autenticado, a janela segura do driver será aberta automaticamente."
); );
winDesc.getStyleClass().add("dialog-subtitle"); winDesc.getStyleClass().add("dialog-subtitle");
winDesc.setStyle("-fx-font-size: 12px;");
winDesc.setWrapText(true); winDesc.setWrapText(true);
winBox.getChildren().addAll(winTitle, winDesc); winBox.getChildren().addAll(winTitle, winDesc);
@@ -194,11 +193,10 @@ public class SignaturePromptDialog {
rememberedBox.setAlignment(Pos.CENTER_LEFT); rememberedBox.setAlignment(Pos.CENTER_LEFT);
Label rememberedBadge = new Label("● PIN salvo nesta sessão ativa"); Label rememberedBadge = new Label("● PIN salvo nesta sessão ativa");
rememberedBadge.setStyle("-fx-text-fill: #10b981; -fx-font-weight: bold; -fx-font-size: 12px;"); rememberedBadge.getStyleClass().addAll("text-success", "text-bold");
Button btnChangePin = new Button("Alterar PIN"); Button btnChangePin = new Button("Alterar PIN");
btnChangePin.getStyleClass().add("btn-secondary"); btnChangePin.getStyleClass().add("btn-secondary");
btnChangePin.setStyle("-fx-padding: 4px 10px; -fx-font-size: 11px;");
VBox inputWrapper = new VBox(8); VBox inputWrapper = new VBox(8);
inputWrapper.setVisible(false); inputWrapper.setVisible(false);
@@ -222,7 +220,6 @@ public class SignaturePromptDialog {
VBox inputWrapper = new VBox(8); VBox inputWrapper = new VBox(8);
Label pinPromptLabel = new Label("Informe o PIN do dispositivo para autorizar a chave privada:"); Label pinPromptLabel = new Label("Informe o PIN do dispositivo para autorizar a chave privada:");
pinPromptLabel.getStyleClass().add("dialog-subtitle"); pinPromptLabel.getStyleClass().add("dialog-subtitle");
pinPromptLabel.setStyle("-fx-font-size: 12px;");
cbSavePin.setSelected(false); cbSavePin.setSelected(false);
inputWrapper.getChildren().addAll(pinPromptLabel, pinField, cbSavePin); inputWrapper.getChildren().addAll(pinPromptLabel, pinField, cbSavePin);
@@ -233,7 +230,7 @@ public class SignaturePromptDialog {
// Label de Alerta de Validação // Label de Alerta de Validação
Label validationLabel = new Label(); Label validationLabel = new Label();
validationLabel.setStyle("-fx-text-fill: #f87171; -fx-font-size: 12px;"); validationLabel.getStyleClass().addAll("text-danger", "text-bold");
validationLabel.setVisible(false); validationLabel.setVisible(false);
validationLabel.setManaged(false); validationLabel.setManaged(false);
@@ -152,7 +152,7 @@ public final class SignatureValidationDialog {
ScrollPane scrollResult = new ScrollPane(resultBox); ScrollPane scrollResult = new ScrollPane(resultBox);
scrollResult.setFitToWidth(true); scrollResult.setFitToWidth(true);
scrollResult.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); scrollResult.getStyleClass().add("cyber-scroll-pane");
VBox.setVgrow(scrollResult, Priority.ALWAYS); VBox.setVgrow(scrollResult, Priority.ALWAYS);
// Rodapé // Rodapé
@@ -277,27 +277,26 @@ public final class SignatureValidationDialog {
statusBadge.setPadding(new Insets(10, 14, 10, 14)); statusBadge.setPadding(new Insets(10, 14, 10, 14));
Label lblBadge = new Label(result.status().getDescription()); Label lblBadge = new Label(result.status().getDescription());
lblBadge.setStyle("-fx-font-weight: bold; -fx-font-size: 14px;");
if (result.status() == ValidationStatus.VALID) { if (result.status() == ValidationStatus.VALID) {
statusBadge.setStyle("-fx-background-color: rgba(16, 185, 129, 0.15); -fx-background-radius: 6px; -fx-border-color: #10b981; -fx-border-radius: 6px;"); statusBadge.getStyleClass().add("status-badge-valid");
lblBadge.setStyle(lblBadge.getStyle() + " -fx-text-fill: #10b981;"); lblBadge.getStyleClass().addAll("text-success", "text-bold");
} else if (result.status() == ValidationStatus.INVALID) { } else if (result.status() == ValidationStatus.INVALID) {
statusBadge.setStyle("-fx-background-color: rgba(239, 68, 68, 0.15); -fx-background-radius: 6px; -fx-border-color: #ef4444; -fx-border-radius: 6px;"); statusBadge.getStyleClass().add("status-badge-invalid");
lblBadge.setStyle(lblBadge.getStyle() + " -fx-text-fill: #ef4444;"); lblBadge.getStyleClass().addAll("text-danger", "text-bold");
} else { } else {
statusBadge.setStyle("-fx-background-color: rgba(245, 158, 11, 0.15); -fx-background-radius: 6px; -fx-border-color: #f59e0b; -fx-border-radius: 6px;"); statusBadge.getStyleClass().add("status-badge-warning");
lblBadge.setStyle(lblBadge.getStyle() + " -fx-text-fill: #f59e0b;"); lblBadge.getStyleClass().addAll("text-warning", "text-bold");
} }
Label lblType = new Label("• Formato: " + result.type().getDescription()); Label lblType = new Label("• Formato: " + result.type().getDescription());
lblType.setStyle("-fx-font-size: 12px; -fx-text-fill: #cbd5e1;"); lblType.getStyleClass().add("text-muted");
statusBadge.getChildren().addAll(lblBadge, lblType); statusBadge.getChildren().addAll(lblBadge, lblType);
Label lblMsg = new Label(result.summaryMessage()); Label lblMsg = new Label(result.summaryMessage());
lblMsg.setWrapText(true); lblMsg.setWrapText(true);
lblMsg.setStyle("-fx-font-size: 12.5px; -fx-font-weight: bold;"); lblMsg.getStyleClass().add("text-bold");
resultBox.getChildren().addAll(statusBadge, lblMsg); resultBox.getChildren().addAll(statusBadge, lblMsg);
@@ -324,7 +323,7 @@ public final class SignatureValidationDialog {
lblTime.getStyleClass().add("cert-detail"); lblTime.getStyleClass().add("cert-detail");
Label lblIntegrity = new Label(s.isValid() ? "✓ Assinatura íntegra e chave pública conferida." : "✗ Falha na integridade da assinatura."); Label lblIntegrity = new Label(s.isValid() ? "✓ Assinatura íntegra e chave pública conferida." : "✗ Falha na integridade da assinatura.");
lblIntegrity.setStyle(s.isValid() ? "-fx-text-fill: #10b981; -fx-font-weight: bold; -fx-font-size: 11.5px;" : "-fx-text-fill: #ef4444; -fx-font-weight: bold; -fx-font-size: 11.5px;"); lblIntegrity.getStyleClass().addAll(s.isValid() ? "text-success" : "text-danger", "text-bold");
card.getChildren().addAll(lblSignerName, lblCert, lblTime, lblIntegrity); card.getChildren().addAll(lblSignerName, lblCert, lblTime, lblIntegrity);
resultBox.getChildren().add(card); resultBox.getChildren().add(card);
@@ -71,7 +71,7 @@ public final class TutorialDialog {
ScrollPane scroll = new ScrollPane(content); ScrollPane scroll = new ScrollPane(content);
scroll.setFitToWidth(true); scroll.setFitToWidth(true);
scroll.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); scroll.getStyleClass().add("scroll-transparent");
VBox.setVgrow(scroll, Priority.ALWAYS); VBox.setVgrow(scroll, Priority.ALWAYS);
HBox footer = new HBox(); HBox footer = new HBox();
@@ -125,7 +125,7 @@ public final class XmlSignDialog {
// ScrollPane // ScrollPane
ScrollPane scrollPane = new ScrollPane(); ScrollPane scrollPane = new ScrollPane();
scrollPane.setFitToWidth(true); scrollPane.setFitToWidth(true);
scrollPane.setStyle("-fx-background-color: transparent; -fx-background: transparent; -fx-border-color: transparent;"); scrollPane.getStyleClass().add("cyber-scroll-pane");
VBox formContent = new VBox(16); VBox formContent = new VBox(16);
formContent.setPadding(new Insets(4, 8, 4, 0)); formContent.setPadding(new Insets(4, 8, 4, 0));
@@ -194,7 +194,7 @@ public final class XmlSignDialog {
pinField.setPrefWidth(260); pinField.setPrefWidth(260);
lblPinNotice = new Label(); lblPinNotice = new Label();
lblPinNotice.setStyle("-fx-font-size: 11px;"); lblPinNotice.getStyleClass().addAll("dialog-subtitle", "text-muted");
pinRow.getChildren().addAll(lblPin, pinField, lblPinNotice); pinRow.getChildren().addAll(lblPin, pinField, lblPinNotice);
certSection.getChildren().addAll(lblCertTitle, certCombo, pinRow); certSection.getChildren().addAll(lblCertTitle, certCombo, pinRow);
@@ -289,11 +289,11 @@ public final class XmlSignDialog {
progressIndicator.setVisible(false); progressIndicator.setVisible(false);
lblStatus = new Label(); lblStatus = new Label();
lblStatus.setStyle("-fx-font-size: 12px;"); lblStatus.getStyleClass().addAll("text-muted", "text-small");
HBox.setHgrow(lblStatus, Priority.ALWAYS); HBox.setHgrow(lblStatus, Priority.ALWAYS);
btnCancel = new Button("Cancelar"); btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().addAll("btn-secondary", "btn-dialog"); btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setOnAction(e -> stage.close()); btnCancel.setOnAction(e -> stage.close());
btnSign = new Button("Assinar Documento XML"); btnSign = new Button("Assinar Documento XML");
@@ -340,16 +340,16 @@ public final class XmlSignDialog {
pinField.setDisable(true); pinField.setDisable(true);
pinField.clear(); pinField.clear();
lblPinNotice.setText("✓ PIN memorizado na sessão segura"); lblPinNotice.setText("✓ PIN memorizado na sessão segura");
lblPinNotice.setStyle("-fx-text-fill: #10b981; -fx-font-weight: bold;"); lblPinNotice.getStyleClass().setAll("label", "text-success", "text-bold");
} else if (isA3 && "provider-win-store".equalsIgnoreCase(cert.providerId())) { } else if (isA3 && "provider-win-store".equalsIgnoreCase(cert.providerId())) {
pinField.setDisable(true); pinField.setDisable(true);
pinField.clear(); pinField.clear();
lblPinNotice.setText("Autenticação nativa pelo Windows/Driver"); lblPinNotice.setText("Autenticação nativa pelo Windows/Driver");
lblPinNotice.setStyle("-fx-text-fill: -fx-accent;"); lblPinNotice.getStyleClass().setAll("label", "text-primary");
} else { } else {
pinField.setDisable(false); pinField.setDisable(false);
lblPinNotice.setText(isA3 ? "Requer PIN do Smart Card" : "Requer senha do certificado A1"); lblPinNotice.setText(isA3 ? "Requer PIN do Smart Card" : "Requer senha do certificado A1");
lblPinNotice.setStyle("-fx-text-fill: -fx-text-secondary;"); lblPinNotice.getStyleClass().setAll("label", "text-muted");
} }
} }
@@ -435,7 +435,7 @@ public final class XmlSignDialog {
setFormDisabled(true); setFormDisabled(true);
progressIndicator.setVisible(true); progressIndicator.setVisible(true);
lblStatus.setText("Assinando documento XML (" + profile.getDisplayName() + ")..."); lblStatus.setText("Assinando documento XML (" + profile.getDisplayName() + ")...");
lblStatus.setStyle("-fx-text-fill: -fx-accent;"); lblStatus.getStyleClass().setAll("label", "text-primary");
boolean validate = chkValidateAfter.isSelected(); boolean validate = chkValidateAfter.isSelected();
@@ -459,7 +459,7 @@ public final class XmlSignDialog {
setFormDisabled(false); setFormDisabled(false);
progressIndicator.setVisible(false); progressIndicator.setVisible(false);
lblStatus.setText("✓ Documento XML assinado e validado com sucesso!"); lblStatus.setText("✓ Documento XML assinado e validado com sucesso!");
lblStatus.setStyle("-fx-text-fill: #10b981; -fx-font-weight: bold;"); lblStatus.getStyleClass().setAll("label", "text-success", "text-bold");
showSuccessDialog(targetFile); showSuccessDialog(targetFile);
}); });
@@ -470,7 +470,7 @@ public final class XmlSignDialog {
Throwable ex = signTask.getException(); Throwable ex = signTask.getException();
logger.error("Falha ao assinar XML", ex); logger.error("Falha ao assinar XML", ex);
lblStatus.setText("✕ Falha na assinatura"); lblStatus.setText("✕ Falha na assinatura");
lblStatus.setStyle("-fx-text-fill: #ef4444; -fx-font-weight: bold;"); lblStatus.getStyleClass().setAll("label", "text-danger", "text-bold");
showAlert(Alert.AlertType.ERROR, "Erro na Assinatura do XML", showAlert(Alert.AlertType.ERROR, "Erro na Assinatura do XML",
"Não foi possível concluir a assinatura XMLDSig:\n" + (ex != null ? ex.getMessage() : "Erro desconhecido")); "Não foi possível concluir a assinatura XMLDSig:\n" + (ex != null ? ex.getMessage() : "Erro desconhecido"));
@@ -1,6 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Círculo azul e letra 'i' informativa centrada em (24, 24) --> <circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="2"/>
<circle cx="24" cy="24" r="18" fill="#0288d1"/> <circle cx="12" cy="7.5" r="1.2" fill="currentColor"/>
<circle cx="24" cy="15" r="2.5" fill="#ffffff"/> <line x1="12" y1="11" x2="12" y2="16.5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="24" y1="21" x2="24" y2="33" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 362 B

After

Width:  |  Height:  |  Size: 338 B

@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M 8 5 L 15 12 L 8 19" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M 9 5 L 16 12 L 9 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 224 B

@@ -1,12 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <path d="M 16.5 6.5 L 9.5 13.5 C 8.1 14.9 8.1 17.1 9.5 18.5 C 10.9 19.9 13.1 19.9 14.5 18.5 L 20 13 C 22.2 10.8 22.2 7.2 20 5 C 17.8 2.8 14.2 2.8 12 5 L 6.5 10.5 C 3.7 13.3 3.7 17.7 6.5 20.5 C 9.3 23.3 13.7 23.3 16.5 20.5 L 20 17"
<path d="M 10 4 L 34 4 L 42 12 L 42 44 L 10 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 34 4 L 34 12 L 42 12 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2"/>
<!-- Linhas de texto representativas -->
<line x1="16" y1="20" x2="36" y2="20" stroke="#90caf9" stroke-width="2" stroke-linecap="round"/>
<line x1="16" y1="26" x2="36" y2="26" stroke="#90caf9" stroke-width="2" stroke-linecap="round"/>
<line x1="16" y1="32" x2="30" y2="32" stroke="#90caf9" stroke-width="2" stroke-linecap="round"/>
<!-- Clipe de papel metálico prendendo a folha -->
<path d="M 12 2 C 8 2 6 5 6 9 L 6 25 C 6 29 9 32 14 32 C 18 32 21 29 21 25 L 21 11 C 21 8 19 6 16 6 C 13 6 12 8 12 11 L 12 24"
fill="none" stroke="#455a64" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 976 B

After

Width:  |  Height:  |  Size: 433 B

@@ -1,13 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha traseira (3) --> <path d="M 3.5 7.5 H 16.5 V 20.5 H 3.5 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 16 4 L 38 4 L 44 10 L 44 32 L 16 32 Z" fill="#e1f5fe" stroke="#4fc3f7" stroke-width="2" stroke-linejoin="round"/> <path d="M 7.5 4.5 H 20.5 V 17.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<!-- Folha do meio (2) --> <line x1="7" y1="11.5" x2="13" y2="11.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<path d="M 10 10 L 32 10 L 38 16 L 38 38 L 10 38 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/> <line x1="7" y1="15.5" x2="11" y2="15.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<!-- Folha frontal (1) -->
<path d="M 4 16 L 26 16 L 32 22 L 32 44 L 4 44 Z" fill="#ffffff" stroke="#01579b" stroke-width="2.2" stroke-linejoin="round"/>
<!-- Dobra folha frontal -->
<path d="M 26 16 L 26 22 L 32 22 Z" fill="#e1f5fe" stroke="#01579b" stroke-width="1.8"/>
<!-- Checkmark de execução/lote concluído -->
<circle cx="34" cy="34" r="10" fill="#00c853"/>
<path d="M 29 34 L 33 38 L 39 30" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 920 B

After

Width:  |  Height:  |  Size: 543 B

@@ -1,11 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Pasta de arquivos de certificados --> <rect x="3" y="4" width="18" height="16" rx="2.5" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M 4 10 L 16 10 L 20 14 L 44 14 L 44 40 L 4 40 Z" fill="#e1f5fe" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/> <circle cx="12" cy="10" r="2.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
<!-- Aba superior da pasta --> <path d="M 10.5 12.2 L 9.5 17 L 12 15.5 L 14.5 17 L 13.5 12.2" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linejoin="round"/>
<path d="M 4 18 L 44 18" stroke="#0288d1" stroke-width="2"/> <line x1="6" y1="7" x2="8" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<!-- Cadeado de segurança dourado/azul --> <line x1="16" y1="7" x2="18" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<rect x="26" y="24" width="14" height="12" rx="3" fill="#0288d1"/>
<!-- Arco do cadeado -->
<path d="M 29 24 L 29 20 C 29 17 31 15 33 15 C 35 15 37 17 37 20 L 37 24" fill="none" stroke="#01579b" stroke-width="2.5"/>
<circle cx="33" cy="30" r="1.8" fill="#ffffff"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 625 B

@@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<circle cx="24" cy="24" r="20" fill="#10b981"/> <circle cx="12" cy="12" r="9" fill="#10b981"/>
<path d="M 14 24 L 21 31 L 34 17" fill="none" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M 8 12 L 11 15 L 16 9" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 269 B

@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M 6 6 L 18 18 M 18 6 L 6 18" fill="none" stroke="#64748b" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M 6 6 L 18 18 M 18 6 L 6 18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 228 B

After

Width:  |  Height:  |  Size: 231 B

@@ -1,12 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha secundária --> <path d="M 13 3.5 H 5 C 4.4 3.5 4 3.9 4 4.5 V 20.5 C 4 21.1 4.4 21.5 5 21.5 H 17 C 17.6 21.5 18 21.1 18 20.5 V 13"
<path d="M 6 10 L 26 10 L 32 16 L 32 40 L 6 40 Z" fill="#ffffff" stroke="#1976d2" stroke-width="2.2" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<!-- Folha primária --> <path d="M 12 18 C 14 18 16 17 18 15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<path d="M 16 4 L 36 4 L 42 10 L 42 34 L 16 34 Z" fill="#e3f2fd" stroke="#0288d1" stroke-width="2.2" stroke-linejoin="round"/> <path d="M 18.5 3.5 L 21 6 L 14 13 L 11.5 13.5 L 12 11 Z" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linejoin="round"/>
<path d="M 36 4 L 36 10 L 42 10 Z" fill="#bbdefb" stroke="#0288d1" stroke-width="1.8"/>
<!-- Ícone de dois usuários / parceiros de assinatura -->
<circle cx="16" cy="24" r="4" fill="#0d47a1"/>
<path d="M 10 36 C 10 31 13 30 16 30 C 19 30 22 31 22 36 Z" fill="#0d47a1"/>
<circle cx="26" cy="22" r="3.5" fill="#0288d1"/>
<path d="M 21 34 C 21 30 24 29 26 29 C 29 29 32 30 32 34 Z" fill="#0288d1"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 815 B

After

Width:  |  Height:  |  Size: 546 B

@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<circle cx="24" cy="24" r="20" fill="#ef4444"/> <circle cx="12" cy="12" r="9" fill="#ef4444"/>
<line x1="16" y1="16" x2="32" y2="32" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round"/> <line x1="8.5" y1="8.5" x2="15.5" y2="15.5" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/>
<line x1="32" y1="16" x2="16" y2="32" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round"/> <line x1="15.5" y1="8.5" x2="8.5" y2="15.5" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 343 B

After

Width:  |  Height:  |  Size: 350 B

@@ -1,8 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Porta de saída / batente --> <path d="M 10 3.5 H 5.5 C 4.4 3.5 3.5 4.4 3.5 5.5 V 18.5 C 3.5 19.6 4.4 20.5 5.5 20.5 H 10"
<path d="M 24 8 L 12 8 C 9.8 8 8 9.8 8 12 L 8 36 C 8 38.2 9.8 40 12 40 L 24 40" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
fill="none" stroke="#546e7a" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/> <line x1="8.5" y1="12" x2="20.5" y2="12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/>
<!-- Seta vermelha apontando para fora --> <polyline points="16.5 8, 20.5 12, 16.5 16" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="18" y1="24" x2="40" y2="24" stroke="#d32f2f" stroke-width="3.2" stroke-linecap="round"/>
<polyline points="32 16, 40 24, 32 32" fill="none" stroke="#d32f2f" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 598 B

After

Width:  |  Height:  |  Size: 537 B

@@ -1,13 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<!-- Dobra de canto --> <path d="M 14 3.5 V 8.5 H 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/> <line x1="8" y1="13" x2="15" y2="13" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<!-- Linhas de texto representativas --> <line x1="8" y1="17" x2="13" y2="17" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<line x1="14" y1="20" x2="34" y2="20" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<line x1="14" y1="26" x2="34" y2="26" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<!-- Caneta / Pena de assinatura eletrônica -->
<path d="M 16 38 L 30 24 L 35 29 L 21 43 L 14 44 Z" fill="#0288d1"/>
<path d="M 30 24 L 34 20 L 39 25 L 35 29 Z" fill="#01579b"/>
<circle cx="16" cy="42" r="1.5" fill="#ffffff"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 626 B

@@ -1,13 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Janela de terminal / console --> <rect x="2.5" y="3.5" width="19" height="17" rx="3" fill="none" stroke="currentColor" stroke-width="2"/>
<rect x="4" y="6" width="40" height="36" rx="6" fill="#1e293b" stroke="#334155" stroke-width="2"/> <path d="M 6.5 8.5 L 9.5 11 L 6.5 13.5" fill="none" stroke="#0288d1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<!-- Barra de título do terminal com botões --> <line x1="11.5" y1="13.5" x2="16.5" y2="13.5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<circle cx="10" cy="12" r="2" fill="#ef4444"/> <line x1="6.5" y1="16.5" x2="14" y2="16.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.6"/>
<circle cx="16" cy="12" r="2" fill="#f59e0b"/>
<circle cx="22" cy="12" r="2" fill="#10b981"/>
<!-- Linha divisória -->
<line x1="4" y1="18" x2="44" y2="18" stroke="#334155" stroke-width="1.5"/>
<!-- Texto e prompt de código </> -->
<path d="M 12 24 L 18 29 L 12 34" fill="none" stroke="#38bdf8" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="22" y1="34" x2="32" y2="34" stroke="#94a3b8" stroke-width="2.5" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 811 B

After

Width:  |  Height:  |  Size: 572 B

@@ -1,11 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<!-- Folha de documento com dobra --> <path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
<path d="M 8 4 L 30 4 L 38 12 L 38 34 L 8 34 Z" fill="#ffffff" stroke="#00838f" stroke-width="2.5" stroke-linejoin="round"/> fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
<path d="M 30 4 L 30 12 L 38 12 Z" fill="#b2dfdb" stroke="#00838f" stroke-width="2"/> <circle cx="14" cy="15" r="4.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
<!-- Linhas no documento --> <polyline points="14 12.5, 14 15, 16 15" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round"/>
<line x1="14" y1="18" x2="30" y2="18" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<line x1="14" y1="24" x2="24" y2="24" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
<!-- Selo LTV com fita de proteção permanente -->
<circle cx="32" cy="32" r="12" fill="#e0f2f1" stroke="#00897b" stroke-width="2.5"/>
<text x="32" y="36.5" font-family="Segoe UI, Arial, sans-serif" font-size="9" font-weight="bold" fill="#00695c" text-anchor="middle">LTV</text>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 861 B

After

Width:  |  Height:  |  Size: 507 B

Some files were not shown because too many files have changed in this diff Show More