Initial commit — Meridian OS browser desktop demo

This commit is contained in:
2026-04-19 23:18:55 +00:00
commit 8e30dd3597
30 changed files with 6277 additions and 0 deletions

107
js/core/state.js Normal file
View File

@@ -0,0 +1,107 @@
/**
* Central state store with persistence.
* Keys: user, windows, wallpaper, achievements, connection
*/
const STORAGE_KEY = 'meridian:state';
const State = (() => {
const listeners = new Map();
let _state = loadState();
function loadState() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw) {
const parsed = JSON.parse(raw);
// achievements is stored as array, reconstruct as Set
if (parsed.achievements) {
parsed._achievementSet = new Set(parsed.achievements);
}
return parsed;
}
} catch (e) {
console.warn('State load failed:', e);
}
return {
user: null,
windows: [],
wallpaper: 'graphite',
achievements: [],
_achievementSet: new Set(),
connection: navigator.onLine
};
}
function saveState() {
try {
const toSave = {
user: _state.user,
windows: _state.windows,
wallpaper: _state.wallpaper,
achievements: Array.from(_state._achievementSet || _state.achievements)
};
localStorage.setItem(STORAGE_KEY, JSON.stringify(toSave));
} catch (e) {
console.warn('State save failed:', e);
}
}
function set(key, val) {
_state[key] = val;
saveState();
notify(key);
}
function get(key) {
return _state[key];
}
function subscribe(key, cb) {
if (!listeners.has(key)) listeners.set(key, new Set());
listeners.get(key).add(cb);
// immediate call with current value
try { cb(_state[key]); } catch (e) { console.error('State subscribe error:', e); }
return () => off(key, cb);
}
function off(key, cb) {
const set = listeners.get(key);
if (set) {
set.delete(cb);
if (set.size === 0) listeners.delete(key);
}
}
function notify(key) {
const set = listeners.get(key);
if (set) {
for (const cb of set) {
try { cb(_state[key]); } catch (e) { console.error('State notify error:', e); }
}
}
}
function addAchievement(id) {
if (!_state._achievementSet) {
_state._achievementSet = new Set(_state.achievements || []);
_state.achievements = Array.from(_state._achievementSet);
}
_state._achievementSet.add(id);
_state.achievements = Array.from(_state._achievementSet);
saveState();
notify('achievements');
}
function initConnection() {
_state.connection = navigator.onLine;
window.addEventListener('online', () => { _state.connection = true; notify('connection'); saveState(); });
window.addEventListener('offline', () => { _state.connection = false; notify('connection'); saveState(); });
}
return {
set, get, subscribe, off, addAchievement, initConnection
};
})();
export default State;
export { State };