Initial commit — Meridian OS browser desktop demo
This commit is contained in:
148
js/core/registry.js
Normal file
148
js/core/registry.js
Normal file
@@ -0,0 +1,148 @@
|
||||
import MeridianWM from './wm.js';
|
||||
import State from './state.js';
|
||||
import Bus from './bus.js';
|
||||
|
||||
const Registry = (() => {
|
||||
const APPS = {};
|
||||
let _launcherOpen = false;
|
||||
|
||||
function registerApp(def) {
|
||||
if (def.id) {
|
||||
APPS[def.id] = def;
|
||||
}
|
||||
}
|
||||
|
||||
function unregisterApp(id) {
|
||||
delete APPS[id];
|
||||
}
|
||||
|
||||
function getApp(id) {
|
||||
return APPS[id] || null;
|
||||
}
|
||||
|
||||
function launchApp(id) {
|
||||
const def = APPS[id];
|
||||
if (!def) {
|
||||
console.warn(`App ${id} not registered`);
|
||||
return;
|
||||
}
|
||||
|
||||
const title = def.title || id;
|
||||
const w = def.width || 640;
|
||||
const h = def.height || 480;
|
||||
|
||||
// Create window with a render-callback; wm will mount container then call it.
|
||||
const win = MeridianWM.openWindow({
|
||||
app: id,
|
||||
title,
|
||||
w, h,
|
||||
content: (container) => {
|
||||
// Tag container for per-app CSS scoping
|
||||
container.setAttribute('data-app', id);
|
||||
const api = {
|
||||
state: State,
|
||||
bus: Bus,
|
||||
close: () => MeridianWM.closeWindow(win && win.id),
|
||||
setTitle: (t) => {
|
||||
const el = document.getElementById(win && win.id);
|
||||
if (el) {
|
||||
const titleEl = el.querySelector('.m-window-title');
|
||||
if (titleEl) titleEl.textContent = t;
|
||||
}
|
||||
},
|
||||
};
|
||||
try {
|
||||
def.render(container, api);
|
||||
} catch (e) {
|
||||
container.textContent = `Error loading ${id}: ${e.message}`;
|
||||
console.error(`[${id}] render error`, e);
|
||||
}
|
||||
},
|
||||
});
|
||||
closeLauncher();
|
||||
}
|
||||
|
||||
function getRegisteredApps() {
|
||||
return Object.values(APPS);
|
||||
}
|
||||
|
||||
function toggleLauncher() {
|
||||
_launcherOpen = !_launcherOpen;
|
||||
const popover = document.getElementById('launcher-popover');
|
||||
const btn = document.getElementById('launcher');
|
||||
if (popover) {
|
||||
if (_launcherOpen) {
|
||||
renderLauncherApps(popover);
|
||||
popover.classList.remove('hidden');
|
||||
} else {
|
||||
popover.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
if (btn) {
|
||||
btn.classList.toggle('active', _launcherOpen);
|
||||
}
|
||||
return _launcherOpen;
|
||||
}
|
||||
|
||||
function closeLauncher() {
|
||||
_launcherOpen = false;
|
||||
const popover = document.getElementById('launcher-popover');
|
||||
const btn = document.getElementById('launcher');
|
||||
if (popover) popover.classList.add('hidden');
|
||||
if (btn) btn.classList.remove('active');
|
||||
}
|
||||
|
||||
function renderLauncherApps(popover) {
|
||||
const apps = getRegisteredApps();
|
||||
popover.innerHTML = '';
|
||||
if (apps.length === 0) {
|
||||
popover.innerHTML = '<div style="padding:12px;text-align:center;color:var(--text-faint);font-size:13px;">No apps registered</div>';
|
||||
return;
|
||||
}
|
||||
for (const app of apps) {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'launcher-app-btn';
|
||||
btn.setAttribute('aria-label', `Launch ${app.title || app.id}`);
|
||||
btn.innerHTML = `
|
||||
<div class="launcher-app-icon">${app.icon || '◆'}</div>
|
||||
<div class="launcher-app-label">${escapeHtml(app.title || app.id)}</div>
|
||||
`;
|
||||
btn.addEventListener('click', () => launchApp(app.id));
|
||||
popover.appendChild(btn);
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = str;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function init() {
|
||||
const btn = document.getElementById('launcher');
|
||||
if (btn) {
|
||||
btn.addEventListener('click', toggleLauncher);
|
||||
}
|
||||
|
||||
// Close launcher when clicking elsewhere
|
||||
document.addEventListener('mousedown', (e) => {
|
||||
if (_launcherOpen && !e.target.closest('#launcher') && !e.target.closest('#launcher-popover')) {
|
||||
closeLauncher();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
APPS,
|
||||
registerApp,
|
||||
unregisterApp,
|
||||
getApp,
|
||||
launchApp,
|
||||
getRegisteredApps,
|
||||
toggleLauncher,
|
||||
init
|
||||
};
|
||||
})();
|
||||
|
||||
export default Registry;
|
||||
export { Registry };
|
||||
Reference in New Issue
Block a user