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
2 changes: 1 addition & 1 deletion packages/omnibioai-ui/dist/index.css

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions packages/omnibioai-ui/src/components/Table/Table.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
border: 0.5px solid var(--color-border);
border-radius: var(--radius-lg);
overflow: hidden;
/* Narrow viewports: scroll the table horizontally inside its own box
instead of overflowing the page (the wrap's own rounded corners /
border still clip vertically via `overflow: hidden` above — this
just adds a scroll axis, it doesn't change desktop behavior since
content that already fits never triggers a scrollbar). */
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}

table.omni-table {
Expand Down
132 changes: 132 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,91 @@ a:focus:not(:focus-visible) {
}
}

/* Verified at 390/428px: 2 tiles/row leaves ~175px per tile, which wraps
the longer plugin names (e.g. "Multi-Agent Orchestrator") to 3 lines —
still readable, but 1 column reads noticeably better on the narrowest
phones. Scoped tighter than the 600px rule above so nothing changes
between 421-600px. */
@media (max-width: 420px) {
.app-grid { grid-template-columns: 1fr; }
}

@media (max-width: 767px) {
.workbench-header-actions button { min-height: 44px; }
}

/* ── Generic: horizontal table scroll instead of page overflow ── */
/* Used by raw <table> elements that don't go through the shared
@omnibioai/ui <Table> component (which got its own overflow-x:auto on
.omni-table-wrap in a separate commit). */
.studio-table-scroll { overflow-x: auto; }

/* ── Jobs page: fixed N-col grids collapse below 768px ── */
/* !important is needed here (not elsewhere in this stylesheet) because
these specific grid-template-columns values are set inline in Jobs.jsx
and some are computed from JS state (e.g. selected ? "1fr 1fr" : "1fr"),
so a plain class rule of lower precedence can't win against them. */
@media (max-width: 767px) {
.jobs-submit-grid { grid-template-columns: 1fr !important; }
.jobs-stats-grid { grid-template-columns: repeat(2, 1fr) !important; }
.jobs-main-grid { grid-template-columns: 1fr !important; }
.jobs-info-grid { grid-template-columns: 1fr !important; }
}
@media (max-width: 400px) {
.jobs-stats-grid { grid-template-columns: 1fr !important; }
}

/* ── Config/wizard pages: fixed N-col panel grids collapse to 1 column ── */
/* Settings, LLM (x2), Cloud, HPC (x2), Launch's Summary+Logs, IdeServices —
same "several Nfr panels side by side" shape, all readable as a single
stacked column below 768px. !important for the same inline-style-override
reason as the Jobs rules above. */
@media (max-width: 767px) {
.studio-grid-1 { grid-template-columns: 1fr !important; }
}

/* Mode's runtime-mode selector cards (title + 2-line description) — needs
more room per card than a status tile, so drop to 2 columns first, then
1 on the narrowest phones. */
@media (max-width: 767px) {
.studio-mode-grid { grid-template-columns: repeat(2, 1fr) !important; }
}
@media (max-width: 480px) {
.studio-mode-grid { grid-template-columns: 1fr !important; }
}

/* HealthCard status-tile rows (Mode + Launch) — compact enough to stay
multi-column on mobile, just fewer of them. */
@media (max-width: 767px) {
.studio-health-grid { grid-template-columns: repeat(3, 1fr) !important; }
}
@media (max-width: 480px) {
.studio-health-grid { grid-template-columns: repeat(2, 1fr) !important; }
}

/* Shared UI.jsx Input/Select/Btn — 44px touch target on mobile only.
min-height (not height) so multi-line/larger variants aren't clamped
down; a plain min-height addition never shrinks anything, so this is
safe to apply uniformly across every page that imports these. */
@media (max-width: 767px) {
.studio-field { min-height: 44px; }
}

/* ── Logs page: fixed-px row grid (60px 80px 80px 1fr) degrades badly on
narrow screens — three fixed columns eat ~220px regardless of viewport,
leaving the message column crushed. Below 640px, keep time/level/source
on one compact auto-sized row and drop the message to its own full-width
row underneath (grid auto-placement via the message span's 1/-1). ── */
@media (max-width: 640px) {
.studio-log-row {
grid-template-columns: auto auto 1fr !important;
row-gap: 3px;
}
.studio-log-row > span:nth-child(4) {
grid-column: 1 / -1;
}
}

.toggle {
width: 32px;
height: 18px;
Expand All @@ -160,3 +245,50 @@ a:focus:not(:focus-visible) {
}
.toggle.on::after { left: 16px; }
.toggle.off::after { left: 2px; }

/* ── App shell: mobile nav (additive — desktop unaffected above 767px) ── */
/* Desktop's <Sidebar> wrapper already sets width inline (200 or 0 when a
service is open); below the breakpoint MobileNav (drawer) takes over as
the only nav surface, so the inline sidebar rail is force-collapsed. */
@media (max-width: 767px) {
.studio-sidebar-wrap {
width: 0 !important;
}
}

/* Hamburger trigger — hidden by default (desktop), shown only under the
breakpoint. Mirrors Tailwind's `md:hidden` without pulling Tailwind into
a file that otherwise uses none of it. */
.studio-hamburger {
display: none;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
min-width: 44px;
min-height: 44px;
border-radius: var(--radius-sm);
background: var(--bg3);
border: 1px solid var(--border2);
color: var(--text);
cursor: pointer;
flex-shrink: 0;
font-size: 16px;
padding: 0;
}
@media (max-width: 767px) {
.studio-hamburger { display: inline-flex; }
}

/* ── Login: mobile touch-target + card padding polish ── */
/* Base (desktop) value matches Login.jsx's previous inline 2.5rem exactly;
pulled into a class only so the mobile media query below has something
to override without an !important fight against the inline style. */
.studio-login-card { padding: 2.5rem; }
@media (max-width: 480px) {
.studio-login-card { padding: 1.75rem 1.25rem; }
}
@media (max-width: 767px) {
.studio-login-btn,
.studio-login-tab { min-height: 44px; }
}
24 changes: 22 additions & 2 deletions src/ui/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react";
import LicenseGate from "./components/LicenseGate";
import BugReport from "./components/BugReport";
import Sidebar from "./components/Sidebar";
import MobileNav from "./components/MobileNav";
import UpdateBanner from "./components/UpdateBanner";
import Mode from "./pages/Mode";
import LLM from "./pages/LLM";
Expand Down Expand Up @@ -93,6 +94,7 @@ export default function App() {
const [authChecked, setAuthChecked] = useState(false); // has the initial session check resolved? (web only)
const [oauthNotice, setOauthNotice] = useState(null); // result of an OAuth redirect: link_required | error
const [returnTo, setReturnTo] = useState(() => getSafeReturnTo()); // ?return_to= target, captured once
const [mobileNavOpen, setMobileNavOpen] = useState(false); // MobileNav drawer — mobile only, no desktop effect

// ─── Load saved config + first-run detection ───────────
useEffect(() => {
Expand Down Expand Up @@ -255,8 +257,10 @@ export default function App() {
background:"var(--bg)", color:"var(--text)",
fontFamily:"var(--font)", overflow:"hidden",
}}>
{/* Sidebar — auto-hides when inside a service/app view */}
<div style={{
{/* Sidebar — auto-hides when inside a service/app view (desktop);
also force-collapsed below 768px via .studio-sidebar-wrap, where
MobileNav's drawer is the nav surface instead (see index.css). */}
<div className="studio-sidebar-wrap" style={{
width: service ? 0 : 200,
overflow: "hidden",
transition: "width 0.2s ease",
Expand All @@ -282,6 +286,14 @@ export default function App() {
display:"flex", alignItems:"center", flexWrap:"wrap",
padding:"8px 20px", gap:12, flexShrink:0,
}}>
{/* Mobile-only nav trigger — hidden on desktop via .studio-hamburger (index.css) */}
<button
className="studio-hamburger"
onClick={() => setMobileNavOpen(true)}
aria-label="Open navigation"
aria-haspopup="dialog"
>☰</button>

<div style={{
fontSize:'var(--font-size-xs)', fontFamily:"var(--mono)", color:"var(--color-text-muted)",
display:"flex", alignItems:"center", gap:6,
Expand Down Expand Up @@ -438,6 +450,14 @@ export default function App() {
</div>
)}
</div>

{/* MobileNav drawer — position:fixed, so it's out of the flex flow
entirely; renders identically on desktop (just permanently closed
since the hamburger that opens it is display:none there). */}
<MobileNav
nav={nav} step={step} setStep={setStep} currentUser={currentUser}
open={mobileNavOpen} onClose={() => setMobileNavOpen(false)}
/>
</div>
)}

Expand Down
3 changes: 2 additions & 1 deletion src/ui/components/GrafanaViewer/GrafanaViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,9 @@ export function GrafanaViewer({ onBack, label }) {
<div style={{
display: "flex", alignItems: "center", justifyContent: "center",
height: "100%", background: "var(--color-bg)",
padding: 16, boxSizing: "border-box",
}}>
<div style={{ width: 380, textAlign: "center" }}>
<div style={{ width: "100%", maxWidth: 380, textAlign: "center", boxSizing: "border-box" }}>
<Card elevated>
<div style={{ marginBottom: 20 }}>
<div style={{ fontSize: 32, marginBottom: 12 }}>📈</div>
Expand Down
5 changes: 4 additions & 1 deletion src/ui/components/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,11 @@ export default function Login({ title, description }) {

<div style={{ width: "100%", maxWidth: 420, position: "relative", zIndex: 1 }}>
<div
className="studio-login-card"
style={{
background: CARD_BG,
border: "1px solid rgba(0, 212, 170, 0.25)",
borderRadius: 12,
padding: "2.5rem",
}}
>
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", marginBottom: 16 }}>
Expand Down Expand Up @@ -209,6 +209,7 @@ export default function Login({ title, description }) {
<button
key={m}
type="button"
className="studio-login-tab"
onClick={() => { setMode(m); setError(""); }}
style={{
flex: 1, padding: "8px 0", cursor: "pointer",
Expand Down Expand Up @@ -264,6 +265,7 @@ export default function Login({ title, description }) {
<button
type="submit"
disabled={busy}
className="studio-login-btn"
style={{
width: "100%",
padding: "10px 0",
Expand Down Expand Up @@ -295,6 +297,7 @@ export default function Login({ title, description }) {
<button
key={provider}
type="button"
className="studio-login-btn"
onClick={() => startOAuth(provider)}
style={{
width: "100%",
Expand Down
Loading
Loading