class WeatherWidget extends HTMLElement { constructor() { super(); this.state = window.WeatherState; this.attachShadow({ mode: 'open' }); } connectedCallback() { this.render(); this.state.addListener(() => this.render()); this.setupEventListeners(); } setupEventListeners() { this.shadowRoot.addEventListener('click', (e) => { if (e.target.closest('[data-action="search"]')) { this.handleSearch(); } if (e.target.closest('[data-action="refresh"]')) { window.loadCurrentLocationWeather(); } if (e.target.closest('[data-action="location"]')) { this.toggleLocationSearch(); } }); this.shadowRoot.addEventListener('input', (e) => { if (e.target.name === 'location-search') { this.handleSearchInput(e.target.value); } }); this.shadowRoot.addEventListener('keypress', (e) => { if (e.key === 'Enter' && e.target.name === 'location-search') { this.handleSearch(); } }); } handleSearchInput(value) { const searchBtn = this.shadowRoot.querySelector('[data-action="search"]'); searchBtn.disabled = !value.trim(); } handleSearch() { const input = this.shadowRoot.querySelector('[name="location-search"]'); if (input.value.trim()) { window.searchLocation(input.value.trim()); input.value = ''; this.toggleLocationSearch(); } } toggleLocationSearch() { const searchContainer = this.shadowRoot.querySelector('.location-search-container'); searchContainer.classList.toggle('hidden'); if (!searchContainer.classList.contains('hidden')) { const input = this.shadowRoot.querySelector('[name="location-search"]'); input.focus(); } } render() { this.shadowRoot.innerHTML = `
${this.renderHeader()} ${this.renderContent()} ${this.renderForecast()} ${this.renderDetails()}
`; // Re-initialize feather icons if (window.feather) { setTimeout(() => window.feather.replace(), 0); } } renderHeader() { return `

Weather

${this.state.currentLocation}

`; } renderContent() { if (this.state.loading) { return this.renderLoading(); } if (this.state.error) { return this.renderError(); } if (!this.state.weatherData) { return this.renderEmpty(); } const { current } = this.state.weatherData; const temp = window.WeatherUtils.kelvinToCelsius(current.temp); const feelsLike = window.WeatherUtils.kelvinToCelsius(current.feels_like); const icon = window.WeatherUtils.getWeatherIcon(current.weather[0].icon); return `
${temp}°
${current.weather[0].description}
Feels like ${feelsLike}°
`; } renderForecast() { if (this.state.loading || this.state.error || !this.state.weatherData) { return ''; } const { daily } = this.state.weatherData; const forecastDays = daily.slice(1, 6); // Next 5 days return `

5-Day Forecast

${forecastDays.map(day => { const date = window.WeatherUtils.formatDate(day.dt); const temp = window.WeatherUtils.kelvinToCelsius(day.temp.day); const icon = window.WeatherUtils.getWeatherIcon(day.weather[0].icon); return `
${date}
${temp}°
`; }).join('')}
`; } renderDetails() { if (this.state.loading || this.state.error || !this.state.weatherData) { return ''; } const { current } = this.state.weatherData; return `

Details

Wind
${current.wind_speed} m/s
Humidity
${current.humidity}%
Pressure
${current.pressure} hPa
`; } renderLoading() { return `

Loading weather data...

`; } renderError() { return `

${this.state.error}

`; } renderEmpty() { return `

No weather data available

`; } } customElements.define('weather-widget', WeatherWidget);