From f9ccfa9177f11d8e76e1f3059b5a29eabc619f7f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 19 Feb 2026 19:15:43 +0000 Subject: [PATCH] feat: mobile-optimized layout + phone access instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CSS: - Responsive grid: 2-col desktop → 1-col mobile (≤768px) - Sidebar becomes horizontal scroll strip on mobile - 100dvh for correct mobile viewport height - env(safe-area-inset-*) for iPhone notch/home bar - 16px input font-size prevents iOS auto-zoom - 44px min touch targets on input + send button - touch-action: manipulation stops double-tap zoom - overscroll-behavior: none prevents iOS bounce bleed - -webkit-overflow-scrolling: touch for smooth scroll HTML (base.html): - viewport-fit=cover for full-bleed on notched iPhones - apple-mobile-web-app-capable + status-bar-style meta - theme-color meta (#060d14) README: - "Access from your phone" section with exact steps: --host 0.0.0.0, ipconfig getifaddr en0, same-WiFi note https://claude.ai/code/session_01M4L3R98N5fgXFZRvV8X9b6 --- README.md | 32 ++++++++++ src/dashboard/templates/base.html | 5 +- static/style.css | 99 +++++++++++++++++++++++++++++-- 3 files changed, 129 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4ca5673..60662ec 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,38 @@ Open your browser to **http://localhost:8000** --- +## Access from your phone + +The dashboard is mobile-optimized. To open it on your phone: + +**Step 1 — bind to your local network** (instead of just localhost): + +```bash +uvicorn dashboard.app:app --host 0.0.0.0 --port 8000 --reload +``` + +**Step 2 — find your Mac's IP address:** + +```bash +ipconfig getifaddr en0 +``` + +This prints something like `192.168.1.42`. If you're on ethernet instead of Wi-Fi, try `en1`. + +**Step 3 — open on your phone:** + +Make sure your phone is on the **same Wi-Fi network** as your Mac, then open: + +``` +http://192.168.1.42:8000 +``` + +(replace with your actual IP) + +On mobile the layout switches to a single column — status panels become a horizontal scroll strip at the top, chat fills the rest of the screen. The input field is sized to prevent iOS from zooming in when you tap it. + +--- + ## What you'll see The dashboard has two panels on the left and a chat window on the right: diff --git a/src/dashboard/templates/base.html b/src/dashboard/templates/base.html index db0c0d2..4e84890 100644 --- a/src/dashboard/templates/base.html +++ b/src/dashboard/templates/base.html @@ -2,7 +2,10 @@ - + + + + {% block title %}Timmy Time — Mission Control{% endblock %} diff --git a/static/style.css b/static/style.css index 67a5dd8..e3e9614 100644 --- a/static/style.css +++ b/static/style.css @@ -15,6 +15,7 @@ --red-dim: #7a1a22; --blue: #00aaff; --font: 'JetBrains Mono', 'Courier New', monospace; + --header-h: 52px; } * { box-sizing: border-box; margin: 0; padding: 0; } @@ -24,8 +25,10 @@ body { color: var(--text); font-family: var(--font); font-size: 13px; - min-height: 100vh; + min-height: 100dvh; overflow-x: hidden; + /* prevent bounce-scroll from revealing background on iOS */ + overscroll-behavior: none; } /* ── Header ─────────────────────────────────────── */ @@ -34,12 +37,14 @@ body { justify-content: space-between; align-items: center; padding: 12px 24px; + padding-top: max(12px, env(safe-area-inset-top)); background: var(--bg-panel); border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 100; } +.mc-header-left { display: flex; align-items: baseline; gap: 0; } .mc-title { font-size: 18px; font-weight: 700; @@ -58,13 +63,13 @@ body { letter-spacing: 0.1em; } -/* ── Layout ──────────────────────────────────────── */ +/* ── Layout — desktop ────────────────────────────── */ .mc-main { display: grid; grid-template-columns: 260px 1fr; gap: 16px; padding: 16px; - height: calc(100vh - 52px); + height: calc(100dvh - var(--header-h)); } /* ── Panels ──────────────────────────────────────── */ @@ -86,7 +91,7 @@ body { } .panel-body { padding: 14px; } -/* ── Sidebar ─────────────────────────────────────── */ +/* ── Sidebar — desktop ───────────────────────────── */ .sidebar { grid-column: 1; display: flex; @@ -156,11 +161,13 @@ body { display: flex; flex-direction: column; grid-column: 2; + min-height: 0; } .chat-log { flex: 1; overflow-y: auto; padding: 14px; + -webkit-overflow-scrolling: touch; } .chat-message { margin-bottom: 16px; } .msg-meta { @@ -169,8 +176,8 @@ body { margin-bottom: 4px; letter-spacing: 0.12em; } -.chat-message.user .msg-meta { color: var(--blue); } -.chat-message.agent .msg-meta { color: var(--green); } +.chat-message.user .msg-meta { color: var(--blue); } +.chat-message.agent .msg-meta { color: var(--green); } .chat-message.error-msg .msg-meta { color: var(--red); } .msg-body { @@ -189,10 +196,13 @@ body { /* ── Chat Input ──────────────────────────────────── */ .chat-input-bar { padding: 12px 14px; + /* safe area for iPhone home bar */ + padding-bottom: max(12px, env(safe-area-inset-bottom)); background: var(--bg-card); border-top: 1px solid var(--border); display: flex; gap: 8px; + flex-shrink: 0; } .chat-input-bar input { flex: 1; @@ -222,6 +232,8 @@ body { cursor: pointer; letter-spacing: 0.12em; transition: background 0.15s, color 0.15s; + /* prevent double-tap zoom on iOS */ + touch-action: manipulation; } .chat-input-bar button:hover { background: var(--blue); color: var(--bg-deep); } @@ -236,3 +248,78 @@ body { ::-webkit-scrollbar-track { background: var(--bg-deep); } ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } ::-webkit-scrollbar-thumb:hover { background: var(--border-glow); } + + +/* ════════════════════════════════════════════════════ + MOBILE (≤ 768 px) + ════════════════════════════════════════════════════ */ +@media (max-width: 768px) { + + :root { --header-h: 44px; } + + /* Compact header */ + .mc-header { padding: 10px 16px; padding-top: max(10px, env(safe-area-inset-top)); } + .mc-title { font-size: 14px; letter-spacing: 0.1em; } + .mc-subtitle { display: none; } + .mc-time { font-size: 12px; } + + /* Single-column stack; sidebar on top, chat below */ + .mc-main { + grid-template-columns: 1fr; + grid-template-rows: auto minmax(0, 1fr); + padding: 8px; + gap: 8px; + height: calc(100dvh - var(--header-h)); + } + + /* Sidebar becomes a horizontal scroll strip */ + .sidebar { + grid-column: 1; + grid-row: 1; + flex-direction: row; + overflow-x: auto; + overflow-y: hidden; + gap: 8px; + flex-shrink: 0; + scrollbar-width: none; /* Firefox */ + -webkit-overflow-scrolling: touch; + } + .sidebar::-webkit-scrollbar { display: none; } + + /* Each panel card has a fixed width so they don't squash */ + .sidebar .panel { + min-width: 200px; + flex-shrink: 0; + } + + /* Chat fills remaining vertical space */ + .chat-panel { + grid-column: 1; + grid-row: 2; + min-height: 0; + } + + /* Tighter message padding */ + .chat-log { padding: 10px; } + .msg-body { padding: 8px 10px; font-size: 13px; } + .chat-message { margin-bottom: 12px; } + + /* Touch-friendly input bar */ + .chat-input-bar { + padding: 8px 10px; + padding-bottom: max(8px, env(safe-area-inset-bottom)); + gap: 6px; + } + .chat-input-bar input { + /* 16px prevents iOS from zooming when the field focuses */ + font-size: 16px; + min-height: 44px; + padding: 0 12px; + } + .chat-input-bar button { + min-height: 44px; + min-width: 64px; + font-size: 12px; + padding: 0 14px; + } +}