ui(ucp): en-tête compact mobile et dégradé latéral onglets (v2.5.6)
This commit is contained in:
1 parent
d8ec7e4508
commit
26cac163d6
3 files changed
+62
-9
No files matched your search
@@ -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
@@ -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 & Renvois</span>
|
<span>📱 Mes Postes & 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
@@ -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)",
|
||||||
|
|||||||
Reference in new issue
Block a user