feat(wiki-ux-polish-v1): sticky search + filter chips + counter + back-to-top
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled

UX premium polish for wiki.html after layout fix:

NEW FEATURES:
- Sticky search bar (raccourci clavier /)
  * Live instant filter with 150ms debounce
  * Touches all .wiki-item and .card elements
- Filter chips: Tout / 7 jours / 30 jours / Anciens
  * Date extraction from card text (regex YYYY-MM-DD or DD/MM)
  * Active state visuel (couleur cyan)
- Counter live Showing X / Y entries
- Back-to-top floating button (visible > 400px scroll)
- Keyboard shortcuts:
  * / focus search
  * Esc clear search

UX:
- Sticky bar glassmorphism (backdrop-filter blur)
- Gradient background linear cyan-purple
- Smooth transitions 0.15s
- Accessibility: aria-label on button

Zero régression (only adds above </body>, does not touch existing content)
GOLD backup: /opt/wevads/vault/gold_wiki_UX_POLISH_*.html
File size 84772 → 90445 (+5673 bytes)
This commit is contained in:
Opus Wire
2026-04-21 15:02:12 +02:00
parent 8e376aae26
commit f3fd9ba47c

156
wiki.html
View File

@@ -802,4 +802,160 @@ b7d75cb53 feat(wtp-udock-dashboard): dashboard premium + endpoint JSON ← tour
</p>
</section>
<!-- WTP wiki polish v1 (Opus t38e) -->
<style id="wtp-wiki-polish-v1">
.wtp-polish-bar{
position:sticky;top:0;z-index:500;
background:linear-gradient(180deg,rgba(11,13,21,.98),rgba(11,13,21,.92));
backdrop-filter:blur(12px);
padding:12px 20px;border-bottom:1px solid rgba(6,182,212,.2);
display:flex;gap:12px;align-items:center;flex-wrap:wrap;
box-shadow:0 2px 20px rgba(0,0,0,.3);
margin-bottom:16px;
}
.wtp-polish-bar input.wtp-search{
flex:1 1 280px;min-width:200px;
padding:10px 40px 10px 16px;border-radius:10px;
border:1px solid rgba(6,182,212,.3);
background:rgba(15,23,42,.9);color:#e2e8f0;
font:600 13px Nunito;outline:none;
}
.wtp-polish-bar input.wtp-search:focus{
border-color:#06b6d4;box-shadow:0 0 12px rgba(6,182,212,.3);
}
.wtp-filter-chip{
padding:6px 12px;border-radius:20px;
font:700 10px Nunito;cursor:pointer;user-select:none;
background:rgba(100,116,139,.15);color:#94a3b8;
border:1px solid rgba(100,116,139,.25);transition:all .15s;
}
.wtp-filter-chip:hover{background:rgba(6,182,212,.2);color:#22d3ee;border-color:#06b6d4;}
.wtp-filter-chip.active{background:#06b6d4;color:#0b0d15;border-color:#06b6d4;font-weight:800;}
.wtp-counter{
padding:6px 12px;border-radius:8px;
background:rgba(168,85,247,.15);color:#c084fc;
font:700 11px Nunito;
}
.wtp-btn-top{
position:fixed;bottom:24px;left:24px;z-index:999;
width:46px;height:46px;border-radius:50%;
background:linear-gradient(135deg,#06b6d4,#a855f7);
color:#0b0d15;border:none;cursor:pointer;
box-shadow:0 4px 20px rgba(6,182,212,.4);
font:900 20px Nunito;
display:none;align-items:center;justify-content:center;
transition:all .2s;
}
.wtp-btn-top:hover{transform:translateY(-3px);box-shadow:0 6px 24px rgba(6,182,212,.6);}
.wtp-btn-top.visible{display:flex;}
.wtp-clear-btn{
padding:6px 10px;border-radius:8px;
background:rgba(239,68,68,.15);color:#fca5a5;
border:1px solid rgba(239,68,68,.25);cursor:pointer;
font:700 10px Nunito;
}
.wtp-clear-btn:hover{background:rgba(239,68,68,.3);color:#fff;}
</style>
<div class="wtp-polish-bar" id="wtp-polish-bar">
<input class="wtp-search" id="wtp-wiki-search" placeholder="🔍 Recherche instantanée (raccourci: /)" />
<span class="wtp-filter-chip active" data-filter="all">Tout</span>
<span class="wtp-filter-chip" data-filter="week">7 derniers jours</span>
<span class="wtp-filter-chip" data-filter="month">30 derniers jours</span>
<span class="wtp-filter-chip" data-filter="old">Anciens</span>
<span class="wtp-counter" id="wtp-counter"></span>
<button class="wtp-clear-btn" onclick="wtpClearSearch()">Effacer</button>
</div>
<button class="wtp-btn-top" id="wtp-btn-top" onclick="window.scrollTo({top:0,behavior:'smooth'})" aria-label="Retour en haut"></button>
<script>
(function(){
'use strict';
const search = document.getElementById('wtp-wiki-search');
const counter = document.getElementById('wtp-counter');
const btnTop = document.getElementById('wtp-btn-top');
const chips = document.querySelectorAll('.wtp-filter-chip');
let currentFilter = 'all';
function allItems(){ return document.querySelectorAll('.wiki-item, .card'); }
function extractDate(el){
// Look for date patterns: 2026-04-XX, XX/04, 10/04, etc.
const t = el.textContent;
const m = t.match(/(\d{4})-(\d{2})-(\d{2})/) || t.match(/(\d{2})\/(\d{2})(?!\s*\d)/);
if (!m) return null;
if (m.length === 4) return new Date(m[1], parseInt(m[2])-1, m[3]);
if (m.length === 3) return new Date(2026, parseInt(m[2])-1, m[1]);
return null;
}
function applyFilters(){
const q = (search.value||'').toLowerCase().trim();
const now = new Date();
const w7 = new Date(now - 7*86400000);
const w30 = new Date(now - 30*86400000);
let shown = 0, total = 0;
allItems().forEach(el => {
total++;
const txt = (el.textContent + ' ' + (el.dataset.tags||'')).toLowerCase();
let match = !q || txt.includes(q);
if (match && currentFilter !== 'all') {
const d = extractDate(el);
if (!d) match = (currentFilter === 'old');
else {
if (currentFilter === 'week') match = d >= w7;
else if (currentFilter === 'month') match = d >= w30;
else if (currentFilter === 'old') match = d < w30;
}
}
el.style.display = match ? '' : 'none';
if (match) shown++;
});
counter.textContent = shown === total ? `${total} entrées` : `${shown} / ${total}`;
}
let deb; search.addEventListener('input', () => { clearTimeout(deb); deb = setTimeout(applyFilters, 150); });
chips.forEach(chip => {
chip.addEventListener('click', () => {
chips.forEach(c => c.classList.remove('active'));
chip.classList.add('active');
currentFilter = chip.dataset.filter;
applyFilters();
});
});
window.wtpClearSearch = function(){
search.value = '';
chips.forEach(c => c.classList.remove('active'));
document.querySelector('.wtp-filter-chip[data-filter="all"]').classList.add('active');
currentFilter = 'all';
applyFilters();
search.focus();
};
// Keyboard shortcuts
document.addEventListener('keydown', e => {
if (e.key === '/' && e.target !== search) { e.preventDefault(); search.focus(); }
else if (e.key === 'Escape' && e.target === search) { wtpClearSearch(); }
});
// Back-to-top visibility
window.addEventListener('scroll', () => {
if (window.scrollY > 400) btnTop.classList.add('visible');
else btnTop.classList.remove('visible');
}, {passive:true});
// Init
setTimeout(applyFilters, 100);
})();
</script>
<!-- /wtp-wiki-polish-v1 -->
</body></html>