From dffd25fb47443b2615955af8f895b5e7b5efd3f0 Mon Sep 17 00:00:00 2001 From: Gogs Date: Tue, 7 Jul 2026 10:42:45 +0200 Subject: [PATCH] Split CSS --- app/public/assets/css/channels.css | 34 ++++ app/public/assets/css/day.css | 19 -- app/public/assets/css/now.css | 30 +++ app/public/assets/css/timeline.css | 47 ----- app/public/assets/js/app.js | 221 +---------------------- app/public/assets/js/modules/modal.js | 50 +++++ app/public/assets/js/modules/now.js | 13 ++ app/public/assets/js/modules/search.js | 72 ++++++++ app/public/assets/js/modules/timeline.js | 68 +++++++ app/templates/layout.php | 2 +- 10 files changed, 278 insertions(+), 278 deletions(-) create mode 100644 app/public/assets/js/modules/modal.js create mode 100644 app/public/assets/js/modules/now.js create mode 100644 app/public/assets/js/modules/search.js create mode 100644 app/public/assets/js/modules/timeline.js diff --git a/app/public/assets/css/channels.css b/app/public/assets/css/channels.css index e69de29..e7541cd 100644 --- a/app/public/assets/css/channels.css +++ b/app/public/assets/css/channels.css @@ -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; +} diff --git a/app/public/assets/css/day.css b/app/public/assets/css/day.css index 5e44979..fb20be2 100644 --- a/app/public/assets/css/day.css +++ b/app/public/assets/css/day.css @@ -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; } diff --git a/app/public/assets/css/now.css b/app/public/assets/css/now.css index e69de29..a92b2d2 100644 --- a/app/public/assets/css/now.css +++ b/app/public/assets/css/now.css @@ -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; +} diff --git a/app/public/assets/css/timeline.css b/app/public/assets/css/timeline.css index d82d655..58d9c01 100644 --- a/app/public/assets/css/timeline.css +++ b/app/public/assets/css/timeline.css @@ -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; diff --git a/app/public/assets/js/app.js b/app/public/assets/js/app.js index 8dd1714..78e8432 100644 --- a/app/public/assets/js/app.js +++ b/app/public/assets/js/app.js @@ -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 = `
Nichts gefunden
`; - results.hidden = false; - return; - } - - results.innerHTML = matches.map((programme) => ` -
- ${programme.title || "Ohne Titel"} - ${programme.channel || ""} · ${programme.start || ""} – ${programme.stop || ""} -
- `).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'); - diff --git a/app/public/assets/js/modules/modal.js b/app/public/assets/js/modules/modal.js new file mode 100644 index 0000000..ce68720 --- /dev/null +++ b/app/public/assets/js/modules/modal.js @@ -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(); + } + }); +} diff --git a/app/public/assets/js/modules/now.js b/app/public/assets/js/modules/now.js new file mode 100644 index 0000000..b3d60b7 --- /dev/null +++ b/app/public/assets/js/modules/now.js @@ -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 + ); +} diff --git a/app/public/assets/js/modules/search.js b/app/public/assets/js/modules/search.js new file mode 100644 index 0000000..a69b5e7 --- /dev/null +++ b/app/public/assets/js/modules/search.js @@ -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 = `
Nichts gefunden
`; + results.hidden = false; + return; + } + + results.innerHTML = matches.map((programme) => ` +
+ ${programme.title || "Ohne Titel"} + ${programme.channel || ""} · ${programme.start || ""} – ${programme.stop || ""} +
+ `).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; + } + }); +} diff --git a/app/public/assets/js/modules/timeline.js b/app/public/assets/js/modules/timeline.js new file mode 100644 index 0000000..3c75531 --- /dev/null +++ b/app/public/assets/js/modules/timeline.js @@ -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; + }); +} diff --git a/app/templates/layout.php b/app/templates/layout.php index b94a705..516d066 100644 --- a/app/templates/layout.php +++ b/app/templates/layout.php @@ -19,6 +19,6 @@ - +