Section, dodanie sekcji z rozdzieleniem na standardowa i tą pod iframe
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -40,5 +40,5 @@ temp/
|
||||
|
||||
# Public generated
|
||||
public/**/*.avif
|
||||
public/**/*.webp
|
||||
# public/**/*.webp
|
||||
public/og/*.txt
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"@preact/signals": "^2.5.1",
|
||||
"astro": "^5.16.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"marked": "^17.0.1",
|
||||
"preact": "^10.27.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
BIN
public/images/fiber2.webp
Normal file
BIN
public/images/fiber2.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
BIN
public/images/section-fiber.webp
Normal file
BIN
public/images/section-fiber.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
public/images/section-phone.webp
Normal file
BIN
public/images/section-phone.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 232 KiB |
BIN
public/images/section-radiowy.webp
Normal file
BIN
public/images/section-radiowy.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 278 KiB |
BIN
public/images/section-tv.webp
Normal file
BIN
public/images/section-tv.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 252 KiB |
36
src/components/sections/SectionDefault.astro
Normal file
36
src/components/sections/SectionDefault.astro
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
import Markdown from "../../islands/Markdown.jsx";
|
||||
|
||||
const { section, index } = Astro.props;
|
||||
|
||||
const hasImage = !!section.image;
|
||||
const reverse = index % 2 === 1;
|
||||
---
|
||||
<section class="fuz-section">
|
||||
<div class={`fuz-section-grid ${hasImage ? "md:grid-cols-2" : "md:grid-cols-1"}`}>
|
||||
|
||||
{hasImage && (
|
||||
<img
|
||||
src={section.image}
|
||||
alt={section.title}
|
||||
class={`fuz-section-image ${reverse ? "md:order-1" : "md:order-2"}
|
||||
${section.dimmed ? "fuz-image-dimmed" : ""}`}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div class={`fuz-section-text ${hasImage ? (reverse ? "md:order-2" : "md:order-1") : ""}`}>
|
||||
<h2 class="fuz-section-title text-center">{section.title}</h2>
|
||||
|
||||
<Markdown text={section.content} />
|
||||
|
||||
{section.button && (
|
||||
<div class="mt-8 flex justify-center">
|
||||
<a href={section.button.url} class="btn btn-outline">
|
||||
{section.button.text}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
20
src/components/sections/SectionIframeChannels.astro
Normal file
20
src/components/sections/SectionIframeChannels.astro
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
import IframeChannelSwitcher from "../../islands/ChannelSwitcher.jsx";
|
||||
|
||||
const { section } = Astro.props;
|
||||
---
|
||||
<section class="fuz-section bg-transparent">
|
||||
<div class="max-w-7xl mx-auto text-center">
|
||||
|
||||
{section.title && (
|
||||
<h2 class="fuz-section-title">{section.title}</h2>
|
||||
)}
|
||||
|
||||
{section.content && (
|
||||
<div class="fuz-markdown mb-10" set:html={section.html} />
|
||||
)}
|
||||
|
||||
<IframeChannelSwitcher client:load sets={section.iframe_sets} />
|
||||
|
||||
</div>
|
||||
</section>
|
||||
29
src/components/sections/SectionRenderer.astro
Normal file
29
src/components/sections/SectionRenderer.astro
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
import yaml from "js-yaml";
|
||||
import fs from "fs";
|
||||
import { marked } from "marked";
|
||||
|
||||
import SectionDefault from "./SectionDefault.astro";
|
||||
import SectionIframeChannels from "./SectionIframeChannels.astro";
|
||||
|
||||
const { src } = Astro.props;
|
||||
|
||||
// Load YAML
|
||||
const data = yaml.load(fs.readFileSync(src, "utf8")) ?? { sections: [] };
|
||||
|
||||
// Markdown → HTML
|
||||
const sections = (data.sections as any[]).map((s: any) => ({
|
||||
...s,
|
||||
html: marked(s.content || "")
|
||||
}));
|
||||
---
|
||||
|
||||
{sections.map((section: any, index: number) => {
|
||||
const type = section.type || "default";
|
||||
|
||||
if (type === "iframe-channels") {
|
||||
return <SectionIframeChannels section={section} index={index} />;
|
||||
}
|
||||
|
||||
return <SectionDefault section={section} index={index} />;
|
||||
})}
|
||||
@@ -1,7 +1,8 @@
|
||||
sections:
|
||||
- title: "Internet Światłowodowy"
|
||||
image: "/images/section-fiber.jpg"
|
||||
image: "/images/section-fiber.webp"
|
||||
dimmed: true
|
||||
type: default
|
||||
button:
|
||||
text: "Zobacz ofertę →"
|
||||
url: "/internet-swiatlowod/"
|
||||
@@ -10,13 +11,36 @@ sections:
|
||||
|
||||
Odkryj komfort technologii stworzonej do pracy, rozrywki i życia bez ograniczeń.
|
||||
|
||||
- title: "Internet Radiowy"
|
||||
image: "/images/section-radiowy.jpg"
|
||||
- title: "Internet i Telewizja"
|
||||
image: "/images/section-tv.webp"
|
||||
dimmed: true
|
||||
button:
|
||||
text: "Zobacz ofertę →"
|
||||
url: "/internet-telewizja/"
|
||||
content: |
|
||||
Internet + TV to połączenie stabilnego, szybkiego łącza z bogatą ofertą telewizyjną dla całej rodziny.
|
||||
|
||||
Korzystaj z internetu bez limitów i oglądaj swoje ulubione programy w perfekcyjnej jakości — w jednym prostym pakiecie.
|
||||
|
||||
- title: "Internet Radiowy"
|
||||
image: "/images/section-radiowy.webp"
|
||||
dimmed: true
|
||||
type: default
|
||||
button:
|
||||
text: "Zobacz ofertę →"
|
||||
url: "/internet-radiowy/"
|
||||
content: |
|
||||
Nowoczesna technologia radiowa gwarantuje stabilny internet o wysokiej wydajności tam, gdzie inne łącza nie mają szans.
|
||||
|
||||
To szybki start w świat cyfrowej pracy i rozrywki — bez konieczności instalacji kabli.
|
||||
To szybki start w świat cyfrowej pracy i rozrywki — bez konieczności instalacji kabli.
|
||||
|
||||
- title: "Telefon"
|
||||
image: "/images/section-phone.webp"
|
||||
dimmed: true
|
||||
button:
|
||||
text: "Zobacz ofertę →"
|
||||
url: "/internet-telewizja/"
|
||||
content: |
|
||||
Nasza telefonia wykorzystuje zaawansowaną technologię VoIP, dzięki której dźwięk jest wyraźny, a połączenia stabilne.
|
||||
|
||||
To idealne rozwiązanie dla domu i firm, które potrzebują jakości i przewidywalnych kosztów.
|
||||
39
src/islands/ChannelSwitcher.jsx
Normal file
39
src/islands/ChannelSwitcher.jsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useState } from "preact/hooks";
|
||||
|
||||
export default function ChannelSwitcher({ sets = [] }) {
|
||||
const [activeId, setActiveId] = useState(sets[0]?.id);
|
||||
|
||||
const active = sets.find((x) => x.id === activeId);
|
||||
const iframeSrc = `https://www.jambox.pl/iframe-pakiet-logo?p=${active?.p}`;
|
||||
|
||||
return (
|
||||
<div class="w-full">
|
||||
<div class="flex justify-center mb-10">
|
||||
<div class="fuz-switch-group">
|
||||
{sets.map((s) => (
|
||||
<button
|
||||
type="button"
|
||||
class={`fuz-switch ${activeId === s.id ? "active" : ""}`}
|
||||
onClick={() => setActiveId(s.id)}
|
||||
>
|
||||
{s.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 🔹 Iframe */}
|
||||
<div class="w-full">
|
||||
<div class="fuz-iframe-wrapper">
|
||||
<iframe
|
||||
title="Lista kanałów"
|
||||
src={iframeSrc}
|
||||
class="fuz-iframe"
|
||||
loading="lazy"
|
||||
></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
63
src/islands/Markdown.jsx
Normal file
63
src/islands/Markdown.jsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { marked } from "marked";
|
||||
|
||||
marked.setOptions({
|
||||
gfm: true,
|
||||
breaks: true,
|
||||
headerIds: false,
|
||||
mangle: false,
|
||||
sanitize: false,
|
||||
smartLists: true,
|
||||
smartypants: false,
|
||||
});
|
||||
|
||||
|
||||
function applyShortcodes(md, ctx = {}) {
|
||||
md = md.replace(/{{\s*channels\s*}}/g, () => {
|
||||
if (!ctx.kanaly) return "";
|
||||
|
||||
const html = ctx.kanaly
|
||||
.map(
|
||||
(k) => `
|
||||
<div class="flex items-center justify-center p-1">
|
||||
<img
|
||||
src="${k.logo}"
|
||||
alt="${k.name}"
|
||||
title="${k.name}"
|
||||
class="channel-logo w-20 h-auto object-contain rounded"
|
||||
/>
|
||||
</div>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
|
||||
return `
|
||||
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-10 gap-2 my-4">
|
||||
${html}
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
export default function FuzMarkdown({ text, ctx = {} }) {
|
||||
if (!text) return null;
|
||||
|
||||
|
||||
let processed = applyShortcodes(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>`
|
||||
);
|
||||
|
||||
const html = marked(processed);
|
||||
|
||||
return (
|
||||
<div
|
||||
class="fuz-markdown max-w-none"
|
||||
dangerouslySetInnerHTML={{ __html: html }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
import DefaultLayout from "../layouts/DefaultLayout.astro";
|
||||
import Hero from "../components/hero/Hero.astro";
|
||||
import SectionRenderer from "../components/sections/SectionRenderer.astro"
|
||||
|
||||
import yaml from "js-yaml";
|
||||
import fs from "fs";
|
||||
@@ -11,4 +12,5 @@ const hero = yaml.load(fs.readFileSync("./src/content/home/hero.yaml", "utf8"));
|
||||
|
||||
<DefaultLayout seo={seo}>
|
||||
<Hero {...hero} />
|
||||
<SectionRenderer src="./src/content/site/site.section.yaml" />
|
||||
</DefaultLayout>
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
@import "./theme.css";
|
||||
@import "./navbar.css";
|
||||
@import "./hero.css";
|
||||
@import "./buttons.css";
|
||||
@import "./buttons.css";
|
||||
@import "./sections.css";
|
||||
@import "./markdown.css";
|
||||
45
src/styles/markdown.css
Normal file
45
src/styles/markdown.css
Normal file
@@ -0,0 +1,45 @@
|
||||
.fuz-markdown {
|
||||
@apply leading-relaxed text-base md:text-lg;
|
||||
|
||||
/* odstępy między elementami */
|
||||
}
|
||||
|
||||
.fuz-markdown p {
|
||||
@apply mb-4 text-3xl;
|
||||
}
|
||||
|
||||
.fuz-markdown h1 {
|
||||
@apply text-3xl font-bold mt-8 mb-4;
|
||||
}
|
||||
|
||||
.fuz-markdown h2 {
|
||||
@apply text-2xl font-semibold mt-6 mb-3;
|
||||
}
|
||||
|
||||
.fuz-markdown h3 {
|
||||
@apply text-xl font-semibold mt-4 mb-2;
|
||||
}
|
||||
|
||||
.fuz-markdown ul {
|
||||
@apply list-disc pl-6 mb-4;
|
||||
}
|
||||
|
||||
.fuz-markdown ol {
|
||||
@apply list-decimal pl-6 mb-4;
|
||||
}
|
||||
|
||||
.fuz-markdown li {
|
||||
@apply mb-1;
|
||||
}
|
||||
|
||||
.fuz-markdown a {
|
||||
@apply text-blue-600 dark:text-blue-400 underline hover:no-underline;
|
||||
}
|
||||
|
||||
.fuz-markdown blockquote {
|
||||
@apply border-l-4 border-gray-300 dark:border-gray-700 pl-4 italic mb-4;
|
||||
}
|
||||
|
||||
.fuz-markdown strong {
|
||||
@apply font-semibold;
|
||||
}
|
||||
23
src/styles/sections.css
Normal file
23
src/styles/sections.css
Normal file
@@ -0,0 +1,23 @@
|
||||
.fuz-section {
|
||||
@apply py-20 px-6;
|
||||
}
|
||||
|
||||
.fuz-section-grid {
|
||||
@apply grid items-center gap-10 max-w-7xl mx-auto;
|
||||
}
|
||||
|
||||
.fuz-section-image {
|
||||
@apply w-full h-full object-cover ;
|
||||
}
|
||||
|
||||
.fuz-image-dimmed {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.fuz-section-title {
|
||||
@apply text-5xl md:text-5xl font-bold mb-6;
|
||||
}
|
||||
|
||||
.fuz-section-text {
|
||||
@apply max-w-4xl mx-auto;
|
||||
}
|
||||
Reference in New Issue
Block a user