Internet plus Telewizja, dodanie modal, poprawki w Markdown

This commit is contained in:
dm
2025-11-22 06:06:07 +01:00
parent c04d63647e
commit ae4b7a04ac
12 changed files with 217 additions and 52 deletions

BIN
public/assets/logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -17,8 +17,8 @@ const links = [
<!-- Logo -->
<a href="/" class="flex items-center gap-2 font-semibold">
<span class="inline-flex h-8 w-8 items-center justify-center rounded-full bg-sky-500 text-white text-sm font-bold">
F
<span class="inline-flex h-8 w-8 items-center justify-center rounded-full text-sm font-bold">
<img src="/assets/logo.webp" alt="FUZ Logo" class="h-5 w-5" />
</span>
<span>FUZ</span>
</a>

View File

@@ -1,23 +1,4 @@
sections:
# - title:
# image:
# dimmed: true
# type: default
# content: |
# Światłowody to najbardziej zaawansowana technologia przesyłu danych.
# Gwarantują błyskawiczną prędkość, stabilność i niezawodność bez względu na warunki.
# Dedykowane pasmo,pełna prędkość tylko dla Ciebie.
# Stała jakość, pogoda ani liczba użytkowników w sieci nie mają znaczenia.
# Wiele urządzeń jednocześnie, komputer, telefon, tablet, konsola wszystko działa płynnie.
# Światłowód to również dostęp do telewizji i telefonu w najwyższej jakości.
# Sprawdź naszą pełną ofertę i wybierz rozwiązanie dopasowane do Twoich potrzeb.
- title: Sprawdź dostępność usługi
image: "/assets/internet/internet.webp"
content: |
@@ -25,7 +6,9 @@ sections:
Sprawdź czy pod Twoim adresem dostępna jest nasza usługa internetu światłowodowego.
Tam gdzie nie docierają światłowody stosuje się inne technologie. Jeśli pod Twoim adresem nie ma jeszcze usług światłowodowych, to sprawdź czy dociera tam nasz [internet radiowy](/internet-radiowy)
Tam gdzie nie docierają światłowody stosuje się inne technologie.
Jeśli pod Twoim adresem nie ma jeszcze usług światłowodowych, to sprawdź czy dociera tam nasz [internet radiowy →](/internet-radiowy)
- title: Router WiFi 5 AC1200
image: "/assets/internet/E5400.webp"

View File

@@ -0,0 +1,50 @@
catchup:
title: CATCHUP - ARCHIWUM TV
content: |
Funkcja CatchUp pozwala na oglądanie archiwalnych audycji na wybranych kanałach do 7 dni wstecz.
Przegapiłeś jakiś program? Zapomniałeś nagrać?
Odnajdź go w EPG, cofając się w lewo na osi czasu.
![Catchup screen](/assets/tv/jambox-kyanit-catchup1.png)
nagrywarka:
title: NAGRYWARKA
content: |
Nasze dekodery posiadają możliwość nagrywania wybranych lub wszystkich kanałów, w zależności od modelu dekodera.
Nagrywarka sieciowa pozwala na nagrywanie i oglądanie audycji bez dysku.
Dzięki tej wersji nagrywarki możesz zlecać w tym samym czasie 3 niezależne nagrania.
Korzyści jakie daje nagrywarka to między innymi możliwość oglądania nagrania od początku, nawet jak włączyłeś je w trakcie emisji na żywo.
Przydatna funkcja to możliwość zaprogramowania nagrywarki także z aplikacji JAMBOX go! Nagrania są dostępne na dekoderze przez 7 dni.
Nagrywanie w chmurze dostępne jest na dekoderach Abox M15, Hybroad Z123 oraz Arris VIP 4302.
![Nagrywarka](/assets/tv/jambox-kyanit-jpvr.png)
startover:
title: STARTOVER - OGLĄDAJ OD POCZĄTKU
content: |
Funkcja StartOver pozwala na oglądanie od początku tych audycji, które już się rozpoczęły, lecz jeszcze nie skończyły.
Spóźniłeś się na emisję na żywo?
Nic nie szkodzi! Kliknij "Oglądaj od początku" i już nic Ci nie umknie!
![STARTOVER](/assets/tv/jambox-kyanit-startover1.png)
nagrywanie_cykliczne:
title: NAGRYWANIE CZASOWE/CYKLICZNE
content: |
Jeśli lubisz oglądać każdego dnia wiadomości, albo chcesz nagrać Twojemu dziecku wszystkie wieczorynki to możesz teraz w prosty sposób zaplanować nagrania.
Nagrywanie według czasu to funkcja, która umożliwia Ci zaprogramowanie nagrań powtarzających się.
Zaplanuj nagrania codzienne, weekendowe czy w wybranych przez Ciebie dniach. Dodatkowo możesz nagrać dowolny przedział czasu na kanale.
Nagrywanie czasowe jest dostępne na dekoderze wyposażonym w dysk dedykowany lub USB.

View File

@@ -2,17 +2,13 @@ sections:
- title: Dodatkowe możliwości naszej telewizji"
image: "/assets/tv/ekosystem-kyanit.png"
content: |
- **Catchup** — na wybranych kanałach możesz obejrzeć audycję z ostatnich 7 dni.
[Poznaj szczegóły](#catchup)
- **Catchup** — na wybranych kanałach możesz obejrzeć audycję z ostatnich 7 dni. [Więcej →](#catchup)
- **Nagrywanie** — nagraj interesującą Cię audycję i obejrzyj ją kiedy chcesz.
[Poznaj szczegóły](#nagrywarka)
- **Nagrywanie** — nagraj interesującą Cię audycję i obejrzyj ją kiedy chcesz. [Więcej →](#nagrywarka)
- **StartOver** — obejrzyj od początku audycję, która już się rozpoczęła (do 3h wstecz).
[Poznaj szczegóły](#startover)
- **StartOver** — obejrzyj od początku audycję, która już się rozpoczęła (do 3h wstecz). [Więcej →](#startover)
- **Nagrywanie serii** — zaplanuj nagrywanie kolejnych odcinków ulubionego serialu.
[Poznaj szczegóły](#nagrywanie_cykliczne)
- **Nagrywanie serii** — zaplanuj nagrywanie kolejnych odcinków ulubionego serialu. [Więcej →](#nagrywanie_cykliczne)
- **Pauzowanie** — zatrzymuj i cofaj audycje.

View File

@@ -49,9 +49,13 @@ export default function FuzMarkdown({ text, ctx = {} }) {
// Konwersja kinków na modal linki
processed = processed.replace(
/\[([^\]]+)\]\(#([^)]+)\)/g,
`<a href="#" class="modal-link text-cyan-600 underline" data-modal="$2">$1</a>`
`<a href="#" class="modal-link" data-modal="$2">$1</a>`
);
// processed = processed.replace(
// /\[([^\]]+)\]\(#([^)]+)\)/g,
// `<button type="button" class="btn btn-outline modal-link" data-modal="$2">$1</button>`
// );
const html = marked(processed);
return (

69
src/islands/Modal.jsx Normal file
View File

@@ -0,0 +1,69 @@
import { marked } from "marked";
import { useEffect, useState } from "preact/hooks";
import "../styles/modal.css";
marked.setOptions({
gfm: true,
breaks: true,
headerIds: false,
mangle: false,
smartLists: true,
});
export default function Modal({ modalData }) {
const [open, setOpen] = useState(false);
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
useEffect(() => {
const clickHandler = (e) => {
const el = e.target.closest("[data-modal]");
if (!el) return;
// 🚀 BLOKADA WSZYSTKICH DOMYŚLNYCH ZACHOWAŃ
e.preventDefault();
e.stopPropagation();
const id = el.getAttribute("data-modal");
const modal = modalData[id];
if (!modal) return;
setTitle(modal.title || "");
setContent((modal.content || "").replace(/\n(?!\n)/g, "\n\n"));
setOpen(true);
};
document.addEventListener("click", clickHandler, { capture: true });
return () =>
document.removeEventListener("click", clickHandler, { capture: true });
}, [modalData]);
if (!open) return null;
return (
<div class="fuz-modal-overlay" onClick={() => setOpen(false)}>
<button
class="fuz-modal-close"
onClick={(e) => {
e.stopPropagation();
setOpen(false);
}}
>
</button>
<div class="fuz-modal-panel" onClick={(e) => e.stopPropagation()}>
<div class="fuz-modal-inner">
<h2 class="fuz-modal-title">{title}</h2>
<div
class="fuz-modal-content"
dangerouslySetInnerHTML={{
__html: marked(content),
}}
/>
</div>
</div>
</div>
);
}

View File

@@ -19,7 +19,7 @@ export default function OffersExtraServices({
<tr>
<th class="fuz-table-heading">Usługa</th>
<th class="fuz-table-heading center">Cena</th>
<th class="fuz-table-heading center w-32">Szczegóły</th>
<th class="fuz-table-heading center w-32">Więcej</th>
</tr>
</thead>
@@ -31,7 +31,7 @@ export default function OffersExtraServices({
<td class="fuz-feature-cell center">{srv.cena}</td>
<td class="fuz-feature-cell-btn center">
<button class="btn-link" onClick={() => toggle(srv.id)}>
{openId === srv.id ? "Zwiń" : "Szczegóły"}
{openId === srv.id ? "Zwiń" : "Więcej"}
</button>
</td>
</tr>

View File

@@ -3,6 +3,7 @@ import DefaultLayout from "../../layouts/DefaultLayout.astro";
import Hero from "../../components/hero/Hero.astro";
import SectionRenderer from "../../components/sections/SectionRenderer.astro";
import Markdown from "../../islands/Markdown.jsx";
import Modal from "../../islands/Modal.jsx";
import OffersIsland from "../../islands/OffersIsland.jsx";
import yaml from "js-yaml";
@@ -17,6 +18,9 @@ const hero = yaml.load(
const page = yaml.load(
fs.readFileSync("./src/content/internet-telewizja/page.yaml", "utf8"),
);
const modalData = yaml.load(
fs.readFileSync("./src/content/internet-telewizja/modal.yaml", "utf8")
);
type Paragraph = {
title?: string;
@@ -42,23 +46,19 @@ const rest = page.paragraphs.slice(1);
</section>
<OffersIsland client:load data={data} />
{rest.map((p: Paragraph) => (
<section class="fuz-section text-center">
<div class="fuz-section-grid md:grid-cols-1">
{p.title && <h3 class="fuz-section-title">{p.title}</h3>}
<Markdown text={p.content.replace(/\n/g, "\n\n")} />
</div>
</section>
))}
{
rest.map((p: Paragraph) => (
<section class="fuz-section text-center">
<div class="fuz-section-grid md:grid-cols-1">
{p.title && <h3 class="fuz-section-title">{p.title}</h3>}
<Markdown text={p.content.replace(/\n/g, "\n\n")} />
</div>
</section>
))
}
<SectionRenderer src="./src/content/internet-telewizja/section.yaml" />
<!-- <section class="fuz-section">
<div class="fuz-container">
<h1 class="fuz-hero-title">Internet FUZ</h1>
<p class="mt-4 text-gray-600 dark:text-gray-300">
Ta podstrona jest na razie szkieletem. Możemy tu później wczytać treść z YAML.
</p>
</div>
</section> -->
<Modal client:load modalData={modalData} />
</DefaultLayout>

View File

@@ -41,9 +41,15 @@
}
.fuz-markdown a {
@apply text-blue-600 dark:text-blue-400 underline hover:no-underline;
@apply no-underline hover:no-underline;
color: var(--fuz-accent);
}
.fuz-markdown button.modal-link {
@apply no-underline hover:no-underline mt-2;
background: var(--fuz-bg);
color: var(--fuz-accent);
}
.fuz-markdown blockquote {
@apply border-l-4 border-gray-300 dark:border-gray-700 pl-4 italic mb-4;
}

57
src/styles/modal.css Normal file
View File

@@ -0,0 +1,57 @@
/* MODAL — FULLSCREEN OVERLAY */
.fuz-modal-overlay {
@apply fixed inset-0 z-[9999] flex flex-col;
background: rgba(0, 0, 0, 0.65);
backdrop-filter: blur(6px);
animation: fadeIn 0.25s ease-out forwards;
}
/* CLOSE BUTTON */
.fuz-modal-close {
@apply absolute top-4 right-6 text-3xl font-bold cursor-pointer transition-opacity;
color: var(--fuz-text);
opacity: 0.7;
}
.fuz-modal-close:hover {
@apply opacity-100;
}
/* PANEL — FULLSCREEN PANEL */
.fuz-modal-panel {
@apply w-full h-full overflow-y-auto;
@apply px-6 py-8 md:px-12 md:py-12;
background: var(--fuz-bg);
color: var(--fuz-text);
}
/* INNER LAYOUT */
.fuz-modal-inner {
@apply max-w-4xl mx-auto;
}
.fuz-modal-title {
@apply text-4xl font-bold mb-8 text-center;
color: var(--fuz-text);
}
/* CONTENT STYLE */
.fuz-modal-content p {
@apply leading-relaxed text-2xl text-center;
}
.fuz-modal-content p img {
@apply mt-2 leading-relaxed;
}
/* ANIMATIONS */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

View File

@@ -1,5 +1,5 @@
.fuz-section {
@apply py-10 px-0;
@apply py-10 px-4;
}
.fuz-section-grid {