Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
125b60f
test(home-gui): phone and tablet layout ratchet smoke with the mobile…
SashaMIT Sep 23, 2026
a739b25
feat(home-gui): phone viewport truth and one form-factor reader
SashaMIT Sep 23, 2026
8e13366
home-gui: phone bar and Dock (M2)
SashaMIT Sep 23, 2026
44aff23
home-gui: phone Dock icons sit centred in the pill
SashaMIT Sep 23, 2026
9f52836
home-gui: phone Dock launcher and Assistant glyphs at 1.3x
SashaMIT Sep 23, 2026
1dfdf53
home-gui: phone window title bar (M3a)
SashaMIT Sep 23, 2026
1f0bfe6
home-gui: phone app switcher, title swipe and stage history (M3b)
SashaMIT Sep 23, 2026
1bd902b
docs: HOME_MOBILE milestone table — M3 scope as delivered
SashaMIT Sep 23, 2026
958580f
scripts: serve Home's gateway clients in the Browser and Library layo…
SashaMIT Sep 23, 2026
0e07065
home-gui: phone Dock glyph tiles stay whole and sheets span the stage
SashaMIT Sep 23, 2026
7fe128d
capsules: phone size class from the shell, touch tokens and a shared …
SashaMIT Sep 23, 2026
b230968
marketplace: phone sidebar as the push drawer
SashaMIT Sep 23, 2026
2498b92
documents: full-width editor on phone with the list as the push drawer
SashaMIT Sep 23, 2026
ee149bc
library: one phone header with sliding Favorites
SashaMIT Sep 23, 2026
d6c4b43
system: phone menu button on the page title's line
SashaMIT Sep 23, 2026
49c45fb
inbox: the narrow request list hugs its requests
SashaMIT Sep 23, 2026
3810566
browser: phone toolbar spans the stage
SashaMIT Sep 23, 2026
f52d881
docs: HOME_MOBILE — capsules on the phone stage
SashaMIT Sep 23, 2026
c325873
home-gui: phone Dock glyphs at 1.3x
SashaMIT Sep 23, 2026
43f6edd
home-gui: phone Dock glyphs at 1.15x
SashaMIT Sep 23, 2026
0829a6e
home-gui, assistant: phone Assistant morph keeps the Dock's width
SashaMIT Sep 23, 2026
2d62899
home-gui: larger ElastOS wordmark on the phone bar
SashaMIT Sep 23, 2026
cff78b4
home-gui: phone bar shows time only and brings Wallet back
SashaMIT Sep 23, 2026
db0f184
home-gui: phone Apps and Assistant morphs at 1100 ms
SashaMIT Sep 23, 2026
e16d666
phone smoke: ratchet small targets inside app frames
SashaMIT Sep 23, 2026
5781b58
people: 44 px touch targets on the phone stage
SashaMIT Sep 23, 2026
b05cb62
system: side menu is the shared push drawer on the phone stage
SashaMIT Sep 23, 2026
4b192ca
inbox: filters and 44 px actions on the phone stage
SashaMIT Sep 23, 2026
5ce0a44
documents: secondary actions in a More menu on the phone stage
SashaMIT Sep 23, 2026
e3e3c50
documents: 44 px title and view tabs on the phone stage
SashaMIT Sep 23, 2026
2188c32
archive-manager: 44 px start buttons on the phone stage
SashaMIT Sep 23, 2026
1a9c80d
assistant: vendor the shared UI runtime so the room hears the size class
SashaMIT Sep 23, 2026
6b13ec3
assistant: 44 px targets on the phone stage
SashaMIT Sep 23, 2026
459d4b6
docs: M6 phone layouts for People, System, Inbox, Documents, Archive …
SashaMIT Sep 23, 2026
6eca0a3
home: the host page relays the soft-keyboard height to the shell
SashaMIT Sep 24, 2026
07dfa8d
library: 44 px view toggle on the phone stage
SashaMIT Sep 24, 2026
57a631c
marketplace: 44 px row actions on the phone stage
SashaMIT Sep 24, 2026
0bc89fc
browser: 44 px controls and snackbar Copy on the phone stage
SashaMIT Sep 24, 2026
89f8f81
docs: every capsule at 0 small targets on the phone stage
SashaMIT Sep 24, 2026
2e7db8a
people: sections as the push drawer on the phone stage
SashaMIT Sep 24, 2026
6a3a434
system: the shared drawer icon for the phone menu button
SashaMIT Sep 24, 2026
6bbfe3d
home: Control Centre as a phone sheet with 44 px targets
SashaMIT Sep 24, 2026
71875d2
home: Notification Centre reads at 12 px on the phone
SashaMIT Sep 24, 2026
3392cf3
home: the launcher fills the phone stage
SashaMIT Sep 24, 2026
a7d79aa
home: Spotlight hangs under the bar and clears the keyboard on a phone
SashaMIT Sep 24, 2026
d5bb922
home: a touch that scrolls Spotlight no longer opens a result
SashaMIT Sep 24, 2026
f291910
home: the phone smoke holds every shell surface at 0/0
SashaMIT Sep 24, 2026
ecd0ed0
docs: phone sheets (M4) and their 0/0 measurements
SashaMIT Sep 24, 2026
7a1e084
home: bar sheets announce themselves as non-modal dialogs
SashaMIT Sep 24, 2026
d850bca
home: reduced motion also skips the launcher's height growth
SashaMIT Sep 24, 2026
e347382
home: phone sheets close from a grab handle
SashaMIT Sep 24, 2026
fa6b52e
home: the phone bar shows only the Reconnecting dot
SashaMIT Sep 30, 2026
e9cd21c
docs: phone sheet handles and non-modal sheet semantics
SashaMIT Sep 24, 2026
35522ff
home: long-press opens shell menus on touch
SashaMIT Sep 24, 2026
1a09018
home: phone menus open as a bottom sheet
SashaMIT Sep 24, 2026
efc7d1e
docs: touch menus on the phone (long-press, menu sheet)
SashaMIT Sep 24, 2026
8de2750
home: the phone Home is the app grid
SashaMIT Sep 24, 2026
d60d8e2
home: retire the phone Apps sheet
SashaMIT Sep 24, 2026
c6a8f9a
docs: the phone Home is the app grid
SashaMIT Sep 24, 2026
fc32b73
home: the server keeps the phone Home arrangement clean
SashaMIT Sep 24, 2026
34b349e
home: phone Home pages, edit mode and the Assistant page
SashaMIT Sep 24, 2026
95b2cf0
docs: phone Home pages, edit mode and the phone's own arrangement
SashaMIT Sep 24, 2026
040dd56
system: models page controls are 44 px targets on phone
SashaMIT Sep 30, 2026
f271632
assistant: settings controls are 44 px targets on phone
SashaMIT Sep 30, 2026
7194268
services: hosted share terms checkbox is a 44px target on a phone
SashaMIT Sep 29, 2026
5a6be37
home-gui: phone title bar is opaque in every chrome mode
SashaMIT Sep 29, 2026
24bf1df
ui: a pushed-aside view's rounded corners show the drawer's fill
SashaMIT Sep 29, 2026
4a54eac
marketplace: phone drawer lists its sections and categories as rows
SashaMIT Sep 29, 2026
fcaba16
system: phone drawer drops the desktop sidebar border and shadow
SashaMIT Sep 29, 2026
d4218e9
Merge remote-tracking branch 'origin/feat/home-desktop-coherence-0.7.…
SashaMIT Oct 2, 2026
7a339be
Merge branch 'feat/home-desktop-coherence-0.7.1-models' into feat/hom…
SashaMIT Oct 3, 2026
08931e6
test(home): drop the phone layout source-text contracts
SashaMIT Oct 3, 2026
d8ea667
ci: run the phone layout unit tests in source-gate
SashaMIT Oct 3, 2026
790be4a
Merge branch 'feat/home-desktop-coherence-0.7.1-models' into feat/hom…
SashaMIT Oct 4, 2026
a89d223
documents: the phone drawer always shows the list
SashaMIT Oct 4, 2026
cae3eb4
scripts: serve the Library fixture's navigation client once
SashaMIT Oct 4, 2026
c915337
test(home): report the bar geometry when a phone surface does not open
SashaMIT Oct 4, 2026
4c24cd5
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 4, 2026
39ba2e5
home-gui: drop the retired checker from the phone media comment
SashaMIT Oct 4, 2026
bc87e63
test: stub targetTitle and isPhone in the window-focus fixture
SashaMIT Oct 4, 2026
6624887
test: phone smoke records where pointer events land when a surface do…
SashaMIT Oct 4, 2026
54f9eeb
merge develop into feat/home-phone-layout-0.7.1-models
SashaMIT Oct 5, 2026
f9b752a
test: phone smoke holds the Home event stream open
SashaMIT Oct 5, 2026
8380806
test: phone smoke reopens Spotlight without Playwright's hit check
SashaMIT Oct 5, 2026
1f1d529
test: revert the Spotlight reopen without Playwright's hit check
SashaMIT Oct 5, 2026
e756721
test: phone smoke re-applies the viewport after each Chromium screenshot
SashaMIT Oct 5, 2026
5568c3c
test: phone smoke captures Chromium screenshots inside the viewport
SashaMIT Oct 5, 2026
a8f0694
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 5, 2026
32cc09d
test(home): the phone smoke's event poll reply carries its schema
SashaMIT Oct 5, 2026
46ced6b
test(home): phone smoke holds a Dock tile through a closed-stream redraw
SashaMIT Oct 5, 2026
4d1b18f
docs(home): swipe-down, Minimise and iOS Back match the shell
SashaMIT Oct 5, 2026
f02cdba
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 5, 2026
2cf55bd
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 6, 2026
4d1555a
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 7, 2026
1868161
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 7, 2026
8c9ccb9
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 8, 2026
52d6805
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 10, 2026
12c06a6
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 11, 2026
8604440
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 11, 2026
aed3673
Merge remote-tracking branch 'origin/develop' into feat/home-phone-la…
SashaMIT Oct 12, 2026
a0dc89d
fix(home): phone Back closes Assistant and the long-press menu
SashaMIT Oct 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions capsules/_shared/elastos-drawer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/* ElastOS UI — phone push drawer (the Assistant's saved-chats pattern).
*
* On the phone stage (html[data-el-form-factor="phone"], see elastos-theme.js)
* a capsule's sidebar leaves the layout and becomes a drawer: the sidebar
* slides in from the leading edge and the main view slides aside with a
* rounded edge; tapping that view, Escape, or picking an item closes it. On
* tablet and desktop this module does nothing and the sidebar stays a column.
*
* Markup contract (no capsule JS needed):
* <aside id="x" data-el-drawer> the sidebar
* <main data-el-drawer-room="x"> the view it pushes aside
* <button data-el-drawer-toggle="x"> opens / closes it
* [data-el-drawer-close] inside the drawer closes after a tap
* Enter in a search field inside the drawer also closes it so the results are
* visible. State lands as data-el-drawer-state="open|closed" on the drawer and
* its room; layout and motion live in elastos-ui.css.
* Vendored by `just vendor-ui` to the capsules that carry a sidebar.
*/
(function () {
const OPEN = "open";
const CLOSED = "closed";

function onPhone() {
return document.documentElement.getAttribute("data-el-form-factor") === "phone";
}

function bindDrawer(drawer) {
const id = drawer.id;
const room = document.querySelector(`[data-el-drawer-room="${id}"]`);
const toggles = Array.from(document.querySelectorAll(`[data-el-drawer-toggle="${id}"]`));
if (!id || !room || toggles.length === 0) {
return;
}
let open = false;

function render() {
const phone = onPhone();
const state = phone && open ? OPEN : CLOSED;
drawer.setAttribute("data-el-drawer-state", state);
room.setAttribute("data-el-drawer-state", state);
// An off-screen drawer must not take focus or speak; off the phone the
// sidebar is a normal column again.
drawer.inert = phone && !open;
for (const toggle of toggles) {
toggle.setAttribute("aria-controls", id);
toggle.setAttribute("aria-expanded", String(phone && open));
}
}

function setOpen(next, { restoreFocus = false } = {}) {
open = Boolean(next) && onPhone();
render();
if (open) {
drawer.focus({ preventScroll: true });
} else if (restoreFocus) {
toggles[0].focus({ preventScroll: true });
}
}

if (!drawer.hasAttribute("tabindex")) {
drawer.setAttribute("tabindex", "-1");
}
for (const toggle of toggles) {
toggle.addEventListener("click", () => setOpen(!open));
}
// A tap on the pushed-aside view closes the drawer and goes no further,
// so it never also activates whatever sat under the finger.
room.addEventListener(
"click",
(event) => {
if (!open || toggles.some((toggle) => toggle.contains(event.target))) {
return;
}
event.preventDefault();
event.stopPropagation();
setOpen(false);
},
true,
);
drawer.addEventListener("click", (event) => {
if (open && event.target.closest?.("[data-el-drawer-close]")) {
setOpen(false);
}
});
drawer.addEventListener("keydown", (event) => {
if (!open) {
return;
}
if (event.key === "Escape") {
event.preventDefault();
setOpen(false, { restoreFocus: true });
return;
}
if (event.key === "Enter" && event.target.matches?.('input[type="search"]')) {
setOpen(false);
}
});
new MutationObserver(() => {
if (!onPhone()) {
open = false;
}
render();
}).observe(document.documentElement, { attributes: true, attributeFilter: ["data-el-form-factor"] });
render();
}

function bindAll() {
document.querySelectorAll("[data-el-drawer]").forEach(bindDrawer);
}

if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", bindAll, { once: true });
} else {
bindAll();
}
})();
25 changes: 25 additions & 0 deletions capsules/_shared/elastos-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,27 @@
});
}

// The shell's size class (`elastos:shell-layout`): phone means the shell's
// own title bar sits above the frame and no window controls overlay it, so
// elastos-ui.css drops the desktop chrome safe areas and capsules take
// their phone layout. Unknown values clear the attribute (desktop).
const FORM_FACTORS = ["phone", "tablet", "desktop"];
const POINTERS = ["coarse", "fine"];

function setOrClear(name, value, allowed) {
if (allowed.includes(value)) {
document.documentElement.setAttribute(name, value);
} else {
document.documentElement.removeAttribute(name);
}
}

function applyShellLayout(layout) {
const value = layout && typeof layout === "object" ? layout : {};
setOrClear("data-el-form-factor", value.formFactor, FORM_FACTORS);
setOrClear("data-el-pointer", value.pointer, POINTERS);
}

// Opaque-sandboxed frames (no allow-same-origin) own no browser-profile
// storage, so persistence stays with the host and the shell relays
// preferences by message instead. Cross-frame updates arrive as
Expand All @@ -215,6 +236,10 @@
return;
}
const message = event.data || {};
if (message.type === "elastos:shell-layout") {
applyShellLayout(message.layout);
return;
}
if (message.type !== "elastos:ui-preference") {
return;
}
Expand Down
107 changes: 105 additions & 2 deletions capsules/_shared/elastos-ui.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
* then run `just vendor-ui`; `scripts/vendor-ui-tokens.sh --check` fails on drift.
*
* Contents: Inter (OFL, latin variable subset), palette, type scale, radii,
* hairlines, blur/elevation steps, motion tokens, and minimal control
* primitives. Layout is each app's business — tokens only.
* hairlines, blur/elevation steps, motion tokens, minimal control
* primitives, and the phone push drawer (with elastos-drawer.js). Layout is
* otherwise each app's business — tokens only.
*/

@font-face {
Expand Down Expand Up @@ -385,6 +386,108 @@
display: none;
}

/* Phone stage (html[data-el-form-factor="phone"], set from the shell's
`elastos:shell-layout` message by elastos-theme.js). The shell's own 44 px
title bar sits above the frame and no traffic lights overlay it, so the
desktop chrome safe areas are zero. The drawer tokens are the Assistant's
push-sidebar values, so every capsule's sidebar moves the same way. */
:root {
--el-drawer-w: min(300px, 82vw);
--el-drawer-ms: 420ms;
--el-drawer-ease: cubic-bezier(0.22, 1, 0.36, 1);
--el-drawer-room-radius: 28px;
--el-touch-target: 44px;
}

:root[data-el-form-factor="phone"] {
--window-chrome-safe-top: 0px;
--window-chrome-safe-leading: 0px;
}

@media (prefers-reduced-motion: reduce) {
:root {
--el-drawer-ms: 1ms;
}
}

/* Phone push drawer (elastos-drawer.js): the sidebar leaves the layout and
sits under the leading edge; opening slides it in and pushes the room
aside by the same width with a rounded edge. Transform only — no reflow of
the room while it moves. */
.el-drawer-toggle {
display: none;
}

:root[data-el-form-factor="phone"] .el-drawer-toggle {
display: inline-grid;
place-items: center;
flex: 0 0 auto;
width: var(--el-touch-target);
height: var(--el-touch-target);
padding: 0;
border: 0;
border-radius: var(--el-radius-md);
background: transparent;
color: var(--el-text);
cursor: pointer;
}

:root[data-el-form-factor="phone"] .el-drawer-toggle::before {
content: "";
width: 22px;
height: 22px;
background: currentColor;
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='16' rx='3'/%3E%3Cpath d='M9 4v16'/%3E%3C/svg%3E") center / contain no-repeat;
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='16' rx='3'/%3E%3Cpath d='M9 4v16'/%3E%3C/svg%3E") center / contain no-repeat;
}

:root[data-el-form-factor="phone"] .el-drawer-toggle:active {
background: var(--el-lift);
}

:root[data-el-form-factor="phone"] .el-drawer-toggle:focus-visible {
outline: 2px solid var(--el-focus);
outline-offset: -2px;
}

:root[data-el-form-factor="phone"] [data-el-drawer] {
position: fixed;
top: 0;
bottom: 0;
left: 0;
z-index: 40;
width: var(--el-drawer-w);
max-width: none;
overflow-y: auto;
overscroll-behavior: contain;
outline: none;
transform: translateX(-105%);
visibility: hidden;
transition:
transform var(--el-drawer-ms) var(--el-drawer-ease),
visibility 0s linear var(--el-drawer-ms);
}

:root[data-el-form-factor="phone"] [data-el-drawer][data-el-drawer-state="open"] {
transform: none;
visibility: visible;
transition: transform var(--el-drawer-ms) var(--el-drawer-ease);
}

:root[data-el-form-factor="phone"] [data-el-drawer-room] {
transition:
transform var(--el-drawer-ms) var(--el-drawer-ease),
border-radius var(--el-drawer-ms) var(--el-drawer-ease);
}

:root[data-el-form-factor="phone"] [data-el-drawer-room][data-el-drawer-state="open"] {
transform: translateX(var(--el-drawer-w));
border-radius: var(--el-drawer-room-radius) 0 0 var(--el-drawer-room-radius);
overflow: hidden;
box-shadow: -1px 0 0 var(--el-hairline);
cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
.el-app *,
.el-app *::before,
Expand Down
25 changes: 25 additions & 0 deletions capsules/archive-manager/browser/elastos-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,27 @@
});
}

// The shell's size class (`elastos:shell-layout`): phone means the shell's
// own title bar sits above the frame and no window controls overlay it, so
// elastos-ui.css drops the desktop chrome safe areas and capsules take
// their phone layout. Unknown values clear the attribute (desktop).
const FORM_FACTORS = ["phone", "tablet", "desktop"];
const POINTERS = ["coarse", "fine"];

function setOrClear(name, value, allowed) {
if (allowed.includes(value)) {
document.documentElement.setAttribute(name, value);
} else {
document.documentElement.removeAttribute(name);
}
}

function applyShellLayout(layout) {
const value = layout && typeof layout === "object" ? layout : {};
setOrClear("data-el-form-factor", value.formFactor, FORM_FACTORS);
setOrClear("data-el-pointer", value.pointer, POINTERS);
}

// Opaque-sandboxed frames (no allow-same-origin) own no browser-profile
// storage, so persistence stays with the host and the shell relays
// preferences by message instead. Cross-frame updates arrive as
Expand All @@ -216,6 +237,10 @@
return;
}
const message = event.data || {};
if (message.type === "elastos:shell-layout") {
applyShellLayout(message.layout);
return;
}
if (message.type !== "elastos:ui-preference") {
return;
}
Expand Down
Loading
Loading