Add mode READMEs and move Bigscreen app

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.
This commit is contained in:
Andrew Zambazos
2026-05-21 20:11:18 +12:00
parent b141c0a058
commit f0d2926872
87 changed files with 974 additions and 322 deletions
+228
View File
@@ -0,0 +1,228 @@
const SETTINGS_TEMPLATE = `
<section class="view settings-view" data-view="settings">
<header class="shell-topbar">
<div class="shell-topbar-content">
<p class="shell-brand">Nebula OS</p>
<div class="shell-status">
<span class="shell-avatar" aria-hidden="true"></span>
<p class="shell-time" data-clock>--:--</p>
</div>
</div>
<div class="shell-accent-line"></div>
</header>
<section class="settings-header-copy">
<p class="muted">System</p>
<h1 class="view-title">Settings</h1>
</section>
<section class="settings-body" data-focus-root>
<section class="settings-category-bar">
<button class="focusable settings-category" data-focusable="true" data-row="0" data-col="0" data-cat="network" data-focus-key="network">Network</button>
<button class="focusable settings-category" data-focusable="true" data-row="0" data-col="1" data-cat="audio" data-focus-key="audio">Audio</button>
<button class="focusable settings-category" data-focusable="true" data-row="0" data-col="2" data-cat="display" data-focus-key="display">Display</button>
<button class="focusable settings-category" data-focusable="true" data-row="0" data-col="3" data-cat="storage" data-focus-key="storage">Storage</button>
<button class="focusable settings-category" data-focusable="true" data-row="0" data-col="4" data-cat="system" data-focus-key="system">System</button>
</section>
<article class="panel settings-panel">
<div class="settings-panel-head">
<h2 class="settings-panel-title" data-panel-title>Network</h2>
<p class="muted" data-panel-copy>Optimize connection and online routing.</p>
</div>
<div class="settings-card-grid">
<button class="focusable settings-card" data-focusable="true" data-row="1" data-col="0" data-toggle="passkey-enabled" data-focus-key="passkey-enabled">
<p class="settings-card-title">Passkey Lock</p>
<p class="muted" data-passkey-enabled>Enabled</p>
</button>
<button class="focusable settings-card" data-focusable="true" data-row="1" data-col="1" data-toggle="passkey-change" data-focus-key="passkey-change">
<p class="settings-card-title">Reset Passkey</p>
<p class="muted" data-passkey-change>Clear and set a new passkey</p>
</button>
<button class="focusable settings-card" data-focusable="true" data-row="1" data-col="2" data-toggle="passkey-length" data-focus-key="passkey-length">
<p class="settings-card-title">Required Length</p>
<p class="muted" data-passkey-length>6 digits</p>
<p class="muted">Fixed for testing</p>
</button>
<button class="focusable settings-card" data-focusable="true" data-row="1" data-col="3" data-toggle="passkey-confirm" data-focus-key="passkey-confirm">
<p class="settings-card-title">Require Confirm</p>
<p class="muted" data-passkey-confirm>Disabled</p>
</button>
<button class="focusable settings-card" data-focusable="true" data-row="1" data-col="4" data-toggle="passkey-keyboard" data-focus-key="passkey-keyboard">
<p class="settings-card-title">Keyboard Support</p>
<p class="muted" data-passkey-keyboard>Enabled</p>
</button>
<div class="settings-card settings-card-info">
<p class="settings-card-title">Status</p>
<p class="muted" data-status-note>Applying Nebula profile</p>
</div>
</div>
</article>
</section>
</section>
`;
const CATEGORIES = {
network: "Network",
audio: "Audio",
display: "Display",
storage: "Storage",
system: "System",
};
export const createSettingsView = ({ state, renderView }) => {
const updatePasskey = (partial) => {
state.passkey.updateConfig(partial);
refreshPanel();
};
const refreshPanel = () => {
const title = document.querySelector("[data-panel-title]");
const copy = document.querySelector("[data-panel-copy]");
const passkeyEnabled = document.querySelector("[data-passkey-enabled]");
const passkeyLength = document.querySelector("[data-passkey-length]");
const passkeyConfirm = document.querySelector("[data-passkey-confirm]");
const passkeyKeyboard = document.querySelector("[data-passkey-keyboard]");
const status = document.querySelector("[data-status-note]");
const passkeyConfig = state.passkey.getConfig();
document.querySelectorAll(".settings-category").forEach((button) => {
button.classList.toggle("is-active", button.dataset.cat === state.settingsCategory);
});
if (title) {
title.textContent = CATEGORIES[state.settingsCategory] ?? "Settings";
}
if (copy) {
if (state.settingsCategory === "system") {
copy.textContent = "Configure passkey security and controller login behavior.";
} else {
copy.textContent = `Tune ${CATEGORIES[state.settingsCategory] ?? "system"} options with controller-first cards.`;
}
}
if (passkeyEnabled) {
passkeyEnabled.textContent = passkeyConfig.enabled ? "Enabled" : "Disabled";
}
if (passkeyLength) {
passkeyLength.textContent = `${passkeyConfig.length} digits`;
}
if (passkeyConfirm) {
passkeyConfirm.textContent = passkeyConfig.requireConfirm ? "Enabled" : "Disabled";
}
if (passkeyKeyboard) {
passkeyKeyboard.textContent = passkeyConfig.keyboardSupport ? "Enabled" : "Disabled";
}
if (status) {
status.textContent = state.settingsCategory === "system"
? `Attempts: ${passkeyConfig.maxAttempts}, cooldown: ${passkeyConfig.cooldownSeconds}s`
: `${CATEGORIES[state.settingsCategory] ?? "System"} profile synced`;
}
document.querySelectorAll("[data-toggle^='passkey']").forEach((button) => {
button.classList.toggle("is-disabled", state.settingsCategory !== "system");
button.setAttribute("aria-disabled", state.settingsCategory === "system" ? "false" : "true");
});
};
const toggleCurrent = (suffix = "") => {
const key = suffix ? `${state.settingsCategory}_${suffix}` : state.settingsCategory;
state.settingsValues[key] = !Boolean(state.settingsValues[key]);
refreshPanel();
};
return {
id: "settings",
render: () => SETTINGS_TEMPLATE,
mount: () => {
const root = document.querySelector("[data-focus-root]");
root?.addEventListener("focusin", (event) => {
const focused = event.target.closest("[data-focusable='true']");
const col = Number(focused?.dataset.col ?? 0);
document.documentElement.style.setProperty("--nebula-accent-line-x", `${24 + col * 110}px`);
});
refreshPanel();
document.documentElement.style.setProperty("--nebula-focus-strength", "1");
},
getNavigationContract: () => {
const root = document.querySelector("[data-focus-root]");
return {
focusRoot: root,
defaultFocus: root?.querySelector("[data-cat='network']") ?? null,
layout: { type: "grid", cols: 5, rows: 2 },
hintsTemplate: "#global-hints-template",
nebulaNavigation: state.nebula.navigation,
onAccept: (element) => {
if (!element) {
return;
}
const category = element.dataset.cat;
const toggle = element.dataset.toggle;
if (category) {
state.settingsCategory = category;
refreshPanel();
return;
}
if (toggle === "primary") {
toggleCurrent();
return;
}
if (toggle === "secondary") {
toggleCurrent("secondary");
return;
}
if (state.settingsCategory !== "system") {
return;
}
if (toggle === "passkey-enabled") {
updatePasskey({ enabled: !state.passkey.getConfig().enabled });
return;
}
if (toggle === "passkey-change") {
state.passkey.resetSequence();
state.passkeySetupRequired = true;
state.locked = true;
state.activeView = "lock";
renderView("lock");
return;
}
if (toggle === "passkey-length") {
return;
}
if (toggle === "passkey-confirm") {
updatePasskey({ requireConfirm: !state.passkey.getConfig().requireConfirm });
return;
}
if (toggle === "passkey-keyboard") {
updatePasskey({ keyboardSupport: !state.passkey.getConfig().keyboardSupport });
}
},
onBack: () => {
state.activeView = "home";
renderView("home");
},
onMenu: () => {},
onAction: (action, element) => {
if (state.settingsCategory !== "system") {
return false;
}
if (element?.dataset.toggle !== "passkey-length") {
return false;
}
return false;
},
};
},
};
};