refactor: split monolithic index.php into src/tpl + src/js modules

This commit is contained in:
Johnnybegood90
2026-03-11 23:47:22 +01:00
parent 2b163be684
commit 0be8c34b31
17 changed files with 1526 additions and 1517 deletions
+125
View File
@@ -0,0 +1,125 @@
// ── GRID ──────────────────────────────────────────────────────────────────────
function renderGrid() {
renderChannels(); renderRuler(); renderPrograms(); positionNowLine();
}
function makePlaceholder(name) {
const el = document.createElement('div');
el.className = 'channel-logo-placeholder';
el.textContent = name.substring(0,2).toUpperCase();
return el;
}
function renderChannels() {
const list = document.getElementById('channelsList');
list.innerHTML = '';
channels.forEach(ch => {
const cell = document.createElement('div');
cell.className = 'channel-cell';
if (ch.icon) {
const img = document.createElement('img');
img.className = 'channel-logo'; img.src = ch.icon;
img.onerror = () => img.replaceWith(makePlaceholder(ch.name));
cell.appendChild(img);
} else { cell.appendChild(makePlaceholder(ch.name)); }
const name = document.createElement('div');
name.className = 'channel-name'; name.textContent = ch.name; name.title = ch.name;
cell.appendChild(name);
cell.addEventListener('click', () => openPip(ch.name, getNowPlaying(ch.id)));
list.appendChild(cell);
});
}
function renderRuler() {
const ruler = document.getElementById('timeRulerInner');
ruler.innerHTML = ''; ruler.style.width = TOTAL_WIDTH_PX + 'px';
document.getElementById('timeRuler').style.width = TOTAL_WIDTH_PX + 'px';
let t = new Date(GRID_START); t.setSeconds(0,0);
const rem = t.getMinutes()%15; if (rem) t.setMinutes(t.getMinutes()+(15-rem));
while (t <= GRID_END) {
const x = msToX(t.getTime()); const isHour = t.getMinutes()===0;
const tick = document.createElement('div'); tick.className='time-tick'; tick.style.left=x+'px';
const lbl = document.createElement('div'); lbl.className='time-tick-label'+(isHour?' hour':''); lbl.textContent=fmtTime(t);
const line = document.createElement('div'); line.className='time-tick-line'+(isHour?' hour':'');
tick.appendChild(lbl); tick.appendChild(line); ruler.appendChild(tick);
t = new Date(t.getTime()+15*60000);
}
}
function renderPrograms() {
const ROW_H = 80;
const inner = document.getElementById('programsInner');
const totalH = channels.length * ROW_H;
inner.innerHTML = '';
inner.style.width = TOTAL_WIDTH_PX+'px';
inner.style.height = totalH+'px';
// Remettre la now-line (détruite par innerHTML='')
const nowLine = document.createElement('div');
nowLine.className = 'now-line'; nowLine.id = 'nowLine';
nowLine.style.height = totalH + 'px';
inner.appendChild(nowLine);
const now = new Date();
channels.forEach((ch, i) => {
const row = document.createElement('div');
row.className = 'program-row';
row.style.cssText = `top:${i*ROW_H}px;position:absolute;left:0;right:0;`;
(programs[ch.id]||[]).filter(p => p.stop>GRID_START && p.start<GRID_END).forEach(p => {
const x = Math.max(0, msToX(p.start.getTime()));
const w = Math.min(TOTAL_WIDTH_PX, msToX(p.stop.getTime())) - x;
if (w < 2) return;
const block = document.createElement('div'); block.className='program-block';
if (p.stop < now) block.classList.add('is-past');
if (p.start <= now && p.stop > now) {
block.classList.add('is-live');
block.style.setProperty('--progress',(((now-p.start)/(p.stop-p.start))*100).toFixed(1)+'%');
}
block.style.left=x+'px'; block.style.width=w+'px';
if (w>40) { const t=document.createElement('div'); t.className='program-title'; t.textContent=p.title; block.appendChild(t); }
if (w>80) {
const ep = fmtEpisode(p.season, p.episode);
const t=document.createElement('div'); t.className='program-time';
t.textContent = (ep ? ep + ' ' : '') + `${fmtTime(p.start)}${fmtTime(p.stop)}`;
block.appendChild(t);
}
block.addEventListener('mouseenter', e=>showTooltip(e,p));
block.addEventListener('mousemove', e=>moveTooltip(e));
block.addEventListener('mouseleave', hideTooltip);
if (p.start <= now && p.stop > now) {
block.addEventListener('click', () => openPip(ch.name, p.title));
}
row.appendChild(block);
});
inner.appendChild(row);
});
positionNowLine();
if (!scrollListenerAdded) {
scrollListenerAdded = true;
document.getElementById('timelineArea').addEventListener('scroll', function() {
document.getElementById('channelsList').scrollTop = this.scrollTop;
});
}
}
function positionNowLine() {
const x = msToX(Date.now());
const line = document.getElementById('nowLine');
if (line) line.style.left = x + 'px';
}
function centerNow() {
const area = document.getElementById('timelineArea');
area.scrollLeft = Math.max(0, msToX(Date.now()) - area.offsetWidth * 0.3);
document.querySelectorAll('.nav-btn').forEach((b,i) => b.classList.toggle('active', i===1));
}
function shiftView(mins) {
const area = document.getElementById('timelineArea');
area.scrollLeft = Math.max(0, area.scrollLeft + mins * PX_PER_MIN);
document.querySelectorAll('.nav-btn').forEach(b => b.classList.remove('active'));
}