Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions visor/src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub(crate) const CSS: &str = r#"
display: flex; align-items: center; gap: 12px;
padding: 0 12px;
background: #18181b;
border-top: 1px solid #3f3f46;
border-bottom: 1px solid #3f3f46;
}

/* Content-sized, capped, and scrolling past the cap: growth is bounded so
Expand All @@ -26,7 +26,7 @@ pub(crate) const CSS: &str = r#"
max-height: 60vh; overflow-y: auto;
padding: 12px;
background: #27272a;
border-top: 1px solid #3f3f46;
border-bottom: 1px solid #3f3f46;
}

#visor-identity { display: flex; align-items: center; gap: 8px; }
Expand Down
72 changes: 38 additions & 34 deletions visor/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,40 +469,10 @@ pub(crate) fn Visor() -> Element {
// visor ships its own stylesheet as part of its own tree.
style { "{CSS}" }

div { id: "visor-strip", class: "{strip_class}",
Identity { ident }
div { id: "visor-context",
match (&live, &*notice.read()) {
(Some((_, app)), _) => rsx! {
span { class: "{Voice::Framework.class()}", "showing " }
AppVoice { text: app.title.clone() }
},
(None, Some(Notice::Ended { app, reason })) => rsx! {
AppVoice { text: app.clone() }
span { class: "{Voice::Framework.class()}", " ended: {reason}" }
},
(None, Some(Notice::Plain(message))) => rsx! {
span { class: "{Voice::Framework.class()}", "{message}" }
},
(None, None) => rsx! {
span { class: "{Voice::Framework.class()}", "nothing is running" }
},
}
}
div { id: "visor-actions",
// Both tenants need a kernel that answers, so neither is
// offered before the seal opens; the ceremony the boot
// raised is what the user has to act on instead.
TenantButton { label: "Apps", tenant: Tenant::Apps, open: tenant == Some(Tenant::Apps), disabled: !claimed,
onpress: toggle_apps }
TenantButton { label: "Settings", tenant: Tenant::Settings, open: tenant == Some(Tenant::Settings), disabled: !claimed,
onpress: show_settings }
if let Some((id, _)) = live {
button { onclick: move |_| async move { close_session(id).await }, "Close" }
}
}
}

// Drawer above strip: the strip is the line between trusted pixels
// and the app zone, so whatever the visor opens goes on its own side
// of that line and pushes the strip down rather than sitting between
// it and the app.
if let Some(tenant) = tenant {
div { id: "visor-drawer",
match tenant {
Expand Down Expand Up @@ -635,6 +605,40 @@ pub(crate) fn Visor() -> Element {
}
}
}

div { id: "visor-strip", class: "{strip_class}",
Identity { ident }
div { id: "visor-context",
match (&live, &*notice.read()) {
(Some((_, app)), _) => rsx! {
span { class: "{Voice::Framework.class()}", "showing " }
AppVoice { text: app.title.clone() }
},
(None, Some(Notice::Ended { app, reason })) => rsx! {
AppVoice { text: app.clone() }
span { class: "{Voice::Framework.class()}", " ended: {reason}" }
},
(None, Some(Notice::Plain(message))) => rsx! {
span { class: "{Voice::Framework.class()}", "{message}" }
},
(None, None) => rsx! {
span { class: "{Voice::Framework.class()}", "nothing is running" }
},
}
}
div { id: "visor-actions",
// Both tenants need a kernel that answers, so neither is
// offered before the seal opens; the ceremony the boot
// raised is what the user has to act on instead.
TenantButton { label: "Apps", tenant: Tenant::Apps, open: tenant == Some(Tenant::Apps), disabled: !claimed,
onpress: toggle_apps }
TenantButton { label: "Settings", tenant: Tenant::Settings, open: tenant == Some(Tenant::Settings), disabled: !claimed,
onpress: show_settings }
if let Some((id, _)) = live {
button { onclick: move |_| async move { close_session(id).await }, "Close" }
}
}
}
}
}

Expand Down
18 changes: 10 additions & 8 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@
flex-direction: column;
font: 16px/1.4 system-ui, sans-serif;
}
/* The app zone fills everything above the visor. Frames are the only
/* The visor sits at the top, where browsers put their own trusted UI,
and out of thumb range on a handheld — app interactions are the
common case. Its geometry must not move when an app mounts
(docs/design.md "M1": "strip geometry immobile with the app
mounted"). */
#visor {
flex: 0 0 auto;
}
/* The app zone fills everything below the visor. Frames are the only
thing that ever goes in it. */
#app-zone {
flex: 1 1 auto;
Expand All @@ -34,17 +42,11 @@
height: 100%;
display: block;
}
/* The visor is fixed to the bottom: its geometry must not move when an
app mounts (docs/design.md "M1": "strip geometry immobile with the
app mounted"). */
#visor {
flex: 0 0 auto;
}
</style>
</head>
<body>
<div id="app-zone"></div>
<div id="visor"></div>
<div id="app-zone"></div>
<script type="module" src="./boot.js"></script>
</body>
</html>