From 2f591e55ce572cdab31227ef905477e39125f620 Mon Sep 17 00:00:00 2001 From: Luca Sacchi Ricciardi Date: Fri, 24 Apr 2026 20:15:19 +0200 Subject: [PATCH] feat: open model details modal on hover and refine cards layout - Add on-hover modal opening for model cards with debounce - Keep click-to-open behavior as fallback - Prevent accidental hover triggers while moving inside same card - Convert models list to responsive grid layout - Improve card visual feedback and helper text for interaction --- app/web/static/js/app.js | 49 ++++++++++++++++++++++++++++++++++-- app/web/templates/index.html | 7 ++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/app/web/static/js/app.js b/app/web/static/js/app.js index 714aaf4..3e8daae 100644 --- a/app/web/static/js/app.js +++ b/app/web/static/js/app.js @@ -7,6 +7,8 @@ class LLMMonitorApp { constructor() { this.worker = null; this.selectedModelName = null; + this.hoverOpenDelayMs = 180; + this.hoverOpenTimer = null; this.lastData = { health: null, models: null @@ -50,6 +52,49 @@ class LLMMonitorApp { this.showModelDetails(decodeURIComponent(modelKey)); }); + // Apertura modal on-hover (con piccolo delay per evitare aperture involontarie) + document.getElementById("models-container")?.addEventListener("mouseover", (event) => { + const card = event.target.closest("[data-model-key]"); + if (!card) { + return; + } + + // Evita trigger quando il mouse si muove dentro la stessa card + if (event.relatedTarget && card.contains(event.relatedTarget)) { + return; + } + + const modelKey = card.getAttribute("data-model-key"); + if (!modelKey) { + return; + } + + if (this.hoverOpenTimer) { + clearTimeout(this.hoverOpenTimer); + } + + this.hoverOpenTimer = setTimeout(() => { + this.showModelDetails(decodeURIComponent(modelKey)); + }, this.hoverOpenDelayMs); + }); + + document.getElementById("models-container")?.addEventListener("mouseout", (event) => { + const card = event.target.closest("[data-model-key]"); + if (!card) { + return; + } + + // Non cancellare se si resta all'interno della stessa card + if (event.relatedTarget && card.contains(event.relatedTarget)) { + return; + } + + if (this.hoverOpenTimer) { + clearTimeout(this.hoverOpenTimer); + this.hoverOpenTimer = null; + } + }); + // Chiusura modal con pulsante X document.getElementById("model-details-close")?.addEventListener("click", () => { this.hideModelDetails(); @@ -187,7 +232,7 @@ class LLMMonitorApp { const modelName = this.escapeHtml(model.name); const modelKey = encodeURIComponent(model.name); return ` -
+

${modelName}

Caricato @@ -206,7 +251,7 @@ class LLMMonitorApp {

Digest

${this.escapeHtml(model.digest.substring(0, 64))}...

-

Clicca per vedere dettagli show

+

Passa il mouse o clicca per vedere dettagli show

`; } diff --git a/app/web/templates/index.html b/app/web/templates/index.html index a77aab7..ffa2c98 100644 --- a/app/web/templates/index.html +++ b/app/web/templates/index.html @@ -60,14 +60,17 @@
-

Modelli Disponibili

+
+

Modelli Disponibili

+

Passa il mouse o clicca una card per aprire la modal dettagli.

+
-
+

Caricamento modelli...