Skip to content

UI/UX port onto the ElastOS Shell Protocol architecture (shell chrome, per-app UI, unlock arrival) - #14

Closed
SashaMIT wants to merge 24 commits into
feat/elastos-shell-protocolfrom
feat/shell-ui-esp
Closed

SashaMIT wants to merge 24 commits into
feat/elastos-shell-protocolfrom
feat/shell-ui-esp

Conversation

@SashaMIT

Copy link
Copy Markdown
Contributor

What this is

The pure UI/UX work from feat/shell-ui-v1, re-ported (not merged) onto this branch's architecture. Everything follows the host/GUI split: the host keeps unlock/mount/routing/recovery; all product UI lives in home-gui and the app capsules. No provider paths, host allowlists, or token paths were touched, and zero Rust changed (git diff on elastos/ vs this branch's head is empty).

Port inventory (6 commits)

  1. Design system — _shared/elastos-ui.css + elastos-theme.js tokens, scripts/vendor-ui-tokens.sh, just vendor-ui recipe, vendored copies into 16 first-party capsules (target list trimmed to this branch's capsules).
  2. home-gui shell chrome — full desktop chrome on your lazy-template contract: system bar, identity menu, clock, dock (magnification, label bubbles, running dots, launch bounce, Trash), desktop multi-select + marquee, window lifecycle motion, People window list/detail. Module-scope DOM work was refactored into bind*() functions called after template injection; your fail-closed desktop-object capability gating is preserved.
  3. Shell overlays — menubar (home:menu-manifest / elastos:menu-command, sanitized, UI-data-only), Spotlight, Notification Center, keyboard shortcuts + window switcher, Exposé, Quick Look, UI sounds. All hidden at mount, retired on dormant.
  4. Per-app UI (14 surfaces) — Library, Wallet, Browser, Inbox, Services, Marketplace, Archive Manager, Documents, Chat Room, GBA emulator, System, and the three wallet connectors: token palettes, light/dark theming, app anatomy, menu manifests. System was a true three-way merge — the ESP shell picker and esp-projections.mjs are intact, with sidebar search and theme/accent controls added around them.
  5. Unlock arrival — first-boot welcome beat (Welcome → Get started → create passkey), focus trap on the unlock card, unlock dismiss cross-fade in the host, and the desktop settle-in reimplemented as home-gui's own mount transition. The neutral mask never carries the desktop; the data-surface contract is untouched.

Exclusion ledger (returns with the Flint bring-across)

  • Network status glyph + System Network pane (/api/apps/home/network-status, market index, carrier status — Flint gateway backend).
  • Library .ddrm cover-art loader (thumbnail_uri is never populated on this branch).
  • capsule-inspector, elacity-player, marketplace-content, ddrm-viewer, creator, mandates UI (capsules absent here).
  • Flint owned-asset viewer flow in shell-windows.js (dKMS loading stages, rights-denied handling).

Gates (run on macOS, honest results)

Passing: all 9 home-shell-* smokes; passkey virtual-auth smoke on a fresh Home through welcome → create → signed → System → shell switch; vendor-ui --check; git diff --check; check-elastos-bus-wit; cargo fmt --check; syntax parse of every ported JS file; all app routes serve 200.

Pre-existing failures, byte-identical or same-failure at this branch's untouched head (verified against a detached worktree at b2fea63db):

  • home-entropy-check.mjs (reads removed capsules/home/browser/shell.js) and browser-entropy-check.mjs (manifest assertion) — left as-is rather than guessing your intended contract; happy to reconcile them with you.
  • alignment-check (state.md pattern), local-carrier-setup-smoke (Linux-only), command-smoke / candidate-command-audit (macOS env: no timeout, shared config dir).
  • cargo clippy -D warnings fails in elastos-vz (doc-list indentation, needless_return) at your head too.
  • cargo test -p elastos-server: ~10-15 failures under parallel threads at your head and here (flaky, all pass with --test-threads=1), plus test_home_launch_rejects_source_wasi_materialization which fails deterministically at your head as well.
  • Passkey smoke times out at shell-switch:reload-home-cli on a fresh throwaway Home — identical at your head.

Notes for review

  • Menu protocol: manifests are sanitized UI data (≤6 menus, ≤20 items, length/charset caps), rendered via textContent, bound to the sender's window; every command still ends at existing flows and their approval gates. Menus add no authority.
  • The manual-UX report needs regeneration after this lands (home-shell-manual-ux-report.mjs is the human-filled template).
  • Side-by-side parity reference: the feat/shell-ui-v1 branch running against a Flint gateway.

Made with Cursor

SashaMIT and others added 24 commits July 17, 2026 13:17
One token source (capsules/_shared/elastos-ui.css + elastos-theme.js + Inter)
stamped into each capsule's browser dir by scripts/vendor-ui-tokens.sh; no
gateway route and no runtime sharing. just vendor-ui re-stamps, and the
--check mode joins just verify so vendored drift fails closed. Targets cover
the shell host, home-gui, and the main-line app capsules only.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bring the Apple-grade GUI shell (dock with magnification and auto-hide,
identity menu, clock, multi-select desktop with marquee, window enter/
minimize/exit motion, People list-detail view, UI sounds) from the
shell-ui-v1 line into the home/home-gui split. DOM bindings move into
bind functions called after the lazy GUI template mounts, desktop object
actions stay fail-closed on capability metadata, and shell-switch
retirement removes stale windows synchronously. Cache-bust version
unified to home-20260717b across host, GUI, and smoke harnesses.

Co-authored-by: Cursor <cursoragent@cursor.com>
The data-home-gui-hidden-by-host marker tells the host to restore a node
to visible on GUI mount; stamping it statically on Spotlight, Quick Look,
window switcher, shortcuts overlay, and notification center made them all
open at once with no bindings to close them yet. They now start plain
hidden until their own controllers (Chunk C) open them.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ose, Quick Look

Six presentation modules from the shell-ui-v1 line, re-fit to the lazy GUI
template: DOM nodes and listeners bind through explicit bind functions
called by the facade after ensureHomeGuiDom(). The keyboard layer sleeps
unless Home GUI is the mounted shell, and shell-switch retirement now also
closes Spotlight, Notification Center, Quick Look, Expose, the window
switcher, the shortcuts overlay, and open menus. The host routes
home:menu-manifest to the GUI after verifying the sender frame, keeping
manifests bound to the declaring window only. Smoke stubs gain the
standard Element.append().

Co-authored-by: Cursor <cursoragent@cursor.com>
…urfaces

Ports the app-level UI pass (design tokens, dark/light theming via the
vendored elastos-theme runtime, app anatomy, and home:menu-manifest menus)
from feat/shell-ui-v1 into this architecture, per app:

- Library: three-dots overflow menu, expanding toolbar search, local colour
  tags (tags.js), footer object count, token palette. The .ddrm cover-art
  loader is intentionally NOT ported (its gateway/thumbnail backend is
  Flint-side; returns with the Flint bring-across).
- Wallet: File/Account menu manifest routed to existing flows, dark token
  palette, unified cache-bust versions. No sidebar (entropy contract).
- Browser: File/View/History menus, in-window profile-reset confirm.
- Inbox: token palette + listbox keyboard navigation.
- Services: settings-pane treatment on tokens.
- Marketplace: menus, Cmd+K search focus, CSS consolidated onto tokens.
- Archive Manager, Documents, Chat Room, GBA emulator, wallet connectors
  (metamask/unisat/walletconnect): token/theming + anatomy pass.
- System: three-way merge — keeps the ESP shell picker + esp-projections
  intact and adds sidebar search, theme/accent controls in Personalization,
  and the settings anatomy. The Network pane is NOT ported (its
  /api/apps/home/network-status backend is Flint gateway code).

Gates: all home-shell smoke scripts pass; vendor-ui --check OK; both
entropy checkers byte-identical to the branch baseline (their failures
pre-exist this work); every ported JS file parses clean; all referenced
local assets/imports resolve; all app routes serve 200 on the dev gateway.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ract

Ports the unlock arrival UX from feat/shell-ui-v1, re-fit to the host/GUI
split so the neutral boot mask never carries the desktop:

- shell-auth.js: first boot lands on a welcome beat (Welcome to ElastOS ->
  Get started -> create admin passkey) before the passkey form; returning
  users still go straight to sign-in with automatic passkey. The unlock
  card gains a keyboard focus trap and initial focus on the primary
  action. Unlock dismissal cross-fades the overlay out (compositor-only),
  skipped under reduced motion or when already hidden. The neutral/desktop
  data-surface contract is preserved untouched.
- host shell-core.js: adds the trapTabWithin focus-trap util the unlock
  card uses.
- home-gui.js: the desktop's settle-in is now the GUI's own mount
  transition — on dormant->mounted the backdrop/workspace get a gentle
  scale settle and the bars fade in, skipped under reduced motion. This
  replaces the flint version's coupling of unlock dismissal to a
  .desktop-shell node the host no longer owns.
- home-passkey-virtual-auth-smoke.mjs: first-boot path clicks Get started
  before waiting for the passkey name field.

Gates: all home-shell smokes pass. Passkey virtual smoke against a fresh
throwaway Home passes welcome -> create -> signed -> System launch ->
shell switch; it then times out at shell-switch:reload-home-cli, and the
unmodified baseline fails at the identical stage on a fresh Home, so that
failure pre-exists this change. Entropy checkers unchanged from baseline.

Co-authored-by: Cursor <cursoragent@cursor.com>
The account/system dropdown moves from the right-side identity chip to the
ElastOS brand at the far left — the macOS Apple-menu position. The menu
keeps the signed-in header and gains Show desktop (the brand button's old
go-home action), then Enter fullscreen, System, and Sign out. The avatar +
name on the right becomes a passive identity indicator. Menu behavior
(APG menu-button pattern, outside dismiss, keyboard nav) is unchanged;
only the trigger and anchoring moved.

Gates: all home-shell smokes pass; ported JS parses clean.
Co-authored-by: Cursor <cursoragent@cursor.com>
…ntity chip

Web-projection capsules are gateway-served surfaces whose canonical open
path is the launch route; the runtime deliberately refuses plain Wasm
capsules, so forwarding them into it could only ever fail the launch.
launch_runtime_backed_home_target now returns None for
execution=web-projection, letting Home open the app iframe cleanly.

In the bar, the right-side avatar + name chip is removed: the ElastOS
system menu at the far left already carries the signed-in principal in
its header, so the chip duplicated it (macOS keeps that spot free too).

Gates: cargo check + fmt clean on elastos-server; all home-shell smokes
pass. cargo test `launch` filter: 45 pass, 1 pre-existing failure
(test_home_launch_rejects_source_wasi_materialization expects an error
message that exists nowhere in published source — fails identically
without this change).

Co-authored-by: Cursor <cursoragent@cursor.com>
…ophy)

The desktop is the user's surface — files, folders, Trash — projected from
the runtime's desktop_objects facts. Apps now live in exactly two places,
the dock and the launcher, matching the macOS grammar the shell already
speaks everywhere else.

- Desktop app icons become opt-in: layout state tracks desktopApps (the
  apps a user explicitly added) instead of desktopHidden (everything minus
  removals). Object-kind targets still default onto the desktop; Add to
  Desktop / Remove from Desktop keep working through the same single list.
- Fresh principals get default dock pins (Browser, Library, Documents,
  Chat, System); pre-migration layouts with an empty dock are seeded once
  so apps never become unreachable-by-pointer.
- First-contact teaching (Norman gate): a one-time dismissible hint above
  the dock plus a soft launcher-button pulse answer "where are my apps";
  both retire forever on first launcher open and respect reduced motion.
- Smoke fixtures move to the desktopApps model; the regression smoke keeps
  exercising position de-collision with explicitly desktop-resident apps.

Removals ledger (Rams gate): desktop app-icon grid as the default surface;
the desktopHidden opt-out model.

Gates: all home-shell smokes pass; no linter errors. home-entropy-check
still fails at its pre-existing ENOENT (tracks deleted capsules/home
shell.js) — unchanged by this commit.

Co-authored-by: Cursor <cursoragent@cursor.com>
New bar glyph (two toggle pills, macOS grammar) between Search and the
bell, opening a frosted popover with exactly the v1 scope the review
board fixed: appearance (Auto/Light/Dark), UI sounds, fullscreen, and a
wallet entry point. Everything the panel touches already has a canonical
owner — elastos-theme.js, shell-sounds.js, the fullscreen facade — so the
panel projects and toggles, it stores nothing of its own and adds no new
runtime surface.

- shell-control-centre.js follows the established popover contract: lazy
  DOM bind, starts hidden, Escape/outside-pointerdown dismiss, focus back
  to the invoker, retired by the host on shell switch. Mutual exclusion
  with the notification center falls out of each panel's outside-dismiss.
- Fullscreen moves out of the ELASTOS menu into the Control Centre (its
  new permanent home); same button contract, new row markup.
- The wallet row is hidden entirely when the summary carries no wallet
  target — no dead buttons (fail-closed, same capability discipline as
  desktop objects). It opens the Wallet app today and will point at the
  wallet rail when WS3 lands.

Removals ledger (Rams gate): "Enter fullscreen" item in the ELASTOS menu.

Gates: all home-shell smokes pass; no linter errors; syntax-checked.
Co-authored-by: Cursor <cursoragent@cursor.com>
The system menu now reads like a menu, not a grab-bag: About ElastOS and
System Settings… first, then the workspace actions (Show Desktop,
Keyboard Shortcuts with its ⌘/ glyph right-aligned, macOS menu grammar),
then Sign Out…. Every keyboard-only feature gains a pointer path — the
shortcuts overlay was previously reachable by ⌘/ alone.

About ElastOS is the smallest honest dialog: logo, product name, which
shell this is, who is signed in. No version string is claimed because the
shell has no verified runtime fact to back one — it can grow that line
when ESP exposes it.

Same modal contract as every other overlay: starts hidden, Escape /
backdrop dismiss, focus returns to the menu button, retired by the host
on shell switch, listed in the host-managed selectors.

Gates: all home-shell smokes pass; no linter errors.
Co-authored-by: Cursor <cursoragent@cursor.com>
One grammar for refusal moments: what happened (headline), why (one
sentence), what you can do (action), technical facts last and folded into
the facts list. Applied to the two places the shell talks to a person
under stress:

- Launch failures gain a Try Again action — offered only when the caller
  can honestly retry (the button re-runs the same canonical openTarget
  path; no hidden alternate route). Copy now says retrying is safe
  instead of leaving the person to guess.
- Spotlight answers a searched-for miss with "No results for X" instead
  of a silently empty panel; the pre-typing prompt state stays quiet.

Gates: all home-shell smokes pass; no linter errors.
Co-authored-by: Cursor <cursoragent@cursor.com>
…tial)

Motion review verdict applied: state changes move through space, they do
not teleport.

- The Control Centre appearance segment gets one physical thumb that
  slides between Auto/Light/Dark (240ms, decelerating curve) instead of
  repainting the active option; labels crossfade underneath. The
  controller drives it with a CSS variable, so reopening the panel snaps
  into place without a phantom slide.
- The ELASTOS menu now enters like every other bar surface (140ms fade +
  4px settle from its anchor) instead of blinking on.
- Both honor prefers-reduced-motion.

Gates: all home-shell smokes pass.
Co-authored-by: Cursor <cursoragent@cursor.com>
…e (WS3)

Right-hand slide-over hosting the wallet capsule, opened from the Control
Centre wallet row. The rail is chrome only: it launches Wallet through
the exact same canonical path as a window (POST /api/apps/home/launch)
and mounts the returned route in an iframe with the same sandbox/allow
policy windows compute (iframeSandboxForLaunch/iframeAllowForLaunch, now
exported). The shell holds no wallet state and no wallet logic — accounts,
connectors, and approvals all stay inside the capsule where the authority
lives, so nothing about the trust model moved.

- Session-friendly: closing the rail hides it (the capsule keeps its
  session); the frame is fully torn down when the host retires the GUI
  surface on shell switch.
- "Open as window" hands off to the normal windowed launch for people who
  want the wallet on the desktop instead.
- Launch failures use the WS6 error grammar inline in the rail, with the
  same honest Try Again.
- Fail-closed: no wallet target in the summary means no rail and no
  Control Centre row — never a dead button.
- Standard overlay contract: Escape / outside pointerdown dismiss, focus
  restore, host-managed selector list, 200ms slide honoring reduced
  motion.

Gates: all home-shell smokes pass; no linter errors; 8091 serves the new
module and markup.

Co-authored-by: Cursor <cursoragent@cursor.com>
Review feedback: the wallet deserves a first-class entry in the system
bar, and the rail should read as a sidebar, not a floating card.

- New wallet glyph in the bar (between Control Centre and the bell). It
  toggles the rail directly, carries aria-expanded, and exists exactly
  when the summary carries a wallet target — synced on every chrome
  refresh, so it disappears (and the rail retires) if the target goes
  away. The Control Centre row remains as the second path.
- The rail now runs flush: top under the bar, right and bottom edges at
  the screen edge, border-left only (macOS sidebar grammar — no floating
  gap). Enter motion is a full 240ms slide from the right edge instead of
  a fade-nudge, honoring reduced motion.

Gates: all home-shell smokes pass; no linter errors.
Co-authored-by: Cursor <cursoragent@cursor.com>
…ttom gap

Restore the rounded floating card (8px margins, 14px radius, full border)
but let it run the full usable height — bottom margin is now the same 8px
as the other edges instead of stopping above the dock band. Enter motion
slides the card in from past the right edge.

Co-authored-by: Cursor <cursoragent@cursor.com>
Frosted glass (translucent menu-fill + backdrop blur) was picking up the
wallpaper's violet band along the bottom edge. The rail now uses the
opaque frame fill and a neutral soft shadow — same card shape, no tint.

Co-authored-by: Cursor <cursoragent@cursor.com>
The violet band at the foot of the wallet rail was a decorative
bottom-right radial (oklch hue 290) painted by the wallet capsule itself,
not the shell chrome. Both theme variants now use a solid --bg.

Co-authored-by: Cursor <cursoragent@cursor.com>
…rame

Promote Wallets & signers onto the main wallet view and make the sidebar
rail a first-class shell citizen — same capsule, same postMessage trust
path as the windowed wallet. No backend or authority changes.

Shell / host:
- homeGuiMessageContextForSource trusts #wallet-rail-frame when home_token
  matches the launch route; deliver + runtime-event broadcast include the rail
- Prefer open rail for wallet payload delivery; Open as window retires the
  rail (single session)
- Host allowlist adds wallet-walletconnect for wallet-originated opens
- Wallet-approval toast Review opens the rail (not Inbox)
- Pending-approval badge on the wallet bar icon from summary.notifications
- Default dock pins include wallet

Capsule IA:
- #wallet-signers on the main slide (shared renderMethods); Settings is
  prefs only — no second Approval methods home
- Empty state: Create account | Connect a wallet (scrolls to signers);
  Create/Import stay visible after the first account
- Human-first empty copy; narrow-rail layout polish; cache-bust wallet-20260718a

Gates: all home-shell smokes pass; no linter errors.
Co-authored-by: Cursor <cursoragent@cursor.com>
Connecting MetaMask (and UniSat / WalletConnect) no longer opens a second
desktop product window with empty Connected accounts / Approval requests
lists. Wallet asks for presentation=sheet; the shell mounts the connector
through the same /api/apps/home/launch path in a rail-aligned overlay.

- shell-connector-sheet.js: launch, trust frame for postMessage, close on
  successful home:refresh-summary so the user returns to Wallet
- Connector capsules in sheet mode hide duplicate panels and show only the
  Connect ceremony (authority boundary unchanged — EIP-1193 stays in the
  connector capsule)
- Wallet rail outside-dismiss ignores the sheet while it is open

Gates: all home-shell smokes pass.
Co-authored-by: Cursor <cursoragent@cursor.com>
home:refresh-summary only updates Home chrome. After MetaMask (etc.)
linked successfully we closed the sheet without telling the Wallet
iframe to reload accounts — so Connect looked like a no-op.

On connector success, broadcast elastos:wallet-refresh to the wallet rail
and every Wallet window; Wallet listens and calls refreshWalletState.

Co-authored-by: Cursor <cursoragent@cursor.com>
Put approve/reject under Send/Receive, keep Approvals as history, compact
account cards, Accounts-flip menus, and method icons so the rail stays
one clear money surface without mid-page request chrome.

Co-authored-by: Cursor <cursoragent@cursor.com>
Commit drawer enter/exit motion with forced reflow, badge pending count
on Approvals, and Escape that no longer clears selection while dismissing
overlays. Alias home-gui shell paths in entropy so the gate fails on
contract drift instead of ENOENT after the Home split.

Co-authored-by: Cursor <cursoragent@cursor.com>
Idle-preload the Wallet iframe, soft-refresh on show, retire hidden
sessions before window launch, and harden edge-peek close plus chrome
message source binding. Bump home/wallet cache tips and entropy gates.

Co-authored-by: Cursor <cursoragent@cursor.com>
@SashaMIT SashaMIT closed this Jul 19, 2026
@SashaMIT
SashaMIT deleted the feat/shell-ui-esp branch July 19, 2026 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant