diff --git a/src/App.css b/src/App.css index 895443b..726cfd0 100644 --- a/src/App.css +++ b/src/App.css @@ -169,7 +169,6 @@ button { font: inherit; } ready states float as a small pill so they never push the lesson down. */ .r-status { display: flex; align-items: center; gap: 0.6rem; font-size: 0.85rem; padding: 0.45rem 0.6rem 0.45rem 0.9rem; border-radius: 999px; } .r-status.ready, .r-status.busy { - position: fixed; z-index: 35; right: max(1rem, env(safe-area-inset-right)); bottom: max(1rem, env(safe-area-inset-bottom)); box-shadow: var(--shadow); border: 1px solid var(--line); background: var(--surface); animation: pill-in var(--medium) var(--ease) both; } @@ -558,7 +557,7 @@ button { font: inherit; } } @media print { - .topbar, .sidebar, .nav-backdrop, .r-status, .lesson-nav, .reading-progress, .section-guide, .toaster { display: none !important; } + .topbar, .sidebar, .nav-backdrop, .r-status, .corner-stack, .lesson-nav, .reading-progress, .section-guide, .toaster { display: none !important; } .app { display: block; } body { background: #fff; } .app-main { max-width: none; padding: 0; } diff --git a/src/App.tsx b/src/App.tsx index 81406db..00bea60 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -114,7 +114,7 @@ export default function App() { {navOpen && ); diff --git a/src/components/RStatus.tsx b/src/components/RStatus.tsx index b344be5..dcb0161 100644 --- a/src/components/RStatus.tsx +++ b/src/components/RStatus.tsx @@ -1,13 +1,18 @@ import { useEffect, useState } from 'react'; import { onStatus, restartR, type RStatus as Status } from '../r/webrClient'; -export default function RStatus() { +/** + * `where` splits the two homes: an error sits in the page ("page"), the ready + * and busy pill stacks under the helper in the corner ("corner"). + */ +export default function RStatus({ where }: { where?: 'page' | 'corner' }) { const [status, setStatus] = useState({ phase: 'idle' }); useEffect(() => onStatus(setStatus), []); // Nothing has started yet, so claim nothing: an amber "Starting R…" pill for // idle would be a lie on any page reached before the boot effect runs. if (status.phase === 'idle') return null; + if (where === (status.phase === 'error' ? 'corner' : 'page')) return null; if (status.phase === 'ready') { return
R is ready
; diff --git a/src/components/SiteGuide.css b/src/components/SiteGuide.css index c8997f8..9fc6f94 100644 --- a/src/components/SiteGuide.css +++ b/src/components/SiteGuide.css @@ -1,5 +1,6 @@ /* The avatar helper in the bottom right corner. */ -.site-guide { position: fixed; right: max(1rem, env(safe-area-inset-right)); bottom: max(1rem, env(safe-area-inset-bottom)); z-index: 50; display: flex; flex-direction: column; align-items: flex-end; gap: 0.6rem; } +.corner-stack { position: fixed; right: max(1rem, env(safe-area-inset-right)); bottom: max(1rem, env(safe-area-inset-bottom)); z-index: 50; display: flex; flex-direction: column; align-items: flex-end; gap: 0.6rem; } +.site-guide { display: flex; flex-direction: column; align-items: flex-end; gap: 0.6rem; } .site-guide-button { display: flex; align-items: center; gap: 0.4rem; padding: 0.25rem 0.9rem 0.25rem 0.25rem; border-radius: 999px; cursor: pointer; border: 1.5px solid var(--brand); background: var(--surface); color: var(--brand-ink); font-weight: 700; box-shadow: var(--shadow-lg); @@ -27,6 +28,4 @@ @media print { .site-guide { display: none; } } .site-guide-compact .site-guide-label { display: none; } .site-guide-compact .site-guide-button { padding: 0.25rem; } -/* The R status pill also sits bottom right: stand on top of it while it shows. */ -body:has(.r-status.ready, .r-status.busy) .site-guide { bottom: calc(max(1rem, env(safe-area-inset-bottom)) + 3.5rem); } .site-guide-tour { display: block; margin: 0.8rem 0 0; padding: 0; font: inherit; font-size: 0.88rem; background: none; border: 0; color: var(--brand-ink); text-decoration: underline; cursor: pointer; }