Compare commits
10 Commits
4e44fff8c0
...
146e738c09
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
146e738c09 | ||
|
|
92edbad2c2 | ||
|
|
b065db4faf | ||
|
|
ed513957c3 | ||
|
|
12be46d038 | ||
|
|
0d967ea6c8 | ||
|
|
259ee007db | ||
|
|
e9f440353d | ||
|
|
f91b557efd | ||
|
|
832ee2e796 |
@@ -17,6 +17,7 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
minify: "esbuild",
|
minify: "esbuild",
|
||||||
cssMinify: "esbuild",
|
cssMinify: "esbuild",
|
||||||
|
chunkSizeWarningLimit: 500,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
integrations: [
|
integrations: [
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "fuz20",
|
"name": "fuz-site",
|
||||||
|
"type": "module",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
15
public/robots.txt
Normal file
15
public/robots.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# robots.txt dla FUZ Adam Rojek
|
||||||
|
# https://www.fuz.pl/robots.txt
|
||||||
|
|
||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# Sitemap
|
||||||
|
Sitemap: https://www.fuz.dariuszm.eu/sitemap.xml
|
||||||
|
|
||||||
|
# Crawl-delay (opcjonalnie)
|
||||||
|
# Crawl-delay: 1
|
||||||
|
|
||||||
|
# Zablokuj crawlowanie zbędnych ścieżek (jeśli są)
|
||||||
|
Disallow: /pages/api/
|
||||||
|
Disallow: /_astro/
|
||||||
@@ -12,31 +12,3 @@ const sorted = cities.sort((a: string, b: any) => a.localeCompare(b, "pl"));
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
|
||||||
.fuz-cities-box {
|
|
||||||
|
|
||||||
background: var(--f-background);
|
|
||||||
color: var(--f-text);
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.fuz-cities-title {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
font-weight: 600;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fuz-cities-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
|
|
||||||
gap: 6px 14px;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fuz-city-item {
|
|
||||||
color: var(--f-text);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -102,21 +102,21 @@ const domId = `fuz-map-${Math.random().toString(36).slice(2)}`;
|
|||||||
position: { lat, lng: lon }
|
position: { lat, lng: lon }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (title || desc) {
|
// if (title || desc) {
|
||||||
const { InfoWindow } = await google.maps.importLibrary("maps");
|
// const { InfoWindow } = await google.maps.importLibrary("maps");
|
||||||
const info = new InfoWindow({
|
// const info = new InfoWindow({
|
||||||
content: `
|
// content: `
|
||||||
<div class="f-info-window">
|
// <div class="f-info-window">
|
||||||
<div class="f-info-header">
|
// <div class="f-info-header">
|
||||||
<div class="f-info-city">${title}</div>
|
// <div class="f-info-city">${title}</div>
|
||||||
<div class="f-info-street">${desc}</div>
|
// <div class="f-info-street">${desc}</div>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
`
|
// `
|
||||||
});
|
// });
|
||||||
|
|
||||||
info.open({ map, anchor: marker });
|
// info.open({ map, anchor: marker });
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error initializing map:", error);
|
console.error("Error initializing map:", error);
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ const sectionImages = import.meta.glob<{ default: ImageMetadata }>(
|
|||||||
const sectionImage = section.image ? findSectionImage(sectionImages, section.image) : null;
|
const sectionImage = section.image ? findSectionImage(sectionImages, section.image) : null;
|
||||||
const isAboveFold = index === 0;
|
const isAboveFold = index === 0;
|
||||||
|
|
||||||
// ✅ Konfiguracja wyświetlania
|
// Konfiguracja wyświetlania
|
||||||
const showTitle = section.showTitle !== false; // domyślnie true
|
const showTitle = section.showTitle !== false; // domyślnie true
|
||||||
|
|
||||||
// ✅ Formatowanie listy miejscowości jako string
|
// Formatowanie listy miejscowości jako string
|
||||||
const citiesText = cities.join(", ");
|
const citiesText = cities.join(", ");
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -66,33 +66,6 @@ const citiesText = cities.join(", ");
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<!-- {
|
|
||||||
section.button && (
|
|
||||||
<div class="f-section-nav mt-6">
|
|
||||||
|
|
||||||
<a href={section.button.url}
|
|
||||||
class="btn btn-primary"
|
|
||||||
title={section.button.title}
|
|
||||||
>
|
|
||||||
{section.button.text}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
} -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- <style>
|
|
||||||
.f-cities-paragraph {
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
line-height: 1.8;
|
|
||||||
color: var(--f-text, #212529);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.dark) .f-cities-paragraph {
|
|
||||||
color: var(--f-text-dark, #f7fafc);
|
|
||||||
}
|
|
||||||
</style> -->
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
|
# tytuł dokumentu jednoczesnie tytułem strony <title></title>
|
||||||
title: "Polityka Prywatności"
|
title: "Polityka Prywatności"
|
||||||
|
# opis wstawiany w <meta name="description" content=""
|
||||||
|
description: Polityka prywatności, opisuje zasady ochrony Twoich danych osobowych.
|
||||||
visible: true
|
visible: true
|
||||||
intro: Polityka prywatności, opisuje zasady ochrony Twoich danych osobowych.
|
|
||||||
content: |
|
content: |
|
||||||
## §1. Informacje podstawowe.
|
## §1. Informacje podstawowe.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
title: "Promocja świąteczna"
|
title: "Promocja świąteczna"
|
||||||
|
description: Przykładowo gdybysmy dodali promocję do dokumentów
|
||||||
visible: true
|
visible: true
|
||||||
intro: Przykładowo gdybysmy dodali promocję do dokumentów
|
|
||||||
content: |
|
content: |
|
||||||
Jeśli kupujesz w sklepach internetowych, prawdopodobnie co pewien czas natykasz się na opisy, które nie zachęcają do zakupów.
|
Jeśli kupujesz w sklepach internetowych, prawdopodobnie co pewien czas natykasz się na opisy, które nie zachęcają do zakupów.
|
||||||
Do najczęściej powtarzanych błędów opisów produktów należą:
|
Do najczęściej powtarzanych błędów opisów produktów należą:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
page:
|
page:
|
||||||
title: "FUZ Adam Rojek - Internet Światłowodowy Wyszków | Szybki i Stabilny"
|
title: "FUZ Adam Rojek - Internet Światłowodowy Wyszków"
|
||||||
description: "Internet światłowodowy w Wyszkowie i okolicach. Lokalny operator z doświadczeniem - stabilne łącze, profesjonalny serwis, konkurencyjne ceny. Sprawdź dostępność!"
|
description: "Internet światłowodowy w Wyszkowie i okolicach. Lokalny operator z doświadczeniem - stabilne łącze, profesjonalny serwis, konkurencyjne ceny."
|
||||||
image: "/og/home-og.png"
|
image: "/og/home-og.png"
|
||||||
url: "/"
|
url: "/"
|
||||||
keywords:
|
keywords:
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
title: Możliwości telewizji JAMBOX
|
||||||
|
description: Poznaj funkcje i udogodnienia dostępne na dekoderach telewizji JAMBOX.
|
||||||
sections:
|
sections:
|
||||||
- title: CatchUp - Archiwum TV
|
- title: CatchUp - Archiwum TV
|
||||||
image: https://www.jambox.pl/sites/default/files/jambox-kyanit-catchup1.png
|
image: https://www.jambox.pl/sites/default/files/jambox-kyanit-catchup1.png
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useMemo } from "preact/hooks";
|
import { useMemo } from "preact/hooks";
|
||||||
import { marked } from "marked";
|
import { marked } from "marked";
|
||||||
import { useLocalSearch } from "../../hooks/useLocalSearch.js";
|
import { useLocalSearch } from "../../hooks/useLocalSearch.js";
|
||||||
import { highlightText, highlightHtml } from "../../lib/highlightUtils.js";
|
import { highlightText, highlightHtml } from "../../lib/highlightUtils.jsx";
|
||||||
import "../../styles/jambox-search.css";
|
import "../../styles/jambox-search.css";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,6 +46,7 @@ export default function JamboxMozliwosciSearch({ items = [] }) {
|
|||||||
<div className="f-chsearch__top">
|
<div className="f-chsearch__top">
|
||||||
<div className="f-chsearch__inputwrap">
|
<div className="f-chsearch__inputwrap">
|
||||||
<input
|
<input
|
||||||
|
name="search"
|
||||||
className="f-chsearch__input"
|
className="f-chsearch__input"
|
||||||
type="search"
|
type="search"
|
||||||
value={search.query}
|
value={search.query}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ const jsonExtra = meta.extraSchema ? JSON.stringify(meta.extraSchema) : null;
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<link rel="canonical" href={meta.canonical} />
|
<link rel="canonical" href={meta.canonical} />
|
||||||
|
<link rel="sitemap" type="application/xml" title="Sitemap" href="/sitemap.xml" />
|
||||||
|
|
||||||
<!-- OpenGraph -->
|
<!-- OpenGraph -->
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
|
|||||||
@@ -11,13 +11,44 @@ import Cookie from "../islands/Cookie.jsx";
|
|||||||
|
|
||||||
import rawCookie from "../content/site/cookie.yaml?raw";
|
import rawCookie from "../content/site/cookie.yaml?raw";
|
||||||
const cookieCfg = yaml.parse(rawCookie);
|
const cookieCfg = yaml.parse(rawCookie);
|
||||||
const { seo } = Astro.props;
|
|
||||||
|
// ✅ Pobierz wszystkie możliwe props
|
||||||
|
const {
|
||||||
|
seo, // Pełny obiekt SEO (stary sposób)
|
||||||
|
title, // Indywidualny title (nowy sposób)
|
||||||
|
description, // Indywidualny description (nowy sposób)
|
||||||
|
image, // Opcjonalny image
|
||||||
|
keywords, // Opcjonalne keywords
|
||||||
|
url, // Opcjonalny url
|
||||||
|
} = Astro.props;
|
||||||
|
|
||||||
|
// ✅ PRIORYTET: title/description → seo → undefined
|
||||||
|
let finalSeo;
|
||||||
|
|
||||||
|
// Jeśli mamy indywidualne pola (title lub description) - użyj ich
|
||||||
|
if (title || description) {
|
||||||
|
finalSeo = {
|
||||||
|
page: {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
image,
|
||||||
|
keywords,
|
||||||
|
url,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Jeśli nie ma indywidualnych, ale jest seo object - użyj go
|
||||||
|
else if (seo) {
|
||||||
|
finalSeo = seo;
|
||||||
|
}
|
||||||
|
// Jeśli nic nie ma - undefined (użyje global defaults z BaseHead)
|
||||||
|
else {
|
||||||
|
finalSeo = undefined;
|
||||||
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang="pl" class="scroll-smooth">
|
<html lang="pl" class="scroll-smooth">
|
||||||
<head>
|
<BaseHead seo={finalSeo} />
|
||||||
<BaseHead seo={seo} />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="min-h-screen flex flex-col">
|
<body class="min-h-screen flex flex-col">
|
||||||
<Header />
|
<Header />
|
||||||
|
|||||||
@@ -396,3 +396,90 @@ export function getRequiredEnv(key: string): string {
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== SITEMAP HELPERS ====================
|
||||||
|
|
||||||
|
export type SitemapUrl = {
|
||||||
|
loc: string;
|
||||||
|
lastmod?: string;
|
||||||
|
changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
||||||
|
priority?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generuje sitemap XML z listy URL-i
|
||||||
|
* @param urls - Tablica URL-i do sitemap
|
||||||
|
* @returns String z XML sitemap
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const urls = [
|
||||||
|
* { loc: 'https://example.com/', priority: 1.0, changefreq: 'daily' },
|
||||||
|
* { loc: 'https://example.com/about', priority: 0.8, changefreq: 'monthly' }
|
||||||
|
* ];
|
||||||
|
* const xml = generateSitemapXml(urls);
|
||||||
|
*/
|
||||||
|
export function generateSitemapXml(urls: SitemapUrl[]): string {
|
||||||
|
const urlEntries = urls.map(url => {
|
||||||
|
const parts = [
|
||||||
|
' <url>',
|
||||||
|
` <loc>${url.loc}</loc>`,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (url.lastmod) {
|
||||||
|
parts.push(` <lastmod>${url.lastmod}</lastmod>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.changefreq) {
|
||||||
|
parts.push(` <changefreq>${url.changefreq}</changefreq>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.priority !== undefined) {
|
||||||
|
parts.push(` <priority>${url.priority.toFixed(1)}</priority>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.push(' </url>');
|
||||||
|
return parts.join('\n');
|
||||||
|
}).join('\n');
|
||||||
|
|
||||||
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${urlEntries}
|
||||||
|
</urlset>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatyczne określenie changefreq na podstawie ścieżki URL
|
||||||
|
* @param path - Ścieżka URL (np. "/internet-swiatlowodowy")
|
||||||
|
* @returns Częstotliwość zmian
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* inferChangeFreq('/') // => 'daily'
|
||||||
|
* inferChangeFreq('/dokumenty/regulamin') // => 'yearly'
|
||||||
|
*/
|
||||||
|
export function inferChangeFreq(path: string): SitemapUrl['changefreq'] {
|
||||||
|
if (path === '/') return 'daily';
|
||||||
|
if (path.includes('/internet-') || path.includes('/telefon')) return 'weekly';
|
||||||
|
if (path.includes('/mapa-zasiegu') || path.includes('/kontakt')) return 'monthly';
|
||||||
|
if (path.includes('/dokumenty')) return 'yearly';
|
||||||
|
if (path.includes('/premium')) return 'monthly';
|
||||||
|
return 'weekly';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatyczne określenie priority na podstawie ścieżki URL
|
||||||
|
* @param path - Ścieżka URL
|
||||||
|
* @returns Priorytet (0.0 - 1.0)
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* inferPriority('/') // => 1.0
|
||||||
|
* inferPriority('/dokumenty/polityka-prywatnosci') // => 0.5
|
||||||
|
*/
|
||||||
|
export function inferPriority(path: string): number {
|
||||||
|
if (path === '/') return 1.0;
|
||||||
|
if (path.includes('/internet-') || path.includes('/telefon')) return 0.9;
|
||||||
|
if (path.includes('/mapa-zasiegu') || path.includes('/kontakt')) return 0.8;
|
||||||
|
if (path.includes('/premium')) return 0.7;
|
||||||
|
if (path.includes('/telewizja-mozliwosci')) return 0.7;
|
||||||
|
if (path.includes('/dokumenty')) return 0.5;
|
||||||
|
return 0.7;
|
||||||
|
}
|
||||||
@@ -4,14 +4,15 @@ import yaml from "js-yaml";
|
|||||||
|
|
||||||
export type DocYaml = {
|
export type DocYaml = {
|
||||||
title: string;
|
title: string;
|
||||||
|
description: string;
|
||||||
visible?: boolean;
|
visible?: boolean;
|
||||||
intro?: string;
|
|
||||||
content: string;
|
content: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DocEntry = DocYaml & {
|
export type DocEntry = DocYaml & {
|
||||||
slug: string;
|
slug: string;
|
||||||
file: string;
|
file: string;
|
||||||
|
description: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DOCS_DIR = path.join(process.cwd(), "src", "content", "document");
|
const DOCS_DIR = path.join(process.cwd(), "src", "content", "document");
|
||||||
@@ -34,13 +35,14 @@ export function listDocuments(): DocEntry[] {
|
|||||||
|
|
||||||
if (!data.title || typeof data.title !== "string") continue;
|
if (!data.title || typeof data.title !== "string") continue;
|
||||||
if (!data.content || typeof data.content !== "string") continue;
|
if (!data.content || typeof data.content !== "string") continue;
|
||||||
|
if (!data.description || typeof data.description !== "string") continue;
|
||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
slug,
|
slug,
|
||||||
file,
|
file,
|
||||||
title: data.title,
|
title: data.title,
|
||||||
|
description: data.description,
|
||||||
visible: data.visible ?? false,
|
visible: data.visible ?? false,
|
||||||
intro: data.intro ?? "",
|
|
||||||
content: data.content,
|
content: data.content,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -60,14 +62,15 @@ export function getDocumentBySlug(slug: string): DocEntry | null {
|
|||||||
|
|
||||||
if (!data.title || typeof data.title !== "string") return null;
|
if (!data.title || typeof data.title !== "string") return null;
|
||||||
if (!data.content || typeof data.content !== "string") return null;
|
if (!data.content || typeof data.content !== "string") return null;
|
||||||
|
if (!data.description || typeof data.description !== "string") continue;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
slug,
|
slug,
|
||||||
file,
|
file,
|
||||||
title: data.title,
|
title: data.title,
|
||||||
visible: data.visible ?? false,
|
visible: data.visible ?? false,
|
||||||
intro: data.intro ?? "",
|
|
||||||
content: data.content,
|
content: data.content,
|
||||||
|
description: data.description,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ if (!doc || doc.visible !== true) {
|
|||||||
const html = marked.parse(doc.content);
|
const html = marked.parse(doc.content);
|
||||||
---
|
---
|
||||||
|
|
||||||
<DefaultLayout title={doc.title}>
|
<DefaultLayout title={doc.title} description={doc.description}>
|
||||||
<section class="f-section">
|
<section class="f-section">
|
||||||
<div class="f-section-grid-single">
|
<div class="f-section-grid-single">
|
||||||
<a href="/dokumenty" class="f-document-link">
|
<a href="/dokumenty" class="f-document-link">
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ type YamlSection = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type YamlData = {
|
type YamlData = {
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
sections?: YamlSection[];
|
sections?: YamlSection[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,10 +24,16 @@ let items: Array<{
|
|||||||
content: string;
|
content: string;
|
||||||
}> = [];
|
}> = [];
|
||||||
|
|
||||||
|
let pageTitle = "";
|
||||||
|
let pageDescription = "";
|
||||||
let err = "";
|
let err = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = loadYaml<YamlData>("./src/content/internet-telewizja/telewizja-mozliwosci.yaml");
|
const data = loadYaml<YamlData>(
|
||||||
|
"./src/content/internet-telewizja/telewizja-mozliwosci.yaml",
|
||||||
|
);
|
||||||
|
pageTitle = data?.title || pageTitle;
|
||||||
|
pageDescription = data?.description || pageDescription;
|
||||||
const sections = safeArray<YamlSection>(data?.sections);
|
const sections = safeArray<YamlSection>(data?.sections);
|
||||||
|
|
||||||
items = sections
|
items = sections
|
||||||
@@ -42,7 +50,7 @@ try {
|
|||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
<DefaultLayout title="Możliwości JAMBOX">
|
<DefaultLayout title={pageTitle} description={pageDescription}>
|
||||||
<section class="f-section" id="top">
|
<section class="f-section" id="top">
|
||||||
<div class="f-section-grid-single">
|
<div class="f-section-grid-single">
|
||||||
<h1 class="f-section-title">Możliwości JAMBOX</h1>
|
<h1 class="f-section-title">Możliwości JAMBOX</h1>
|
||||||
|
|||||||
@@ -42,17 +42,20 @@ const form = data.form;
|
|||||||
|
|
||||||
<DefaultLayout seo={seo}>
|
<DefaultLayout seo={seo}>
|
||||||
<section class="f-section">
|
<section class="f-section">
|
||||||
|
<!-- ✅ Zmieniona struktura - osobne bloki zamiast grida -->
|
||||||
<div class="f-contact-grid">
|
<div class="f-contact-grid">
|
||||||
{/* row 1: tytuły */}
|
|
||||||
<h1 class="f-section-title m-0">{data.title}</h1>
|
|
||||||
<h1 class="f-section-title m-0">{data.contactFormTitle}</h1>
|
|
||||||
|
|
||||||
{/* row 2: treść */}
|
{/* Lewa kolumna: Kontakt */}
|
||||||
|
<div class="f-contact-column">
|
||||||
|
<h1 class="f-section-title">{data.title}</h1>
|
||||||
<div class="f-contact-item">
|
<div class="f-contact-item">
|
||||||
<Markdown text={data.description} />
|
<Markdown text={data.description} />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="form">
|
{/* Prawa kolumna: Formularz */}
|
||||||
|
<div class="f-contact-column" id="form">
|
||||||
|
<h2 class="f-section-title">{data.contactFormTitle}</h2>
|
||||||
|
|
||||||
<form id="contactForm" class="f-contact-form">
|
<form id="contactForm" class="f-contact-form">
|
||||||
<div class="f-contact-form-inner">
|
<div class="f-contact-form-inner">
|
||||||
@@ -135,6 +138,7 @@ const form = data.form;
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-10">
|
<div class="mt-10">
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const seo = loadYaml("./src/content/mapa-zasiegu/seo.yaml");
|
|||||||
class="w-full md:w-[340px] bg-[var(--f-background)] text-[var(--f-text)]
|
class="w-full md:w-[340px] bg-[var(--f-background)] text-[var(--f-text)]
|
||||||
pt-6 px-6 flex flex-col gap-6 overflow-y-auto z-40"
|
pt-6 px-6 flex flex-col gap-6 overflow-y-auto z-40"
|
||||||
>
|
>
|
||||||
<h3 class="text-3xl">Sprawdź dostępność usług</h3>
|
<h1 class="text-3xl">Sprawdź dostępność usług</h1>
|
||||||
<p class="text-sm">
|
<p class="text-sm">
|
||||||
Wybierz swoją miejscowość i ulicę oraz numer budynku, aby sprawdzić
|
Wybierz swoją miejscowość i ulicę oraz numer budynku, aby sprawdzić
|
||||||
dostępność usług światłowodowych FUZ.
|
dostępność usług światłowodowych FUZ.
|
||||||
@@ -49,7 +49,9 @@ const seo = loadYaml("./src/content/mapa-zasiegu/seo.yaml");
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<div class="container md:pl-16">
|
||||||
<SectionRenderer src="./src/content/site/area-section.yaml" />
|
<SectionRenderer src="./src/content/site/area-section.yaml" />
|
||||||
|
</div>
|
||||||
<script is:inline>
|
<script is:inline>
|
||||||
let fiberLayer = null;
|
let fiberLayer = null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
import { globby } from 'globby';
|
|
||||||
|
|
||||||
export async function GET() {
|
|
||||||
const base = "https://www.fuz.pl";
|
|
||||||
|
|
||||||
// Pobieramy wszystkie pliki .astro
|
|
||||||
const files = await globby([
|
|
||||||
"src/pages/**/*.astro",
|
|
||||||
"!src/pages/_*.astro", // pomiń pliki zaczynające się od _
|
|
||||||
"!src/pages/**/[...*", // pomiń catch-all
|
|
||||||
"!src/pages/**/[**", // pomiń dynamiczne parametry
|
|
||||||
"!src/pages/sitemap.xml.js", // pomiń samą sitemapę
|
|
||||||
"!src/pages/api/**" // pomiń API endpoints
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Konwersja ścieżek plikowych → URL-e
|
|
||||||
const urls = files.map((file) => {
|
|
||||||
let url = file
|
|
||||||
.replace("src/pages", "")
|
|
||||||
.replace(".astro", "");
|
|
||||||
|
|
||||||
// obsługa index: /index.astro → /
|
|
||||||
if (url.endsWith("/index")) {
|
|
||||||
url = url.replace("/index", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
});
|
|
||||||
|
|
||||||
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
||||||
${urls
|
|
||||||
.map((url) => {
|
|
||||||
return `
|
|
||||||
<url>
|
|
||||||
<loc>${base}${url}</loc>
|
|
||||||
<changefreq>weekly</changefreq>
|
|
||||||
<priority>${url === "/" ? "1.0" : "0.8"}</priority>
|
|
||||||
</url>`;
|
|
||||||
})
|
|
||||||
.join("")}
|
|
||||||
</urlset>`;
|
|
||||||
|
|
||||||
return new Response(body, {
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/xml",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
100
src/pages/sitemap.xml.ts
Normal file
100
src/pages/sitemap.xml.ts
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import type { APIRoute } from 'astro';
|
||||||
|
import {
|
||||||
|
getEnv,
|
||||||
|
generateSitemapXml,
|
||||||
|
inferChangeFreq,
|
||||||
|
inferPriority,
|
||||||
|
type SitemapUrl
|
||||||
|
} from '../lib/astro-helpers';
|
||||||
|
import { listDocuments } from '../lib/documents';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamiczny sitemap generator
|
||||||
|
* GET /sitemap.xml
|
||||||
|
*/
|
||||||
|
export const GET: APIRoute = async ({ site }) => {
|
||||||
|
const base = site?.toString().replace(/\/$/, '') ||
|
||||||
|
getEnv('PUBLIC_SITE_URL') ||
|
||||||
|
"https://www.fuz.pl";
|
||||||
|
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
const urls: SitemapUrl[] = [];
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// STATYCZNE STRONY
|
||||||
|
// ========================================
|
||||||
|
const staticPages = [
|
||||||
|
'/',
|
||||||
|
'/internet-swiatlowodowy',
|
||||||
|
'/internet-telewizja',
|
||||||
|
'/telefon',
|
||||||
|
'/mapa-zasiegu',
|
||||||
|
'/kontakt',
|
||||||
|
'/dokumenty',
|
||||||
|
'/premium',
|
||||||
|
'/telewizja-mozliwosci',
|
||||||
|
];
|
||||||
|
|
||||||
|
staticPages.forEach(path => {
|
||||||
|
urls.push({
|
||||||
|
loc: `${base}${path}`,
|
||||||
|
lastmod: now,
|
||||||
|
changefreq: inferChangeFreq(path),
|
||||||
|
priority: inferPriority(path),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// DYNAMICZNE STRONY: Dokumenty
|
||||||
|
// ========================================
|
||||||
|
try {
|
||||||
|
const docs = listDocuments();
|
||||||
|
|
||||||
|
docs
|
||||||
|
.filter(d => d.visible === true)
|
||||||
|
.forEach(d => {
|
||||||
|
const path = `/dokumenty/${d.slug}`;
|
||||||
|
urls.push({
|
||||||
|
loc: `${base}${path}`,
|
||||||
|
lastmod: now,
|
||||||
|
changefreq: 'yearly',
|
||||||
|
priority: 0.5,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('⚠️ Sitemap: Could not load documents:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// DYNAMICZNE STRONY: Premium packages (opcjonalnie)
|
||||||
|
// ========================================
|
||||||
|
// TODO: Jeśli masz dynamiczne pakiety premium, dodaj tutaj:
|
||||||
|
/*
|
||||||
|
try {
|
||||||
|
const packages = await loadPremiumPackages();
|
||||||
|
packages.forEach(p => {
|
||||||
|
urls.push({
|
||||||
|
loc: `${base}/premium/${p.tid}`,
|
||||||
|
lastmod: now,
|
||||||
|
changefreq: 'monthly',
|
||||||
|
priority: 0.7,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('⚠️ Sitemap: Could not load premium packages:', e);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// GENERUJ XML
|
||||||
|
// ========================================
|
||||||
|
const sitemap = generateSitemapXml(urls);
|
||||||
|
|
||||||
|
return new Response(sitemap, {
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/xml; charset=utf-8',
|
||||||
|
'Cache-Control': 'public, max-age=3600', // 1h cache
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
.gm-style-iw-c {
|
.gm-style-iw-c {
|
||||||
background: var(--f-background) !important;
|
background: var(--f-background) !important;
|
||||||
border-radius: 14px !important;
|
border-radius: 14px !important;
|
||||||
box-shadow: 0 4px 18px rgba(0,0,0,0.12) !important;
|
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12) !important;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,3 +121,30 @@
|
|||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.fuz-cities-box {
|
||||||
|
|
||||||
|
background: var(--f-background);
|
||||||
|
color: var(--f-text);
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.fuz-cities-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fuz-cities-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
|
||||||
|
gap: 6px 14px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fuz-city-item {
|
||||||
|
color: var(--f-text);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user