Split CSS
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
.channel-number {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 34px;
|
||||
height: 26px;
|
||||
margin-right: 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--panel-3);
|
||||
color: #dbeafe;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.timeline-channel .channel-number {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.timeline-channel-name {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.channel-logo {
|
||||
width: 34px;
|
||||
height: 24px;
|
||||
object-fit: contain;
|
||||
flex: 0 0 auto;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 6px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
@@ -79,20 +79,6 @@
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.channel-number {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 34px;
|
||||
height: 26px;
|
||||
margin-right: 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--panel-3);
|
||||
color: #dbeafe;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.day-programme {
|
||||
display: grid;
|
||||
grid-template-columns: 92px 1fr;
|
||||
@@ -101,11 +87,6 @@
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.day-programme.is-current {
|
||||
background: rgba(34, 197, 94, 0.12);
|
||||
border-left: 5px solid var(--success);
|
||||
}
|
||||
|
||||
.day-programme.is-past {
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
.day-programme.is-current {
|
||||
background: rgba(34, 197, 94, 0.12);
|
||||
border-left: 5px solid var(--success);
|
||||
}
|
||||
|
||||
.timeline-programme.is-current {
|
||||
background: rgba(34, 197, 94, 0.22);
|
||||
border-color: var(--success);
|
||||
}
|
||||
|
||||
.timeline-now-line {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background: #ef4444;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.timeline-now-line::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -5px;
|
||||
top: -5px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: #ef4444;
|
||||
}
|
||||
|
||||
@@ -100,27 +100,6 @@
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.timeline-channel .channel-number {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.timeline-channel-name {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.channel-logo {
|
||||
width: 34px;
|
||||
height: 24px;
|
||||
object-fit: contain;
|
||||
flex: 0 0 auto;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 6px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.timeline-programmes {
|
||||
position: relative;
|
||||
min-height: 72px;
|
||||
@@ -189,36 +168,10 @@
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.timeline-programme.is-current {
|
||||
background: rgba(34, 197, 94, 0.22);
|
||||
border-color: var(--success);
|
||||
}
|
||||
|
||||
.timeline-programme.is-past {
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.timeline-now-line {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background: #ef4444;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.timeline-now-line::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -5px;
|
||||
top: -5px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: #ef4444;
|
||||
}
|
||||
|
||||
.timeline-zoom {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
+10
-211
@@ -1,215 +1,14 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
const wrap = document.querySelector(".timeline-wrap");
|
||||
const line = document.querySelector(".timeline-now-line");
|
||||
|
||||
if (!wrap || !line)
|
||||
return;
|
||||
|
||||
wrap.scrollLeft = Math.max(
|
||||
0,
|
||||
line.offsetLeft - wrap.clientWidth / 3
|
||||
);
|
||||
|
||||
});
|
||||
import { initNowLine } from "./modules/now.js";
|
||||
import { initProgrammeModal } from "./modules/modal.js";
|
||||
import { initGuideSearch } from "./modules/search.js";
|
||||
import { initTimelineZoom, initTimelineDrag } from "./modules/timeline.js";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const modal = document.getElementById("programmeModal");
|
||||
initNowLine();
|
||||
initProgrammeModal();
|
||||
initGuideSearch();
|
||||
initTimelineZoom();
|
||||
initTimelineDrag();
|
||||
|
||||
if (!modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const title = document.getElementById("modalTitle");
|
||||
const subtitle = document.getElementById("modalSubtitle");
|
||||
const description = document.getElementById("modalDescription");
|
||||
const category = document.getElementById("modalCategory");
|
||||
const time = document.getElementById("modalTime");
|
||||
|
||||
const openModal = (programmeElement) => {
|
||||
const id = programmeElement.dataset.programmeId;
|
||||
const programme = window.TVGUIDE_PROGRAMMES?.[id];
|
||||
|
||||
if (!programme) {
|
||||
return;
|
||||
}
|
||||
|
||||
title.textContent = programme.title || "";
|
||||
subtitle.textContent = programme.subtitle || "";
|
||||
description.textContent = programme.description || "Keine Beschreibung vorhanden.";
|
||||
category.textContent = programme.category || "";
|
||||
time.textContent = `${programme.channel || ""} · ${programme.start || ""} – ${programme.stop || ""}`;
|
||||
|
||||
modal.hidden = false;
|
||||
document.body.classList.add("modal-open");
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
modal.hidden = true;
|
||||
document.body.classList.remove("modal-open");
|
||||
};
|
||||
|
||||
document.querySelectorAll(".timeline-programme").forEach((programme) => {
|
||||
programme.addEventListener("click", () => openModal(programme));
|
||||
});
|
||||
|
||||
modal.querySelectorAll("[data-modal-close]").forEach((element) => {
|
||||
element.addEventListener("click", closeModal);
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape" && !modal.hidden) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
console.log("TVGuide loaded");
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const search = document.getElementById("guideSearch");
|
||||
const results = document.getElementById("guideSearchResults");
|
||||
const programmes = window.TVGUIDE_PROGRAMMES || {};
|
||||
|
||||
if (!search || !results) {
|
||||
return;
|
||||
}
|
||||
|
||||
const openProgrammeById = (id) => {
|
||||
const element = document.querySelector(`[data-programme-id="${CSS.escape(id)}"]`);
|
||||
if (element) {
|
||||
element.click();
|
||||
}
|
||||
};
|
||||
|
||||
search.addEventListener("input", () => {
|
||||
const query = search.value.trim().toLowerCase();
|
||||
|
||||
if (query.length < 2) {
|
||||
results.hidden = true;
|
||||
results.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
const matches = Object.values(programmes)
|
||||
.filter((programme) => {
|
||||
return [
|
||||
programme.title,
|
||||
programme.subtitle,
|
||||
programme.description,
|
||||
programme.category,
|
||||
programme.channel
|
||||
].some((value) => (value || "").toLowerCase().includes(query));
|
||||
})
|
||||
.slice(0, 12);
|
||||
|
||||
if (!matches.length) {
|
||||
results.innerHTML = `<div class="guide-search-result"><strong>Nichts gefunden</strong></div>`;
|
||||
results.hidden = false;
|
||||
return;
|
||||
}
|
||||
|
||||
results.innerHTML = matches.map((programme) => `
|
||||
<div class="guide-search-result" data-search-programme-id="${programme.id}">
|
||||
<strong>${programme.title || "Ohne Titel"}</strong>
|
||||
<span>${programme.channel || ""} · ${programme.start || ""} – ${programme.stop || ""}</span>
|
||||
</div>
|
||||
`).join("");
|
||||
|
||||
results.hidden = false;
|
||||
});
|
||||
|
||||
results.addEventListener("click", (event) => {
|
||||
const item = event.target.closest("[data-search-programme-id]");
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
openProgrammeById(item.dataset.searchProgrammeId);
|
||||
results.hidden = true;
|
||||
search.value = "";
|
||||
});
|
||||
|
||||
document.addEventListener("click", (event) => {
|
||||
if (!event.target.closest(".guide-search")) {
|
||||
results.hidden = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const timelineWrap = document.querySelector(".timeline-wrap");
|
||||
const zoomButtons = document.querySelectorAll("[data-zoom]");
|
||||
|
||||
if (!timelineWrap || !zoomButtons.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const savedZoom = localStorage.getItem("tvguideTimelineZoom") || "2";
|
||||
|
||||
const applyZoom = (zoom) => {
|
||||
timelineWrap.style.setProperty("--minute-width", `${zoom}px`);
|
||||
|
||||
zoomButtons.forEach((button) => {
|
||||
button.classList.toggle("active", button.dataset.zoom === zoom);
|
||||
});
|
||||
|
||||
localStorage.setItem("tvguideTimelineZoom", zoom);
|
||||
};
|
||||
|
||||
zoomButtons.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
applyZoom(button.dataset.zoom);
|
||||
});
|
||||
});
|
||||
|
||||
applyZoom(savedZoom);
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
const timeline = document.querySelector(".timeline-wrap");
|
||||
|
||||
if (!timeline)
|
||||
return;
|
||||
|
||||
let isDragging = false;
|
||||
let startX = 0;
|
||||
let scrollLeft = 0;
|
||||
|
||||
timeline.addEventListener("mousedown", (e) => {
|
||||
|
||||
// nicht wenn auf eine Sendung geklickt wird
|
||||
if (e.target.closest(".timeline-programme"))
|
||||
return;
|
||||
|
||||
isDragging = true;
|
||||
|
||||
timeline.classList.add("dragging");
|
||||
|
||||
startX = e.pageX;
|
||||
scrollLeft = timeline.scrollLeft;
|
||||
});
|
||||
|
||||
document.addEventListener("mouseup", () => {
|
||||
|
||||
isDragging = false;
|
||||
|
||||
timeline.classList.remove("dragging");
|
||||
});
|
||||
|
||||
document.addEventListener("mousemove", (e) => {
|
||||
|
||||
if (!isDragging)
|
||||
return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const walk = e.pageX - startX;
|
||||
|
||||
timeline.scrollLeft = scrollLeft - walk;
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
console.log('TVGuide loaded');
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
export function initProgrammeModal() {
|
||||
const modal = document.getElementById("programmeModal");
|
||||
|
||||
if (!modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const title = document.getElementById("modalTitle");
|
||||
const subtitle = document.getElementById("modalSubtitle");
|
||||
const description = document.getElementById("modalDescription");
|
||||
const category = document.getElementById("modalCategory");
|
||||
const time = document.getElementById("modalTime");
|
||||
|
||||
const openModal = (programmeElement) => {
|
||||
const id = programmeElement.dataset.programmeId;
|
||||
const programme = window.TVGUIDE_PROGRAMMES?.[id];
|
||||
|
||||
if (!programme) {
|
||||
return;
|
||||
}
|
||||
|
||||
title.textContent = programme.title || "";
|
||||
subtitle.textContent = programme.subtitle || "";
|
||||
description.textContent = programme.description || "Keine Beschreibung vorhanden.";
|
||||
category.textContent = programme.category || "";
|
||||
time.textContent = `${programme.channel || ""} · ${programme.start || ""} – ${programme.stop || ""}`;
|
||||
|
||||
modal.hidden = false;
|
||||
document.body.classList.add("modal-open");
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
modal.hidden = true;
|
||||
document.body.classList.remove("modal-open");
|
||||
};
|
||||
|
||||
document.querySelectorAll(".timeline-programme").forEach((programme) => {
|
||||
programme.addEventListener("click", () => openModal(programme));
|
||||
});
|
||||
|
||||
modal.querySelectorAll("[data-modal-close]").forEach((element) => {
|
||||
element.addEventListener("click", closeModal);
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape" && !modal.hidden) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
export function initNowLine() {
|
||||
const wrap = document.querySelector(".timeline-wrap");
|
||||
const line = document.querySelector(".timeline-now-line");
|
||||
|
||||
if (!wrap || !line) {
|
||||
return;
|
||||
}
|
||||
|
||||
wrap.scrollLeft = Math.max(
|
||||
0,
|
||||
line.offsetLeft - wrap.clientWidth / 3
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
export function initGuideSearch() {
|
||||
const search = document.getElementById("guideSearch");
|
||||
const results = document.getElementById("guideSearchResults");
|
||||
const programmes = window.TVGUIDE_PROGRAMMES || {};
|
||||
|
||||
if (!search || !results) {
|
||||
return;
|
||||
}
|
||||
|
||||
const openProgrammeById = (id) => {
|
||||
const element = document.querySelector(`[data-programme-id="${CSS.escape(id)}"]`);
|
||||
|
||||
if (element) {
|
||||
element.click();
|
||||
}
|
||||
};
|
||||
|
||||
search.addEventListener("input", () => {
|
||||
const query = search.value.trim().toLowerCase();
|
||||
|
||||
if (query.length < 2) {
|
||||
results.hidden = true;
|
||||
results.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
const matches = Object.values(programmes)
|
||||
.filter((programme) => {
|
||||
return [
|
||||
programme.title,
|
||||
programme.subtitle,
|
||||
programme.description,
|
||||
programme.category,
|
||||
programme.channel
|
||||
].some((value) => (value || "").toLowerCase().includes(query));
|
||||
})
|
||||
.slice(0, 12);
|
||||
|
||||
if (!matches.length) {
|
||||
results.innerHTML = `<div class="guide-search-result"><strong>Nichts gefunden</strong></div>`;
|
||||
results.hidden = false;
|
||||
return;
|
||||
}
|
||||
|
||||
results.innerHTML = matches.map((programme) => `
|
||||
<div class="guide-search-result" data-search-programme-id="${programme.id}">
|
||||
<strong>${programme.title || "Ohne Titel"}</strong>
|
||||
<span>${programme.channel || ""} · ${programme.start || ""} – ${programme.stop || ""}</span>
|
||||
</div>
|
||||
`).join("");
|
||||
|
||||
results.hidden = false;
|
||||
});
|
||||
|
||||
results.addEventListener("click", (event) => {
|
||||
const item = event.target.closest("[data-search-programme-id]");
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
openProgrammeById(item.dataset.searchProgrammeId);
|
||||
results.hidden = true;
|
||||
search.value = "";
|
||||
});
|
||||
|
||||
document.addEventListener("click", (event) => {
|
||||
if (!event.target.closest(".guide-search")) {
|
||||
results.hidden = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
export function initTimelineZoom() {
|
||||
const timelineWrap = document.querySelector(".timeline-wrap");
|
||||
const zoomButtons = document.querySelectorAll("[data-zoom]");
|
||||
|
||||
if (!timelineWrap || !zoomButtons.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const savedZoom = localStorage.getItem("tvguideTimelineZoom") || "2";
|
||||
|
||||
const applyZoom = (zoom) => {
|
||||
timelineWrap.style.setProperty("--minute-width", `${zoom}px`);
|
||||
|
||||
zoomButtons.forEach((button) => {
|
||||
button.classList.toggle("active", button.dataset.zoom === zoom);
|
||||
});
|
||||
|
||||
localStorage.setItem("tvguideTimelineZoom", zoom);
|
||||
};
|
||||
|
||||
zoomButtons.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
applyZoom(button.dataset.zoom);
|
||||
});
|
||||
});
|
||||
|
||||
applyZoom(savedZoom);
|
||||
}
|
||||
|
||||
export function initTimelineDrag() {
|
||||
const timeline = document.querySelector(".timeline-wrap");
|
||||
|
||||
if (!timeline) {
|
||||
return;
|
||||
}
|
||||
|
||||
let isDragging = false;
|
||||
let startX = 0;
|
||||
let scrollLeft = 0;
|
||||
|
||||
timeline.addEventListener("mousedown", (event) => {
|
||||
if (event.target.closest(".timeline-programme")) {
|
||||
return;
|
||||
}
|
||||
|
||||
isDragging = true;
|
||||
timeline.classList.add("dragging");
|
||||
|
||||
startX = event.pageX;
|
||||
scrollLeft = timeline.scrollLeft;
|
||||
});
|
||||
|
||||
document.addEventListener("mouseup", () => {
|
||||
isDragging = false;
|
||||
timeline.classList.remove("dragging");
|
||||
});
|
||||
|
||||
document.addEventListener("mousemove", (event) => {
|
||||
if (!isDragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const walk = event.pageX - startX;
|
||||
timeline.scrollLeft = scrollLeft - walk;
|
||||
});
|
||||
}
|
||||
@@ -19,6 +19,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/js/app.js"></script>
|
||||
<script type="module" src="/assets/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user