v1.2 mobile PWA: installable app + mobile-first UI
- Installable PWA: manifest.json (standalone, portrait, maskable icons), theme-color + apple-mobile-web-app meta, generated 192/512 PNG icons, service worker (network-first, never caches /api/). - Mobile UI (≤720px): sticky blurred header, agent grid -> horizontal snap-scroll carousel, fixed bottom composer with safe-area insets, modals -> full-screen bottom sheets, 16px inputs (no iOS zoom), bigger touch targets, icon-only header actions. - /app remains the app shell; / is the landing page.
This commit is contained in:
@@ -2,7 +2,15 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#070b1a">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="apple-mobile-web-app-title" content="Astraea">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<link rel="manifest" href="/static/manifest.json">
|
||||
<link rel="apple-touch-icon" href="/static/icon-192.png">
|
||||
<link rel="icon" type="image/png" href="/static/icon-192.png">
|
||||
<title>Astraea — Your Attorney</title>
|
||||
<style>
|
||||
:root { --bg:#070b1a; --panel:#101832; --panel2:#141d3d; --line:#233055; --text:#e8edfb; --muted:#8b98c4; --gold:#f5d06f; }
|
||||
@@ -102,6 +110,47 @@
|
||||
footer { text-align:center; margin-top:26px; font-size:12px; color:var(--muted); }
|
||||
footer a { color:var(--muted); }
|
||||
@media (max-width:640px){ .msg{max-width:92%;} .grid2{grid-template-columns:1fr;} .avatar-grid{grid-template-columns:repeat(4,1fr);} }
|
||||
|
||||
/* ───────────────────────── Mobile app experience (≤720px) ───────────────────────── */
|
||||
@media (max-width:720px){
|
||||
body { background:var(--bg); overscroll-behavior-y:none; }
|
||||
.app { max-width:100%; padding:0 0 120px; }
|
||||
/* sticky, blurred header */
|
||||
header { position:sticky; top:0; z-index:20; padding:12px 14px; padding-top:calc(12px + env(safe-area-inset-top)); background:rgba(7,11,26,.82); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); border-bottom:1px solid var(--line); margin-bottom:4px; }
|
||||
.logo { width:36px; height:36px; font-size:18px; }
|
||||
.brand h1 { font-size:17px; }
|
||||
.top-actions .btn { padding:8px 11px; font-size:12px; }
|
||||
.top-actions .btn .lbl { display:none; }
|
||||
.hero { padding:8px 14px 6px; }
|
||||
.hero h2 { font-size:21px; }
|
||||
.hero p { font-size:13.5px; }
|
||||
.label { padding:0 14px; margin:10px 0 10px; }
|
||||
/* agents -> horizontal snap carousel */
|
||||
.grid { display:flex; overflow-x:auto; scroll-snap-type:x mandatory; gap:11px; padding:2px 14px 10px; -webkit-overflow-scrolling:touch; scrollbar-width:none; }
|
||||
.grid::-webkit-scrollbar { display:none; }
|
||||
.card { flex:0 0 78%; scroll-snap-align:center; padding:15px; }
|
||||
.card:hover { transform:none; }
|
||||
.chat-panel { margin-top:6px; border-radius:18px 18px 0 0; border-left:none; border-right:none; border-bottom:none; }
|
||||
.messages { max-height:none; height:calc(100vh - 300px); min-height:200px; padding:14px; }
|
||||
.chat-head { padding:11px 14px; }
|
||||
.chips { order:3; width:100%; margin-left:0; padding-top:8px; }
|
||||
/* fixed composer with safe-area */
|
||||
.composer { position:fixed; left:0; right:0; bottom:0; z-index:25; background:rgba(16,24,50,.96); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); border-top:1px solid var(--line); padding:10px 12px; padding-bottom:calc(10px + env(safe-area-inset-bottom)); }
|
||||
.composer textarea { font-size:16px; } /* 16px prevents iOS zoom-on-focus */
|
||||
.send { padding:12px 16px; }
|
||||
.tools-row { overflow-x:auto; flex-wrap:nowrap; padding:0 14px 10px; scrollbar-width:none; }
|
||||
.tools-row .btn { flex:0 0 auto; }
|
||||
/* modals -> full-screen bottom sheets */
|
||||
.modal-bg { align-items:flex-end; padding:0; }
|
||||
.modal { max-width:100%; width:100%; max-height:92vh; border-radius:22px 22px 0 0; padding:22px 18px; padding-bottom:calc(24px + env(safe-area-inset-bottom)); }
|
||||
.modal.wide { width:100%; max-height:92vh; }
|
||||
.modal .close { font-size:26px; padding:0 4px; }
|
||||
.avatar-grid { grid-template-columns:repeat(4,1fr); }
|
||||
/* bigger touch targets */
|
||||
.btn, .chip, .send, .speak, .cite-toggle { min-height:40px; }
|
||||
.chip { font-size:12px; padding:7px 12px; }
|
||||
footer { padding:0 14px 20px; font-size:11px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -110,8 +159,8 @@
|
||||
<header>
|
||||
<div class="brand"><div class="logo">⚖️</div><div><h1>ASTRA<span>EA</span></h1></div></div>
|
||||
<div class="top-actions">
|
||||
<button class="btn" onclick="openDocs()">📄 Documents</button>
|
||||
<button class="btn" onclick="openSettings()">⚙️ Settings</button>
|
||||
<button class="btn" onclick="openDocs()">📄 <span class="lbl">Documents</span></button>
|
||||
<button class="btn" onclick="openSettings()">⚙️ <span class="lbl">Settings</span></button>
|
||||
<div class="avatar-sm" id="myAvatar" onclick="openProfile()" style="background:linear-gradient(135deg,#6ea8ff,#a78bfa)">⚖</div>
|
||||
</div>
|
||||
</header>
|
||||
@@ -241,6 +290,10 @@
|
||||
</div></div>
|
||||
|
||||
<script>
|
||||
// Register the service worker for installable PWA (skips on non-secure origins)
|
||||
if ('serviceWorker' in navigator && location.protocol === 'https:') {
|
||||
navigator.serviceWorker.register('/static/sw.js').catch(() => {});
|
||||
}
|
||||
const AGENTS = {{ agents | tojson }};
|
||||
const token = localStorage.getItem('astraea_token') || '';
|
||||
let active = AGENTS[0].id;
|
||||
|
||||
Reference in New Issue
Block a user