ui(ucp): en-tête compact mobile et dégradé latéral onglets (v2.5.6)

This commit is contained in:
sorcier committed 2026-11-11 23:13:37 +01:00
1 parent d8ec7e4508
commit 26cac163d6
3 files changed
+62 -9

No files matched your search

+35
View File
@@ -145,7 +145,11 @@ function switchUcpTab(tabName) {
btn.className = isMe btn.className = isMe
? 'ucp-tab-btn px-3.5 py-2 rounded-xl text-xs font-semibold transition flex items-center gap-2 bg-indigo-50 text-indigo-700' ? 'ucp-tab-btn px-3.5 py-2 rounded-xl text-xs font-semibold transition flex items-center gap-2 bg-indigo-50 text-indigo-700'
: 'ucp-tab-btn px-3.5 py-2 rounded-xl text-xs font-semibold transition flex items-center gap-2 text-slate-600 hover:bg-slate-100'; : 'ucp-tab-btn px-3.5 py-2 rounded-xl text-xs font-semibold transition flex items-center gap-2 text-slate-600 hover:bg-slate-100';
if (isMe && typeof btn.scrollIntoView === 'function') {
btn.scrollIntoView({ behavior: 'smooth', inline: 'nearest', block: 'nearest' });
}
}); });
setTimeout(updateUcpNavScrollHints, 120);
if (tabName === 'voicemail') { if (tabName === 'voicemail') {
loadVoicemailsForSelected(); loadVoicemailsForSelected();
@@ -989,6 +993,7 @@ if (passwordForm) {
if (window.UCP_IS_AUTH) { if (window.UCP_IS_AUTH) {
refreshUcpState(false); refreshUcpState(false);
initUcpNavScrollHints();
pollTimer = setInterval(() => { pollTimer = setInterval(() => {
if (!document.hidden) { if (!document.hidden) {
refreshUcpState(false); refreshUcpState(false);
@@ -996,3 +1001,33 @@ if (window.UCP_IS_AUTH) {
}, 15000); }, 15000);
} }
function updateUcpNavScrollHints() {
const scroller = document.getElementById('ucp-nav-scroller');
const leftHint = document.getElementById('ucp-nav-hint-left');
const rightHint = document.getElementById('ucp-nav-hint-right');
if (!scroller || !leftHint || !rightHint) return;
const hasLeft = scroller.scrollLeft > 4;
const hasRight = scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth - 4;
leftHint.classList.toggle('hidden', !hasLeft);
leftHint.classList.toggle('flex', hasLeft);
rightHint.classList.toggle('hidden', !hasRight);
rightHint.classList.toggle('flex', hasRight);
}
function scrollUcpNav(direction) {
const scroller = document.getElementById('ucp-nav-scroller');
if (!scroller) return;
scroller.scrollBy({ left: direction * 170, behavior: 'smooth' });
}
function initUcpNavScrollHints() {
const scroller = document.getElementById('ucp-nav-scroller');
if (!scroller) return;
scroller.addEventListener('scroll', updateUcpNavScrollHints, { passive: true });
window.addEventListener('resize', updateUcpNavScrollHints);
requestAnimationFrame(updateUcpNavScrollHints);
setTimeout(updateUcpNavScrollHints, 250);
}
+25 -8
View File
@@ -53,6 +53,13 @@ $csrfToken = UcpAuth::getCsrfToken();
font-size: 16px !important; font-size: 16px !important;
} }
} }
.ucp-nav-scroll {
scrollbar-width: none;
-ms-overflow-style: none;
}
.ucp-nav-scroll::-webkit-scrollbar {
display: none;
}
::-webkit-scrollbar { width: 7px; height: 7px; } ::-webkit-scrollbar { width: 7px; height: 7px; }
::-webkit-scrollbar-track { background: #f1f5f9; } ::-webkit-scrollbar-track { background: #f1f5f9; }
::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; } ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
@@ -179,27 +186,32 @@ $csrfToken = UcpAuth::getCsrfToken();
<span class="font-bold text-slate-900 text-sm sm:text-base truncate"><?= htmlspecialchars($companyName ?: 'NexusPBX') ?></span> <span class="font-bold text-slate-900 text-sm sm:text-base truncate"><?= htmlspecialchars($companyName ?: 'NexusPBX') ?></span>
<span class="hidden sm:inline-flex px-2 py-0.5 rounded-full bg-indigo-50 text-indigo-700 border border-indigo-100 text-[10px] font-bold uppercase tracking-wide">UCP</span> <span class="hidden sm:inline-flex px-2 py-0.5 rounded-full bg-indigo-50 text-indigo-700 border border-indigo-100 text-[10px] font-bold uppercase tracking-wide">UCP</span>
</div> </div>
<p class="text-[11px] text-slate-500 truncate">Espace personnel de <strong class="text-slate-700"><?= htmlspecialchars((string)($currentUser['display_name'] ?: $currentUser['username'])) ?></strong></p> <p class="text-[11px] text-slate-500 truncate"><span class="hidden sm:inline">Espace personnel de </span><strong class="text-slate-700"><?= htmlspecialchars((string)($currentUser['display_name'] ?: $currentUser['username'])) ?></strong></p>
</div> </div>
</div> </div>
<div class="flex items-center gap-2 shrink-0"> <div class="flex items-center gap-2 shrink-0">
<button type="button" onclick="refreshUcpState(true)" title="Actualiser" <button type="button" onclick="refreshUcpState(true)" title="Actualiser" aria-label="Actualiser"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl border border-slate-200 bg-white hover:bg-slate-50 text-xs font-semibold text-slate-600 transition"> class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl border border-slate-200 bg-white hover:bg-slate-50 text-xs font-semibold text-slate-600 transition">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg> <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
<span class="hidden sm:inline">Actualiser</span> <span class="hidden sm:inline">Actualiser</span>
</button> </button>
<button type="button" onclick="ucpLogout()" <button type="button" onclick="ucpLogout()" title="Déconnexion" aria-label="Déconnexion"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl border border-rose-200 bg-rose-50 hover:bg-rose-100 text-xs font-semibold text-rose-700 transition"> class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl border border-rose-200 bg-rose-50 hover:bg-rose-100 text-xs font-semibold text-rose-700 transition">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"/></svg> <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"/></svg>
<span>Déconnexion</span> <span class="hidden sm:inline">Déconnexion</span>
</button> </button>
</div> </div>
</div> </div>
<!-- Navigation Onglets --> <!-- Navigation Onglets avec dégradé latéral discret sur mobile -->
<div class="max-w-6xl mx-auto px-4 sm:px-6 border-t border-slate-100 overflow-x-auto"> <div class="relative max-w-6xl mx-auto border-t border-slate-100">
<nav class="flex items-center gap-1 py-2 whitespace-nowrap" id="ucp-nav"> <button type="button" id="ucp-nav-hint-left" onclick="scrollUcpNav(-1)" aria-label="Onglets précédents"
class="hidden absolute left-0 top-0 bottom-0 z-10 w-9 items-center justify-start pl-1 bg-gradient-to-r from-white via-white/95 to-transparent text-slate-400 hover:text-indigo-600 transition">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.2" d="M15 19l-7-7 7-7"/></svg>
</button>
<div id="ucp-nav-scroller" class="ucp-nav-scroll px-4 sm:px-6 overflow-x-auto scroll-smooth">
<nav class="flex items-center gap-1 py-2 whitespace-nowrap pr-6 sm:pr-0" id="ucp-nav">
<button type="button" data-ucp-tab="extensions" onclick="switchUcpTab('extensions')" <button type="button" data-ucp-tab="extensions" onclick="switchUcpTab('extensions')"
class="ucp-tab-btn px-3.5 py-2 rounded-xl text-xs font-semibold transition flex items-center gap-2 bg-indigo-50 text-indigo-700"> class="ucp-tab-btn px-3.5 py-2 rounded-xl text-xs font-semibold transition flex items-center gap-2 bg-indigo-50 text-indigo-700">
<span>📱 Mes Postes &amp; Renvois</span> <span>📱 Mes Postes &amp; Renvois</span>
@@ -226,7 +238,12 @@ $csrfToken = UcpAuth::getCsrfToken();
class="ucp-tab-btn px-3.5 py-2 rounded-xl text-xs font-semibold transition flex items-center gap-2 text-slate-600 hover:bg-slate-100"> class="ucp-tab-btn px-3.5 py-2 rounded-xl text-xs font-semibold transition flex items-center gap-2 text-slate-600 hover:bg-slate-100">
<span>🔐 Mon Compte</span> <span>🔐 Mon Compte</span>
</button> </button>
</nav> </nav>
</div>
<button type="button" id="ucp-nav-hint-right" onclick="scrollUcpNav(1)" aria-label="Onglets suivants"
class="hidden absolute right-0 top-0 bottom-0 z-10 w-10 items-center justify-end pr-1.5 bg-gradient-to-l from-white via-white/95 to-transparent text-slate-400 hover:text-indigo-600 transition">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.2" d="M9 5l7 7-7 7"/></svg>
</button>
</div> </div>
</header> </header>
+2 -1
View File
@@ -1,9 +1,10 @@
{ {
"version": "2.5.5", "version": "2.5.6",
"codename": "Pulsar UCP", "codename": "Pulsar UCP",
"release_date": "2026-11-11", "release_date": "2026-11-11",
"min_php_version": "8.2", "min_php_version": "8.2",
"changelog": [ "changelog": [
"Correctif v2.5.6 : ergonomie mobile iPhone (en-tête compact + dégradé latéral discret sur la barre d'onglets UCP sans scrollbar visible)",
"Correctif v2.5.5 : suppression du zoom automatique iOS/iPhone sur les champs (<16px) et blocage du débordement horizontal mobile dans l'UCP", "Correctif v2.5.5 : suppression du zoom automatique iOS/iPhone sur les champs (<16px) et blocage du débordement horizontal mobile dans l'UCP",
"Correctif v2.5.4 : correction du journal personnel UCP « Mes Appels » (correspondance caller_number/callee_number/canaux PJSIP et filtres Répondus/Manqués)", "Correctif v2.5.4 : correction du journal personnel UCP « Mes Appels » (correspondance caller_number/callee_number/canaux PJSIP et filtres Répondus/Manqués)",
"Nouveauté v2.5.3 : onglet UCP « Notice & Codes » avec mémo pas-à-pas, codes de fonction dynamiques et export PDF / impression A4 corporate (logo, encarts, poste utilisateur)", "Nouveauté v2.5.3 : onglet UCP « Notice & Codes » avec mémo pas-à-pas, codes de fonction dynamiques et export PDF / impression A4 corporate (logo, encarts, poste utilisateur)",