Skip to content

Instantly share code, notes, and snippets.

@MatsA
Last active April 25, 2026 16:49
Show Gist options
  • Select an option

  • Save MatsA/da974732172378cc3806939b7d3aacae to your computer and use it in GitHub Desktop.

Select an option

Save MatsA/da974732172378cc3806939b7d3aacae to your computer and use it in GitHub Desktop.
Weather template, html. Link to blogpost in the code !
<!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 &amp; 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