Kto jest kim w IMGW-PIB LMM
Przewodnik po stronie
Prognozy wideo
Pogoda kosmiczna
Portal zimowy
Portal letni
Aerologia (mapy górne)
Prognozy wiązkowe
Pogoda bieżąca
Pomiary (Stacje SYNOP)
Zanieczyszczenia (GIOŚ)
Odbiciowość radarowa (CMAX)
Opad (RainGRS)
Wyładowania
Sondaż aerologiczny
Ultra-krótkoterminowe
INCA-PL2 (8 godz.)
MERGE (Opad, 8 godz.)
TSP (Burze, 1 godz.)
SPT (Typ opadu, 2 godz.)
Krótkoterminowe
ALARO (72 godz.)
AROME (30 godz.)
COSMO 7k0 (96 godz.)
COSMO 2k8 (60 godz.)
ICON-LAM 2k5 (60 godz.)
ICON-EU (Opad, 72 godz.)
ECMWF-EU (Opad, 72 godz.)
Prognoza synoptyczna (2 dni)
Średnioterminowe
ECMWF AIFS (10 dni)
ECMWF HRES PL (10 dni)
ECMWF HRES EU (10 dni)
GFS (Opad, 10 dni)
GFS LAGGED (Temp., 10 dni)
Prognoza synoptyczna (6 dni)
Długoterminowe
ECMWF (5 tyg.)
4 miesięczne
CFS
Specjalne
Zagrożenia pożarowe (2 dni)
Trajektorie
Zanieczyszczenie powietrza (4 dni)
Pogoda na Marsie
Atlas wiatrowy AMEW-PL
Atlas solarny AES-PL
Modelowanie pożarowe
Zjawiska ekstremalne (EFI, SOT)
Zjawiska ekstremalne (Raporty)
Meteogramy ALARO
Serwis OZE
Monitoring warunków opadowych
Konferencja zdrowie
Pogoda dla granic
Pożary i skażenia
Zestawiania danych SYNOP
Pracownia Klimatu
Aktualności
#AkademiaLMM
Informator meteorologiczny LMM
Słownik dla mediów
Vademecum/Produkty
R&D (Badania i rozwój)
Kontakt
Skip to content
Podsumowanie bieżącego miesiąca
Statystyka 30-letnia
Zestawienie miesięczne
<div id="forecast-app" class="forecast-app current-month-app"> <div class="layout-container"> <div class="left-column"> <div class="section"> <h3>Podsumowanie:</h3> <div id="modeButtons" class="buttons mode-buttons"></div> </div> <div class="section"> <h3>Charakterystyka:</h3> <div id="paramButtons" class="buttons params-buttons"></div> </div> <div class="keyboard-info"> <strong>💡 Skróty klawiszowe:</strong><br> 1-2 wybór widoku<br> ↑, ↓ zmiana charakterystyki<br> < > zmiana karty głównej </div> </div> <div class="right-column"> <div class="section images"> <div id="loader" class="loader-container" style="display: none;"> <div class="loader"></div> </div> <div id="images" class="images-grid"></div> <div id="noData" class="date-warning">Brak dostępnej mapy dla wybranego zestawu.</div> </div> </div> </div> </div> <style> .forecast-app { font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; } .layout-container { display: flex; flex-wrap: wrap; gap: 10px; } .left-column { flex: 1; min-width: 260px; max-width: 300px; } .right-column { flex: 2; min-width: 400px; } .section { margin-bottom: 12px; background: #f9f9f9; padding: 10px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .section h3 { margin-top: 0; margin-bottom: 6px; border-bottom: 1px solid #ddd; padding-bottom: 5px; color: #333; } .buttons { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; } .buttons button { padding: 8px 10px; min-width: 45px; border: 1px solid #666; border-radius: 8px; background: #f5f5f5; cursor: pointer; transition: all 0.2s; font-size: 0.9em; font-weight: 600; } .buttons button:hover { background: #e3f5f3; border-color: rgba(86, 221, 208, 1); } .buttons button.active { background: rgba(86, 221, 208, 1); border-color: rgba(56, 191, 178, 1); color: #fff; } .mode-buttons, .params-buttons { display: grid; grid-template-columns: 1fr; gap: 8px; } .mode-buttons button, .params-buttons button { width: 100%; text-align: center; } .images-grid { display: grid; grid-template-columns: 1fr; gap: 14px; min-height: 420px; } .image-card { margin: 0; border: 1px solid #ddd; border-radius: 8px; padding: 8px; background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); } .image-card img { width: 100%; height: auto; display: block; border-radius: 5px; } .loader-container { display: flex; justify-content: center; align-items: center; flex-direction: column; width: 100%; height: 300px; z-index: 100; position: relative; background-color: rgba(245, 245, 245, 0.7); border-radius: 8px; margin-bottom: 10px; } .loader { border: 12px solid #f3f3f3; border-radius: 50%; border-top: 12px solid rgba(86, 221, 208, 1); width: 90px; height: 90px; animation: spin 0.8s linear infinite; box-shadow: 0 0 20px rgba(86, 221, 208, 0.7); } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .date-warning { display: none; text-align: center; padding: 8px 15px; background: rgba(255, 152, 0, 0.1); border: 1px solid rgba(255, 152, 0, 0.3); border-radius: 6px; font-size: 13px; color: #e65100; margin: 10px 0; font-weight: 500; } .keyboard-info { font-size: 11px; color: #555; margin-top: 20px; padding: 10px; line-height: 1.6; background-color: #f0f8ff; border-left: 3px solid rgba(86, 221, 208, 1); border-radius: 4px; } .keyboard-info strong { color: rgba(86, 221, 208, 1); font-size: 12px; } @media (max-width: 768px) { .layout-container { flex-direction: column; } .left-column, .right-column { max-width: 100%; width: 100%; min-width: 0; } .keyboard-info { display: none; } } </style> <script> const modeConfig = { summary: { id: "summary", label: "Podsumowanie miesiąca", folder: "aktu_mies", parameters: [ { id: "TAVE", label: "Temperatura średnia", file: "TAVE.png" }, { id: "TAVE_ANOM", label: "Anomalia temperatury", file: "TAVE_anom.png" }, { id: "TMAX", label: "Temperatura maksymalna", file: "TMAX.png" }, { id: "TMIN", label: "Temperatura minimalna", file: "TMIN.png" }, { id: "RRR_ACU", label: "Suma opadu", file: "RRR_acu.png" }, { id: "RRR_ANOM", label: "Anomalia opadu", file: "RRR_anom.png" }, { id: "SSS_ACU", label: "Usłonecznienie", file: "SSS_acu.png" }, { id: "SSS_ANOM", label: "Anomalia usłonecznienia", file: "SSS_anom.png" } ] }, daily: { id: "daily", label: "Zestawienie dni", folder: "aktu_mies_kazdy_dzien", parameters: [ { id: "TAVE", label: "Temperatura średnia", file: "TAVE.png" }, { id: "TMAX", label: "Temperatura maksymalna", file: "TMAX.png" }, { id: "TMIN", label: "Temperatura minimalna", file: "TMIN.png" }, { id: "RR", label: "Opad", file: "RR.png" } ] } }; const orderedModes = ["summary", "daily"]; const state = { mode: "summary", param: "TAVE" }; const bridge = window.__switcherBridge; const initialState = bridge ? bridge.getInitialState("current") : null; if (initialState) { if (typeof initialState.mode === "string" && orderedModes.includes(initialState.mode)) { state.mode = initialState.mode; } if (typeof initialState.param === "string") { state.param = initialState.param; } } const modeButtonsEl = document.getElementById("modeButtons"); const paramButtonsEl = document.getElementById("paramButtons"); const imagesEl = document.getElementById("images"); const noDataEl = document.getElementById("noData"); const loaderEl = document.getElementById("loader"); const pageCacheToken = String(Date.now()); const imageAvailabilityCache = new Map(); const imagePreloadPromises = new Map(); let renderToken = 0; function syncUrlState() { if (!bridge) { return; } bridge.updateState("current", { mode: state.mode, param: state.param }); } function getCurrentParameters() { return modeConfig[state.mode].parameters; } function ensureActiveParameter() { const params = getCurrentParameters(); if (!params.some((item) => item.id === state.param)) { state.param = params[0].id; } } function getSelectedParameter() { const params = getCurrentParameters(); return params.find((item) => item.id === state.param) || params[0]; } function setLoading(isLoading) { loaderEl.style.display = isLoading ? "flex" : "none"; } function setActiveModeButton() { modeButtonsEl.querySelectorAll("button").forEach((button) => { button.classList.toggle("active", button.dataset.mode === state.mode); }); } function setActiveParamButton() { paramButtonsEl.querySelectorAll("button").forEach((button) => { button.classList.toggle("active", button.dataset.param === state.param); }); } function buildImagePathFor(modeId, paramFile) { return `/cmm/wp-content/uploads/production/analizy_meteo/${modeConfig[modeId].folder}/${paramFile}?v=${pageCacheToken}`; } function buildImagePath() { const selectedParam = getSelectedParameter(); return buildImagePathFor(state.mode, selectedParam.file); } function preloadImage(src) { if (imageAvailabilityCache.has(src)) { return Promise.resolve(imageAvailabilityCache.get(src)); } if (imagePreloadPromises.has(src)) { return imagePreloadPromises.get(src); } const preloadPromise = new Promise((resolve) => { const img = new Image(); img.onload = () => { imageAvailabilityCache.set(src, true); imagePreloadPromises.delete(src); resolve(true); }; img.onerror = () => { imageAvailabilityCache.set(src, false); imagePreloadPromises.delete(src); resolve(false); }; img.src = src; }); imagePreloadPromises.set(src, preloadPromise); return preloadPromise; } function preloadModeImages(modeId) { const params = modeConfig[modeId].parameters; params.forEach((param) => { const src = buildImagePathFor(modeId, param.file); void preloadImage(src); }); } function checkImageExists(src) { return preloadImage(src); } function renderModeButtons() { modeButtonsEl.innerHTML = ""; orderedModes.forEach((modeId) => { const button = document.createElement("button"); button.type = "button"; button.dataset.mode = modeId; button.textContent = modeConfig[modeId].label; button.addEventListener("click", () => { state.mode = modeId; ensureActiveParameter(); preloadModeImages(state.mode); setActiveModeButton(); renderParamButtons(); renderImage(); }); modeButtonsEl.appendChild(button); }); setActiveModeButton(); } function renderParamButtons() { paramButtonsEl.innerHTML = ""; getCurrentParameters().forEach((param) => { const button = document.createElement("button"); button.type = "button"; button.dataset.param = param.id; button.textContent = param.label; button.addEventListener("click", () => { state.param = param.id; setActiveParamButton(); renderImage(); }); paramButtonsEl.appendChild(button); }); setActiveParamButton(); } function appendImageCard(imagePath) { const figure = document.createElement("figure"); figure.className = "image-card"; const link = document.createElement("a"); link.href = imagePath; link.target = "_blank"; link.rel = "noopener"; const image = document.createElement("img"); image.src = imagePath; image.alt = "Mapa aktualnego miesiąca"; link.appendChild(image); figure.appendChild(link); imagesEl.appendChild(figure); } async function renderImage() { imagesEl.innerHTML = ""; noDataEl.style.display = "none"; setLoading(true); syncUrlState(); const token = ++renderToken; const imagePath = buildImagePath(); const exists = await checkImageExists(imagePath); if (token !== renderToken) { return; } if (exists) { appendImageCard(imagePath); } else { noDataEl.style.display = "block"; } setLoading(false); } function selectModeByIndex(index) { const modeId = orderedModes[index]; if (!modeId) { return; } state.mode = modeId; ensureActiveParameter(); setActiveModeButton(); renderParamButtons(); renderImage(); } function selectNextParam(step) { const params = getCurrentParameters(); const currentIndex = params.findIndex((item) => item.id === state.param); if (currentIndex === -1) { return; } const nextIndex = (currentIndex + step + params.length) % params.length; state.param = params[nextIndex].id; setActiveParamButton(); renderImage(); } function shouldIgnoreKeyboardEvent(event) { const target = event.target; if (!target) { return false; } const tag = target.tagName ? target.tagName.toLowerCase() : ""; return tag === "input" || tag === "textarea" || tag === "select" || target.isContentEditable; } document.addEventListener("keydown", (event) => { if (shouldIgnoreKeyboardEvent(event)) { return; } if (event.key === "1") { event.preventDefault(); selectModeByIndex(0); return; } if (event.key === "2") { event.preventDefault(); selectModeByIndex(1); return; } if (event.key === "ArrowUp") { event.preventDefault(); selectNextParam(-1); return; } if (event.key === "ArrowDown") { event.preventDefault(); selectNextParam(1); } }); renderModeButtons(); ensureActiveParameter(); orderedModes.forEach((modeId) => preloadModeImages(modeId)); renderParamButtons(); renderImage(); console.log("Autor Bartłomiej Sobczyk 2026"); </script>
<div id="forecast-app" class="forecast-app monthly-summary-app"> <div class="layout-container"> <div class="left-column"> <div class="section"> <h3>Rocznik:</h3> <div id="yearButtons" class="buttons year-buttons"></div> </div> <div class="section"> <h3>Miesiąc:</h3> <div class="month-slider-wrap"> <div id="monthValue" class="month-value">Styczeń</div> <input type="range" id="monthSlider" class="horizontal-slider" min="1" max="12" step="1" value="1" aria-label="Wybierz miesiąc"> <div class="month-labels"> <span>01</span><span>02</span><span>03</span><span>04</span><span>05</span><span>06</span> <span>07</span><span>08</span><span>09</span><span>10</span><span>11</span><span>12</span> </div> </div> </div> <div class="section"> <h3>Charakterystyka:</h3> <div class="buttons params-buttons tab" id="paramTabs"> <button class="tablinks" data-param="TEMPSR" id="defaultOpen" onclick="wrf(event, 'TEMPSR')">Temperatura średnia</button> <button class="tablinks" data-param="TEMPMAX" onclick="wrf(event, 'TEMPMAX')">Temperatura maksymalna</button> <button class="tablinks" data-param="TEMPMIN" onclick="wrf(event, 'TEMPMIN')">Temperatura minimalna</button> <button class="tablinks" data-param="OPAD" onclick="wrf(event, 'OPAD')">Opad</button> </div> </div> <div class="keyboard-info"> <strong>💡 Skróty klawiszowe:</strong><br> ↑, ↓ Zmiana rocznika<br> ←, → Zmiana miesiąca<br> 1-4 Wybór charakterystyki<br> A Wszystkie miesiące<br> S Ten sam miesiąc w latach<br> < > zmiana karty głównej </div> </div> <div class="right-column"> <div class="section images"> <div class="image-header"> <h3 id="imageTitle">Temperatura średnia | Styczeń 2026</h3> <div class="header-actions"> <button id="showAllBtn" class="control-btn" type="button">Pokaż wszystkie miesiące w roku</button> <button id="showAllYearsBtn" class="control-btn" type="button">Pokaż ten sam miesiąc w latach</button> </div> </div> <div id="loader" class="loader-container" style="display: none;"> <div class="loader"></div> </div> <div id="images" class="images-grid"></div> <div id="noData" class="date-warning">Brak dostępnych map dla wybranego zestawu.</div> </div> </div> </div> </div> <style> .forecast-app { font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; } .layout-container { display: flex; flex-wrap: wrap; gap: 10px; } .left-column { flex: 1; min-width: 230px; max-width: 230px; } .right-column { flex: 2; min-width: 400px; } .section { margin-bottom: 12px; background: #f9f9f9; padding: 10px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .section h3 { margin-top: 0; margin-bottom: 6px; border-bottom: 1px solid #ddd; padding-bottom: 5px; color: #333; } .buttons { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 3px; } .buttons button { padding: 6px 10px; min-width: 45px; border: 1px solid #666; border-radius: 6px; background: #f5f5f5; cursor: pointer; transition: all 0.2s; font-size: 0.9em; } .buttons button:hover { background: #e3f5f3; border-color: rgba(86, 221, 208, 1); } .buttons button.active, .tablinks.active { background: rgba(86, 221, 208, 1); border-color: rgba(56, 191, 178, 1); color: #fff; } .year-buttons { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; } .year-buttons button { width: 100%; min-width: 0; font-variant-numeric: tabular-nums; } .params-buttons { display: grid; grid-template-columns: 1fr; gap: 6px; } .params-buttons button { width: 100%; text-align: center; } .month-slider-wrap { margin-top: 4px; } .month-value { font-size: 1.1em; font-weight: bold; color: rgba(86, 221, 208, 1); margin-bottom: 6px; } .horizontal-slider { -webkit-appearance: none; appearance: none; width: 100%; height: 10px; border-radius: 5px; background: #e0e0e0; outline: none; margin: 4px 0 8px; } .horizontal-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 22px; height: 22px; border-radius: 50%; background: rgba(86, 221, 208, 1); cursor: pointer; border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); } .horizontal-slider::-moz-range-thumb { width: 22px; height: 22px; border-radius: 50%; background: rgba(86, 221, 208, 1); cursor: pointer; border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); } .month-labels { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 2px; font-size: 10px; color: #777; text-align: center; } .image-header { display: flex; align-items: center; gap: 10px; justify-content: space-between; margin-bottom: 10px; } .image-header h3 { margin: 0; padding: 0; border: none; } .header-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; } .control-btn { background: rgba(86, 221, 208, 0.1); border: 2px solid rgba(86, 221, 208, 1); color: rgba(56, 191, 178, 1); border-radius: 8px; cursor: pointer; transition: all 0.2s; padding: 7px 10px; font-size: 0.85em; font-weight: bold; white-space: nowrap; } .control-btn:hover { background: rgba(86, 221, 208, 0.2); } .control-btn.active { background: rgba(86, 221, 208, 1); color: #fff; } .images-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; min-height: 420px; } .image-card { margin: 0; border: 1px solid #ddd; border-radius: 8px; padding: 8px; background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); } .image-card img { width: 100%; height: auto; display: block; border-radius: 5px; } .loader-container { display: flex; justify-content: center; align-items: center; flex-direction: column; width: 100%; height: 300px; z-index: 100; position: relative; background-color: rgba(245, 245, 245, 0.7); border-radius: 8px; margin-bottom: 10px; } .loader { border: 12px solid #f3f3f3; border-radius: 50%; border-top: 12px solid rgba(86, 221, 208, 1); width: 90px; height: 90px; animation: spin 0.8s linear infinite; box-shadow: 0 0 20px rgba(86, 221, 208, 0.7); } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .date-warning { display: none; text-align: center; padding: 8px 15px; background: rgba(255, 152, 0, 0.1); border: 1px solid rgba(255, 152, 0, 0.3); border-radius: 6px; font-size: 13px; color: #e65100; margin: 10px 0; font-weight: 500; } .keyboard-info { font-size: 11px; color: #555; margin-top: 20px; padding: 10px; line-height: 1.6; background-color: #f0f8ff; border-left: 3px solid rgba(86, 221, 208, 1); border-radius: 4px; } .keyboard-info strong { color: rgba(86, 221, 208, 1); font-size: 12px; } @media (max-width: 768px) { .layout-container { flex-direction: column; } .left-column, .right-column { max-width: 100%; width: 100%; min-width: 0; } .images-grid { grid-template-columns: 1fr; } .image-header { flex-direction: column; align-items: flex-start; } .header-actions { justify-content: flex-start; } } </style> <script> const months = [ { value: 1, label: "Styczeń" }, { value: 2, label: "Luty" }, { value: 3, label: "Marzec" }, { value: 4, label: "Kwiecień" }, { value: 5, label: "Maj" }, { value: 6, label: "Czerwiec" }, { value: 7, label: "Lipiec" }, { value: 8, label: "Sierpień" }, { value: 9, label: "Wrzesień" }, { value: 10, label: "Październik" }, { value: 11, label: "Listopad" }, { value: 12, label: "Grudzień" } ]; const paramsConfig = { TEMPSR: { label: "Temperatura średnia", suffix: "TAVE" }, TEMPMAX: { label: "Temperatura maksymalna", suffix: "TMAX" }, TEMPMIN: { label: "Temperatura minimalna", suffix: "TMIN" }, OPAD: { label: "Opad", suffix: "RR" } }; const firstYear = 2013; const now = new Date(); const currentYear = now.getFullYear(); const currentMonth = now.getMonth() + 1; const defaultMonthDate = new Date(currentYear, currentMonth - 2, 1); const defaultYear = defaultMonthDate.getFullYear(); const defaultMonth = defaultMonthDate.getMonth() + 1; const latestYear = Math.max(firstYear, currentYear); const years = Array.from({ length: latestYear - firstYear + 1 }, (_, i) => latestYear - i); const state = { year: defaultYear, month: defaultMonth, param: "TEMPSR", viewMode: "single" }; const bridge = window.__switcherBridge; const initialState = bridge ? bridge.getInitialState("monthly") : null; if (initialState) { if (Number.isInteger(initialState.year) && years.includes(initialState.year)) { state.year = initialState.year; } if (Number.isInteger(initialState.month) && initialState.month >= 1 && initialState.month <= 12) { state.month = initialState.month; } if (typeof initialState.param === "string" && paramsConfig[initialState.param]) { state.param = initialState.param; } if ( typeof initialState.viewMode === "string" && ["single", "allMonths", "allYears"].includes(initialState.viewMode) ) { state.viewMode = initialState.viewMode; } } const hasPinnedPeriodFromUrl = Boolean(initialState && initialState.periodPinned === true); const yearButtonsEl = document.getElementById("yearButtons"); const monthSliderEl = document.getElementById("monthSlider"); const monthValueEl = document.getElementById("monthValue"); const imageTitleEl = document.getElementById("imageTitle"); const imagesEl = document.getElementById("images"); const noDataEl = document.getElementById("noData"); const showAllBtnEl = document.getElementById("showAllBtn"); const showAllYearsBtnEl = document.getElementById("showAllYearsBtn"); const loaderEl = document.getElementById("loader"); const imageAvailabilityCache = new Map(); const imagePreloadPromises = new Map(); let renderToken = 0; function syncUrlState() { if (!bridge) { return; } bridge.updateState("monthly", { year: state.year, month: state.month, param: state.param, viewMode: state.viewMode }); } function getMonthMeta(monthNumber) { return months.find((m) => m.value === monthNumber) || months[0]; } function createImagePath(year, month, suffix) { return `/cmm/wp-content/uploads/production/analizy_meteo/miesieczne/${year}_${month}_${suffix}.png`; } function checkImageExists(src) { return preloadImage(src); } async function findLatestAvailableYearMonth(paramId) { const suffix = paramsConfig[paramId].suffix; for (const year of years) { const monthsDesc = Array.from({ length: 12 }, (_, i) => 12 - i); const checks = await Promise.all( monthsDesc.map(async (month) => { const path = createImagePath(year, month, suffix); return { month: month, ok: await checkImageExists(path) }; }) ); const found = checks.find((item) => item.ok); if (found) { return { year: year, month: found.month }; } } return null; } function createYearButtons() { yearButtonsEl.innerHTML = ""; years.forEach((year) => { const btn = document.createElement("button"); btn.type = "button"; btn.textContent = year; btn.dataset.year = String(year); if (year === state.year) { btn.classList.add("active"); } btn.addEventListener("click", () => { state.year = year; yearButtonsEl.querySelectorAll("button").forEach((b) => b.classList.remove("active")); btn.classList.add("active"); renderImages(); }); yearButtonsEl.appendChild(btn); }); } function setLoading(isLoading) { loaderEl.style.display = isLoading ? "flex" : "none"; } async function initializeDefaultSelection() { setLoading(true); try { const preferredPeriod = hasPinnedPeriodFromUrl ? { year: state.year, month: state.month } : { year: defaultYear, month: defaultMonth }; state.year = preferredPeriod.year; state.month = preferredPeriod.month; if (!years.includes(state.year)) { state.year = years[0]; } monthSliderEl.value = String(state.month); updateActiveYearButton(); setActiveParamButton(state.param); await renderImages(); } finally { setLoading(false); } } function updateMonthLabel() { const monthMeta = getMonthMeta(state.month); monthValueEl.textContent = monthMeta.label; } function syncViewModeButtons() { const allMonthsActive = state.viewMode === "allMonths"; const allYearsActive = state.viewMode === "allYears"; showAllBtnEl.classList.toggle("active", allMonthsActive); showAllYearsBtnEl.classList.toggle("active", allYearsActive); showAllBtnEl.textContent = allMonthsActive ? "Wróć do jednego miesiąca" : "Pokaż wszystkie miesiące"; showAllYearsBtnEl.textContent = allYearsActive ? "Wróć do jednego roku" : "Pokaż ten sam miesiąc w latach"; } function updateTitle() { const monthMeta = getMonthMeta(state.month); const paramLabel = paramsConfig[state.param].label; const period = state.viewMode === "allMonths" ? `${state.year} (wszystkie miesiące)` : state.viewMode === "allYears" ? `${monthMeta.label} (różne lata)` : `${monthMeta.label} ${state.year}`; imageTitleEl.textContent = `${paramLabel} | ${period}`; } function setActiveParamButton(activeParam) { document.querySelectorAll(".tablinks").forEach((button) => { button.classList.toggle("active", button.dataset.param === activeParam); }); } function preloadImage(src) { if (imageAvailabilityCache.has(src)) { return Promise.resolve(imageAvailabilityCache.get(src)); } if (imagePreloadPromises.has(src)) { return imagePreloadPromises.get(src); } const preloadPromise = new Promise((resolve) => { const img = new Image(); img.onload = () => { imageAvailabilityCache.set(src, true); imagePreloadPromises.delete(src); resolve(true); }; img.onerror = () => { imageAvailabilityCache.set(src, false); imagePreloadPromises.delete(src); resolve(false); }; img.src = src; }); imagePreloadPromises.set(src, preloadPromise); return preloadPromise; } function appendImageCard(src) { const figure = document.createElement("figure"); figure.className = "image-card"; const link = document.createElement("a"); link.href = src; link.target = "_blank"; link.rel = "noopener"; const img = document.createElement("img"); img.src = src; img.alt = "Mapa"; link.appendChild(img); figure.appendChild(link); imagesEl.appendChild(figure); } function updateActiveYearButton() { yearButtonsEl.querySelectorAll("button").forEach((button) => { button.classList.toggle("active", Number(button.dataset.year) === state.year); }); } function toggleShowAll() { state.viewMode = state.viewMode === "allMonths" ? "single" : "allMonths"; syncViewModeButtons(); renderImages(); } function toggleShowAllYears() { state.viewMode = state.viewMode === "allYears" ? "single" : "allYears"; syncViewModeButtons(); renderImages(); } function changeYearByOffset(offset) { const currentIndex = years.indexOf(state.year); if (currentIndex === -1) { return; } const nextIndex = Math.max(0, Math.min(years.length - 1, currentIndex + offset)); if (nextIndex === currentIndex) { return; } state.year = years[nextIndex]; updateActiveYearButton(); renderImages(); } function changeMonthByOffset(offset) { const nextMonth = Math.max(1, Math.min(12, state.month + offset)); if (nextMonth === state.month) { return; } state.month = nextMonth; monthSliderEl.value = String(nextMonth); renderImages(); } function selectParamByIndex(index) { const orderedParams = ["TEMPSR", "TEMPMAX", "TEMPMIN", "OPAD"]; const paramId = orderedParams[index]; if (!paramId) { return; } state.param = paramId; setActiveParamButton(paramId); renderImages(); } function shouldIgnoreKeyboardEvent(event) { const target = event.target; if (!target) { return false; } const tag = target.tagName ? target.tagName.toLowerCase() : ""; return tag === "input" || tag === "textarea" || tag === "select" || target.isContentEditable; } async function renderImages() { imagesEl.innerHTML = ""; noDataEl.style.display = "none"; const token = ++renderToken; setLoading(true); syncUrlState(); updateMonthLabel(); updateTitle(); const renderTargets = state.viewMode === "allMonths" ? months.map((monthMeta) => ({ year: state.year, month: monthMeta.value })) : state.viewMode === "allYears" ? years.map((year) => ({ year: year, month: state.month })) : [{ year: state.year, month: state.month }]; const suffix = paramsConfig[state.param].suffix; try { const checks = await Promise.all( renderTargets.map(async (target) => { const filePath = createImagePath(target.year, target.month, suffix); const ok = await preloadImage(filePath); return { ok: ok, filePath: filePath }; }) ); if (token !== renderToken) { return; } checks.forEach((item) => { if (item.ok) { appendImageCard(item.filePath); } }); if (!checks.some((item) => item.ok)) { noDataEl.style.display = "block"; } } finally { if (token === renderToken) { setLoading(false); } } } function wrf(evt, paramId) { state.param = paramId; setActiveParamButton(paramId); renderImages(); if (evt && evt.currentTarget) { evt.preventDefault(); } } monthSliderEl.addEventListener("input", (event) => { state.month = Number(event.target.value); renderImages(); }); showAllBtnEl.addEventListener("click", toggleShowAll); showAllYearsBtnEl.addEventListener("click", toggleShowAllYears); document.addEventListener("keydown", (event) => { if (shouldIgnoreKeyboardEvent(event)) { return; } if (event.key === "ArrowLeft") { event.preventDefault(); changeMonthByOffset(-1); return; } if (event.key === "ArrowRight") { event.preventDefault(); changeMonthByOffset(1); return; } if (event.key === "ArrowUp") { event.preventDefault(); changeYearByOffset(-1); return; } if (event.key === "ArrowDown") { event.preventDefault(); changeYearByOffset(1); return; } if (event.key === "1") { selectParamByIndex(0); return; } if (event.key === "2") { selectParamByIndex(1); return; } if (event.key === "3") { selectParamByIndex(2); return; } if (event.key === "4") { selectParamByIndex(3); return; } if (event.key === "a" || event.key === "A") { event.preventDefault(); toggleShowAll(); return; } if (event.key === "s" || event.key === "S") { event.preventDefault(); toggleShowAllYears(); } }); createYearButtons(); syncViewModeButtons(); initializeDefaultSelection(); console.log("Autor Bartłomiej Sobczyk 2026"); </script>
<div id="forecast-app" class="forecast-app climate-stats-app"> <div class="layout-container"> <div class="left-column"> <div class="section"> <h3>Zakres statystyki:</h3> <div id="modeButtons" class="buttons mode-buttons"></div> </div> <div class="section"> <h3 id="paramTitle">Charakterystyka:</h3> <div id="paramButtons" class="buttons params-buttons"></div> </div> <div class="keyboard-info"> <strong>💡 Skróty klawiszowe:</strong><br> 1-3 zmiana zakresu statystyki <br>↑, ↓ zmiana charakterystyki <br>< > zmiana karty głównej </div> </div> <div class="right-column"> <div class="section images"> <div id="loader" class="loader-container" style="display: none;"> <div class="loader"></div> </div> <div id="images" class="images-grid"></div> <div id="noData" class="date-warning">Brak dostępnej mapy dla wybranego zestawu.</div> </div> </div> </div> </div> <style> .forecast-app { font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; } .layout-container { display: flex; flex-wrap: wrap; gap: 10px; } .left-column { flex: 1; min-width: 280px; max-width: 320px; } .right-column { flex: 2; min-width: 400px; } .section { margin-bottom: 12px; background: #f9f9f9; padding: 10px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .section h3 { margin-top: 0; margin-bottom: 6px; border-bottom: 1px solid #ddd; padding-bottom: 5px; color: #333; } .buttons { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; } .buttons button { padding: 8px 10px; min-width: 45px; border: 1px solid #666; border-radius: 8px; background: #f5f5f5; cursor: pointer; transition: all 0.2s; font-size: 0.9em; font-weight: 600; } .buttons button:hover { background: #e3f5f3; border-color: rgba(86, 221, 208, 1); } .buttons button.active { background: rgba(86, 221, 208, 1); border-color: rgba(56, 191, 178, 1); color: #fff; } .mode-buttons { display: grid; grid-template-columns: 1fr; gap: 8px; } .mode-buttons button { width: 100%; text-align: center; } .params-buttons { display: grid; grid-template-columns: 1fr; gap: 8px; } .params-buttons button { width: 100%; text-align: center; } .param-select-wrap { position: relative; width: 100%; min-height: 44px; } .param-select { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; } .param-select-display { min-height: 44px; padding: 10px 40px 10px 12px; border: 1px solid #666; border-radius: 8px; background: #fff; font-size: 16px; line-height: 1.35; font-weight: 500; white-space: normal; word-break: break-word; position: relative; pointer-events: none; } .param-select-display::after { content: ""; position: absolute; right: 14px; top: 50%; margin-top: -3px; width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 7px solid #666; } .param-select-wrap:focus-within .param-select-display { outline: 2px solid rgba(86, 221, 208, 0.35); border-color: rgba(86, 221, 208, 1); } .images-grid { display: grid; grid-template-columns: 1fr; gap: 14px; min-height: 420px; } .image-card { margin: 0; border: 1px solid #ddd; border-radius: 8px; padding: 8px; background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); } .image-card img { width: 100%; height: auto; display: block; border-radius: 5px; } .loader-container { display: flex; justify-content: center; align-items: center; flex-direction: column; width: 100%; height: 300px; z-index: 100; position: relative; background-color: rgba(245, 245, 245, 0.7); border-radius: 8px; margin-bottom: 10px; } .loader { border: 12px solid #f3f3f3; border-radius: 50%; border-top: 12px solid rgba(86, 221, 208, 1); width: 90px; height: 90px; animation: spin 0.8s linear infinite; box-shadow: 0 0 20px rgba(86, 221, 208, 0.7); } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .date-warning { display: none; text-align: center; padding: 8px 15px; background: rgba(255, 152, 0, 0.1); border: 1px solid rgba(255, 152, 0, 0.3); border-radius: 6px; font-size: 13px; color: #e65100; margin: 10px 0; font-weight: 500; } .keyboard-info { font-size: 11px; color: #555; margin-top: 20px; padding: 10px; line-height: 1.6; background-color: #f0f8ff; border-left: 3px solid rgba(86, 221, 208, 1); border-radius: 4px; } .keyboard-info strong { color: rgba(86, 221, 208, 1); font-size: 12px; } @media (max-width: 768px) { .layout-container { flex-direction: column; } .left-column, .right-column { max-width: 100%; width: 100%; min-width: 0; } .params-buttons { grid-template-columns: 1fr; } .keyboard-info { display: none; } } </style> <script> const monthNamesUpperGen = [ "stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", "lipca", "sierpnia", "września", "października", "listopada", "grudnia" ]; const monthNamesUpperNom = [ "styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień" ]; const modeConfig = { day: { id: "day", titlePrefix: "Zestawienie na dzień", sectionTitle: "Charakterystyka:", folders: ["dobowe_30lat"] }, period: { id: "period", titlePrefix: "Zestawienie", sectionTitle: "Charakterystyka:", folders: ["15dni_30lat"] }, month: { id: "month", titlePrefix: "Zestawienie za", sectionTitle: "Charakterystyka:", folders: ["miesieczne_30lat"] } }; const orderedModes = ["day", "period", "month"]; const dayParameters = [ { id: "TEMPSR", label: "Temperatura średnia", code: "TAVE" }, { id: "TEMPMAX", label: "Temperatura maksymalna", code: "TMAX" }, { id: "TEMPMIN", label: "Temperatura minimalna", code: "TMIN" }, { id: "OPAD", label: "Opad", code: "RR" }, { id: "WIATR", label: "Wiatr", code: "WIATR" }, { id: "PKSN", label: "Pokrywa śnieżna", code: "PKSN" } ]; const periodMonthParameters = [ { id: "LD_OPAD_01", label: "Liczba dni z opadem >= 0.1mm", code: "LD_OPAD_01" }, { id: "LD_PKSN", label: "Liczba dni z pokrywą śnieżną >= 1cm", code: "LD_PKSN" }, { id: "LD_PORYWY_55", label: "Liczba dni z porywem wiatru >= 55km/h", code: "LD_PORYWY_55" }, { id: "LD_TMAX_25", label: "Liczba dni z temperaturą >= 25°C", code: "LD_TMAX_25" }, { id: "LD_TMAX_30", label: "Liczba dni z temperaturą >= 30°C", code: "LD_TMAX_30" }, { id: "LD_TMIN_PON_0", label: "Liczba dni z temperaturą < 0°C", code: "LD_TMIN_PON_0" }, { id: "LD_TMIN_PON_10", label: "Liczba dni z temperaturą <= -10°C", code: "LD_TMIN_PON_10" }, { id: "LD_TMIN_PON_15", label: "Liczba dni z temperaturą <= -15°C", code: "LD_TMIN_PON_15" }, { id: "LD_TMIN_PON_20", label: "Liczba dni z temperaturą <= -20°C", code: "LD_TMIN_PON_20" }, { id: "LD_TMIN_PON_25", label: "Liczba dni z temperaturą <= -25°C", code: "LD_TMIN_PON_25" }, { id: "PKSN", label: "Maksymalna grubość pokrywy śnieżnej (cm)", code: "PKSN" }, { id: "PKSN_AVE", label: "Średnia grubość pokrywy śnieżnej (cm)", code: "PKSN_AVE" }, { id: "RR_ANOM", label: "Anomalia sumy opadu (%) względem lat 1991-2020", code: "RR_anom" }, { id: "RR", label: "Suma opadu (mm)", code: "RR" }, { id: "SMBD", label: "Maksymalny dobowy opad (mm)", code: "SMBD" }, { id: "TAVE_ANOM", label: "Anomalia średniej temperatury (°C) względem lat 1991-2020", code: "TAVE_anom" }, { id: "TAVE", label: "Średnia temperatura (°C)", code: "TAVE" }, { id: "TMAX_AVE", label: "Średnia maksymalna temperatura (°C)", code: "TMAX_AVE" }, { id: "TMAX", label: "Maksymalna temperatura (°C)", code: "TMAX" }, { id: "TMIN_AVE", label: "Średnia minimalna temperatura (°C)", code: "TMIN_AVE" }, { id: "TMIN", label: "Minimalna temperatura (°C)", code: "TMIN" }, { id: "WIATR_AVG", label: "Średnia prędkość wiatru (km/h)", code: "Wiatr" } ]; const modeButtonsEl = document.getElementById("modeButtons"); const paramButtonsEl = document.getElementById("paramButtons"); const paramTitleEl = document.getElementById("paramTitle"); const imagesEl = document.getElementById("images"); const noDataEl = document.getElementById("noData"); const loaderEl = document.getElementById("loader"); const now = new Date(); const dayDate = new Date(now.getFullYear(), now.getMonth(), now.getDate()); const periodStartDate = new Date(now.getFullYear(), now.getMonth(), now.getDate()); periodStartDate.setDate(periodStartDate.getDate() - 7); const periodEndDate = new Date(now.getFullYear(), now.getMonth(), now.getDate()); periodEndDate.setDate(periodEndDate.getDate() + 7); const monthDate = new Date(now.getFullYear(), now.getMonth(), 1); const state = { mode: "day", param: "TEMPSR" }; const bridge = window.__switcherBridge; const initialState = bridge ? bridge.getInitialState("climate") : null; if (initialState) { if (typeof initialState.mode === "string" && orderedModes.includes(initialState.mode)) { state.mode = initialState.mode; } if (typeof initialState.param === "string") { state.param = initialState.param; } } let renderToken = 0; const imageAvailabilityCache = new Map(); const imagePreloadPromises = new Map(); function syncUrlState() { if (!bridge) { return; } bridge.updateState("climate", { mode: state.mode, param: state.param }); } function isDropdownMode(modeId) { return modeId === "period" || modeId === "month"; } function getParametersForMode(modeId) { if (modeId === "day") { return dayParameters; } return periodMonthParameters; } function ensureActiveParameterForMode() { const modeParams = getParametersForMode(state.mode); if (!modeParams.some((item) => item.id === state.param)) { state.param = modeParams[0].id; } } function formatDayLabel(date) { return `${date.getDate()} ${monthNamesUpperGen[date.getMonth()]}`; } function formatMonthLabel(date) { return monthNamesUpperNom[date.getMonth()]; } function formatPeriodLabel(startDate, endDate) { const startPart = `${startDate.getDate()} ${monthNamesUpperGen[startDate.getMonth()]}`; const endPart = `${endDate.getDate()} ${monthNamesUpperGen[endDate.getMonth()]}`; return `${startPart} - ${endPart}`; } function getModeButtonText(modeId) { if (modeId === "day") { return `${modeConfig.day.titlePrefix} ${formatDayLabel(dayDate)}`; } if (modeId === "period") { return `${modeConfig.period.titlePrefix} ${formatPeriodLabel(periodStartDate, periodEndDate)}`; } return `${modeConfig.month.titlePrefix} ${formatMonthLabel(monthDate)}`; } function getModeDisplayPeriod(modeId) { if (modeId === "day") { return formatDayLabel(dayDate); } if (modeId === "period") { return formatPeriodLabel(periodStartDate, periodEndDate); } return formatMonthLabel(monthDate); } function setLoading(isLoading) { loaderEl.style.display = isLoading ? "flex" : "none"; } function setActiveModeButton() { modeButtonsEl.querySelectorAll("button").forEach((button) => { button.classList.toggle("active", button.dataset.mode === state.mode); }); } function setActiveParamButton() { const select = paramButtonsEl.querySelector("select"); if (select) { const modeParams = getParametersForMode(state.mode); const selected = modeParams.find((item) => item.id === state.param) || modeParams[0]; select.value = selected.id; select.title = selected.label; const display = paramButtonsEl.querySelector(".param-select-display"); if (display) { display.textContent = selected.label; } } paramButtonsEl.querySelectorAll("button").forEach((button) => { button.classList.toggle("active", button.dataset.param === state.param); }); } function getFileCandidates(paramCode, modeId) { if (modeId === "day" && paramCode === "WIATR") { return ["WIATR.png", "Wiatr.png"]; } return [`${paramCode}.png`]; } function buildImageCandidates(paramCode, modeId) { const folders = modeConfig[modeId].folders; const fileCandidates = getFileCandidates(paramCode, modeId); const urls = []; folders.forEach((folder) => { fileCandidates.forEach((fileName) => { urls.push(`/cmm/wp-content/uploads/production/analizy_meteo/${folder}/${fileName}`); }); }); return urls; } function preloadImage(src) { if (imageAvailabilityCache.has(src)) { return Promise.resolve(imageAvailabilityCache.get(src)); } if (imagePreloadPromises.has(src)) { return imagePreloadPromises.get(src); } const preloadPromise = new Promise((resolve) => { const img = new Image(); img.onload = () => { imageAvailabilityCache.set(src, true); imagePreloadPromises.delete(src); resolve(true); }; img.onerror = () => { imageAvailabilityCache.set(src, false); imagePreloadPromises.delete(src); resolve(false); }; img.src = src; }); imagePreloadPromises.set(src, preloadPromise); return preloadPromise; } function preloadModeImages(modeId) { const modeParams = getParametersForMode(modeId); modeParams.forEach((param) => { const candidates = buildImageCandidates(param.code, modeId); candidates.forEach((src) => { void preloadImage(src); }); }); } function checkImageExists(src) { return preloadImage(src); } async function findFirstAvailableImagePath(paramCode, modeId) { const candidates = buildImageCandidates(paramCode, modeId); for (const candidate of candidates) { const exists = await checkImageExists(candidate); if (exists) { return candidate; } } return null; } function renderModeButtons() { modeButtonsEl.innerHTML = ""; orderedModes.forEach((modeId) => { const button = document.createElement("button"); button.type = "button"; button.dataset.mode = modeId; button.textContent = getModeButtonText(modeId); button.addEventListener("click", () => { state.mode = modeId; ensureActiveParameterForMode(); preloadModeImages(state.mode); paramTitleEl.textContent = modeConfig[modeId].sectionTitle; setActiveModeButton(); renderParamButtons(); renderImage(); }); modeButtonsEl.appendChild(button); }); setActiveModeButton(); } function selectNextMode(step) { const currentIndex = orderedModes.indexOf(state.mode); if (currentIndex === -1) { return; } const nextIndex = (currentIndex + step + orderedModes.length) % orderedModes.length; state.mode = orderedModes[nextIndex]; ensureActiveParameterForMode(); paramTitleEl.textContent = modeConfig[state.mode].sectionTitle; setActiveModeButton(); renderParamButtons(); renderImage(); } function selectModeByIndex(index) { const modeId = orderedModes[index]; if (!modeId) { return; } state.mode = modeId; ensureActiveParameterForMode(); paramTitleEl.textContent = modeConfig[state.mode].sectionTitle; setActiveModeButton(); renderParamButtons(); renderImage(); } function renderParamButtons() { paramButtonsEl.innerHTML = ""; const modeParams = getParametersForMode(state.mode); if (isDropdownMode(state.mode)) { const wrap = document.createElement("div"); wrap.className = "param-select-wrap"; const select = document.createElement("select"); select.className = "param-select"; select.setAttribute("aria-label", "Wybierz charakterystykę"); modeParams.forEach((param) => { const option = document.createElement("option"); option.value = param.id; option.textContent = param.label; select.appendChild(option); }); select.addEventListener("change", (event) => { state.param = event.target.value; setActiveParamButton(); renderImage(); }); const display = document.createElement("div"); display.className = "param-select-display"; wrap.appendChild(select); wrap.appendChild(display); paramButtonsEl.appendChild(wrap); setActiveParamButton(); return; } modeParams.forEach((param) => { const button = document.createElement("button"); button.type = "button"; button.dataset.param = param.id; button.textContent = param.label; button.addEventListener("click", () => { state.param = param.id; setActiveParamButton(); renderImage(); }); paramButtonsEl.appendChild(button); }); setActiveParamButton(); } function appendImageCard(imagePath) { const figure = document.createElement("figure"); figure.className = "image-card"; const link = document.createElement("a"); link.href = imagePath; link.target = "_blank"; link.rel = "noopener"; const image = document.createElement("img"); image.src = imagePath; image.alt = "Mapa statystyki 30-letniej"; link.appendChild(image); figure.appendChild(link); imagesEl.appendChild(figure); } async function renderImage() { imagesEl.innerHTML = ""; noDataEl.style.display = "none"; setLoading(true); syncUrlState(); const token = ++renderToken; const modeParams = getParametersForMode(state.mode); const selectedParam = modeParams.find((item) => item.id === state.param) || modeParams[0]; const imagePath = await findFirstAvailableImagePath(selectedParam.code, state.mode); if (token !== renderToken) { return; } if (imagePath) { appendImageCard(imagePath); } else { noDataEl.style.display = "block"; } setLoading(false); } function selectNextParam(step) { const modeParams = getParametersForMode(state.mode); const currentIndex = modeParams.findIndex((item) => item.id === state.param); if (currentIndex === -1) { return; } const nextIndex = (currentIndex + step + modeParams.length) % modeParams.length; state.param = modeParams[nextIndex].id; setActiveParamButton(); renderImage(); } function shouldIgnoreKeyboardEvent(event) { const target = event.target; if (!target) { return false; } const tag = target.tagName ? target.tagName.toLowerCase() : ""; return tag === "input" || tag === "textarea" || tag === "select" || target.isContentEditable; } document.addEventListener("keydown", (event) => { if (shouldIgnoreKeyboardEvent(event)) { return; } if (event.key === "1") { event.preventDefault(); selectModeByIndex(0); return; } if (event.key === "2") { event.preventDefault(); selectModeByIndex(1); return; } if (event.key === "3") { event.preventDefault(); selectModeByIndex(2); return; } if (event.key === "ArrowUp") { event.preventDefault(); selectNextParam(-1); return; } if (event.key === "ArrowDown") { event.preventDefault(); selectNextParam(1); } }); renderModeButtons(); ensureActiveParameterForMode(); orderedModes.forEach((modeId) => preloadModeImages(modeId)); renderParamButtons(); paramTitleEl.textContent = modeConfig[state.mode].sectionTitle; renderImage(); console.log("Autor Bartłomiej Sobczyk 2026"); </script>
UDOSTĘPNIJ STRONĘ
Scroll Up
account
android
arrow-alt-circle-down
arrow-alt-circle-left
arrow-alt-circle-right
arrow-alt-circle-up
arrow-down
arrow-left
arrow-right
arrow-up
author
bars
behance
blogger
buffer
caret-down
caret-left
caret-right
caret-square-down
caret-square-left
caret-square-right
caret-square-up
caret-up
cart-menu-1
cart-menu-2
cart-menu-3
cart-menu-4
categories
chevron-down
chevron-left
chevron-right
chevron-up
clock
close
comments
cookies
copyright
coupon-discount
date-modified
date-published
discord
double-arrows-down
double-arrows-left
double-arrows-right
double-arrows-up
dribbble
envelope-open
envelope
eye
facebook
fax
flickr
foursquare
github
gmail
google-drive
grid-view
hashtag
hollow-ring
homepage
instagram
ios
level-down-alt
level-up-alt
line
link
linkedin
list-view
login
logout
long-arrow-alt-down
long-arrow-alt-left
long-arrow-alt-right
long-arrow-alt-up
medium
messenger
mobile-menu
mobile
phone
pinterest
place
qq
quote-left
quote-right
quotes
reading-time-hourglass
reading-time-stopwatch
reddit
rss
scroll-to-top
search
shazam
shopping-bag
shopping-cart
side-panel-opening-2-left
side-panel-opening-2-right
side-panel-opening-left
side-panel-opening-right
skype
slack
small-arrow-down
small-arrow-left
small-arrow-right
small-arrow-up
sms
snapchat
soundcloud
spinner
spotify
stackoverflow
sync
telegram
tiktok
times-circle
tinder
trello
tripadvisor
tumblr
twitch
twitter
viber
vimeo
vine
vkontakte
website
wechat
whatsapp
windows
wishlist
xing
yelp
youtube
zoom