Initial commit — Meridian OS browser desktop demo
This commit is contained in:
107
js/core/state.js
Normal file
107
js/core/state.js
Normal 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 };
|
||||
Reference in New Issue
Block a user