f0d2926872
Add comprehensive READMEs for Bigscreen and Desktop modes, and relocate the Tauri frontend prototype into a new Bigscreen/ subdirectory. This moves package.json/package-lock, src, src-tauri, assets, views, styles and related files into Bigscreen/ to separate the controller-first shell from top-level docs. Update the root README.md to reframe the project as "NebulaOS", describe Bigscreen/Desktop modes, the vision, tech stack and development notes. This reorganizes the repo layout for clearer mode separation and documentation.
153 lines
4.1 KiB
JavaScript
153 lines
4.1 KiB
JavaScript
const PANEL_COPY = {
|
|
search: {
|
|
title: "Search",
|
|
description: "Search games, apps, and settings across NebulaOS.",
|
|
placeholder: "Search NebulaOS…",
|
|
},
|
|
notifications: {
|
|
title: "Notifications",
|
|
description: "System alerts and download updates will appear here.",
|
|
},
|
|
downloads: {
|
|
title: "Downloads",
|
|
description: "Active and completed downloads will be listed here.",
|
|
},
|
|
controller: {
|
|
title: "Controller Settings",
|
|
description: "Map buttons, adjust dead zones, and test input.",
|
|
},
|
|
};
|
|
|
|
export const createGuidePanelOverlay = ({ mountRoot }) => {
|
|
let openState = false;
|
|
let activePanel = null;
|
|
let onClose = null;
|
|
let overlay = null;
|
|
|
|
const renderMarkup = () => {
|
|
mountRoot.insertAdjacentHTML(
|
|
"beforeend",
|
|
`
|
|
<section class="guide-panel-overlay" data-guide-panel-overlay hidden aria-label="Guide panel">
|
|
<div class="guide-panel-sheet panel" role="dialog" aria-modal="true">
|
|
<header class="guide-panel-sheet-head">
|
|
<h2 class="guide-panel-sheet-title" data-panel-title>Panel</h2>
|
|
<p class="muted guide-panel-sheet-desc" data-panel-desc></p>
|
|
</header>
|
|
<div class="guide-panel-sheet-body" data-panel-body></div>
|
|
<button
|
|
type="button"
|
|
class="focusable guide-panel-close"
|
|
data-focusable="true"
|
|
data-row="0"
|
|
data-col="0"
|
|
data-action="close"
|
|
data-focus-key="guide-panel-close"
|
|
>Close</button>
|
|
</div>
|
|
</section>
|
|
`,
|
|
);
|
|
overlay = mountRoot.querySelector("[data-guide-panel-overlay]");
|
|
};
|
|
|
|
const getBodyHtml = (panelId) => {
|
|
const copy = PANEL_COPY[panelId];
|
|
if (!copy) {
|
|
return `<p class="muted">This panel is not available yet.</p>`;
|
|
}
|
|
|
|
if (panelId === "search") {
|
|
return `
|
|
<label class="guide-panel-search-label">
|
|
<span class="sr-only">Search query</span>
|
|
<input
|
|
type="search"
|
|
class="guide-panel-search-input"
|
|
placeholder="${copy.placeholder}"
|
|
data-panel-search
|
|
autocomplete="off"
|
|
/>
|
|
</label>
|
|
<p class="muted guide-panel-hint">Results will appear here. (Placeholder)</p>
|
|
`;
|
|
}
|
|
|
|
return `
|
|
<div class="guide-panel-placeholder-card">
|
|
<p class="guide-panel-placeholder-title">${copy.title}</p>
|
|
<p class="muted">${copy.description}</p>
|
|
<p class="guide-panel-placeholder-note">Connected to guide quick actions · stub UI</p>
|
|
</div>
|
|
`;
|
|
};
|
|
|
|
const close = () => {
|
|
openState = false;
|
|
activePanel = null;
|
|
if (overlay) {
|
|
overlay.hidden = true;
|
|
}
|
|
onClose?.();
|
|
onClose = null;
|
|
};
|
|
|
|
const bindOverlayEvents = () => {
|
|
overlay?.addEventListener("click", (event) => {
|
|
if (event.target === overlay) {
|
|
close();
|
|
}
|
|
});
|
|
overlay?.querySelector(".guide-panel-close")?.addEventListener("click", () => close());
|
|
};
|
|
|
|
const open = (panelId, options = {}) => {
|
|
if (!overlay) {
|
|
renderMarkup();
|
|
bindOverlayEvents();
|
|
}
|
|
|
|
const copy = PANEL_COPY[panelId] ?? { title: "Panel", description: "" };
|
|
overlay.querySelector("[data-panel-title]").textContent = copy.title;
|
|
overlay.querySelector("[data-panel-desc]").textContent = copy.description ?? "";
|
|
overlay.querySelector("[data-panel-body]").innerHTML = getBodyHtml(panelId);
|
|
|
|
openState = true;
|
|
activePanel = panelId;
|
|
onClose = options.onClose ?? null;
|
|
overlay.hidden = false;
|
|
|
|
const closeBtn = overlay.querySelector("[data-guide-panel-close], .guide-panel-close");
|
|
closeBtn?.focus({ preventScroll: true });
|
|
closeBtn?.classList.add("is-focused");
|
|
|
|
console.log(`[GuidePanel] Opened: ${panelId}`);
|
|
};
|
|
|
|
const handleAction = (action) => {
|
|
if (!openState) {
|
|
return false;
|
|
}
|
|
|
|
if (action === "accept") {
|
|
close();
|
|
return true;
|
|
}
|
|
|
|
if (action === "back" || action === "menu") {
|
|
close();
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
return {
|
|
open,
|
|
close,
|
|
isOpen: () => openState,
|
|
getActivePanel: () => activePanel,
|
|
handleAction,
|
|
};
|
|
};
|