index.html Repository wynajem_motorowek Original path index.htmlRole SOURCE Size 22481 bytes Lines 724 SHA-256 6867d08365abf9bdb2687c8c8c63a141d5cf5818220acf583e1fcc00c54b96dcDisplayed range 1–500 Previous file/page · Project index · Next file/page
<!doctype html>
<html lang="pl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Firma Szuwary — motorówki bez patentu</title>
<link rel="stylesheet" href="assets/style.css?v=20260223-5" />
<link rel="stylesheet" href="assets/booking.css" />
<script src="assets/booking.js?v=20260304-1" defer></script>
<style>
.tiles .tile{
border: 0 !important;
background: transparent !important;
padding: 8px !important;
box-shadow: none !important;
outline: none;
position: relative;
}
.tiles .tile .tile-name{
position: absolute;
top: 2px;
left: 8px;
right: 8px;
z-index: 2;
text-align: center;
color: #fff;
font-size: 11px;
font-weight: 800;
letter-spacing: .8px;
text-transform: uppercase;
pointer-events: none;
text-shadow: 0 1px 2px rgba(0,0,0,.85);
}
.tiles .tile img{
display:block;
width: 140px;
height: 80px;
object-fit: contain;
background: transparent !important;
border: 0 !important;
border-radius: 0 !important;
box-shadow: none !important;
filter: none;
}
/* =========================
✅ CTA domyślnie ukryte (desktop/tablet bez zmian)
========================= */
.cta-bar{ display:none; }
/* =========================
✅ Menu łódek "bardziej na wierzchu"/mniej przygaszone
(nie rusza układu)
========================= */
.sidebar{
position: relative;
z-index: 5;
background: rgba(0,0,0,.35) !important;
border-color: rgba(255,255,255,.18) !important;
}
.sidebar .tiles .tile img{
filter: brightness(1.15) contrast(1.05) saturate(1.15) !important;
opacity: 1 !important;
}
/* =========================
✅ MOBILE: sidebar ma licować z frame + większe miniatury + CTA między
========================= */
@media (max-width: 900px){
/* Uwaga: nie zmieniamy desktop layoutu – tylko mobile */
.panel{
display: flex !important;
flex-direction: column !important;
gap: 12px !important;
}
/* Kolejność NA TELEFONIE:
1) treść
2) CTA
3) miniatury
*/
.frame{ order: 1 !important; width:100% !important; max-width:100% !important; }
.cta-bar{ order: 2 !important; }
.sidebar{ order: 3 !important; width:100% !important; max-width:100% !important; }
/* ✅ CTA (3 przyciski) widoczne tylko na telefonie */
.cta-bar{
display: grid !important;
grid-template-columns: repeat(3, 1fr) !important;
gap: 10px !important;
width: 100% !important;
margin: 0 !important;
}
.cta-btn{
display: flex !important;
align-items: center !important;
justify-content: center !important;
min-height: 54px !important;
border-radius: 16px !important;
border: 1px solid rgba(255,255,255,.22) !important;
background: rgba(0,0,0,.35) !important;
color: rgba(255,255,255,.92) !important;
font-weight: 700 !important;
letter-spacing: .2px !important;
text-decoration: none !important;
user-select: none !important;
-webkit-tap-highlight-color: transparent !important;
}
.cta-btn:active{ transform: translateY(1px); }
/* ✅ wyśrodkowanie kafelków + dopasowanie do szerokości */
.sidebar .menu{
display: flex !important;
justify-content: center !important;
}
.sidebar .tiles{
width: auto !important;
max-width: 100% !important;
margin: 0 auto !important;
justify-content: center !important;
align-items: center !important;
opacity: 1 !important;
}
/* ✅ miniatury +25% */
.tiles .tile{ padding: 10px !important; }
.tiles .tile img{
width: 175px !important;
height: 100px !important;
object-fit: contain !important;
}
}
</style>
</head>
<body>
<div class="bg">
<div class="shell">
<header class="top">
<div class="brand" role="button" tabindex="0" id="goHome" title="Wróć do strony głównej">
<h1>Firma Szuwary</h1>
<p class="tag">Wypożyczalnia łódek • motorówki bez patentu</p>
</div>
<nav class="nav" aria-label="Nawigacja">
<button data-view="oferta" id="btnOferta">Oferta</button>
<button data-view="kontakt" id="btnKontakt">Kontakt</button>
</nav>
</header>
<!-- ✅ WRACAMY DO STAREJ KOLEJNOŚCI: sidebar -> frame (desktop znów OK) -->
<main class="panel">
<!-- ✅ Miniatury -->
<aside class="sidebar">
<h3>Nasze łódki</h3>
<div class="menu" id="menu"></div>
</aside>
<!-- ✅ Treść -->
<section class="frame" id="frame">
<div class="frame-inner" id="app"></div>
<!-- ✅ CTA (na telefonie będzie między treścią a miniaturami dzięki order) -->
<div class="cta-bar" id="ctaBar" aria-label="Szybkie akcje" style="margin-top:12px;">
<a class="cta-btn" id="ctaCall" href="#" aria-label="Zadzwoń">Zadzwoń</a>
<a class="cta-btn" id="ctaFb" href="#" target="_blank" rel="noopener" aria-label="Facebook">Facebook</a>
<button class="cta-btn" id="ctaShare" type="button" aria-label="Udostępnij">Udostępnij</button>
</div>
</section>
</main>
<footer class="footer">
<div>© <span id="year"></span> Firma Szuwary</div>
<div style="color:rgba(255,255,255,.55)">Tel: +48 000 000 000 • Zegrze</div>
</footer>
</div>
</div>
<!-- ✅ FULLSCREEN LIGHTBOX -->
<div class="lightbox" id="lightbox" aria-hidden="true">
<button class="lb-close" id="lbClose" aria-label="Zamknij">✕</button>
<button class="lb-btn lb-prev" id="lbPrev" aria-label="Poprzednie">‹</button>
<img id="lbImg" alt="Zdjęcie">
<button class="lb-btn lb-next" id="lbNext" aria-label="Następne">›</button>
<div class="lb-hint">ESC zamyka • ← → zmienia zdjęcie • klik poza zdjęciem zamyka</div>
</div>
<script>
/* =========================
DANE
========================= */
const BOAT_FOLDERS = [
"Bora-Bora",
"Borneo",
"Formuła",
"Ibiza",
];
const CONTACT = {
phone: "+48 000 000 000",
phoneDigits: "48000000000",
addr1: "Zegrze",
addr2: "woj. mazowieckie",
mapsLink: "https://www.google.com/maps/search/?api=1&query=Zegrze",
mapsEmbedSrc: "https://www.google.com/maps?q=Zegrze&z=13&output=embed"
};
const FB_LINK = "#";
const OFFER_TEXT = `Łodzie motorowe na Zalewie Zegrzyńskim - lub bardziej współcześnie "nad Zegrzem :D " `;
/* =========================
HELPERS
========================= */
const $ = (sel) => document.querySelector(sel);
const app = $("#app");
const menu = $("#menu");
const frame = $("#frame");
$("#year").textContent = new Date().getFullYear();
function isMobile(){ return window.matchMedia("(max-width: 900px)").matches; }
function scrollToFrameIfMobile(){
if(!isMobile()) return;
requestAnimationFrame(() => frame.scrollIntoView({ behavior:"smooth", block:"start" }));
}
function setActiveNav(view){
$("#btnOferta").classList.toggle("active", view === "oferta");
$("#btnKontakt").classList.toggle("active", view === "kontakt");
}
function setActiveBoat(boatId){
[...menu.querySelectorAll("button.tile")].forEach(b=>{
b.classList.toggle("active", b.dataset.id === boatId);
});
}
function folderToId(folderName){
return encodeURIComponent(String(folderName||"").trim());
}
function folderToUrl(folderName){
return `./krypy/${encodeURIComponent(String(folderName||"").trim())}/`;
}
/* =========================
BOATS
========================= */
const BOATS = BOAT_FOLDERS.map(folderName => {
const raw = String(folderName || "").trim();
return {
id: folderToId(raw),
name: raw,
folder: folderToUrl(raw),
desc: `Krótki opis ${raw}`,
chips: ["bez patentu"]
};
});
/* =========================
CTA BUTTONS
========================= */
function setupCta(){
const call = $("#ctaCall");
const fb = $("#ctaFb");
const share = $("#ctaShare");
if(call) call.href = "tel:" + CONTACT.phoneDigits;
if(fb) fb.href = FB_LINK;
async function doShare(){
const url = location.href;
const title = document.title || "Firma Szuwary";
const text = "Firma Szuwary — motorówki bez patentu";
if(navigator.share){
try{ await navigator.share({ title, text, url }); return; }catch(_){}
}
try{
await navigator.clipboard.writeText(url);
share.textContent = "Skopiowano!";
setTimeout(()=>{ share.textContent = "Udostępnij"; }, 1400);
}catch(_){
prompt("Skopiuj link:", url);
}
}
if(share) share.onclick = doShare;
}
setupCta();
/* =========================
✅ BIAŁY => PRZEZROCZYSTY (miniatury)
========================= */
const WHITE_ALPHA_CACHE = new Map();
async function whiteToTransparent(imgEl, opts = {}){
const threshold = Number.isFinite(opts.threshold) ? opts.threshold : 250;
const softness = Number.isFinite(opts.softness) ? opts.softness : 12;
if(!imgEl || !imgEl.src) return;
if(!imgEl.classList.contains("tile-thumb")) return;
const src = imgEl.currentSrc || imgEl.src;
if(WHITE_ALPHA_CACHE.has(src)){
imgEl.src = WHITE_ALPHA_CACHE.get(src);
return;
}
if(/^data:/.test(src)) return;
if(!imgEl.complete || !imgEl.naturalWidth) return;
try{
const w = imgEl.naturalWidth;
const h = imgEl.naturalHeight;
if(w*h > 3_000_000) return;
const c = document.createElement("canvas");
c.width = w; c.height = h;
const ctx = c.getContext("2d", { willReadFrequently:true });
if(!ctx) return;
ctx.drawImage(imgEl, 0, 0);
const imgData = ctx.getImageData(0, 0, w, h);
const d = imgData.data;
const t = threshold, s = softness;
for(let i=0;i<d.length;i+=4){
const r=d[i], g=d[i+1], b=d[i+2], a=d[i+3];
if(a===0) continue;
if(r >= (t-s) && g >= (t-s) && b >= (t-s)){
const whiteness = (r+g+b)/3;
const k = Math.min(1, Math.max(0, (whiteness-(t-s))/(255-(t-s))));
d[i+3] = Math.round(a*(1-k));
}
}
ctx.putImageData(imgData, 0, 0);
const out = c.toDataURL("image/png");
WHITE_ALPHA_CACHE.set(src, out);
imgEl.src = out;
}catch(_){}
}
/* =========================
✅ MINIATURY: mini.* priorytet + cache-buster
========================= */
const THUMB_VERSION = "20260223-5";
function withV(u){
return u + (u.includes("?") ? "&" : "?") + "v=" + encodeURIComponent(THUMB_VERSION);
}
function setThumbWithFallback(imgEl, baseFolderUrl){
const chain = [
withV(`${baseFolderUrl}mini.jpg`),
withV(`${baseFolderUrl}mini.png`),
withV(`${baseFolderUrl}mini.jpeg`),
withV(`${baseFolderUrl}mini.webp`),
withV(`${baseFolderUrl}Mini.jpg`),
withV(`${baseFolderUrl}Mini.png`),
withV(`${baseFolderUrl}Mini.jpeg`),
withV(`${baseFolderUrl}Mini.webp`),
`${baseFolderUrl}1.jpg`,
`${baseFolderUrl}1.jpeg`,
`${baseFolderUrl}1.png`,
`${baseFolderUrl}1.webp`,
];
let i = 0;
imgEl.onerror = () => {
i++;
if(i < chain.length) imgEl.src = chain[i];
else imgEl.onerror = null;
};
imgEl.onload = () => whiteToTransparent(imgEl, { threshold:250, softness:12 });
imgEl.src = chain[0];
}
/* =========================
✅ GALERIA: sondowanie obrazków
========================= */
function probeImage(url){
return new Promise((resolve)=>{
const img = new Image();
img.onload = ()=> resolve(true);
img.onerror = ()=> resolve(false);
img.src = url + (url.includes("?") ? "&" : "?") + "p=" + Date.now();
});
}
async function firstWorkingImage(urls){
for(const u of urls){
const ok = await probeImage(u);
if(ok) return u;
}
return "";
}
const MEDIA_CACHE = new Map();
const MAX_PROBE = 80;
const STOP_AFTER_CONSECUTIVE_MISSES = 10;
const IMG_EXTS = ["jpg","jpeg","png","webp"];
async function resolveNumberedImage(boat, i){
const urls = IMG_EXTS.map(ext => `${boat.folder}${i}.${ext}`);
return await firstWorkingImage(urls);
}
async function buildMediaList(boat){
if(MEDIA_CACHE.has(boat.id)) return MEDIA_CACHE.get(boat.id);
const media = [];
let misses = 0;
for(let i=1; i<=MAX_PROBE; i++){
const found = await resolveNumberedImage(boat, i);
if(found){
media.push({ type:"image", src: found });
misses = 0;
}else{
misses++;
if(misses >= STOP_AFTER_CONSECUTIVE_MISSES) break;
}
}
MEDIA_CACHE.set(boat.id, media);
return media;
}
/* =========================
MENU
========================= */
function buildMenu() {
menu.innerHTML = `
<div class="tiles">
${BOATS.map(b => `
<button class="tile" data-id="${b.id}" title="${b.name}">
<span class="tile-name">${b.name}</span>
<img class="tile-thumb" data-folder="${b.folder}" alt="${b.name}" loading="eager" decoding="async" />
</button>
`).join("")}
</div>
`;
[...menu.querySelectorAll("img.tile-thumb")].forEach(img=>{
const folder = img.getAttribute("data-folder");
setThumbWithFallback(img, folder);
});
menu.onclick = e => {
const btn = e.target.closest(".tile");
if (!btn) return;
location.hash = btn.dataset.id;
scrollToFrameIfMobile();
};
}
/* =========================
LIGHTBOX
========================= */
const lightbox = $("#lightbox");
const lbImg = $("#lbImg");
const lbClose = $("#lbClose");
const lbPrev = $("#lbPrev");
const lbNext = $("#lbNext");
let LB_MEDIA = [];
let LB_INDEX = 0;
function openLightbox(index){
if(!LB_MEDIA.length) return;
LB_INDEX = (index + LB_MEDIA.length) % LB_MEDIA.length;
lbImg.src = LB_MEDIA[LB_INDEX].src;
lightbox.classList.add("open");
lightbox.setAttribute("aria-hidden", "false");
document.body.style.overflow = "hidden";
}
function closeLightbox(){
lightbox.classList.remove("open");
lightbox.setAttribute("aria-hidden", "true");
lbImg.src = "";
document.body.style.overflow = "";
}
function lbStep(dir){
if(!LB_MEDIA.length) return;
LB_INDEX = (LB_INDEX + dir + LB_MEDIA.length) % LB_MEDIA.length;
lbImg.src = LB_MEDIA[LB_INDEX].src;
}
lbClose.onclick = closeLightbox;
lbPrev.onclick = (e)=>{ e.stopPropagation(); lbStep(-1); };
lbNext.onclick = (e)=>{ e.stopPropagation(); lbStep(1); };
lightbox.addEventListener("click", (e)=>{ if(e.target === lightbox) closeLightbox(); });
window.addEventListener("keydown", (e)=>{
if(!lightbox.classList.contains("open")) return;
if(e.key === "Escape") closeLightbox();
if(e.key === "ArrowLeft") lbStep(-1);
if(e.key === "ArrowRight") lbStep(1);
});
/* =========================