Initial commit — Meridian OS browser desktop demo
This commit is contained in:
138
js/widgets/wallpaper.js
Normal file
138
js/widgets/wallpaper.js
Normal file
@@ -0,0 +1,138 @@
|
||||
import State from '../core/state.js';
|
||||
import { Bus } from '../core/bus.js';
|
||||
|
||||
const WALLPAPERS = {
|
||||
graphite: {
|
||||
name: 'Graphite',
|
||||
gradient: 'radial-gradient(ellipse at center, #1e2126 0%, #0f1114 100%)'
|
||||
},
|
||||
ember: {
|
||||
name: 'Ember',
|
||||
gradient: 'linear-gradient(135deg, #1a1d21 0%, #2a1f15 40%, #d4a24c33 100%)'
|
||||
},
|
||||
tide: {
|
||||
name: 'Tide',
|
||||
gradient: 'linear-gradient(160deg, #0a1628 0%, #0f2847 40%, #14425a 70%, #1a5c6e 100%)'
|
||||
},
|
||||
vellum: {
|
||||
name: 'Vellum',
|
||||
gradient: 'linear-gradient(145deg, #1e1c1a 0%, #2a2520 50%, #332e28 100%)'
|
||||
},
|
||||
eclipse: {
|
||||
name: 'Eclipse',
|
||||
gradient: 'linear-gradient(160deg, #0a0a0f 0%, #150f20 50%, #1a1030 100%)'
|
||||
},
|
||||
terminal: {
|
||||
name: 'Terminal',
|
||||
gradient: 'radial-gradient(ellipse at 20% 50%, #0a1a0a 0%, #0f1410 40%, #0a0f0a 100%)'
|
||||
}
|
||||
};
|
||||
|
||||
let currentWp = null;
|
||||
let applying = false;
|
||||
|
||||
function applyWallpaper(id) {
|
||||
if (applying) return;
|
||||
const wp = WALLPAPERS[id];
|
||||
if (!wp) return;
|
||||
|
||||
const layer = document.getElementById('wallpaper-layer');
|
||||
if (!layer) return;
|
||||
|
||||
applying = true;
|
||||
|
||||
// Crossfade
|
||||
const overlay = document.createElement('div');
|
||||
overlay.style.position = 'absolute';
|
||||
overlay.style.inset = '0';
|
||||
overlay.style.background = wp.gradient;
|
||||
overlay.style.opacity = '0';
|
||||
overlay.style.transition = 'opacity 250ms ease';
|
||||
overlay.style.zIndex = '1';
|
||||
layer.appendChild(overlay);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
overlay.style.opacity = '1';
|
||||
if (currentWp && currentWp !== overlay) {
|
||||
const old = currentWp;
|
||||
old.style.opacity = '0';
|
||||
setTimeout(() => old.remove(), 300);
|
||||
}
|
||||
currentWp = overlay;
|
||||
});
|
||||
|
||||
if (State.get('wallpaper') !== id) {
|
||||
State.set('wallpaper', id);
|
||||
}
|
||||
applying = false;
|
||||
|
||||
// Update picker swatches
|
||||
document.querySelectorAll('.wallpaper-swatch').forEach(s => {
|
||||
s.classList.toggle('active', s.dataset.id === id);
|
||||
});
|
||||
}
|
||||
|
||||
function initPicker() {
|
||||
const picker = document.getElementById('wallpaper-picker');
|
||||
const grid = document.getElementById('wallpaper-picker-grid');
|
||||
if (!picker || !grid) return;
|
||||
|
||||
// Populate swatches
|
||||
for (const [id, wp] of Object.entries(WALLPAPERS)) {
|
||||
const swatch = document.createElement('div');
|
||||
swatch.className = 'wallpaper-swatch';
|
||||
swatch.dataset.id = id;
|
||||
swatch.setAttribute('role', 'button');
|
||||
swatch.setAttribute('aria-label', `Select ${wp.name} wallpaper`);
|
||||
swatch.style.background = wp.gradient;
|
||||
swatch.innerHTML = `<span class="wallpaper-swatch-label">${wp.name}</span>`;
|
||||
swatch.addEventListener('click', () => applyWallpaper(id));
|
||||
grid.appendChild(swatch);
|
||||
}
|
||||
|
||||
// Apply saved wallpaper
|
||||
const saved = State.get('wallpaper');
|
||||
if (saved && WALLPAPERS[saved]) {
|
||||
applyWallpaper(saved);
|
||||
}
|
||||
|
||||
// Toggle button in status bar
|
||||
const toggleBtn = document.getElementById('wallpaper-toggle');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.addEventListener('click', () => {
|
||||
picker.classList.toggle('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
// Close picker on backdrop click
|
||||
picker.addEventListener('click', (e) => {
|
||||
if (e.target === picker) {
|
||||
picker.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
// Close on Escape
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && !picker.classList.contains('hidden')) {
|
||||
picker.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
// Listen for state changes to wallpaper (external triggers only; applying flag prevents recursion)
|
||||
State.subscribe('wallpaper', (id) => {
|
||||
if (id && WALLPAPERS[id]) {
|
||||
applyWallpaper(id);
|
||||
}
|
||||
});
|
||||
|
||||
// Apply saved or default
|
||||
const saved = State.get('wallpaper');
|
||||
const wpId = (saved && WALLPAPERS[saved]) ? saved : 'graphite';
|
||||
applyWallpaper(wpId);
|
||||
|
||||
initPicker();
|
||||
}
|
||||
|
||||
init();
|
||||
Reference in New Issue
Block a user