{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"sunrise-sunset","type":"registry:component","title":"Sunrise & Sunset","description":"Approximate daylight times from configured coordinates and date.","author":"Notion Arena","categories":["dashboards"],"tags":["widget","free","sunrise","sunset","daylight","location","weather"],"meta":{"kind":"widget","tier":"free","version":"1.0.0","updatedAt":"2026-10-11","notionPlan":"Free","emoji":"🌅","delivery":["embed","html-block","download"],"capabilities":{"interactive":true,"offlineSafe":true,"persistsLocally":false,"writesToNotion":false,"needsNetwork":false},"embedUrl":"https://notionarena.vercel.app/embed/sunrise-sunset","fileUrl":"https://notionarena.vercel.app/widgets/sunrise-sunset.html","downloadUrl":"https://notionarena.vercel.app/api/widget/sunrise-sunset","height":260,"minHeight":210,"maxHeight":360,"params":[{"key":"label","label":"Widget title","type":"text","default":"Sunrise & sunset"},{"key":"place","label":"Place label","type":"text","default":"Islamabad"},{"key":"lat","label":"Latitude","type":"number","default":33.6844,"min":-90,"max":90,"step":0.0001},{"key":"lon","label":"Longitude","type":"number","default":73.0479,"min":-180,"max":180,"step":0.0001},{"key":"timezone","label":"Time zone","type":"text","default":"Asia/Karachi","help":"IANA zone, for example Europe/London."},{"key":"date","label":"Date","type":"date","default":"","help":"Blank uses today's local date."},{"key":"accent","label":"Accent","type":"color","default":"#d9730d"},{"key":"theme","label":"Theme","type":"select","default":"auto","options":[{"value":"auto","label":"Match Notion"},{"value":"light","label":"Light"},{"value":"dark","label":"Dark"}]}]},"files":[{"path":"widgets/sunrise-sunset.html","type":"registry:file","target":"notion/widgets/sunrise-sunset.html","content":"<!doctype html>\n<html lang=\"en\" data-theme=\"auto\">\n<head>\n<meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<title>Sunrise and Sunset</title>\n<style>\n:root{--bg:#fff;--fg:#37352f;--muted:#787774;--surface:#f7f7f5;--border:#e9e9e7;--accent:#d9730d;--font:ui-sans-serif,-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif}\nhtml[data-theme=\"dark\"]{--bg:#191919;--fg:#e6e6e4;--muted:#9b9a97;--surface:#252525;--border:#343434}\n@media(prefers-color-scheme:dark){html[data-theme=\"auto\"]{--bg:#191919;--fg:#e6e6e4;--muted:#9b9a97;--surface:#252525;--border:#343434}}\n*{box-sizing:border-box}html,body{margin:0;height:100%}body{background:var(--bg);color:var(--fg);font-family:ui-sans-serif,-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;overflow:hidden}\n.wrap{height:100%;min-height:230px;display:flex;flex-direction:column;gap:10px;padding:14px;overflow:auto}.head{display:flex;align-items:center;justify-content:space-between;gap:8px}.kicker{font-size:9px;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:650}.title{font-size:14px;font-weight:650;margin-top:2px}.date{width:130px;height:30px;border:1px solid var(--border);border-radius:7px;background:var(--surface);color:var(--fg);padding:4px 6px;font:inherit;font-size:10px}\n.times{display:grid;grid-template-columns:1fr 1fr;gap:8px;flex:1}.time-card{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;border:1px solid var(--border);border-radius:10px;background:var(--surface);padding:9px}.icon{font-size:22px}.label{font-size:9px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-weight:650}.value{font-size:clamp(22px,7vw,34px);font-weight:650;letter-spacing:-.04em;color:var(--accent);font-variant-numeric:tabular-nums}.daylength{text-align:center;font-size:10px;color:var(--muted)}.note{font-size:9px;color:var(--muted);text-align:center;line-height:1.35}\n@media(max-width:340px){.wrap{padding:10px}.date{width:112px}.value{font-size:23px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}\n</style>\n</head>\n<body><main class=\"wrap\">\n  <header class=\"head\"><div><div class=\"kicker\" id=\"location\">Solar times</div><div class=\"title\" id=\"title\">Sunrise & sunset</div></div><input class=\"date\" id=\"date\" type=\"date\" aria-label=\"Choose date\" /></header>\n  <section class=\"times\"><div class=\"time-card\"><span class=\"icon\" aria-hidden=\"true\">🌅</span><span class=\"label\">Sunrise</span><span class=\"value\" id=\"sunrise\">--:--</span></div><div class=\"time-card\"><span class=\"icon\" aria-hidden=\"true\">🌇</span><span class=\"label\">Sunset</span><span class=\"value\" id=\"sunset\">--:--</span></div></section>\n  <div class=\"daylength\" id=\"daylength\"></div>\n  <div class=\"note\" id=\"note\">Approximate solar calculation from configured coordinates. No location access or network service.</div>\n</main>\n<script>\n(function(){\n  var cfgEl=document.getElementById('bk-config'),base={};try{base=cfgEl?JSON.parse(cfgEl.textContent||'{}'):{};}catch(e){}\n  var q=new URLSearchParams(location.search),c={};for(var k in base)c[k]=base[k];q.forEach(function(v,k){c[k]=v;});\n  function safeColor(v,d){return /^#[0-9a-f]{6}$/i.test(String(v||''))?String(v):d;}\n  function iso(d){return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0');}\n  var theme=['auto','light','dark'].indexOf(String(c.theme||'auto'))>-1?String(c.theme||'auto'):'auto',ACCENT=safeColor(c.accent,'#d9730d'),LABEL=String(c.label||'Sunrise & sunset').slice(0,48),PLACE=String(c.place||'Configured location').slice(0,40),TZ=String(c.timezone||'');\n  document.documentElement.setAttribute('data-theme',theme);document.documentElement.style.setProperty('--accent',ACCENT);document.getElementById('title').textContent=LABEL;document.getElementById('location').textContent=PLACE;document.title=LABEL;\n  var dateInput=document.getElementById('date');\n  var lat=Math.max(-90,Math.min(90,parseFloat(c.lat))),lon=Math.max(-180,Math.min(180,parseFloat(c.lon)));\n  if(!isFinite(lat))lat=33.6844;if(!isFinite(lon))lon=73.0479;\n  if(TZ){try{new Intl.DateTimeFormat(undefined,{timeZone:TZ}).format(new Date());}catch(e){TZ='';}}\n  dateInput.value=/^\\d{4}-\\d{2}-\\d{2}$/.test(String(c.date||''))?String(c.date):iso(new Date());\n  function rad(n){return n*Math.PI/180;}function deg(n){return n*180/Math.PI;}function norm(n,m){return((n%m)+m)%m;}\n  function offsetHours(year,month,day){var noon=Date.UTC(year,month-1,day,12),parts=new Intl.DateTimeFormat('en-US',{timeZone:TZ||undefined,year:'numeric',month:'numeric',day:'numeric',hour:'numeric',minute:'numeric',hourCycle:'h23'}).formatToParts(new Date(noon)),p={};parts.forEach(function(x){p[x.type]=x.value;});return(Date.UTC(Number(p.year),Number(p.month)-1,Number(p.day),Number(p.hour),Number(p.minute))-noon)/3600000;}\n  function solar(sunrise,year,month,day){\n    var N=Math.floor((Date.UTC(year,month-1,day)-Date.UTC(year,0,0))/864e5),lngHour=lon/15,t=N+((sunrise?6:18)-lngHour)/24,M=.9856*t-3.289,L=norm(M+1.916*Math.sin(rad(M))+.020*Math.sin(2*rad(M))+282.634,360),RA=norm(deg(Math.atan(.91764*Math.tan(rad(L)))),360);\n    var Lq=Math.floor(L/90)*90,RAq=Math.floor(RA/90)*90;RA=(RA+(Lq-RAq))/15;\n    var sinDec=.39782*Math.sin(rad(L)),cosDec=Math.cos(Math.asin(sinDec)),cosH=(Math.cos(rad(90.833))-sinDec*Math.sin(rad(lat)))/(cosDec*Math.cos(rad(lat)));\n    if(cosH>1||cosH< -1)return null;\n    var H=(sunrise?360-deg(Math.acos(cosH)):deg(Math.acos(cosH)))/15,Tlocal=H+RA-.06571*t-6.622,UT=norm(Tlocal-lngHour,24);\n    var dayShift=Math.floor((UT+offsetHours(year,month,day))/24);return Date.UTC(year,month-1,day)+(UT-dayShift*24)*3600000;\n  }\n  function format(timestamp){if(timestamp===null)return'No sunrise';try{return new Intl.DateTimeFormat(undefined,{timeZone:TZ||undefined,hour:'numeric',minute:'2-digit'}).format(new Date(timestamp));}catch(e){return new Date(timestamp).toLocaleTimeString(undefined,{hour:'numeric',minute:'2-digit'});}}\n  function paint(){var p=dateInput.value.split('-').map(Number);if(p.length!==3||!p[0])return;var rise=solar(true,p[0],p[1],p[2]),set=solar(false,p[0],p[1],p[2]);document.getElementById('sunrise').textContent=format(rise);document.getElementById('sunset').textContent=format(set);if(rise===null||set===null)document.getElementById('daylength').textContent='No sunrise or sunset at these coordinates on this date.';else{var minutes=Math.round((set-rise)/60000);document.getElementById('daylength').textContent='Daylight about '+Math.floor(minutes/60)+'h '+String(minutes%60).padStart(2,'0')+'m · '+(TZ||'viewer timezone');}}\n  dateInput.addEventListener('input',paint);paint();\n})();\n</script>\n</body>\n</html>\n"}]}