lobsterboard 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lobsterboard.css
CHANGED
package/dist/lobsterboard.esm.js
CHANGED
package/dist/lobsterboard.umd.js
CHANGED
package/js/widgets.js
CHANGED
|
@@ -332,29 +332,35 @@ const WIDGETS = {
|
|
|
332
332
|
</div>
|
|
333
333
|
</div>`,
|
|
334
334
|
generateJs: (props) => `
|
|
335
|
-
// Weather Widget: ${props.id} (uses free
|
|
335
|
+
// Weather Widget: ${props.id} (uses free Open-Meteo API - no key needed)
|
|
336
|
+
const WMO_DESC = {0:'Clear sky',1:'Mainly clear',2:'Partly cloudy',3:'Overcast',45:'Fog',48:'Rime fog',51:'Light drizzle',53:'Drizzle',55:'Dense drizzle',61:'Slight rain',63:'Moderate rain',65:'Heavy rain',71:'Slight snow',73:'Moderate snow',75:'Heavy snow',80:'Slight showers',81:'Moderate showers',82:'Violent showers',95:'Thunderstorm',96:'Hail thunderstorm',99:'Heavy hail'};
|
|
337
|
+
function wmoIcon(code) {
|
|
338
|
+
if (code <= 1) return 'weather-sunny';
|
|
339
|
+
if (code <= 3) return 'weather-cloudy';
|
|
340
|
+
if (code >= 51 && code <= 82) return 'weather-rainy';
|
|
341
|
+
if (code >= 71 && code <= 77) return 'weather-snowy';
|
|
342
|
+
if (code >= 95) return 'weather-rainy';
|
|
343
|
+
return 'weather';
|
|
344
|
+
}
|
|
336
345
|
async function update_${props.id.replace(/-/g, '_')}() {
|
|
337
346
|
const valEl = document.getElementById('${props.id}-value');
|
|
338
347
|
const labelEl = document.getElementById('${props.id}-label');
|
|
339
348
|
const iconEl = document.getElementById('${props.id}-icon');
|
|
340
349
|
try {
|
|
341
|
-
const
|
|
342
|
-
const
|
|
350
|
+
const loc = '${props.location || 'Atlanta'}';
|
|
351
|
+
const geoRes = await fetch('https://geocoding-api.open-meteo.com/v1/search?name=' + encodeURIComponent(loc) + '&count=1');
|
|
352
|
+
const geoData = await geoRes.json();
|
|
353
|
+
if (!geoData.results || !geoData.results.length) throw new Error('City not found');
|
|
354
|
+
const {latitude, longitude} = geoData.results[0];
|
|
355
|
+
const tempUnit = '${props.units}' === 'C' ? 'celsius' : 'fahrenheit';
|
|
356
|
+
const res = await fetch('https://api.open-meteo.com/v1/forecast?latitude=' + latitude + '&longitude=' + longitude + '¤t=temperature_2m,weathercode,windspeed_10m&temperature_unit=' + tempUnit);
|
|
343
357
|
const data = await res.json();
|
|
344
|
-
const
|
|
345
|
-
const temp = '${props.units}' === 'C' ? current.temp_C : current.temp_F;
|
|
358
|
+
const c = data.current;
|
|
346
359
|
const unit = '${props.units}' === 'C' ? '°C' : '°F';
|
|
347
|
-
valEl.textContent =
|
|
348
|
-
labelEl.textContent =
|
|
349
|
-
|
|
350
|
-
const code = parseInt(current.weatherCode);
|
|
351
|
-
let iconId = 'weather';
|
|
352
|
-
if (code === 113) iconId = 'weather-sunny';
|
|
353
|
-
else if (code === 116 || code === 119) iconId = 'weather-cloudy';
|
|
354
|
-
else if (code >= 176 && code <= 359) iconId = 'weather-rainy';
|
|
355
|
-
else if (code >= 368 && code <= 395) iconId = 'weather-snowy';
|
|
360
|
+
valEl.textContent = Math.round(c.temperature_2m) + unit;
|
|
361
|
+
labelEl.textContent = WMO_DESC[c.weathercode] || 'Unknown';
|
|
362
|
+
const iconId = wmoIcon(c.weathercode);
|
|
356
363
|
iconEl.setAttribute('data-icon', iconId);
|
|
357
|
-
// Update emoji fallback for non-themed views
|
|
358
364
|
const icons = window.WIDGET_ICONS || {};
|
|
359
365
|
iconEl.textContent = icons[iconId] ? icons[iconId].emoji : '🌡️';
|
|
360
366
|
} catch (e) {
|
|
@@ -399,35 +405,42 @@ const WIDGETS = {
|
|
|
399
405
|
</div>
|
|
400
406
|
</div>`,
|
|
401
407
|
generateJs: (props) => `
|
|
402
|
-
// Multi Weather Widget: ${props.id} (uses free
|
|
408
|
+
// Multi Weather Widget: ${props.id} (uses free Open-Meteo API - no key needed)
|
|
409
|
+
const WMO_DESC2 = {0:'Clear',1:'Clear',2:'Partly cloudy',3:'Overcast',45:'Fog',48:'Rime fog',51:'Drizzle',53:'Drizzle',55:'Drizzle',61:'Rain',63:'Rain',65:'Heavy rain',71:'Snow',73:'Snow',75:'Heavy snow',80:'Showers',81:'Showers',82:'Showers',95:'Storm',96:'Hail',99:'Hail'};
|
|
410
|
+
function wmoIcon2(code) {
|
|
411
|
+
if (code <= 1) return 'weather-sunny';
|
|
412
|
+
if (code <= 3) return 'weather-cloudy';
|
|
413
|
+
if (code >= 51 && code <= 82) return 'weather-rainy';
|
|
414
|
+
if (code >= 71 && code <= 77) return 'weather-snowy';
|
|
415
|
+
if (code >= 95) return 'weather-rainy';
|
|
416
|
+
return 'weather';
|
|
417
|
+
}
|
|
403
418
|
async function update_${props.id.replace(/-/g, '_')}() {
|
|
404
419
|
const locations = '${props.locations || 'New York; London; Tokyo'}'.split(';').map(l => l.trim());
|
|
405
420
|
const container = document.getElementById('${props.id}-list');
|
|
406
|
-
const
|
|
407
|
-
const unitSymbol =
|
|
421
|
+
const tempUnit = '${props.units}' === 'C' ? 'celsius' : 'fahrenheit';
|
|
422
|
+
const unitSymbol = '${props.units}' === 'C' ? '°C' : '°F';
|
|
408
423
|
|
|
409
424
|
const results = await Promise.all(locations.map(async (loc) => {
|
|
410
425
|
try {
|
|
411
|
-
const
|
|
426
|
+
const geoRes = await fetch('https://geocoding-api.open-meteo.com/v1/search?name=' + encodeURIComponent(loc) + '&count=1');
|
|
427
|
+
const geoData = await geoRes.json();
|
|
428
|
+
if (!geoData.results || !geoData.results.length) return { loc, temp: 'N/A', iconId: 'weather', emoji: '❓' };
|
|
429
|
+
const {latitude, longitude} = geoData.results[0];
|
|
430
|
+
const res = await fetch('https://api.open-meteo.com/v1/forecast?latitude=' + latitude + '&longitude=' + longitude + '¤t=temperature_2m,weathercode&temperature_unit=' + tempUnit);
|
|
412
431
|
const data = await res.json();
|
|
413
|
-
const
|
|
414
|
-
const
|
|
415
|
-
const code = parseInt(current.weatherCode);
|
|
416
|
-
let iconId = 'weather';
|
|
417
|
-
if (code === 113) iconId = 'weather-sunny';
|
|
418
|
-
else if (code === 116 || code === 119) iconId = 'weather-cloudy';
|
|
419
|
-
else if (code >= 176 && code <= 359) iconId = 'weather-rainy';
|
|
420
|
-
else if (code >= 368 && code <= 395) iconId = 'weather-snowy';
|
|
432
|
+
const c = data.current;
|
|
433
|
+
const iconId = wmoIcon2(c.weathercode);
|
|
421
434
|
const icons = window.WIDGET_ICONS || {};
|
|
422
435
|
const emoji = icons[iconId] ? icons[iconId].emoji : '🌡️';
|
|
423
|
-
return { loc, temp, iconId, emoji
|
|
436
|
+
return { loc, temp: Math.round(c.temperature_2m), iconId, emoji };
|
|
424
437
|
} catch (e) {
|
|
425
|
-
return { loc, temp: 'N/A', iconId: 'weather', emoji: '❓'
|
|
438
|
+
return { loc, temp: 'N/A', iconId: 'weather', emoji: '❓' };
|
|
426
439
|
}
|
|
427
440
|
}));
|
|
428
441
|
|
|
429
442
|
container.innerHTML = results.map(r =>
|
|
430
|
-
'<div class="weather-row"><span class="weather-icon lb-icon" data-icon="' + _esc(r.iconId) + '">' + _esc(r.emoji) + '</span><span class="weather-loc">' + _esc(r.loc) + '</span><span class="weather-temp">' + _esc(r.temp) + _esc(unitSymbol) + '</span></div>'
|
|
443
|
+
'<div class="weather-row"><span class="weather-icon lb-icon" data-icon="' + _esc(r.iconId) + '">' + _esc(r.emoji) + '</span><span class="weather-loc">' + _esc(r.loc) + '</span><span class="weather-temp">' + _esc(String(r.temp)) + _esc(unitSymbol) + '</span></div>'
|
|
431
444
|
).join('');
|
|
432
445
|
}
|
|
433
446
|
update_${props.id.replace(/-/g, '_')}();
|
|
@@ -3728,32 +3741,34 @@ const WIDGETS = {
|
|
|
3728
3741
|
</div>
|
|
3729
3742
|
</div>`,
|
|
3730
3743
|
generateJs: (props) => `
|
|
3731
|
-
// World Clock Widget: ${props.id} (
|
|
3744
|
+
// World Clock Widget: ${props.id} (pure Intl.DateTimeFormat - no API needed)
|
|
3745
|
+
const CITY_TZ_MAP = {
|
|
3746
|
+
'New York': 'America/New_York', 'Los Angeles': 'America/Los_Angeles', 'Chicago': 'America/Chicago',
|
|
3747
|
+
'London': 'Europe/London', 'Paris': 'Europe/Paris', 'Berlin': 'Europe/Berlin',
|
|
3748
|
+
'Tokyo': 'Asia/Tokyo', 'Sydney': 'Australia/Sydney', 'Dubai': 'Asia/Dubai',
|
|
3749
|
+
'Singapore': 'Asia/Singapore', 'Hong Kong': 'Asia/Hong_Kong', 'Mumbai': 'Asia/Kolkata',
|
|
3750
|
+
'Shanghai': 'Asia/Shanghai', 'Seoul': 'Asia/Seoul', 'Moscow': 'Europe/Moscow',
|
|
3751
|
+
'Istanbul': 'Europe/Istanbul', 'Bangkok': 'Asia/Bangkok', 'Toronto': 'America/Toronto',
|
|
3752
|
+
'Heidenheim': 'Europe/Berlin', 'Vienna': 'Europe/Vienna', 'Zurich': 'Europe/Zurich',
|
|
3753
|
+
'Amsterdam': 'Europe/Amsterdam', 'Rome': 'Europe/Rome', 'Madrid': 'Europe/Madrid',
|
|
3754
|
+
'São Paulo': 'America/Sao_Paulo', 'Mexico City': 'America/Mexico_City',
|
|
3755
|
+
'Graz': 'Europe/Vienna', 'Munich': 'Europe/Berlin', 'Frankfurt': 'Europe/Berlin',
|
|
3756
|
+
'Santiago': 'America/Santiago', 'Lima': 'America/Lima'
|
|
3757
|
+
};
|
|
3732
3758
|
const locs_${props.id.replace(/-/g, '_')} = '${props.locations || 'New York; London; Tokyo'}'.split(';').map(s => s.trim());
|
|
3733
3759
|
const hour12_${props.id.replace(/-/g, '_')} = ${!props.format24h};
|
|
3734
3760
|
|
|
3735
|
-
|
|
3761
|
+
function update_${props.id.replace(/-/g, '_')}() {
|
|
3736
3762
|
const container = document.getElementById('${props.id}-clocks');
|
|
3737
|
-
const
|
|
3763
|
+
const now = new Date();
|
|
3764
|
+
const results = locs_${props.id.replace(/-/g, '_')}.map(loc => {
|
|
3765
|
+
const tz = CITY_TZ_MAP[loc] || CITY_TZ_MAP[Object.keys(CITY_TZ_MAP).find(k => k.toLowerCase() === loc.toLowerCase())] || null;
|
|
3766
|
+
if (!tz) return { city: loc, time: '(unknown tz)' };
|
|
3738
3767
|
try {
|
|
3739
|
-
const
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
const localTime = data.current_condition[0].localObsDateTime;
|
|
3744
|
-
// Parse the time from format "2026-02-07 12:30 AM"
|
|
3745
|
-
const timePart = localTime.split(' ').slice(1).join(' ');
|
|
3746
|
-
let displayTime = timePart;
|
|
3747
|
-
if (!hour12_${props.id.replace(/-/g, '_')}) {
|
|
3748
|
-
// Convert to 24h if needed
|
|
3749
|
-
const d = new Date('2000-01-01 ' + timePart);
|
|
3750
|
-
displayTime = d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' });
|
|
3751
|
-
}
|
|
3752
|
-
return { city, time: displayTime, ok: true };
|
|
3753
|
-
} catch (e) {
|
|
3754
|
-
return { city: loc, time: '—', ok: false };
|
|
3755
|
-
}
|
|
3756
|
-
}));
|
|
3768
|
+
const fmt = new Intl.DateTimeFormat('en-GB', { timeZone: tz, hour: '2-digit', minute: '2-digit', hour12: hour12_${props.id.replace(/-/g, '_')} });
|
|
3769
|
+
return { city: loc, time: fmt.format(now) };
|
|
3770
|
+
} catch(e) { return { city: loc, time: '—' }; }
|
|
3771
|
+
});
|
|
3757
3772
|
container.innerHTML = results.map(r =>
|
|
3758
3773
|
'<div class="tz-row"><span class="tz-city">' + r.city + '</span><span class="tz-time">' + r.time + '</span></div>'
|
|
3759
3774
|
).join('');
|
package/package.json
CHANGED