refactor(ui): modernize hub layout, certificate cards and dialogs

This commit is contained in:
Claudecio Martins
2026-10-20 20:12:37 -03:00
parent cf63aa6d22
commit 66f3172bfb
25 changed files with 63 additions and 59 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

@@ -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.CertificateType;
import br.com.cybercore.signer.core.domain.ManagedCertificate;
import javafx.scene.Node;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
@@ -34,24 +35,31 @@ public final class CertificateCardNode extends VBox {
setCursor(javafx.scene.Cursor.HAND);
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);
topRow.setAlignment(Pos.CENTER_LEFT);
Node certIcon = Icons.certificates(Icons.SIZE_20);
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");
Label titleLabel = new Label(cleanTitle);
titleLabel.getStyleClass().add("cert-title");
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) {
badgeLabel.getStyleClass().add("cert-badge-a1");
} else {
badgeLabel.getStyleClass().add("cert-badge-a3");
}
topRow.getChildren().addAll(titleLabel, badgeLabel);
topRow.getChildren().addAll(titleBox, badgeLabel);
// Linha 2: Documento (CPF / CNPJ) e Emissor
HBox midRow = new HBox(12);
@@ -19,7 +19,7 @@ import javafx.scene.text.FontWeight;
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/'.
*/
public final class SvgIcons {
@@ -1,6 +1,7 @@
package br.com.cybercore.signer.ui.view;
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.theme.ThemeManager;
import javafx.geometry.Insets;
@@ -9,6 +10,7 @@ import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
@@ -57,7 +59,7 @@ public final class MainAppView {
}
private void initLayout() {
root.getStyleClass().addAll("cyber-root", "serpro-root");
root.getStyleClass().add("cyber-root");
root.setAlignment(Pos.TOP_CENTER);
// 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);
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();
actionGrid.setHgap(12);
actionGrid.setVgap(12);
actionGrid.setAlignment(Pos.CENTER);
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
actionGrid.add(createActionButton(SvgIcons.pdfIcon(), "Assinar\nPDF", () -> trigger(onSignPdf)), 0, 0);
actionGrid.add(createActionButton(SvgIcons.xmlIcon(), "Assinar\nXML", () -> trigger(onSignXml)), 1, 0);
actionGrid.add(createActionButton(SvgIcons.attachedIcon(), "Assinatura\nAtachada", () -> trigger(onAttachedSign)), 2, 0);
actionGrid.add(createActionButton(Icons.pdf(Icons.SIZE_40), "Assinar\nPDF", () -> trigger(onSignPdf)), 0, 0);
actionGrid.add(createActionButton(Icons.xml(Icons.SIZE_40), "Assinar\nXML", () -> trigger(onSignXml)), 1, 0);
actionGrid.add(createActionButton(Icons.attached(Icons.SIZE_40), "Assinatura\nAtachada", () -> trigger(onAttachedSign)), 2, 0);
// Linha 1: Identidade Visual, Auditoria e Saída
actionGrid.add(createActionButton(SvgIcons.sealIcon(), "Gerenciar\nSelos", () -> trigger(onManageSeals)), 0, 1);
actionGrid.add(createActionButton(SvgIcons.validateIcon(), "Validar\nAssinatura", () -> trigger(onValidateSignature)), 1, 1);
actionGrid.add(createActionButton(SvgIcons.exitIcon(), "Sair do\nAgente", () -> trigger(onExit)), 2, 1);
actionGrid.add(createActionButton(Icons.seal(Icons.SIZE_40), "Gerenciar\nSelos", () -> trigger(onManageSeals)), 0, 1);
actionGrid.add(createActionButton(Icons.validate(Icons.SIZE_40), "Validar\nAssinatura", () -> trigger(onValidateSignature)), 1, 1);
actionGrid.add(createActionButton(Icons.exit(Icons.SIZE_40), "Sair do\nAgente", () -> trigger(onExit)), 2, 1);
// --- Painel Lateral Direito (Ferramentas, Certificados e Diagnóstico) ---
VBox sideColumn = new VBox(10);
sideColumn.getStyleClass().add("cyber-side-column");
sideColumn.setPrefWidth(195);
sideColumn.setMinWidth(190);
sideColumn.setMaxWidth(210);
sideColumn.setPrefWidth(210);
sideColumn.setMinWidth(180);
sideColumn.setMaxWidth(230);
sideColumn.setAlignment(Pos.TOP_CENTER);
sideColumn.getChildren().addAll(
createSideButton(SvgIcons.logsIcon(), "Logs", () -> trigger(onLogs)),
createSideButton(SvgIcons.settingsIcon(), "Configurações", () -> trigger(onSettings)),
createSideButton(SvgIcons.tutorialIcon(), "Tutorial", () -> trigger(onTutorial)),
createSideButton(SvgIcons.certificatesIcon(), "Certificados", () -> trigger(onCertificates)),
createSideButton(SvgIcons.aboutIcon(), "Sobre", () -> trigger(onAbout))
createSideButton(Icons.logs(Icons.SIZE_24), "Logs", () -> trigger(onLogs)),
createSideButton(Icons.settings(Icons.SIZE_24), "Configurações", () -> trigger(onSettings)),
createSideButton(Icons.tutorial(Icons.SIZE_24), "Tutorial", () -> trigger(onTutorial)),
createSideButton(Icons.certificates(Icons.SIZE_24), "Certificados", () -> trigger(onCertificates)),
createSideButton(Icons.about(Icons.SIZE_24), "Sobre", () -> trigger(onAbout))
);
// Espaçador elástico e Rodapé de status local
@@ -112,13 +121,13 @@ public final class MainAppView {
HBox brandFooter = new HBox(6);
brandFooter.setAlignment(Pos.CENTER);
Node smallLogo = SvgIcons.cyberShieldLogo(16);
Node smallLogo = Icons.shield(Icons.SIZE_16);
Label lblBrandFoot = new Label("CyberCore");
lblBrandFoot.getStyleClass().addAll("cyber-version-label", "text-bold");
brandFooter.getChildren().addAll(smallLogo, lblBrandFoot);
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);
sideColumn.getChildren().add(footerBox);
@@ -174,13 +183,13 @@ public final class MainAppView {
brandRow.setAlignment(Pos.CENTER_LEFT);
Label lblAssinador = new Label("ASSINADOR");
lblAssinador.getStyleClass().addAll("cyber-brand-title", "serpro-header-title", "cyber-brand-prefix");
lblAssinador.getStyleClass().addAll("cyber-brand-title", "cyber-brand-prefix");
Label lblSep = new Label("|");
lblSep.getStyleClass().add("cyber-brand-separator");
Label lblBrand = new Label("CyberCore");
lblBrand.getStyleClass().addAll("cyber-brand-title", "serpro-header-brand", "text-bold");
lblBrand.getStyleClass().addAll("cyber-brand-title", "text-bold");
brandRow.getChildren().addAll(lblAssinador, lblSep, lblBrand);
@@ -215,7 +224,7 @@ public final class MainAppView {
HBox content = new HBox(8);
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);
iconBox.setPrefSize(18, 18);
iconBox.setMinSize(18, 18);
@@ -231,17 +240,16 @@ public final class MainAppView {
private Button createActionButton(Node icon, String text, Runnable onAction) {
Button btn = new Button();
btn.getStyleClass().addAll("cyber-action-card", "serpro-action-btn");
btn.setPrefWidth(162);
btn.setMinWidth(158);
btn.setPrefHeight(68);
btn.getStyleClass().add("cyber-action-card");
btn.setMaxWidth(Double.MAX_VALUE);
btn.setPrefHeight(72);
btn.setMinHeight(68);
HBox content = new HBox(12);
content.setAlignment(Pos.CENTER_LEFT);
Label lbl = new Label(text);
lbl.getStyleClass().addAll("cyber-action-text", "serpro-action-text");
lbl.getStyleClass().add("cyber-action-text");
lbl.setWrapText(true);
lbl.setAlignment(Pos.CENTER_LEFT);
HBox.setHgrow(lbl, Priority.ALWAYS);
@@ -266,7 +274,7 @@ public final class MainAppView {
private Button createSideButton(Node icon, String text, Runnable onAction) {
Button btn = new Button();
btn.getStyleClass().addAll("cyber-side-card", "serpro-side-btn");
btn.getStyleClass().add("cyber-side-card");
btn.setPrefHeight(42);
btn.setMinHeight(42);
btn.setMaxWidth(Double.MAX_VALUE);
@@ -275,7 +283,7 @@ public final class MainAppView {
content.setAlignment(Pos.CENTER_LEFT);
Label lbl = new Label(text);
lbl.getStyleClass().addAll("cyber-side-text", "serpro-side-text");
lbl.getStyleClass().add("cyber-side-text");
lbl.setWrapText(false);
lbl.setAlignment(Pos.CENTER_LEFT);
HBox.setHgrow(lbl, Priority.ALWAYS);
@@ -1,9 +1,7 @@
/* CyberCore Signer - Modo Diagnóstico: Remoção de sombras/efeitos visuais dinâmicos */
.cyber-action-card,
.serpro-action-btn,
.cyber-side-card,
.serpro-side-btn,
.cyber-header-bar,
.theme-toggle-btn,
.cyber-status-badge {
@@ -11,11 +9,8 @@
}
.theme-light .cyber-action-card:hover,
.theme-light .serpro-action-btn:hover,
.theme-dark .cyber-action-card:hover,
.theme-dark .serpro-action-btn:hover,
.cyber-side-card:hover,
.serpro-side-btn:hover,
.theme-toggle-btn:hover {
-fx-effect: null !important;
}
@@ -131,7 +131,6 @@
========================================================================== */
.cyber-root,
.serpro-root,
.dialog-container {
-fx-background-color: -fx-color-background;
-fx-text-fill: -fx-color-text;
@@ -220,8 +219,7 @@
3. HUB DE AÇÕES E PAINEL LATERAL
========================================================================== */
.cyber-action-card,
.serpro-action-btn {
.cyber-action-card {
-fx-background-color: -fx-color-surface;
-fx-border-color: -fx-color-border;
-fx-border-width: 1.2px;
@@ -236,20 +234,17 @@
-fx-effect: dropshadow(three-pass-box, -fx-color-shadow, 6, 0, 0, 2);
}
.cyber-action-card:hover,
.serpro-action-btn:hover {
.cyber-action-card:hover {
-fx-background-color: -fx-color-surface-hover;
-fx-border-color: -fx-color-primary;
-fx-effect: dropshadow(three-pass-box, -fx-color-shadow-hover, 10, 0, 0, 4);
}
.cyber-action-card:pressed,
.serpro-action-btn:pressed {
.cyber-action-card:pressed {
-fx-background-color: -fx-color-surface-active;
}
.cyber-action-text,
.serpro-action-text {
.cyber-action-text {
-fx-font-size: 13px;
-fx-font-weight: bold;
-fx-text-fill: -fx-color-text;
@@ -266,8 +261,7 @@
-fx-effect: dropshadow(three-pass-box, -fx-color-shadow, 4, 0, 0, 1);
}
.cyber-side-card,
.serpro-side-btn {
.cyber-side-card {
-fx-background-color: transparent;
-fx-border-color: transparent;
-fx-border-width: 1px;
@@ -279,26 +273,22 @@
-fx-max-width: Infinity;
}
.cyber-side-card:hover,
.serpro-side-btn:hover {
.cyber-side-card:hover {
-fx-background-color: -fx-color-surface-hover;
-fx-border-color: -fx-color-border-subtle;
}
.cyber-side-card:pressed,
.serpro-side-btn:pressed {
.cyber-side-card:pressed {
-fx-background-color: -fx-color-surface-active;
}
.cyber-side-text,
.serpro-side-text {
.cyber-side-text {
-fx-font-size: 13px;
-fx-text-fill: -fx-color-text;
-fx-font-weight: 500;
}
.cyber-version-label,
.serpro-version-label {
.cyber-version-label {
-fx-font-size: 11px;
-fx-text-fill: -fx-color-text-muted;
}
@@ -567,7 +557,8 @@
-fx-text-fill: -fx-color-text-muted;
}
.cert-badge-a1 {
.cert-badge-a1,
.badge-a1 {
-fx-background-color: -fx-color-primary-subtle;
-fx-border-color: -fx-color-primary;
-fx-border-radius: 4px;
@@ -578,7 +569,8 @@
-fx-padding: 2px 8px;
}
.cert-badge-a3 {
.cert-badge-a3,
.badge-a3 {
-fx-background-color: -fx-color-warning-subtle;
-fx-border-color: -fx-color-warning-border;
-fx-border-radius: 4px;
@@ -595,7 +587,8 @@
-fx-font-weight: bold;
}
.cert-status-unavailable {
.cert-status-unavailable,
.cert-status-expired {
-fx-text-fill: -fx-color-error;
-fx-font-size: 11px;
-fx-font-weight: bold;