Last active
April 25, 2026 16:49
-
-
Save MatsA/da974732172378cc3806939b7d3aacae to your computer and use it in GitHub Desktop.
Weather template, html. Link to blogpost in the code !
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="sv"> | |
| <!-- | |
| Code created in dialog with Gemini & Claude | |
| Mats A 2026-04 metzallo@gmail.com | |
| https://pysselilivet.blogspot.com/2026/04/dyi-weather-template-with-data-from.html | |
| --> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Väderstation Domsten - Live</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&display=swap" rel="stylesheet"> | |
| <style> | |
| body { | |
| background-color: #121212; | |
| color: #e0e0e0; | |
| font-family: 'Inter', sans-serif; | |
| overflow-x: hidden; | |
| padding: 1rem 2rem; | |
| } | |
| .card { | |
| background-color: #1e1e1e; | |
| border-radius: 12px; | |
| padding: 1.25rem; | |
| border: 1px solid #2d2d2d; | |
| display: flex; | |
| flex-direction: column; | |
| min-height: 185px; | |
| } | |
| .label { | |
| color: rgba(255, 255, 255, 0.7); | |
| text-transform: uppercase; | |
| font-size: 0.7rem; | |
| letter-spacing: 0.1em; | |
| text-align: center; | |
| margin-bottom: 0.5rem; | |
| } | |
| .value-container { | |
| flex-grow: 1; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| /* Standardstorlek för stora värden */ | |
| .value { | |
| font-size: 3rem; | |
| font-weight: 600; | |
| color: #ffffff; | |
| line-height: 1; | |
| } | |
| .unit { | |
| font-size: 1.2rem; | |
| color: rgba(255, 255, 255, 0.4); | |
| margin-left: 4px; | |
| } | |
| .bottom-info { | |
| height: 45px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| border-top: 1px solid #2d2d2d; | |
| width: 100%; | |
| margin-top: 0.5rem; | |
| } | |
| #side-menu { | |
| transition: transform 0.3s ease-in-out; | |
| z-index: 100; | |
| } | |
| @media (max-width: 640px) { | |
| .prognos-icon svg { | |
| width: 40px; | |
| height: 40px; | |
| } | |
| .prognos-icon { | |
| padding: 8px !important; | |
| } | |
| .prognos-icon span { | |
| font-size: 0.5rem !important; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body class="p-4"> | |
| <button onclick="toggleMenu()" | |
| class="fixed top-6 left-6 z-[110] p-3 bg-[#2d2d2d] rounded-md border border-gray-700 shadow-lg"> | |
| <div class="w-6 h-0.5 bg-white mb-1.5"></div> | |
| <div class="w-6 h-0.5 bg-white mb-1.5"></div> | |
| <div class="w-6 h-0.5 bg-white"></div> | |
| </button> | |
| <div id="menu-overlay" onclick="toggleMenu()" | |
| class="fixed inset-0 bg-black opacity-0 pointer-events-none z-90 transition-opacity duration-300"></div> | |
| <nav id="side-menu" | |
| class="fixed top-0 left-0 h-full w-64 bg-[#1a1a1a] p-6 shadow-2xl transform -translate-x-full border-r border-gray-800 text-center"> | |
| <h2 class="text-cyan-500 font-bold text-xl mb-8 mt-16 uppercase tracking-widest">Meny</h2> | |
| <a href="https://vader.domsten.nu/add_on/prognos/prognos.php" target="_blank" | |
| class="block p-3 text-white hover:bg-gray-800 rounded">Prognos vind & vattennivå</a> | |
| <a href="https://domstensbatklubb.se/" target="_blank" | |
| class="block p-3 text-white hover:bg-gray-800 rounded mb-2">Domstens Båtklubb</a> | |
| <a href="https://domsten.nu" target="_blank" | |
| class="block p-3 text-white hover:bg-gray-800 rounded mb-2">Domstens hemsida</a> | |
| <a href="https://vader.domsten.nu/wl_summary.php" target="_blank" | |
| class="block p-3 text-white hover:bg-gray-800 rounded">Davis Weatherlink summary</a> | |
| <a href="https://www.wunderground.com/dashboard/pws/IHELSING326?cm_ven=localwx_pwsdash" target="_blank" | |
| class="block p-3 text-white hover:bg-gray-800 rounded">Väder statistik</a> | |
| <a href="https://pysselilivet.blogspot.com/2026/04/dyi-weather-template-with-data-from.html" target="_blank" | |
| class="block p-3 text-white hover:bg-gray-800 rounded">WEB-site DIY guide</a> | |
| </nav> | |
| <div class="max-w-6xl mx-auto"> | |
| <header class="mb-6 flex justify-between items-center border-b border-gray-800 pb-4 pl-24"> | |
| <div> | |
| <h1 class="text-2xl font-light uppercase">Väderstation <span class="font-bold text-cyan-500">Live</span> | |
| </h1> | |
| <a href="https://maps.app.goo.gl/L8YWFU5qoh5sFpDq7" target="_blank" | |
| class="text-white/80 text-[10px] tracking-widest uppercase underline decoration-cyan-500/50 underline-offset-4 hover:text-cyan-400"> | |
| 📍 Domsten, Sverige | |
| </a> | |
| </div> | |
| <div class="text-right"> | |
| <p class="text-[10px] opacity-100 uppercase mb-1">Senast uppdaterad</p> | |
| <p id="obs-time" class="text-2xl font-mono">--:--</p> | |
| <p id="obs-date" class="text-[10px] opacity-50 uppercase">-----</p> | |
| </div> | |
| </header> | |
| <!-- Ute temperatur boxen --> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
| <div class="card"> | |
| <p class="label">Ute temperatur</p> | |
| <div class="value-container"> | |
| <div class="value" id="temp-out">--<span class="unit">°C</span></div> | |
| </div> | |
| <div class="bottom-info text-[10px] uppercase opacity-60 gap-4"> | |
| <div>Daggpunkt: <span id="dew-point" class="text-white opacity-100">--</span>°C</div> | |
| <div class="mt-0.5">Känns som: <span id="feels-like" class="text-white opacity-100">--</span>°C | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Vatten temperatur boxen --> | |
| <div class="card"> | |
| <p class="label">Vatten temperatur</p> | |
| <div class="value-container"> | |
| <div class="value text-cyan-400" id="water-temp">--<span class="unit">°C</span></div> | |
| </div> | |
| <div class="bottom-info flex flex-col"> | |
| <p class="text-[10px] opacity-50 uppercase">Vattennivå</p> | |
| <p class="text-lg font-bold text-cyan-400" id="water-level">--</p> | |
| </div> | |
| </div> | |
| <!-- Vindriktnings boxen --> | |
| <div class="card row-span-1 md:row-span-2"> | |
| <p class="label">Vindriktning</p> | |
| <div class="value-container"> | |
| <div | |
| class="relative w-52 h-52 border-2 border-white/20 rounded-full flex items-center justify-center"> | |
| <span class="absolute top-2 text-base font-bold">N</span> | |
| <span class="absolute bottom-2 text-base font-bold">S</span> | |
| <span class="absolute left-2 text-base font-bold">V</span> | |
| <span class="absolute right-2 text-base font-bold">Ö</span> | |
| <div id="wind-arrow-container" | |
| class="absolute inset-0 flex justify-center pt-2 transition-transform duration-1000"> | |
| <svg width="16" height="36" viewBox="0 0 16 36" fill="none" xmlns="..."> | |
| <line x1="8" y1="0" x2="8" y2="22" stroke="#34d399" stroke-width="2.5" /> | |
| <polygon points="0,22 8,36 16,22" fill="#34d399" /> | |
| </svg> | |
| </div> | |
| <div class="text-center z-10 bg-[#1e1e1e] px-4 py-2 rounded-full border border-gray-700"> | |
| <div class="text-4xl font-bold" id="wind-deg">--</div> | |
| <div class="text-[10px] opacity-40">GRADER</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Vind boxen --> | |
| <div class="card md:col-span-2 flex-row !justify-around items-center py-4"> | |
| <div class="text-center"> | |
| <p class="label">Vind (Snitt 10 minuter)</p> | |
| <div class="value text-emerald-400" id="wind-speed">--<span class="unit">m/s</span></div> | |
| </div> | |
| <div class="h-16 w-px bg-gray-800"></div> | |
| <div class="text-center"> | |
| <p class="label">Byvind</p> | |
| <div class="value text-emerald-400" id="wind-gust">--<span class="unit">m/s</span></div> | |
| </div> | |
| <div class="h-16 w-px bg-gray-800"></div> | |
| <a href="https://vader.domsten.nu/add_on/prognos/prognos.php" target="_blank" class="prognos-icon" | |
| style="display:flex;flex-direction:column;align-items:center;gap:8px;text-decoration:none; | |
| background:#141414;border:1px solid #2d2d2d;border-radius:10px;padding:12px 16px;"> | |
| <svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| <line x1="32" y1="8" x2="32" y2="30" stroke="#00bcd4" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <line x1="6" y1="16" x2="58" y2="16" stroke="#00bcd4" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <polygon points="4,16 18,9 18,23" fill="#00bcd4" /> | |
| <path d="M46,16 Q52,8 62,11 Q55,16 62,21 Q52,24 46,16 Z" fill="#00bcd4" opacity="0.9" /> | |
| <circle cx="32" cy="16" r="2.5" fill="#00bcd4" /> | |
| <line x1="23" y1="10" x2="41" y2="22" stroke="#00bcd4" stroke-width="2" | |
| stroke-linecap="round" /> | |
| <line x1="41" y1="10" x2="23" y2="22" stroke="#00bcd4" stroke-width="2" | |
| stroke-linecap="round" /> | |
| <path d="M8 37 Q13 33 18 37 Q23 41 28 37 Q33 33 38 37 Q43 41 48 37" stroke="#00bcd4" | |
| stroke-width="2" fill="none" stroke-linecap="round" /> | |
| <path d="M8 43 Q13 39 18 43 Q23 47 28 43 Q33 39 38 43 Q43 47 48 43" stroke="#00bcd4" | |
| stroke-width="2" fill="none" stroke-linecap="round" /> | |
| <path d="M8 49 Q13 45 18 49 Q23 53 28 49 Q33 45 38 49 Q43 53 48 49" stroke="#00bcd4" | |
| stroke-width="2" fill="none" stroke-linecap="round" opacity="0.55" /> | |
| <line x1="56" y1="36" x2="56" y2="52" stroke="#00bcd4" stroke-width="2" | |
| stroke-linecap="round" /> | |
| <polygon points="56,30 52,38 60,38" fill="#00bcd4" /> | |
| <polygon points="56,58 52,50 60,50" fill="#00bcd4" /> | |
| </svg> | |
| <span | |
| style="font-size:0.6rem;letter-spacing:0.12em;text-transform:uppercase;color:#00bcd4;font-weight:500;text-align:center;line-height:1.4;"> | |
| Prognos<br><span style="opacity:0.7;font-size:0.55rem;">vind & vattennivå</span> | |
| </span> | |
| </a> | |
| </div> | |
| <!-- Lufttrycks boxen --> | |
| <div class="card"> | |
| <p class="label">Lufttryck</p> | |
| <div class="value-container"> | |
| <div class="value" id="pressure">--<span class="unit">hPa</span></div> | |
| </div> | |
| <div id="press-trend-icon" class="bottom-info text-sm font-bold tracking-widest">--</div> | |
| </div> | |
| <!-- Solen upp/ner boxen --> | |
| <div class="card"> | |
| <p class="label">Solen upp/ner</p> | |
| <div class="value-container flex justify-around items-center"> | |
| <div class="text-center flex-1"> | |
| <p class="text-[3rem] font-bold text-yellow-500 leading-none" id="sunrise">--:--</p> | |
| </div> | |
| <div class="w-px h-10 bg-gray-800 mx-2"></div> | |
| <div class="text-center flex-1"> | |
| <p class="text-[3rem] font-bold text-orange-600 leading-none" id="sunset">--:--</p> | |
| </div> | |
| </div> | |
| <div class="bottom-info" style="justify-content: center;"> | |
| <svg width="38" height="38" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| <line x1="16" y1="1" x2="16" y2="6" stroke="#FFD700" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <line x1="16" y1="26" x2="16" y2="31" stroke="#FFD700" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <line x1="1" y1="16" x2="6" y2="16" stroke="#FFD700" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <line x1="26" y1="16" x2="31" y2="16" stroke="#FFD700" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <line x1="4.5" y1="4.5" x2="8.0" y2="8.0" stroke="#FFD700" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <line x1="24.0" y1="24.0" x2="27.5" y2="27.5" stroke="#FFD700" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <line x1="27.5" y1="4.5" x2="24.0" y2="8.0" stroke="#FFD700" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <line x1="8.0" y1="24.0" x2="4.5" y2="27.5" stroke="#FFD700" stroke-width="2.5" | |
| stroke-linecap="round" /> | |
| <circle cx="16" cy="16" r="6.5" fill="#FFD700" /> | |
| </svg> | |
| </div> | |
| </div> | |
| <!-- Max byvind & Regn idag boxen --> | |
| <div class="card"> | |
| <p class="label">Max byvind & Regn idag</p> | |
| <div class="value-container flex justify-around items-start pt-4"> | |
| <div class="text-center flex-1"> | |
| <p class="text-[3rem] font-bold text-emerald-400 leading-none" id="day-max-gust">--<span | |
| class="unit">m/s</span></p> | |
| <p class="text-[10px] opacity-50 uppercase mt-1">Max kl: <span id="day-max-time" | |
| class="text-emerald-400 opacity-100">--:--</span></p> | |
| </div> | |
| <div class="w-px h-16 bg-gray-800 mx-2"></div> | |
| <div class="text-center flex-1"> | |
| <p class="text-[3rem] font-bold text-blue-500 leading-none overflow-hidden" id="rain-day"> | |
| --<span class="unit">mm</span></p> | |
| <p class="text-[10px] mt-1 opacity-0">-</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| function toggleMenu() { | |
| const menu = document.getElementById('side-menu'); | |
| const overlay = document.getElementById('menu-overlay'); | |
| const isOpen = menu.style.transform === 'translateX(0px)'; | |
| menu.style.transform = isOpen ? 'translateX(-100%)' : 'translateX(0px)'; | |
| overlay.style.opacity = isOpen ? '0' : '0.5'; | |
| overlay.style.pointerEvents = isOpen ? 'none' : 'auto'; | |
| } | |
| const FtoC = (f) => f ? ((parseFloat(f) - 32) * 5 / 9).toFixed(1) : "--"; | |
| const MphToMs = (mph) => mph ? (parseFloat(mph) * 0.44704).toFixed(1) : "--"; | |
| const InToMm = (inch) => inch ? (parseFloat(inch) * 25.4).toFixed(1) : "--"; | |
| const InToCm = (inch) => inch ? (parseFloat(inch) * 2.54).toFixed(1) : "--"; | |
| const InHgToHpa = (inhg) => inhg ? (parseFloat(inhg) * 33.8639).toFixed(0) : "--"; | |
| function updateSunTimes() { | |
| fetch(`https://api.sunrise-sunset.org/json?lat=56.117&lng=12.603&formatted=0`) | |
| .then(res => res.json()) | |
| .then(data => { | |
| const rise = new Date(data.results.sunrise); | |
| const set = new Date(data.results.sunset); | |
| document.getElementById('sunrise').innerText = rise.toLocaleTimeString('sv-SE', { hour: '2-digit', minute: '2-digit' }); | |
| document.getElementById('sunset').innerText = set.toLocaleTimeString('sv-SE', { hour: '2-digit', minute: '2-digit' }); | |
| }).catch(() => { }); | |
| } | |
| async function updateUI() { | |
| try { | |
| const response = await fetch('add_on/realtime.txt?t=' + new Date().getTime()); | |
| const text = await response.text(); | |
| const data = text.trim().split(/\s+/); | |
| if (data.length < 50) return; | |
| document.getElementById('obs-time').innerText = data[1].substring(0, 5); | |
| const d = data[0].split('/'); | |
| if (d.length === 3) { | |
| document.getElementById('obs-date').innerText = `20${d[2]}-${d[1]}-${d[0]}`; | |
| } | |
| document.getElementById('temp-out').innerHTML = FtoC(data[2]) + '<span class="unit">°C</span>'; | |
| document.getElementById('dew-point').innerText = FtoC(data[4]); | |
| document.getElementById('feels-like').innerText = FtoC(data[24]); | |
| document.getElementById('wind-speed').innerHTML = MphToMs(data[6]) + '<span class="unit">m/s</span>'; | |
| document.getElementById('wind-gust').innerHTML = MphToMs(data[40]) + '<span class="unit">m/s</span>'; | |
| document.getElementById('wind-deg').innerText = data[7]; | |
| document.getElementById('wind-arrow-container').style.transform = `rotate(${data[7]}deg)`; | |
| document.getElementById('pressure').innerHTML = InHgToHpa(data[10]) + '<span class="unit">hPa</span>'; | |
| const trendVal = parseFloat(data[18]); | |
| document.getElementById('press-trend-icon').innerText = trendVal > 0.5 ? "↑ STIGANDE" : (trendVal < -0.5 ? "↓ SJUNKANDE" : "→ STABILT"); | |
| document.getElementById('water-temp').innerHTML = FtoC(data[64]) + '<span class="unit">°C</span>'; | |
| document.getElementById('water-level').innerHTML = InToCm(data[65]) + '<span class="unit uppercase" style="font-size:10px; opacity:0.4"> cm</span>'; | |
| document.getElementById('day-max-gust').innerHTML = MphToMs(data[32]) + '<span class="unit">m/s</span>'; | |
| document.getElementById('day-max-time').innerText = data[33]; | |
| document.getElementById('rain-day').innerHTML = InToMm(data[9]) + '<span class="unit">mm</span>'; | |
| } catch (err) { console.error("Kunde inte ladda realtime.txt"); } | |
| } | |
| async function mainLoop() { | |
| try { await fetch('add_on/cumulusdata.php'); } catch (err) { } | |
| updateUI(); | |
| } | |
| mainLoop(); | |
| updateSunTimes(); | |
| setInterval(mainLoop, 60000); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment