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 generated
|
||||||
public/**/*.avif
|
public/**/*.avif
|
||||||
public/**/*.webp
|
# public/**/*.webp
|
||||||
public/og/*.txt
|
public/og/*.txt
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"@preact/signals": "^2.5.1",
|
"@preact/signals": "^2.5.1",
|
||||||
"astro": "^5.16.0",
|
"astro": "^5.16.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
|
"marked": "^17.0.1",
|
||||||
"preact": "^10.27.2"
|
"preact": "^10.27.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"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:
|
sections:
|
||||||
- title: "Internet Światłowodowy"
|
- title: "Internet Światłowodowy"
|
||||||
image: "/images/section-fiber.jpg"
|
image: "/images/section-fiber.webp"
|
||||||
dimmed: true
|
dimmed: true
|
||||||
|
type: default
|
||||||
button:
|
button:
|
||||||
text: "Zobacz ofertę →"
|
text: "Zobacz ofertę →"
|
||||||
url: "/internet-swiatlowod/"
|
url: "/internet-swiatlowod/"
|
||||||
@@ -10,13 +11,36 @@ sections:
|
|||||||
|
|
||||||
Odkryj komfort technologii stworzonej do pracy, rozrywki i życia bez ograniczeń.
|
Odkryj komfort technologii stworzonej do pracy, rozrywki i życia bez ograniczeń.
|
||||||
|
|
||||||
- title: "Internet Radiowy"
|
- title: "Internet i Telewizja"
|
||||||
image: "/images/section-radiowy.jpg"
|
image: "/images/section-tv.webp"
|
||||||
dimmed: true
|
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:
|
button:
|
||||||
text: "Zobacz ofertę →"
|
text: "Zobacz ofertę →"
|
||||||
url: "/internet-radiowy/"
|
url: "/internet-radiowy/"
|
||||||
content: |
|
content: |
|
||||||
Nowoczesna technologia radiowa gwarantuje stabilny internet o wysokiej wydajności tam, gdzie inne łącza nie mają szans.
|
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 DefaultLayout from "../layouts/DefaultLayout.astro";
|
||||||
import Hero from "../components/hero/Hero.astro";
|
import Hero from "../components/hero/Hero.astro";
|
||||||
|
import SectionRenderer from "../components/sections/SectionRenderer.astro"
|
||||||
|
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
@@ -11,4 +12,5 @@ const hero = yaml.load(fs.readFileSync("./src/content/home/hero.yaml", "utf8"));
|
|||||||
|
|
||||||
<DefaultLayout seo={seo}>
|
<DefaultLayout seo={seo}>
|
||||||
<Hero {...hero} />
|
<Hero {...hero} />
|
||||||
|
<SectionRenderer src="./src/content/site/site.section.yaml" />
|
||||||
</DefaultLayout>
|
</DefaultLayout>
|
||||||
|
|||||||
@@ -2,4 +2,6 @@
|
|||||||
@import "./theme.css";
|
@import "./theme.css";
|
||||||
@import "./navbar.css";
|
@import "./navbar.css";
|
||||||
@import "./hero.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