Rifacimento della UI secondo STILE_UI.md
Adotta lo stile condiviso delle app Integry: superfici piatte, raggi ampi, spaziature a scala fissa, gerarchia data dallo spazio prima che dalla decorazione. La palette storica di SteUP resta intatta; sono stati aggiunti solo i ruoli che mancavano (workspace, surfaceMuted, divider, inkMuted e le triplette dei toni semantici). Fondamenta - tokens.css: ruoli colore, scale di spazio/raggi/tipografia, curve di movimento e scala z-index semantica. Unica fonte di verita': pilotano anche le variabili CSS di MudBlazor. - Inter variabile ospitata in locale (133KB) al posto di Nunito da Google Fonts: l'app lavora offline, un font che arriva dalla rete in campo non arriva. - base.css: shell applicativa e comportamenti da app nativa — niente selezione testo, niente menu al tocco lungo, niente lampo grigio sul tap, niente rimbalzo elastico, niente zoom a doppio tocco, scroll con inerzia. - mudblazor-overrides.css: MudBlazor appiattito (elevation 0, nessun tint, target 44/48, etichette in caso naturale). - Rimossi Bootstrap (CSS, icone e JS) e i 996 righe di CSS con ambito per componente del vecchio sistema: erano tutti inutilizzati. Struttura - Navigazione flottante in basso con icona piena sulla voce attiva; da 720px diventa colonna laterale. Il MudFabMenu e' sostituito da un bottom sheet: stessa funzione, bersagli molto piu' grandi. - Testata alta col titolo a sinistra, fusa con la pagina. - Nel form scheda il salvataggio sta in una barra ancorata in fondo, non in coda a uno scroll lungo. - Scelta di punto vendita e articoli a schermo intero con ricerca; la selezione multipla usa righe da 56px invece di un menu a tendina. - Urgenza scelta a pillole invece che da una select. Stato e riscontro - StatusBadgeHelper: tono, icona ed etichetta di ogni stato in un punto solo, cosi' lo stesso stato si presenta identico ovunque. - Scheletri al posto degli spinner; l'overlay bloccante dice sempre cosa sta facendo; gli stati vuoti suggeriscono la mossa successiva. - Rimosso il ritardo artificiale di 250ms in InspectionCard, che non attendeva nulla. DESIGN.md riscritto sul nuovo sistema. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,105 +1,14 @@
|
||||
// Funzione goBack
|
||||
// Interoperabilità minima con l'host. Il feedback al tocco e gli stati sono
|
||||
// gestiti in CSS: qui resta solo ciò che il CSS non può fare.
|
||||
|
||||
window.goBack = function () {
|
||||
console.log("goBack");
|
||||
history.back();
|
||||
};
|
||||
|
||||
// Funzione per monitorare bottom-sheet-container e gestire la navbar
|
||||
function monitorBottomSheetClass(mutations) {
|
||||
const bottomSheet = document.querySelector(".bottom-sheet-container");
|
||||
const navbar = document.querySelector(".animated-navbar");
|
||||
|
||||
if (!bottomSheet || !navbar) return;
|
||||
|
||||
mutations.forEach(function (mutation) {
|
||||
if (mutation.type === 'attributes' && mutation.attributeName === 'class' && mutation.target === bottomSheet) {
|
||||
if (bottomSheet.classList.contains("show")) {
|
||||
navbar.classList.remove("show-nav");
|
||||
navbar.classList.add("hide-nav");
|
||||
console.log("Navbar nascosta (hide-nav)");
|
||||
} else {
|
||||
navbar.classList.remove("hide-nav");
|
||||
navbar.classList.add("show-nav");
|
||||
console.log("Navbar mostrata (show-nav)");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Observer combinato per tutte le funzionalità
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
// Monitora bottom-sheet-container
|
||||
monitorBottomSheetClass(mutations);
|
||||
});
|
||||
|
||||
// Osserva sia i cambiamenti nel DOM che gli attributi
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
attributeFilter: ['class']
|
||||
});
|
||||
|
||||
// Sync iniziale per la navbar (nel caso la pagina parte già con .show)
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const bottomSheet = document.querySelector(".bottom-sheet-container");
|
||||
const navbar = document.querySelector(".animated-navbar");
|
||||
|
||||
if (bottomSheet && navbar) {
|
||||
if (bottomSheet.classList.contains("show")) {
|
||||
navbar.classList.remove("show-nav");
|
||||
navbar.classList.add("hide-nav");
|
||||
} else {
|
||||
navbar.classList.remove("hide-nav");
|
||||
navbar.classList.add("show-nav");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
(function () {
|
||||
// Ascoltiamo l'evento 'mousedown' su tutto il documento
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
|
||||
// Cerca se l'elemento cliccato (o un suo genitore) ha la classe .ripple-container
|
||||
const target = event.target.closest('.ripple-container');
|
||||
|
||||
if (target) {
|
||||
createRipple(event, target);
|
||||
}
|
||||
});
|
||||
|
||||
function createRipple(event, element) {
|
||||
const circle = document.createElement("span");
|
||||
const diameter = Math.max(element.clientWidth, element.clientHeight);
|
||||
const radius = diameter / 2;
|
||||
|
||||
const rect = element.getBoundingClientRect();
|
||||
|
||||
circle.style.width = circle.style.height = `${diameter}px`;
|
||||
circle.style.left = `${event.clientX - rect.left - radius}px`;
|
||||
circle.style.top = `${event.clientY - rect.top - radius}px`;
|
||||
circle.classList.add("ripple");
|
||||
|
||||
// Rimuovi l'elemento dal DOM alla fine dell'animazione per non intasare la memoria
|
||||
const ripple = element.getElementsByClassName("ripple")[0];
|
||||
if (ripple) {
|
||||
ripple.remove();
|
||||
}
|
||||
|
||||
element.appendChild(circle);
|
||||
|
||||
// Pulizia automatica dopo 600ms (durata animazione CSS)
|
||||
setTimeout(() => {
|
||||
circle.remove();
|
||||
}, 600);
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
// Tastiera: porta il campo attivo dentro l'area visibile.
|
||||
// Il layout e' a 100vh con overflow:hidden, quindi quando l'host riduce la
|
||||
// WebView per la tastiera il browser non scrolla da solo sul campo col focus.
|
||||
// Il layout e' a piena altezza con lo scroll in un contenitore, quindi quando
|
||||
// l'host riduce la WebView per la tastiera il browser non scrolla da solo sul
|
||||
// campo col focus.
|
||||
(function () {
|
||||
const SELECTOR = 'input, textarea, [contenteditable="true"]';
|
||||
let pending = null;
|
||||
@@ -130,3 +39,16 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
window.addEventListener('resize', schedule);
|
||||
}
|
||||
})();
|
||||
|
||||
// Un doppio tocco ravvicinato su una WebView fa zoomare la pagina: e' il
|
||||
// gesto del browser, non quello di un'app. Il viewport lo vieta gia', questo
|
||||
// copre i casi in cui Android lo reintroduce.
|
||||
(function () {
|
||||
let lastTouch = 0;
|
||||
|
||||
document.addEventListener('touchend', function (event) {
|
||||
const now = Date.now();
|
||||
if (now - lastTouch <= 320) event.preventDefault();
|
||||
lastTouch = now;
|
||||
}, {passive: false});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user