mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Discussions : la liste se dessine par pages de 40
Repris d'AJEAN 0.15.6, pour la partie qui nous concerne. Côté serveur, la liste était déjà légère (l'index ne porte que des métadonnées, aucune conversation n'est relue) ; c'est le DOM qui coûtait : des centaines de lignes construites d'un coup à chaque rafraîchissement de la liste. On en dessine 40, puis la suite quand la ligne « afficher N de plus » arrive à l'écran (IntersectionObserver, ou clic). La discussion active reste toujours visible, même au-delà. La recherche filtre toujours la liste ENTIÈRE, qui reste en mémoire ; changer la requête repart de la première page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f7a4ee71e7
commit
04137411fa
3 files changed
+64
-2
No files matched your search
@@ -1746,6 +1746,9 @@ html[data-files="1"] #files-btn{color:var(--accent)}
|
||||
color:var(--dim);letter-spacing:-.01em;overflow:visible}
|
||||
.side .preset:hover .conv-when{opacity:0}
|
||||
.conv-empty{font-size:12px;color:var(--dim);padding:8px 11px}
|
||||
.conv-more{display:block;width:100%;font:inherit;font-size:12px;color:var(--dim);background:none;
|
||||
border:0;padding:8px 11px;text-align:left;cursor:pointer}
|
||||
.conv-more:hover{color:var(--text)}
|
||||
/* Discussion au travail : un anneau qui tourne, à gauche du titre. C'est le seul
|
||||
élément animé de la liste — il désigne sans ambiguïté le fil sur lequel un
|
||||
agent est en train de travailler, y compris depuis un autre appareil. */
|
||||
@@ -9127,6 +9130,12 @@ let CONVS = [], CONV_ACTIVE = '';
|
||||
// ligne doit déjà s'animer si un agent travaille (page rechargée en cours de
|
||||
// route, ou ouverte depuis un autre appareil).
|
||||
let CONV_BUSY = false;
|
||||
// Liste paginée (AJEAN 0.15.6) : avec des centaines de discussions, construire
|
||||
// toutes les lignes d'un coup figeait l'ouverture du panneau. On en dessine
|
||||
// CONV_PAGE, puis la suite quand le bas de la liste devient visible. La
|
||||
// recherche, elle, filtre toujours TOUTE la liste (CONVS est en mémoire).
|
||||
const CONV_PAGE = 40;
|
||||
let CONV_SHOWN = CONV_PAGE, CONV_LAST_Q = '', convMoreObs = null;
|
||||
|
||||
async function loadConversations(){
|
||||
let r;
|
||||
@@ -9149,6 +9158,7 @@ function renderConversations(){
|
||||
if(!cont) return;
|
||||
const q = (document.getElementById('conv-search')?.value || '').trim().toLowerCase();
|
||||
cont.textContent = '';
|
||||
if(q !== CONV_LAST_Q){ CONV_LAST_Q = q; CONV_SHOWN = CONV_PAGE; }
|
||||
const list = q
|
||||
? CONVS.filter(c => (c.title || 'Nouvelle discussion').toLowerCase().includes(q))
|
||||
: CONVS;
|
||||
@@ -9161,7 +9171,10 @@ function renderConversations(){
|
||||
convSyncBusy();
|
||||
return;
|
||||
}
|
||||
for(const c of list){
|
||||
// La discussion active reste toujours visible, même loin dans la liste.
|
||||
const ai = list.findIndex(c => c.id === CONV_ACTIVE);
|
||||
const shown = Math.max(CONV_SHOWN, ai + 1);
|
||||
for(const c of list.slice(0, shown)){
|
||||
const row = document.createElement('div');
|
||||
row.className = 'preset' + (c.id === CONV_ACTIVE ? ' active' : '');
|
||||
// L'identifiant est porté par la ligne : convSyncBusy retrouve ainsi CELLE
|
||||
@@ -9199,10 +9212,28 @@ function renderConversations(){
|
||||
row.append(info, when, acts);
|
||||
cont.appendChild(row);
|
||||
}
|
||||
if(list.length > shown) convMoreRow(cont, list.length - shown);
|
||||
syncTopbarTitle();
|
||||
convSyncBusy();
|
||||
}
|
||||
|
||||
// Ligne « N de plus » en bas de la liste : un clic, ou son arrivée à l'écran
|
||||
// (IntersectionObserver), dessine la page suivante.
|
||||
function convMoreRow(cont, left){
|
||||
const more = document.createElement('button');
|
||||
more.type = 'button';
|
||||
more.className = 'conv-more';
|
||||
more.textContent = 'afficher ' + Math.min(left, CONV_PAGE) + ' de plus (' + left + ' restantes)';
|
||||
const next = () => { CONV_SHOWN += CONV_PAGE; renderConversations(); };
|
||||
more.onclick = next;
|
||||
cont.appendChild(more);
|
||||
if(convMoreObs) convMoreObs.disconnect();
|
||||
if(window.IntersectionObserver){
|
||||
convMoreObs = new IntersectionObserver(es => { if(es.some(e => e.isIntersecting)){ convMoreObs.disconnect(); next(); } });
|
||||
convMoreObs.observe(more);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Discussion au travail : anneau qui tourne ------------------------------
|
||||
// Une seule génération tourne à la fois, et c'est forcément sur la discussion
|
||||
// OUVERTE (le serveur n'a qu'un fil en mémoire) : l'indicateur va donc sur la
|
||||
|
||||
@@ -19,6 +19,12 @@ let CONVS = [], CONV_ACTIVE = '';
|
||||
// ligne doit déjà s'animer si un agent travaille (page rechargée en cours de
|
||||
// route, ou ouverte depuis un autre appareil).
|
||||
let CONV_BUSY = false;
|
||||
// Liste paginée (AJEAN 0.15.6) : avec des centaines de discussions, construire
|
||||
// toutes les lignes d'un coup figeait l'ouverture du panneau. On en dessine
|
||||
// CONV_PAGE, puis la suite quand le bas de la liste devient visible. La
|
||||
// recherche, elle, filtre toujours TOUTE la liste (CONVS est en mémoire).
|
||||
const CONV_PAGE = 40;
|
||||
let CONV_SHOWN = CONV_PAGE, CONV_LAST_Q = '', convMoreObs = null;
|
||||
|
||||
async function loadConversations(){
|
||||
let r;
|
||||
@@ -41,6 +47,7 @@ function renderConversations(){
|
||||
if(!cont) return;
|
||||
const q = (document.getElementById('conv-search')?.value || '').trim().toLowerCase();
|
||||
cont.textContent = '';
|
||||
if(q !== CONV_LAST_Q){ CONV_LAST_Q = q; CONV_SHOWN = CONV_PAGE; }
|
||||
const list = q
|
||||
? CONVS.filter(c => (c.title || 'Nouvelle discussion').toLowerCase().includes(q))
|
||||
: CONVS;
|
||||
@@ -53,7 +60,10 @@ function renderConversations(){
|
||||
convSyncBusy();
|
||||
return;
|
||||
}
|
||||
for(const c of list){
|
||||
// La discussion active reste toujours visible, même loin dans la liste.
|
||||
const ai = list.findIndex(c => c.id === CONV_ACTIVE);
|
||||
const shown = Math.max(CONV_SHOWN, ai + 1);
|
||||
for(const c of list.slice(0, shown)){
|
||||
const row = document.createElement('div');
|
||||
row.className = 'preset' + (c.id === CONV_ACTIVE ? ' active' : '');
|
||||
// L'identifiant est porté par la ligne : convSyncBusy retrouve ainsi CELLE
|
||||
@@ -91,10 +101,28 @@ function renderConversations(){
|
||||
row.append(info, when, acts);
|
||||
cont.appendChild(row);
|
||||
}
|
||||
if(list.length > shown) convMoreRow(cont, list.length - shown);
|
||||
syncTopbarTitle();
|
||||
convSyncBusy();
|
||||
}
|
||||
|
||||
// Ligne « N de plus » en bas de la liste : un clic, ou son arrivée à l'écran
|
||||
// (IntersectionObserver), dessine la page suivante.
|
||||
function convMoreRow(cont, left){
|
||||
const more = document.createElement('button');
|
||||
more.type = 'button';
|
||||
more.className = 'conv-more';
|
||||
more.textContent = 'afficher ' + Math.min(left, CONV_PAGE) + ' de plus (' + left + ' restantes)';
|
||||
const next = () => { CONV_SHOWN += CONV_PAGE; renderConversations(); };
|
||||
more.onclick = next;
|
||||
cont.appendChild(more);
|
||||
if(convMoreObs) convMoreObs.disconnect();
|
||||
if(window.IntersectionObserver){
|
||||
convMoreObs = new IntersectionObserver(es => { if(es.some(e => e.isIntersecting)){ convMoreObs.disconnect(); next(); } });
|
||||
convMoreObs.observe(more);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Discussion au travail : anneau qui tourne ------------------------------
|
||||
// Une seule génération tourne à la fois, et c'est forcément sur la discussion
|
||||
// OUVERTE (le serveur n'a qu'un fil en mémoire) : l'indicateur va donc sur la
|
||||
|
||||
@@ -1711,6 +1711,9 @@ html[data-files="1"] #files-btn{color:var(--accent)}
|
||||
color:var(--dim);letter-spacing:-.01em;overflow:visible}
|
||||
.side .preset:hover .conv-when{opacity:0}
|
||||
.conv-empty{font-size:12px;color:var(--dim);padding:8px 11px}
|
||||
.conv-more{display:block;width:100%;font:inherit;font-size:12px;color:var(--dim);background:none;
|
||||
border:0;padding:8px 11px;text-align:left;cursor:pointer}
|
||||
.conv-more:hover{color:var(--text)}
|
||||
/* Discussion au travail : un anneau qui tourne, à gauche du titre. C'est le seul
|
||||
élément animé de la liste — il désigne sans ambiguïté le fil sur lequel un
|
||||
agent est en train de travailler, y compris depuis un autre appareil. */
|
||||
|
||||
Reference in new issue
Block a user