Fix the Stage 1 Dashboard UX defects found in assembled review
CI / verify (pull_request) Successful in 1m13s
CI / infrastructure-smoke (pull_request) Successful in 34s
CI / package-release (pull_request) Successful in 48s
CI / migration-smoke (pull_request) Successful in 2m22s
CI / image-build (pull_request) Successful in 1m8s
CI / deploy-smoke (same-origin) (pull_request) Successful in 49s
CI / package-publication (pull_request) Successful in 57s
CI / deploy-smoke (split) (pull_request) Successful in 3m38s
CI / verify (pull_request) Successful in 1m13s
CI / infrastructure-smoke (pull_request) Successful in 34s
CI / package-release (pull_request) Successful in 48s
CI / migration-smoke (pull_request) Successful in 2m22s
CI / image-build (pull_request) Successful in 1m8s
CI / deploy-smoke (same-origin) (pull_request) Successful in 49s
CI / package-publication (pull_request) Successful in 57s
CI / deploy-smoke (split) (pull_request) Successful in 3m38s
The assembled Stage 1 Dashboard was reviewed by hand on a desktop, with the sidebar collapsed, and on an iPhone. This fixes what that review found, and records the decisions in ADR 0064: - Discover is its own page at /settings/discover, with Installed and Updates beneath it as children. There is no Browse item any more. /settings/discover/browse is still read, as an alias, and is respelled in place. Parents and children now read as a hierarchy: a guide line, text-only children, a disclosure chevron, and parent and current states that look different. - The sidebar is navigation only. Display pairing moves from the sidebar and drawer to Settings -> Displays: the paired displays, a deliberate Add display dialog, and revocation. Nothing takes focus on arrival; the code field is focused only once Add display is chosen. - Collapsed icons are centred. Nav-link layout moves from inline styles to the shell stylesheet, and every collapsed item is one square centred on the rail. - /settings is an overview of the installation: displays paired, modules installed and running, and a line for each other area. It reads only existing endpoints. - Phones get a sticky, safe-area-aware header holding the menu trigger and the page name. New pages start at the top, and focus no longer scrolls content under the header. - @ekklesia/ui draws checkbox and radio indicators from tokens rather than accent-color, so the selected state is the strong accent in Light and Dark alike. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
186668915b
commit
405e509bcb
@@ -45,6 +45,7 @@ import {
|
||||
} from "./appearance-preference.js";
|
||||
import { ForgotPasswordForm } from "./ForgotPasswordForm.js";
|
||||
import type { HostHistory } from "./host-history.js";
|
||||
import { DisplaysSettingsPage } from "./DisplaysSettingsPage.js";
|
||||
import { createBrowserHostViewport, type HostViewport } from "./host-viewport.js";
|
||||
import { ModuleUnavailablePage, NotFoundPage, OverviewPage } from "./HostPages.js";
|
||||
import { LoginForm } from "./LoginForm.js";
|
||||
@@ -59,6 +60,7 @@ import {
|
||||
SettingsHomePage,
|
||||
SettingsLoadFailedPage,
|
||||
SettingsSectionPage,
|
||||
settingsBack,
|
||||
type SettingsReturn,
|
||||
SettingsUnavailablePage,
|
||||
} from "./SettingsPages.js";
|
||||
@@ -200,17 +202,26 @@ function allEntries(bootstrap: HostBootstrap): readonly DashboardNavigationEntry
|
||||
}
|
||||
|
||||
function SettingsPageView(props: {
|
||||
readonly config: EkklesiaHostConfig;
|
||||
readonly page: SettingsPage;
|
||||
readonly history: HostHistory;
|
||||
readonly onRetry: () => void;
|
||||
readonly returnTo: SettingsReturn;
|
||||
}): ReactElement {
|
||||
const { page, history, returnTo } = props;
|
||||
const { config, page, history, returnTo } = props;
|
||||
switch (page.kind) {
|
||||
case "home":
|
||||
return <SettingsHomePage history={history} settings={page.settings} />;
|
||||
return <SettingsHomePage config={config} history={history} settings={page.settings} />;
|
||||
case "section":
|
||||
return <SettingsSectionPage history={history} returnTo={returnTo} section={page.section} />;
|
||||
return page.section === "displays" ? (
|
||||
<DisplaysSettingsPage
|
||||
back={settingsBack(history, returnTo)}
|
||||
config={config}
|
||||
moduleName={returnTo.moduleName}
|
||||
/>
|
||||
) : (
|
||||
<SettingsSectionPage history={history} returnTo={returnTo} section={page.section} />
|
||||
);
|
||||
case "discover":
|
||||
return <DiscoverPage history={history} returnTo={returnTo} view={page.view} />;
|
||||
case "module":
|
||||
@@ -661,7 +672,12 @@ export function HostApp(props: HostAppProps): ReactElement {
|
||||
return;
|
||||
}
|
||||
if (shownRouteRef.current !== undefined && shownRouteRef.current !== currentRouteKey) {
|
||||
mainRef.current?.focus();
|
||||
// A new page starts at its top, as a full page load would, and focusing it must not scroll
|
||||
// it: focus() alone would scroll the page's top to the very top of the viewport, beneath
|
||||
// the phone's sticky header, so every page opened from the drawer started under it.
|
||||
const main = mainRef.current;
|
||||
main?.focus({ preventScroll: true });
|
||||
main?.ownerDocument.scrollingElement?.scrollTo?.({ left: 0, top: 0 });
|
||||
}
|
||||
shownRouteRef.current = currentRouteKey;
|
||||
}, [currentRouteKey, state.status]);
|
||||
@@ -757,7 +773,6 @@ export function HostApp(props: HostAppProps): ReactElement {
|
||||
|
||||
return (
|
||||
<ShellLayout
|
||||
config={config}
|
||||
history={history}
|
||||
mainRef={mainRef}
|
||||
account={bootstrap.account}
|
||||
@@ -771,6 +786,7 @@ export function HostApp(props: HostAppProps): ReactElement {
|
||||
>
|
||||
{settingsPage !== undefined ? (
|
||||
<SettingsPageView
|
||||
config={config}
|
||||
history={history}
|
||||
onRetry={retryBootstrap}
|
||||
page={settingsPage}
|
||||
|
||||
Reference in New Issue
Block a user