| 1 |
( function () { |
| 2 |
var el = wp.element.createElement; |
| 3 |
var Fragment = wp.element.Fragment; |
| 4 |
var __ = wp.i18n.__; |
| 5 |
var registerBlockType = wp.blocks.registerBlockType; |
| 6 |
var InspectorControls = wp.blockEditor.InspectorControls; |
| 7 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 8 |
var PanelColorSettings = wp.blockEditor.PanelColorSettings; |
| 9 |
var PanelBody = wp.components.PanelBody; |
| 10 |
var TextControl = wp.components.TextControl; |
| 11 |
var ToggleControl = wp.components.ToggleControl; |
| 12 |
var RangeControl = wp.components.RangeControl; |
| 13 |
var SelectControl = wp.components.SelectControl; |
| 14 |
|
| 15 |
var _tc, _tvf; |
| 16 |
Object.defineProperty(window, '_tc', { get: function () { return _tc || (_tc = window.bkbgTypographyControl); } }); |
| 17 |
Object.defineProperty(window, '_tvf', { get: function () { return _tvf || (_tvf = window.bkbgTypoCssVars); } }); |
| 18 |
function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); } |
| 19 |
function getTypoCssVars(attrs) { |
| 20 |
var v = {}; |
| 21 |
_tvf(v, 'tempTypo', attrs, '--bkww-tp-'); |
| 22 |
_tvf(v, 'cityTypo', attrs, '--bkww-ct-'); |
| 23 |
_tvf(v, 'metaTypo', attrs, '--bkww-mt-'); |
| 24 |
return v; |
| 25 |
} |
| 26 |
|
| 27 |
var UNITS = [ |
| 28 |
{ label: 'Celsius (°C)', value: 'metric' }, |
| 29 |
{ label: 'Fahrenheit (°F)', value: 'imperial' }, |
| 30 |
{ label: 'Kelvin (K)', value: 'standard' }, |
| 31 |
]; |
| 32 |
|
| 33 |
var LAYOUTS = [ |
| 34 |
{ label: 'Card (centered)', value: 'card' }, |
| 35 |
{ label: 'Wide (full-width)', value: 'wide' }, |
| 36 |
{ label: 'Minimal (compact)', value: 'minimal' }, |
| 37 |
]; |
| 38 |
|
| 39 |
var BG_STYLES = [ |
| 40 |
{ label: 'Gradient (auto by weather)', value: 'gradient' }, |
| 41 |
{ label: 'Custom color', value: 'custom' }, |
| 42 |
{ label: 'Transparent', value: 'transparent' }, |
| 43 |
]; |
| 44 |
|
| 45 |
var LANGS = [ |
| 46 |
{ label: 'English', value: 'en' }, |
| 47 |
{ label: 'Russian', value: 'ru' }, |
| 48 |
{ label: 'German', value: 'de' }, |
| 49 |
{ label: 'French', value: 'fr' }, |
| 50 |
{ label: 'Spanish', value: 'es' }, |
| 51 |
{ label: 'Japanese', value: 'ja' }, |
| 52 |
]; |
| 53 |
|
| 54 |
/* weather icon emoji map for editor preview */ |
| 55 |
function weatherIcon(code) { |
| 56 |
if (!code) return '🌤'; |
| 57 |
var c = String(code); |
| 58 |
if (c.startsWith('01')) return '☀️'; |
| 59 |
if (c.startsWith('02')) return '� |
| 60 |
'; |
| 61 |
if (c.startsWith('03') || c.startsWith('04')) return '☁️'; |
| 62 |
if (c.startsWith('09') || c.startsWith('10')) return '🌧'; |
| 63 |
if (c.startsWith('11')) return '⛈'; |
| 64 |
if (c.startsWith('13')) return '❄️'; |
| 65 |
if (c.startsWith('50')) return '🌫'; |
| 66 |
return '🌤'; |
| 67 |
} |
| 68 |
|
| 69 |
function unitLabel(units) { |
| 70 |
if (units === 'imperial') return '°F'; |
| 71 |
if (units === 'standard') return 'K'; |
| 72 |
return '°C'; |
| 73 |
} |
| 74 |
|
| 75 |
/* demo forecast data for editor preview */ |
| 76 |
var DEMO_FORECAST = [ |
| 77 |
{ day: 'Mon', icon: '☀️', hi: 22, lo: 14 }, |
| 78 |
{ day: 'Tue', icon: '� |
| 79 |
', hi: 19, lo: 12 }, |
| 80 |
{ day: 'Wed', icon: '🌧', hi: 15, lo: 10 }, |
| 81 |
{ day: 'Thu', icon: '☁️', hi: 17, lo: 11 }, |
| 82 |
{ day: 'Fri', icon: '☀️', hi: 24, lo: 16 }, |
| 83 |
]; |
| 84 |
|
| 85 |
function WeatherPreview(props) { |
| 86 |
var a = props.attributes; |
| 87 |
var deg = unitLabel(a.units); |
| 88 |
var wrapStyle = { |
| 89 |
background: a.backgroundStyle === 'gradient' |
| 90 |
? 'linear-gradient(135deg, #1e3a5f 0%, #2563eb 50%, #0f172a 100%)' |
| 91 |
: a.backgroundStyle === 'custom' ? a.customBg : 'transparent', |
| 92 |
borderRadius: a.borderRadius + 'px', |
| 93 |
padding: a.padding + 'px', |
| 94 |
maxWidth: a.layout === 'card' ? a.maxWidth + 'px' : '100%', |
| 95 |
margin: a.layout === 'card' ? '0 auto' : '0', |
| 96 |
color: a.textColor, |
| 97 |
fontFamily: 'inherit', |
| 98 |
}; |
| 99 |
var cardStyle = { |
| 100 |
background: a.cardBg, |
| 101 |
backdropFilter: 'blur(16px)', |
| 102 |
borderRadius: a.cardRadius + 'px', |
| 103 |
padding: '24px', |
| 104 |
border: '1px solid rgba(255,255,255,0.2)', |
| 105 |
}; |
| 106 |
|
| 107 |
return el('div', { style: wrapStyle }, |
| 108 |
el('div', { style: cardStyle }, |
| 109 |
/* top row: city + icon */ |
| 110 |
el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '12px' } }, |
| 111 |
el('div', null, |
| 112 |
el('div', { className: 'bkbg-ww-city-label', style: { opacity: 0.75, marginBottom: '4px' } }, |
| 113 |
'📍 ' + (a.city || 'Your City')), |
| 114 |
el('div', { className: 'bkbg-ww-temp' }, '22' + deg), |
| 115 |
el('div', { style: { fontSize: '15px', opacity: 0.85, marginTop: '4px' } }, 'Partly Cloudy'), |
| 116 |
), |
| 117 |
el('div', { style: { fontSize: '72px', lineHeight: 1 } }, '� |
| 118 |
') |
| 119 |
), |
| 120 |
/* feels like / hi-lo */ |
| 121 |
a.showFeelsLike && el('div', { style: { fontSize: '13px', opacity: 0.7, marginBottom: '16px' } }, |
| 122 |
'Feels like 20' + deg + ' · H: 25' + deg + ' L: 14' + deg), |
| 123 |
/* stats row */ |
| 124 |
el('div', { style: { display: 'flex', gap: '16px', flexWrap: 'wrap', marginBottom: a.showForecast ? '24px' : '0' } }, |
| 125 |
a.showHumidity && el('div', { style: { background: 'rgba(255,255,255,0.1)', borderRadius: '10px', padding: '10px 14px', flex: '1', minWidth: '80px', textAlign: 'center' } }, |
| 126 |
el('div', { style: { fontSize: '18px' } }, '💧'), |
| 127 |
el('div', { style: { fontSize: '14px', fontWeight: 600 } }, '68%'), |
| 128 |
el('div', { className: 'bkbg-ww-stat-lbl', style: { opacity: 0.7 } }, 'Humidity'), |
| 129 |
), |
| 130 |
a.showWind && el('div', { style: { background: 'rgba(255,255,255,0.1)', borderRadius: '10px', padding: '10px 14px', flex: '1', minWidth: '80px', textAlign: 'center' } }, |
| 131 |
el('div', { style: { fontSize: '18px' } }, '💨'), |
| 132 |
el('div', { style: { fontSize: '14px', fontWeight: 600 } }, '14 km/h'), |
| 133 |
el('div', { className: 'bkbg-ww-stat-lbl', style: { opacity: 0.7 } }, 'Wind'), |
| 134 |
), |
| 135 |
a.showPressure && el('div', { style: { background: 'rgba(255,255,255,0.1)', borderRadius: '10px', padding: '10px 14px', flex: '1', minWidth: '80px', textAlign: 'center' } }, |
| 136 |
el('div', { style: { fontSize: '18px' } }, '🌡'), |
| 137 |
el('div', { style: { fontSize: '14px', fontWeight: 600 } }, '1013 hPa'), |
| 138 |
el('div', { className: 'bkbg-ww-stat-lbl', style: { opacity: 0.7 } }, 'Pressure'), |
| 139 |
), |
| 140 |
), |
| 141 |
/* forecast */ |
| 142 |
a.showForecast && el('div', null, |
| 143 |
el('div', { style: { fontSize: '12px', fontWeight: 600, opacity: 0.7, textTransform: 'uppercase', letterSpacing: '1px', marginBottom: '10px' } }, '5-Day Forecast'), |
| 144 |
el('div', { style: { display: 'flex', gap: '8px' } }, |
| 145 |
DEMO_FORECAST.slice(0, a.forecastDays).map(function (f) { |
| 146 |
return el('div', { |
| 147 |
key: f.day, |
| 148 |
style: { background: a.forecastBg, borderRadius: '10px', padding: '10px 8px', flex: 1, textAlign: 'center' }, |
| 149 |
}, |
| 150 |
el('div', { style: { fontSize: '11px', opacity: 0.7, marginBottom: '4px' } }, f.day), |
| 151 |
el('div', { style: { fontSize: '20px', marginBottom: '4px' } }, f.icon), |
| 152 |
el('div', { style: { fontSize: '12px', fontWeight: 600 } }, f.hi + deg), |
| 153 |
el('div', { style: { fontSize: '11px', opacity: 0.6 } }, f.lo + deg), |
| 154 |
); |
| 155 |
}) |
| 156 |
) |
| 157 |
) |
| 158 |
), |
| 159 |
!a.apiKey && el('div', { style: { marginTop: '10px', padding: '8px 12px', background: 'rgba(255,165,0,0.2)', borderRadius: '8px', fontSize: '12px', color: '#fbbf24', border: '1px solid rgba(251,191,36,0.4)' } }, |
| 160 |
'⚠️ Add your OpenWeatherMap API key in the block settings to fetch live data.') |
| 161 |
); |
| 162 |
} |
| 163 |
|
| 164 |
registerBlockType('blockenberg/weather-widget', { |
| 165 |
edit: function (props) { |
| 166 |
var a = props.attributes; |
| 167 |
var set = props.setAttributes; |
| 168 |
|
| 169 |
return el(Fragment, null, |
| 170 |
el(InspectorControls, null, |
| 171 |
/* API */ |
| 172 |
el(PanelBody, { title: 'API & Location', initialOpen: true }, |
| 173 |
el(TextControl, { __nextHasNoMarginBottom: true, label: 'OpenWeatherMap API Key', value: a.apiKey, onChange: function (v) { set({ apiKey: v }); }, help: 'Free key from openweathermap.org' }), |
| 174 |
el(TextControl, { __nextHasNoMarginBottom: true, label: 'Default City', value: a.city, onChange: function (v) { set({ city: v }); }, help: 'e.g. London, New York, Tokyo' }), |
| 175 |
el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Auto-detect visitor location (Geolocation)', checked: a.autoLocation, onChange: function (v) { set({ autoLocation: v }); } }), |
| 176 |
el(SelectControl, { __nextHasNoMarginBottom: true, label: 'Units', value: a.units, options: UNITS, onChange: function (v) { set({ units: v }); } }), |
| 177 |
el(SelectControl, { __nextHasNoMarginBottom: true, label: 'Language', value: a.lang, options: LANGS, onChange: function (v) { set({ lang: v }); } }), |
| 178 |
el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Auto-refresh interval (minutes)', value: a.refreshInterval, min: 0, max: 60, step: 5, onChange: function (v) { set({ refreshInterval: v }); }, help: '0 = no refresh' }), |
| 179 |
), |
| 180 |
/* Display */ |
| 181 |
el(PanelBody, { title: 'Display Options', initialOpen: false }, |
| 182 |
el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show feels-like temperature', checked: a.showFeelsLike, onChange: function (v) { set({ showFeelsLike: v }); } }), |
| 183 |
el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show humidity', checked: a.showHumidity, onChange: function (v) { set({ showHumidity: v }); } }), |
| 184 |
el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show wind speed', checked: a.showWind, onChange: function (v) { set({ showWind: v }); } }), |
| 185 |
el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show pressure', checked: a.showPressure, onChange: function (v) { set({ showPressure: v }); } }), |
| 186 |
el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show visibility', checked: a.showVisibility, onChange: function (v) { set({ showVisibility: v }); } }), |
| 187 |
el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show animated weather icon', checked: a.showAnimatedIcon, onChange: function (v) { set({ showAnimatedIcon: v }); } }), |
| 188 |
el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show 5-day forecast', checked: a.showForecast, onChange: function (v) { set({ showForecast: v }); } }), |
| 189 |
a.showForecast && el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Forecast days', value: a.forecastDays, min: 2, max: 5, onChange: function (v) { set({ forecastDays: v }); } }), |
| 190 |
), |
| 191 |
/* Layout */ |
| 192 |
el(PanelBody, { title: 'Layout', initialOpen: false }, |
| 193 |
el(SelectControl, { __nextHasNoMarginBottom: true, label: 'Layout', value: a.layout, options: LAYOUTS, onChange: function (v) { set({ layout: v }); } }), |
| 194 |
a.layout === 'card' && el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Max width (px)', value: a.maxWidth, min: 280, max: 800, step: 10, onChange: function (v) { set({ maxWidth: v }); } }), |
| 195 |
el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Padding (px)', value: a.padding, min: 8, max: 64, onChange: function (v) { set({ padding: v }); } }), |
| 196 |
el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Outer radius (px)', value: a.borderRadius, min: 0, max: 48, onChange: function (v) { set({ borderRadius: v }); } }), |
| 197 |
el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Card radius (px)', value: a.cardRadius, min: 0, max: 32, onChange: function (v) { set({ cardRadius: v }); } }), |
| 198 |
), |
| 199 |
/* Typography */ |
| 200 |
el(PanelBody, { title: 'Typography', initialOpen: false }, |
| 201 |
getTypoControl( __( 'Temperature', 'blockenberg' ), 'tempTypo', a, set ), |
| 202 |
getTypoControl( __( 'City Label', 'blockenberg' ), 'cityTypo', a, set ), |
| 203 |
getTypoControl( __( 'Stat Labels', 'blockenberg' ), 'metaTypo', a, set ), |
| 204 |
), |
| 205 |
/* Colors */ |
| 206 |
el(PanelBody, { title: 'Background', initialOpen: false }, |
| 207 |
el(SelectControl, { __nextHasNoMarginBottom: true, label: 'Background style', value: a.backgroundStyle, options: BG_STYLES, onChange: function (v) { set({ backgroundStyle: v }); } }), |
| 208 |
a.backgroundStyle === 'custom' && el('div', { style: { marginTop: '8px' } }, |
| 209 |
el('label', { style: { display: 'block', fontSize: '12px', marginBottom: '4px' } }, 'Background color'), |
| 210 |
el('input', { type: 'color', value: a.customBg, onChange: function (e) { set({ customBg: e.target.value }); }, style: { width: '100%', height: '36px', border: 'none', borderRadius: '4px', cursor: 'pointer' } }) |
| 211 |
), |
| 212 |
), |
| 213 |
el(PanelColorSettings, { |
| 214 |
title: 'Colors', |
| 215 |
initialOpen: false, |
| 216 |
colorSettings: [ |
| 217 |
{ value: a.textColor, onChange: function (v) { set({ textColor: v || '#ffffff' }); }, label: 'Text color' }, |
| 218 |
{ value: a.accentColor, onChange: function (v) { set({ accentColor: v || '#60a5fa' }); }, label: 'Accent color' }, |
| 219 |
{ value: a.cardBg, onChange: function (v) { set({ cardBg: v || 'rgba(255,255,255,0.12)' }); }, label: 'Card background' }, |
| 220 |
{ value: a.forecastBg, onChange: function (v) { set({ forecastBg: v || 'rgba(255,255,255,0.08)' }); }, label: 'Forecast day background' }, |
| 221 |
], |
| 222 |
}), |
| 223 |
), |
| 224 |
el('div', useBlockProps({ style: getTypoCssVars(a) }), |
| 225 |
el(WeatherPreview, { attributes: a }) |
| 226 |
) |
| 227 |
); |
| 228 |
}, |
| 229 |
save: function (props) { |
| 230 |
var a = props.attributes; |
| 231 |
return el('div', useBlockProps.save({ style: getTypoCssVars(a) }), |
| 232 |
el('div', { className: 'bkbg-ww-app', 'data-opts': JSON.stringify(a) }) |
| 233 |
); |
| 234 |
}, |
| 235 |
}); |
| 236 |
}() ); |
| 237 |
|