diff --git a/js/widgets.js b/js/widgets.js
new file mode 100644
index 0000000..5d0318d
--- /dev/null
+++ b/js/widgets.js
@@ -0,0 +1,315 @@
+/**
+ * widgets.js - Dashboard widgets (time, weather, etc.)
+ */
+
+const STORAGE_KEY_WIDGETS = 'enabled-widgets';
+
+// Widget configurations
+const widgetConfigs = {
+ clock: {
+ name: 'Clock',
+ icon: '🕐',
+ enabled: true
+ },
+ weather: {
+ name: 'Weather',
+ icon: '🌤️',
+ enabled: false,
+ apiKey: '', // User needs to set this
+ location: 'auto'
+ },
+ quote: {
+ name: 'Daily Quote',
+ icon: '💭',
+ enabled: false
+ }
+};
+
+// Load widget settings
+function loadWidgetSettings() {
+ try {
+ const saved = localStorage.getItem(STORAGE_KEY_WIDGETS);
+ return saved ? JSON.parse(saved) : widgetConfigs;
+ } catch (e) {
+ console.error('Error loading widget settings:', e);
+ return widgetConfigs;
+ }
+}
+
+// Save widget settings
+function saveWidgetSettings(settings) {
+ try {
+ localStorage.setItem(STORAGE_KEY_WIDGETS, JSON.stringify(settings));
+ } catch (e) {
+ console.error('Error saving widget settings:', e);
+ }
+}
+
+// Clock Widget
+function createClockWidget() {
+ const widget = document.createElement('div');
+ widget.className = 'widget widget-clock';
+
+ const timeDisplay = document.createElement('div');
+ timeDisplay.className = 'widget-time';
+
+ const dateDisplay = document.createElement('div');
+ dateDisplay.className = 'widget-date';
+
+ function updateTime() {
+ const now = new Date();
+
+ // Time
+ const hours = now.getHours().toString().padStart(2, '0');
+ const minutes = now.getMinutes().toString().padStart(2, '0');
+ const seconds = now.getSeconds().toString().padStart(2, '0');
+ timeDisplay.textContent = `${hours}:${minutes}:${seconds}`;
+
+ // Date
+ const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
+ dateDisplay.textContent = now.toLocaleDateString('en-US', options);
+ }
+
+ updateTime();
+ setInterval(updateTime, 1000);
+
+ widget.appendChild(timeDisplay);
+ widget.appendChild(dateDisplay);
+
+ return widget;
+}
+
+// Weather Widget
+function createWeatherWidget(settings) {
+ const widget = document.createElement('div');
+ widget.className = 'widget widget-weather';
+
+ const loading = document.createElement('div');
+ loading.className = 'widget-loading';
+ loading.textContent = '🌤️ Loading weather...';
+ widget.appendChild(loading);
+
+ // Check if API key is set
+ if (!settings.apiKey) {
+ widget.innerHTML = `
+
+ `;
+ return widget;
+ }
+
+ // Fetch weather data
+ let url = `https://api.openweathermap.org/data/2.5/weather?appid=${settings.apiKey}&units=metric`;
+
+ if (settings.location === 'auto') {
+ // Use geolocation
+ navigator.geolocation.getCurrentPosition(
+ (position) => {
+ url += `&lat=${position.coords.latitude}&lon=${position.coords.longitude}`;
+ fetchWeather(url, widget);
+ },
+ () => {
+ widget.innerHTML = 'Unable to get location
';
+ }
+ );
+ } else {
+ url += `&q=${settings.location}`;
+ fetchWeather(url, widget);
+ }
+
+ return widget;
+}
+
+function fetchWeather(url, widget) {
+ fetch(url)
+ .then(res => res.json())
+ .then(data => {
+ widget.innerHTML = `
+
+
${data.name}
+
${Math.round(data.main.temp)}°C
+
${data.weather[0].description}
+
+ 💨 ${data.wind.speed} m/s
+ 💧 ${data.main.humidity}%
+
+
+ `;
+ })
+ .catch(error => {
+ console.error('Weather fetch error:', error);
+ widget.innerHTML = 'Failed to load weather
';
+ });
+}
+
+// Quote Widget
+function createQuoteWidget() {
+ const widget = document.createElement('div');
+ widget.className = 'widget widget-quote';
+
+ const loading = document.createElement('div');
+ loading.className = 'widget-loading';
+ loading.textContent = '💭 Loading quote...';
+ widget.appendChild(loading);
+
+ fetch('https://api.quotable.io/random')
+ .then(res => res.json())
+ .then(data => {
+ widget.innerHTML = `
+
+
"${data.content}"
+
— ${data.author}
+
+ `;
+ })
+ .catch(error => {
+ console.error('Quote fetch error:', error);
+ widget.innerHTML = 'Failed to load quote
';
+ });
+
+ return widget;
+}
+
+// Create widget container
+function createWidgetContainer() {
+ const container = document.createElement('div');
+ container.id = 'widgets-container';
+ container.className = 'widgets-container';
+
+ return container;
+}
+
+// Initialize widgets
+function initWidgets() {
+ const settings = loadWidgetSettings();
+ const container = createWidgetContainer();
+
+ // Add enabled widgets
+ if (settings.clock?.enabled) {
+ container.appendChild(createClockWidget());
+ }
+
+ if (settings.weather?.enabled) {
+ container.appendChild(createWeatherWidget(settings.weather));
+ }
+
+ if (settings.quote?.enabled) {
+ container.appendChild(createQuoteWidget());
+ }
+
+ // Add to header if any widgets are enabled
+ if (container.children.length > 0) {
+ const header = document.querySelector('header');
+ if (header) {
+ header.appendChild(container);
+ }
+ }
+
+ // Create widget settings button
+ createWidgetSettings();
+}
+
+// Create widget settings UI
+function createWidgetSettings() {
+ const button = document.createElement('button');
+ button.className = 'widget-settings-btn control-btn';
+ button.innerHTML = '⚙️ Widgets';
+ button.title = 'Widget Settings';
+
+ button.addEventListener('click', showWidgetSettingsModal);
+
+ const header = document.querySelector('header');
+ if (header) {
+ let controls = header.querySelector('.import-export-controls');
+ if (!controls) {
+ controls = document.createElement('div');
+ controls.className = 'import-export-controls';
+ header.appendChild(controls);
+ }
+ controls.appendChild(button);
+ }
+}
+
+// Show widget settings modal
+function showWidgetSettingsModal() {
+ const settings = loadWidgetSettings();
+
+ const modal = document.createElement('div');
+ modal.className = 'modal';
+ modal.innerHTML = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ document.body.appendChild(modal);
+
+ // Event listeners
+ modal.querySelector('.modal-close').addEventListener('click', () => modal.remove());
+ modal.querySelector('.btn-cancel').addEventListener('click', () => modal.remove());
+ modal.querySelector('.btn-save').addEventListener('click', () => {
+ const newSettings = {
+ clock: {
+ ...widgetConfigs.clock,
+ enabled: modal.querySelector('#widget-clock').checked
+ },
+ weather: {
+ ...widgetConfigs.weather,
+ enabled: modal.querySelector('#widget-weather').checked,
+ apiKey: modal.querySelector('#weather-api-key').value,
+ location: modal.querySelector('#weather-location').value || 'auto'
+ },
+ quote: {
+ ...widgetConfigs.quote,
+ enabled: modal.querySelector('#widget-quote').checked
+ }
+ };
+
+ saveWidgetSettings(newSettings);
+ modal.remove();
+ location.reload();
+ });
+
+ // Close on background click
+ modal.addEventListener('click', (e) => {
+ if (e.target === modal) modal.remove();
+ });
+}
+
+// Export for use in other modules
+window.widgetsModule = {
+ init: initWidgets
+};