mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
refactor(build): place the views in the page instead of expanding templates
index.html now lists each view's host and the loading screen itself, so the gev:template expansion plugin, its view list, the loading-screen template and the ./build/html export are gone. createApplication takes omitViews for views an application leaves out; their hosts are removed, and a view an earlier call rendered is unmounted.
This commit is contained in:
1 parent
f279200af5
commit
5bf797ef71
18 files changed
+176
-174
No files matched your search
@@ -1,11 +0,0 @@
|
||||
<!-- Intelligence HUD Overlay -->
|
||||
<div id="intel-hud"></div>
|
||||
|
||||
<!-- Loading screen -->
|
||||
<div id="loading-screen">
|
||||
<div class="loader-content">
|
||||
<span class="loader-logo brand-logo" data-logo-gaze data-logo-src="/logo.svg" aria-hidden="true"><img src="/logo.svg" alt="" /></span>
|
||||
<h2 translate="no">GOD'S EYE <span class="title-accent">VIEW</span></h2>
|
||||
<p class="loader-status" data-i18n>Initializing photorealistic world...</p>
|
||||
</div>
|
||||
</div>
|
||||
+28
-10
@@ -10,8 +10,9 @@ import SceneChromeView from './SceneChromeView.vue';
|
||||
import ProviderSettingsView from './ProviderSettingsView.vue';
|
||||
|
||||
/**
|
||||
* Application views by template name (build/applicationViews.js lists the
|
||||
* same names). Each renders the markup its static template held.
|
||||
* Application views by name. A page places each one with a host element,
|
||||
* `<div class="gev-view" data-gev-view="NAME"></div>` (`display: contents`),
|
||||
* where the view's markup belongs.
|
||||
*/
|
||||
export const APPLICATION_VIEWS = Object.freeze({
|
||||
'provider-settings': ProviderSettingsView,
|
||||
@@ -24,21 +25,38 @@ export const APPLICATION_VIEWS = Object.freeze({
|
||||
welcome: WelcomeView,
|
||||
});
|
||||
|
||||
const mounted = new WeakSet();
|
||||
const mounted = new WeakMap();
|
||||
|
||||
/**
|
||||
* Render every application view into its host. Views belong to the page, as
|
||||
* their static markup did, so they are never unmounted. Call before anything
|
||||
* their static markup did, so they are unmounted only when a later call omits
|
||||
* them; omit views before any control code is wired to them. Call before anything
|
||||
* reads or translates the page; repeated calls are harmless.
|
||||
* @param {Document} [doc] Page document.
|
||||
* @param {{omit?: string[]}} [options] Views this page leaves out; their
|
||||
* hosts are removed, unmounting a view an earlier call rendered.
|
||||
*/
|
||||
export function mountApplicationViews(doc = globalThis.document) {
|
||||
export function mountApplicationViews(
|
||||
doc = globalThis.document,
|
||||
{ omit = [] } = {},
|
||||
) {
|
||||
for (const name of omit) {
|
||||
if (!Object.hasOwn(APPLICATION_VIEWS, name))
|
||||
throw new Error(`Unknown application view: ${name}`);
|
||||
}
|
||||
for (const host of doc?.querySelectorAll?.('[data-gev-view]') ?? []) {
|
||||
if (mounted.has(host)) continue;
|
||||
const name = host.getAttribute('data-gev-view');
|
||||
const view = APPLICATION_VIEWS[name];
|
||||
if (!view) throw new Error(`Unknown application view: ${name}`);
|
||||
createApp(view).use(applicationPinia()).mount(host);
|
||||
mounted.add(host);
|
||||
if (omit.includes(name)) {
|
||||
mounted.get(host)?.unmount();
|
||||
mounted.delete(host);
|
||||
host.remove();
|
||||
continue;
|
||||
}
|
||||
if (mounted.has(host)) continue;
|
||||
if (!Object.hasOwn(APPLICATION_VIEWS, name))
|
||||
throw new Error(`Unknown application view: ${name}`);
|
||||
const app = createApp(APPLICATION_VIEWS[name]).use(applicationPinia());
|
||||
app.mount(host);
|
||||
mounted.set(host, app);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// src/ui/views/mountApplicationViews.test.mjs — a page's view hosts render
|
||||
// their views, and an application can leave views out, over happy-dom.
|
||||
import '../../testSupport/registerDom.mjs';
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createApplication } from '../../app/application.js';
|
||||
import { mountApplicationViews } from './index.js';
|
||||
|
||||
function page(names) {
|
||||
document.body.replaceChildren();
|
||||
for (const name of names) {
|
||||
const host = document.createElement('div');
|
||||
host.className = 'gev-view';
|
||||
host.setAttribute('data-gev-view', name);
|
||||
document.body.append(host);
|
||||
}
|
||||
}
|
||||
|
||||
const hostNames = () =>
|
||||
[...document.querySelectorAll('[data-gev-view]')].map((host) =>
|
||||
host.getAttribute('data-gev-view'),
|
||||
);
|
||||
|
||||
test('omitted views lose their hosts and the rest render', () => {
|
||||
page(['welcome', 'provider-settings']);
|
||||
mountApplicationViews(document, { omit: ['provider-settings'] });
|
||||
assert.deepEqual(hostNames(), ['welcome']);
|
||||
assert.equal(document.getElementById('key-setup-chip'), null);
|
||||
assert.ok(
|
||||
document.querySelector('[data-gev-view="welcome"]').children.length,
|
||||
);
|
||||
});
|
||||
|
||||
test('a view an earlier call rendered is unmounted when a later call omits it', () => {
|
||||
page(['welcome', 'provider-settings']);
|
||||
mountApplicationViews(document);
|
||||
assert.ok(document.getElementById('key-setup-chip'));
|
||||
mountApplicationViews(document, { omit: ['provider-settings'] });
|
||||
assert.deepEqual(hostNames(), ['welcome']);
|
||||
assert.equal(document.getElementById('key-setup-chip'), null);
|
||||
});
|
||||
|
||||
test('unknown view names are refused, in the page or in the omit list', () => {
|
||||
page([]);
|
||||
for (const name of ['toString', 'constructor'])
|
||||
assert.throws(
|
||||
() => mountApplicationViews(document, { omit: [name] }),
|
||||
/Unknown application view/,
|
||||
);
|
||||
page(['toString']);
|
||||
assert.throws(
|
||||
() => mountApplicationViews(document),
|
||||
/Unknown application view/,
|
||||
);
|
||||
assert.throws(
|
||||
() => mountApplicationViews(document, { omit: ['nope'] }),
|
||||
/Unknown application view: nope/,
|
||||
);
|
||||
page(['nope']);
|
||||
assert.throws(
|
||||
() => mountApplicationViews(document),
|
||||
/Unknown application view: nope/,
|
||||
);
|
||||
});
|
||||
|
||||
test('createApplication leaves out the views its omitViews names', () => {
|
||||
page(['welcome', 'provider-settings']);
|
||||
const noop = () => ({});
|
||||
createApplication({
|
||||
createScene: noop,
|
||||
createControls: noop,
|
||||
createData: noop,
|
||||
createTools: noop,
|
||||
omitViews: ['provider-settings'],
|
||||
});
|
||||
assert.deepEqual(hostNames(), ['welcome']);
|
||||
});
|
||||
Reference in new issue
Block a user