Compare commits

..

8 Commits

Author SHA1 Message Date
dm
a805610cba Telewizja-możliwości poprawa reguły img_dimensions_present
All checks were successful
Deploy FUZ 2.0 / deploy (push) Successful in 1m57s
2025-12-23 08:49:34 +01:00
dm
40929b3604 Dokumenty = zmiana układu, grupowanie 2025-12-23 08:32:17 +01:00
dm
6b73e91ddb Files ponowne dodanie plików, z małych liter
All checks were successful
Deploy FUZ 2.0 / deploy (push) Successful in 1m52s
2025-12-22 18:04:07 +01:00
dm
abc3bd4d41 Files usuniecie plików
All checks were successful
Deploy FUZ 2.0 / deploy (push) Successful in 2m0s
2025-12-22 18:00:06 +01:00
dm
e0095ee10f Dokumenty scieżki do plików
All checks were successful
Deploy FUZ 2.0 / deploy (push) Successful in 2m16s
2025-12-22 17:18:13 +01:00
dm
bbb6742849 Dokumnety - poprawa nazw plików
All checks were successful
Deploy FUZ 2.0 / deploy (push) Successful in 1m56s
2025-12-22 17:07:45 +01:00
dm
2c30704a11 Dokumenty poprawka scieżki do plików
All checks were successful
Deploy FUZ 2.0 / deploy (push) Successful in 1m59s
2025-12-22 16:56:58 +01:00
dm
95b308455c Dokumenty - usuniecie smiec dodanie nowych plików
All checks were successful
Deploy FUZ 2.0 / deploy (push) Successful in 2m9s
2025-12-22 16:51:25 +01:00
22 changed files with 178 additions and 1737 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,95 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations
from pathlib import Path
import argparse
import sys
def iter_astro_files(root: Path) -> list[Path]:
"""Zwraca listę plików .astro w root (rekursywnie), posortowaną stabilnie."""
files = [p for p in root.rglob("*.astro") if p.is_file()]
# sortowanie po ścieżce względnej dla powtarzalności
files.sort(key=lambda p: str(p.as_posix()).lower())
return files
def read_text_fallback(p: Path) -> str:
"""
Czyta plik jako tekst:
- najpierw UTF-8
- jeśli się nie da, to z BOM/latin-1 jako awaryjne (bez crasha)
"""
try:
return p.read_text(encoding="utf-8")
except UnicodeDecodeError:
# Spróbuj UTF-8 z BOM
try:
return p.read_text(encoding="utf-8-sig")
except UnicodeDecodeError:
# Ostatecznie: latin-1 (nie idealne, ale nie przerwie działania)
return p.read_text(encoding="latin-1")
def build_output(pages_dir: Path, files: list[Path]) -> str:
rel_root = pages_dir.parent.parent # zwykle ./src -> parent parent? NIEPEWNE, więc liczymy inaczej
# lepiej: relatywnie do katalogu projektu (cwd)
cwd = Path.cwd()
lines: list[str] = []
lines.append(f"ASTRO DUMP (root: {pages_dir.resolve()})")
lines.append(f"Found files: {len(files)}")
lines.append("=" * 80)
lines.append("")
for f in files:
rel = f.relative_to(cwd) if f.is_relative_to(cwd) else f
content = read_text_fallback(f)
lines.append(f"FILE: {rel.as_posix()}")
lines.append("-" * 80)
lines.append(content.rstrip("\n"))
lines.append("")
lines.append("=" * 80)
lines.append("")
return "\n".join(lines)
def main() -> int:
parser = argparse.ArgumentParser(
description="Zrzuca wszystkie pliki .astro z ./src/pages do jednego pliku txt (ścieżka + zawartość)."
)
parser.add_argument(
"--pages",
default="src/pages",
help="Ścieżka do katalogu pages (domyślnie: src/pages)",
)
parser.add_argument(
"--out",
default="astro-pages-dump.txt",
help="Plik wyjściowy (domyślnie: astro-pages-dump.txt)",
)
args = parser.parse_args()
pages_dir = Path(args.pages).resolve()
out_file = Path(args.out).resolve()
if not pages_dir.exists() or not pages_dir.is_dir():
print(f"[ERR] Nie znaleziono katalogu: {pages_dir}", file=sys.stderr)
return 2
files = iter_astro_files(pages_dir)
dump = build_output(pages_dir, files)
out_file.write_text(dump, encoding="utf-8")
print(f"[OK] Zapisano: {out_file} (files: {len(files)})")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -1,120 +0,0 @@
#!/usr/bin/env python3
import argparse
import os
import re
from pathlib import Path
from typing import Dict, List, Set, Tuple
# --- Regexy do zbierania klas z CSS ---
# Łapie ".class-name" w selektorach (pomija np. ".5" i rzeczy z escapami prosto, ale działa w praktyce)
CSS_CLASS_RE = re.compile(r'(?<![\\\w-])\.([a-zA-Z_-][\w-]*)')
# --- Regexy do zbierania stringów klas z Astro/JSX/TSX ---
# 1) class="..."
CLASS_ATTR_RE = re.compile(r'\bclass\s*=\s*("([^"]*)"|\'([^\']*)\')', re.IGNORECASE)
# 2) className="..."
CLASSNAME_ATTR_RE = re.compile(r'\bclassName\s*=\s*("([^"]*)"|\'([^\']*)\')', re.IGNORECASE)
# Astro: class:list={{ a: cond, "b c": cond2 }} / class:list={[...]} tu łapiemy stringi w środku
STRING_LIT_RE = re.compile(r'("([^"]+)"|\'([^\']+)\')')
# Dla wyszukiwania tokenów klas (żeby "f-card" nie matchowało jako fragment "f-card-x")
def token_pattern(cls: str) -> re.Pattern:
return re.compile(r'(?<![\w-])' + re.escape(cls) + r'(?![\w-])')
def read_text(path: Path) -> str:
try:
return path.read_text(encoding="utf-8", errors="ignore")
except Exception:
return ""
def collect_css_classes(css_dir: Path) -> Tuple[Set[str], Dict[str, Set[Path]]]:
classes: Set[str] = set()
where: Dict[str, Set[Path]] = {}
for p in css_dir.rglob("*.css"):
txt = read_text(p)
for m in CSS_CLASS_RE.finditer(txt):
c = m.group(1)
classes.add(c)
where.setdefault(c, set()).add(p)
return classes, where
def collect_used_classes(code_dir: Path, candidates: Set[str]) -> Tuple[Set[str], Dict[str, Set[Path]]]:
used: Set[str] = set()
used_where: Dict[str, Set[Path]] = {c: set() for c in candidates}
exts = {".astro", ".jsx", ".tsx", ".js", ".ts"}
# prekompilacja patternów dla szybkości
patterns = {c: token_pattern(c) for c in candidates}
for p in code_dir.rglob("*"):
if not p.is_file():
continue
if p.suffix.lower() not in exts:
continue
txt = read_text(p)
if not txt:
continue
# szybki filtr: jeśli żaden kandydat nie ma nawet prefiksu "f-" / "jmb-" itd,
# to i tak skan tokenowy jest ok, ale tu robimy prosty scan wszystkich.
for c, pat in patterns.items():
if pat.search(txt):
used.add(c)
used_where[c].add(p)
# usuń puste wpisy
used_where = {k: v for k, v in used_where.items() if v}
return used, used_where
def main():
ap = argparse.ArgumentParser(description="Znajdź potencjalnie nieużywane klasy CSS w projekcie Astro/JSX.")
ap.add_argument("--css", required=True, help="Katalog z plikami CSS (np. src/styles)")
ap.add_argument("--code", required=True, help="Katalog z kodem (np. src)")
ap.add_argument("--min-len", type=int, default=3, help="Minimalna długość nazwy klasy (domyślnie 3)")
ap.add_argument("--prefix", action="append", default=[], help="Filtruj klasy po prefiksie (np. --prefix f- --prefix jmb-)")
ap.add_argument("--show-where", action="store_true", help="Pokaż gdzie zdefiniowano klasę w CSS")
args = ap.parse_args()
css_dir = Path(args.css).resolve()
code_dir = Path(args.code).resolve()
if not css_dir.exists():
raise SystemExit(f"Brak katalogu CSS: {css_dir}")
if not code_dir.exists():
raise SystemExit(f"Brak katalogu code: {code_dir}")
all_classes, defined_where = collect_css_classes(css_dir)
# filtr długości + prefiksów
classes = {c for c in all_classes if len(c) >= args.min_len}
if args.prefix:
classes = {c for c in classes if any(c.startswith(px) for px in args.prefix)}
used, used_where = collect_used_classes(code_dir, classes)
unused = sorted(classes - used)
print(f"CSS katalog: {css_dir}")
print(f"CODE katalog: {code_dir}")
print(f"Klasy w CSS: {len(classes)} (po filtrach)")
print(f"Użyte w kodzie:{len(used)}")
print(f"NIEUŻYTE: {len(unused)}")
print("-" * 60)
for c in unused:
print(c)
if args.show_where:
files = sorted(defined_where.get(c, []))
for f in files:
rel = f.relative_to(css_dir.parent) if css_dir.parent in f.parents else f
print(f" defined in: {rel}")
print("-" * 60)
# opcjonalnie: pokaż top kilka użyć
# (jak chcesz, dopiszę flagę na raport "gdzie użyte")
if __name__ == "__main__":
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/files/umowa_tv.pdf Normal file

Binary file not shown.

View File

@@ -1,21 +1,68 @@
tytul: Dokumenty
opis: Strona zawiera dokumnety do pobrania lub przeczytania
opis: |
Poniżej dostępne są dokumenty regulujące zasady świadczenia usług, w szczególności regulaminy, cenniki oraz obowiązujące umowy.
grupy:
pobierz:
tytul: Pobierz
pliki:
- nazwa: Lista kanałów EVIO TV
file: /public/files/EVIO TV.pdf
- nazwa: Lista kanałów JAMBOX TV
file: /public/files/EVIO TV.pdf
- nazwa: Lista kanałów coś
file: /public/files/EVIO TV.pdf
otworz:
tytul: Przeczytaj
# Grupa 1: Polityki i regulaminy
polityki:
tytul: Polityki i regulaminy
pliki:
- nazwa: Polityka prywatności
slug: polityka-prywatnosci
- nazwa: Promocja przykład do wyswietlenia
slug: promocja
# - nazwa: Regulamin świadczenia usług
# slug: regulamin-uslug
# - nazwa: Informacja o przetwarzaniu danych osobowych
# slug: rodo
# Grupa 2: Internet
internet:
tytul: Internet
pliki:
- nazwa: Umowa Internet
file: /files/umowa_internet.pdf
- nazwa: Informacje przedumowne Internet
file: /files/informacje_przedumowne_net.pdf
- nazwa: Podsumowanie warunków umowy Internet
file: /files/podsumowanie_warunków_umowy_net.pdf
- nazwa: Oświadczenia Internet
file: /files/oświadczenia_net.pdf
- nazwa: Informacje urządzenia Internet
file: /files/informacje_urządzenia_net.pdf
- nazwa: Formularz odstąpienia Internet
file: /files/formularz_odstapienia_net.pdf
# Grupa 3: Telewizja
telewizja:
tytul: Internet i Telewizja
pliki:
- nazwa: Umowa TV
file: /files/umowa_tv.pdf
- nazwa: Podsumowanie warunków umowy TV
file: /files/podsumowanie_warunków_umowy_tv.pdf
- nazwa: Informacje przedumowne TV
file: /files/informacje_przedumowne_tv.pdf
- nazwa: Lista kanałów EVIO TV
file: /files/EVIO TV.pdf
- nazwa: Lista kanałów JAMBOX TV
file: /files/JAMBOX TV.pdf
# Grupa 4: Cenniki
cenniki:
tytul: Cenniki
pliki:
- nazwa: Cennik usług TV
file: /files/cennik_uslug_tv.pdf
- nazwa: Cennik usług dodatkowych
file: /files/cennik_uslug_dodatkowych.pdf

View File

@@ -1,14 +0,0 @@
title: "Promocja świąteczna"
description: Przykładowo gdybysmy dodali promocję do dokumentów
visible: true
content: |
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żą:
- brak konkretów klient chce wiedzieć, z czego produkt jest wykonany, jakie ma wymiary czy funkcje, a nie tylko, że jest „wysokiej jakości”;
- zbyt techniczny język warto dostosować ton komunikacji do odbiorcy, unikając skomplikowanych terminów (i w drugą stronę jeśli sprzedajesz towar skierowany do profesjonalistów, nie trzeba w opisie ze szczegółami wyjaśniać, jak działa czy do czego służy);
- brak narracji storytelling w opisach produktów pomaga zbudować emocjonalne zaangażowanie klienta;
ignorowanie pytań klientów warto analizować najczęstsze pytania i uwzględniać odpowiedzi w opisach; jeśli np. często dostajesz zapytania dotyczące tego, czy produkt jest wodoodporny, lepiej napisać o tym od razu w opisie;
zbyt długie i skomplikowane opisy należy dbać o przejrzystość treści, używać krótkich akapitów i list wypunktowanych; klient poszukuje konkretów, a nie zawiłych opowieści, które trudno się czyta.

View File

@@ -1,6 +1,6 @@
page:
title: "Dokumenty - FUZ Adam Rojek | Regulaminy i Umowy"
description: "Dokumenty FUZ: regulamin świadczenia usług, wzór umowy, cennik, polityka prywatności, warunki techniczne. Wszystkie dokumenty do pobrania w formacie PDF."
description: "Dokumenty i regulaminy, cenniki oraz umowy związane z usługami oferowanymi przez naszą firmę."
image: "/og/dokumenty-og.png"
url: "/dokumenty"
keywords:

View File

@@ -4,11 +4,9 @@ opis: |
Wybierz rodzaj budynku i czas trwania umowy
uwaga: |
Powyższe „ceny brutto z Rabatami 15zł”
uwzględniają rabat -15 zł (z czego -5 zł - Rabat za wyrażenie zgody na otrzymywanie Rachunków/faktur VAT za świadczone
przez Dostawcę Usług usługi telekomunikacyjne drogą elektroniczną na wskazany w umowie adres mail oraz za pośrednictwem EBOK; -10 zł - Rabat pod warunkiem
złożenia wniosku o dostarczanie przez Dostawcę Usług treści każdej proponowanej zmiany warunków Umowy, w tym określonych w Umowie, Informacjach Przedumownych oraz danych Dostawcy Usług (chyba że przepisy powszechnie obowiązującego prawa przewidują wyłącznie zawiadomienia poprzez publiczne ogłoszenie), jak
również kontaktowanie się ze mną w ramach procedur reklamacyjnych, w tym w szczególności przesłania odpowiedzi na reklamację, na podany w Umowie adres poczty
elektronicznej).
uwzględniają rabat -15 zł (z czego -5 zł - Rabat za wyrażenie zgody na otrzymywanie Rachunków/faktur VAT za świadczone przez Dostawcę Usług usługi telekomunikacyjne drogą elektroniczną na wskazany w umowie adres e-mail oraz za pośrednictwem EBOK;
-10 zł - Rabat pod warunkiem złożenia wniosku o dostarczanie przez Dostawcę Usług treści każdej proponowanej zmiany warunków Umowy, w tym określonych w Umowie, Informacjach Przedumownych oraz danych Dostawcy Usług (chyba że przepisy powszechnie
obowiązującego prawa przewidują wyłącznie zawiadomienia poprzez publiczne ogłoszenie), jak również kontakt w ramach procedur reklamacyjnych, w tym w szczególności przesłania odpowiedzi na reklamację, na podany w Umowie adres poczty elektronicznej).
cena_opis: "zł/mies."
cards:

View File

@@ -86,6 +86,8 @@ export default function JamboxMozliwosciSearch({ items = [] }) {
className={`f-section-image ${reverse ? "md:order-1" : "md:order-2"}`}
loading="lazy"
decoding="async"
width="800"
height="600"
/>
)}

View File

@@ -6,72 +6,94 @@ import {
normalizePublicHref,
type DocumentsYaml,
} from "../../lib/astro-helpers";
import "../../styles/document.css";
const doc = loadYaml<DocumentsYaml>("./src/content/document/documents.yaml");
const seo = loadYaml("./src/content/document/seo.yaml");
const pageTitle = doc?.tytul ?? "Dokumenty";
const pageDesc = doc?.opis ?? "";
const groups = doc?.grupy ?? {};
const left = groups["otworz"] ?? {};
const right = groups["pobierz"] ?? {};
---
<DefaultLayout seo={seo}>
{/* CONTENT */}
<section class="f-section">
<div class="f-section-grid-top md:grid-cols-2 gap-10 items-start">
{/* ===== LEWA CZYTAJ ===== */}
<div>
<h3 class="f-section-title">{left.tytul ?? "Przeczytaj"}</h3>
<div class="f-section-grid md:grid-cols-1">
<h1 class="f-section-title">{pageTitle}</h1>
{pageDesc && <Markdown text={pageDesc} />}
</div>
</section>
<section class="f-section">
<div class="f-section-documents">
<div class="f-documents-columns">
{
!left.pliki?.length ? (
<p class="opacity-70 mt-4">Brak dokumentów.</p>
) : (
<div class="f-documents-grid">
{left.pliki.map((p) =>
p.slug ? (
<a
class="f-document-card"
href={`/dokumenty/${p.slug}`}
title={p.nazwa}
>
<div class="f-document-title">{p.nazwa}</div>
</a>
) : null,
Object.entries(groups).map(([key, group]) => (
<div class="f-documents-group" key={key}>
<h3 class="f-section-title3">{group.tytul}</h3>
{!group.pliki?.length ? (
<p class="f-documents-empty">Brak dokumentów.</p>
) : (
<div class="f-documents-list">
{group.pliki.map((p) => {
// Określ czy to slug (czytaj) czy file (pobierz)
const isRead = !!p.slug;
const href = isRead
? `/dokumenty/${p.slug}`
: normalizePublicHref(p.file);
if (!href) return null;
return (
<a
class="f-document-link"
href={href}
{...(isRead ? {} : { download: true })}
title={p.nazwa}
>
<span class="f-document-icon">
{isRead ? (
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" />
<circle cx="12" cy="12" r="3" />
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="7 10 12 15 17 10" />
<line x1="12" x2="12" y1="15" y2="3" />
</svg>
)}
</span>
<span class="f-document-name">{p.nazwa}</span>
</a>
);
})}
</div>
)}
</div>
)
}
</div>
<div>
<h3 class="f-section-title">{right.tytul ?? "Pobierz"}</h3>
{
!right.pliki?.length ? (
<p class="opacity-70 mt-4">Brak plików.</p>
) : (
<div class="f-documents-grid">
{right.pliki.map((p) => {
const href = normalizePublicHref(p.file);
if (!href) return null;
return (
<a
class="f-document-card"
href={href}
download
title={p.nazwa}
>
<div class="f-document-title">{p.nazwa}</div>
</a>
);
})}
</div>
)
))
}
</div>
</div>

View File

@@ -1,15 +1,37 @@
.f-document-card {
@apply flex items-center gap-2 text-lg;
.f-section-documents {
@apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
}
.f-document-card:hover {
@apply shadow-sm;
transform: translateY(-1px);
.f-documents-columns {
@apply grid grid-cols-1 gap-8 mt-1;
}
/* .f-document-icon {
@apply text-2xl leading-none mt-1;
} */
.f-document-title {
@apply font-normal ;
@media (min-width: 768px) {
.f-documents-columns {
@apply grid-cols-2;
}
}
@media (min-width: 1024px) {
.f-documents-columns {
@apply grid-cols-3;
}
}
.f-section-title3{
@apply border-b-[1px] border-[var(--f-offers-border)];
}
.f-documents-group {
@apply bg-[--f-bg] text-[--f-text] border border-[--f-offers-border] rounded-2xl shadow-md p-6 relative flex flex-col gap-4;
}
.f-documents-list {
@apply flex flex-col gap-1;
}
.f-document-link {
@apply flex items-center py-1 gap-2 rounded-lg text-[var(--f-text,#111827)] no-underline transition-all duration-200 bg-transparent border border-transparent;
}
.f-document-icon {
@apply flex-shrink-0 w-5 h-5 transition-all duration-200 text-[var(--f-text-muted,#6b7280)];
}

View File

@@ -41,6 +41,10 @@
@apply text-4xl md:text-5xl font-bold mb-2 text-[--f-header];
}
.f-section-title3 {
@apply text-2xl md:text-2xl font-bold mb-2 text-[--f-header];
}
.f-section-nav {
@apply mt-0 flex justify-center;
}