Files
Mortdecai b8a7810bfd chore: archive design handoff bundle for toolbar refresh
Stores SethMux_4-24-26.zip + extracted design_handoff_sethmux_toolbar/
so the spec, mockups, and reference jsx components stay in-repo for
future reference. Not served in production — the only file that ships
is static/toolbar.js, which already matches the design's toolbar.js
byte-for-byte.
2026-04-24 19:51:48 -04:00

270 lines
9.6 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>sethmux — mobile</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&family=Roboto+Mono:wght@400&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
background:#0d0d10;
display:flex;align-items:center;justify-content:center;
font-family:'Roboto',sans-serif;
padding:24px;
overflow:auto;
}
/* The phone holds the sethmux app inline (not the floating toolbar).
We render a self-contained mobile UI here that mirrors the toolbar
visuals exactly, plus the compose row open and Gboard below. */
.phone-app{
display:flex;flex-direction:column;height:100%;
background:#1a1a1d;color:#e8eaed;
font-family:'Roboto',sans-serif;
}
.phone-top{
height:44px;flex-shrink:0;
background:#202124;border-bottom:1px solid #3c4043;
display:flex;align-items:center;justify-content:space-between;
padding:0 14px;
}
.phone-top .brand{color:#D35400;font-weight:500;font-size:13px}
.phone-top .tabs{display:flex;gap:10px;color:#9aa0a6;
font-family:'Roboto Mono',ui-monospace,monospace;font-size:11px}
.phone-top .tabs b{color:#D35400;font-weight:500}
.phone-xterm{
flex:1;padding:8px 10px;overflow:hidden;background:#1a1a1d;
font-family:'Roboto Mono',ui-monospace,Menlo,Consolas,monospace;
font-size:12px;line-height:1.5;color:#cfd2d6;
}
.phone-xterm .ps1{color:#81c995}
.phone-xterm .path{color:#8ab4f8}
.phone-xterm .git{color:#fdd663}
.phone-xterm .cmd{color:#e8eaed}
.phone-xterm .dim{color:#5f6368}
.phone-xterm .ok{color:#81c995}
.phone-xterm .err{color:#f28b82}
.phone-xterm .cursor{
display:inline-block;width:7px;height:13px;background:#e8eaed;
vertical-align:-2px;margin-left:1px;animation:blink 1.1s steps(1) infinite;
}
@keyframes blink{50%{opacity:0}}
/* ── inline toolbar (same visuals as toolbar.js, but mounted in-tree) ── */
.tb{
flex-shrink:0;
background:#202124;border-top:1px solid #3c4043;
padding:6px 8px 7px;
box-shadow:0 -1px 0 rgba(0,0,0,.4),0 -8px 24px rgba(0,0,0,.35);
display:flex;flex-direction:column;
font-family:'Roboto',sans-serif;
}
.tb .row{display:flex;gap:4px;justify-content:center;align-items:center;width:100%}
.tb .row + .row{margin-top:4px}
.tb button{
background:#303134;color:#e8eaed;border:1px solid #3c4043;
border-radius:4px;padding:0 8px;height:32px;min-width:38px;
font:500 12px/1 'Roboto',sans-serif;letter-spacing:.1px;
display:inline-flex;align-items:center;justify-content:center;
}
.tb .mono{
font-family:'Roboto Mono',ui-monospace,Menlo,Consolas,monospace;
font-weight:400;color:#9aa0a6;
}
.tb .hi{color:#f0a36b;border-color:#5a3a22;background:#2a1f15}
.tb .on{background:#D35400;border-color:#D35400;color:#0a0a0a}
.tb .grn{color:#81c995}
.tb .sep{width:1px;height:20px;background:#3c4043;margin:0 3px;flex-shrink:0}
.tb .compose{display:flex;width:100%;gap:4px;align-items:center;margin-top:4px}
.tb input{
flex:1;min-width:0;height:36px;padding:0 10px;
background:#303134;color:#e8eaed;
border:1px solid #D35400;border-radius:4px;
font:400 14px/1 'Roboto Mono',ui-monospace,Menlo,Consolas,monospace;
outline:none;-webkit-appearance:none;appearance:none;
caret-color:#D35400;
}
.tb .send{
height:36px;min-width:54px;padding:0 12px;
background:#D35400;border:1px solid #D35400;color:#0a0a0a;
border-radius:4px;font:500 12px/1 'Roboto',sans-serif;
}
.tb .send.nl{
background:#303134;border-color:#3c4043;color:#9aa0a6;
min-width:38px;padding:0 8px;
}
/* annotation captions next to each phone */
.stack{display:flex;gap:32px;align-items:flex-start}
.col{display:flex;flex-direction:column;align-items:center;gap:14px}
.cap{
color:#9aa0a6;font-size:12px;text-align:center;max-width:340px;
font-family:'Roboto',sans-serif;
}
.cap b{color:#e8eaed;font-weight:500;display:block;margin-bottom:4px;font-size:13px}
</style>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
<script type="text/babel" src="android-frame.jsx"></script>
<script type="text/babel">
function PhoneTop({tab='code', n=1, total=4}) {
return (
<div className="phone-top">
<div className="brand">sethmux</div>
<div className="tabs"><b>{tab}</b> · {n}/{total}</div>
</div>
);
}
function PhoneXterm({collapsed}) {
return (
<div className="phone-xterm">
<div><span className="ps1">seth@mux</span> <span className="path">~</span> <span className="dim">$</span> <span className="cmd">tmux ls</span></div>
<div>sethmux: 4 windows</div>
<div className="dim"> code git run logs</div>
<div>&nbsp;</div>
<div><span className="ps1">seth@mux</span> <span className="path">~</span> <span className="dim">$</span> <span className="cmd">make build</span></div>
<div className="ok"> ok in 2.31s</div>
{!collapsed && <>
<div>&nbsp;</div>
<div><span className="ps1">seth@mux</span> <span className="path">~</span> <span className="dim">$</span> <span className="cmd">tail -f logs/run.log</span></div>
<div className="dim">[14:02:11] http 200 /api/notify 4ms</div>
<div className="dim">[14:02:14] http 200 /api/notify 3ms</div>
</>}
<div>&nbsp;</div>
<div><span className="ps1">seth@mux</span> <span className="path">~</span> <span className="dim">$</span> <span className="cursor"/></div>
</div>
);
}
function ToolbarCollapsed() {
return (
<div className="tb">
<div className="row">
<button className="hi">+ Tab</button>
<button>Next</button>
<button>Prev</button>
<div className="sep"/>
<button className="mono">^C</button>
<button className="mono">^D</button>
<button>Clr</button>
<div className="sep"/>
<button className="mono">Esc</button>
<button className="mono">Tab</button>
<button className="mono"></button>
<button className="mono"></button>
</div>
<div className="row">
<button className="hi">Sel</button>
<button className="hi">Paste</button>
<button>Zoom</button>
<button className="grn">Save</button>
<div className="sep"/>
<button>V.Spl</button>
<button>H.Spl</button>
<button>Pane</button>
<button>Kill</button>
<div className="sep"/>
<button className="hi">Type</button>
</div>
</div>
);
}
function ToolbarComposing() {
return (
<div className="tb">
<div className="row">
<button className="hi">+ Tab</button>
<button>Next</button>
<button>Prev</button>
<div className="sep"/>
<button className="mono">^C</button>
<button className="mono">^D</button>
<button>Clr</button>
<div className="sep"/>
<button className="mono">Esc</button>
<button className="mono">Tab</button>
<button className="mono"></button>
<button className="mono"></button>
</div>
<div className="row">
<button className="hi">Sel</button>
<button className="hi">Paste</button>
<button>Zoom</button>
<button className="grn">Save</button>
<div className="sep"/>
<button>V.Spl</button>
<button>H.Spl</button>
<button>Pane</button>
<button>Kill</button>
<div className="sep"/>
<button className="on">Type</button>
</div>
<div className="compose">
<input defaultValue="git commit -m &quot;wire up compose bar&quot;" />
<button className="send nl"></button>
<button className="send">Send</button>
</div>
</div>
);
}
function PhoneCollapsed() {
return (
<AndroidDevice width={360} height={720} dark>
<div className="phone-app">
<PhoneTop tab="code" n={1} total={4}/>
<PhoneXterm/>
<ToolbarCollapsed/>
</div>
</AndroidDevice>
);
}
function PhoneComposing() {
return (
<AndroidDevice width={360} height={720} dark>
<div className="phone-app">
<PhoneTop tab="git" n={2} total={4}/>
<PhoneXterm collapsed/>
<ToolbarComposing/>
</div>
</AndroidDevice>
);
}
function App() {
return (
<div className="stack">
<div className="col">
<PhoneCollapsed/>
<div className="cap"><b>Default 2 rows</b>All chord keys, tabs, splits, and Save in reach. Tap <span style={{color:'#f0a36b'}}>Type</span> to open compose.</div>
</div>
<div className="col">
<PhoneComposing/>
<div className="cap"><b>Compose open 3 rows</b>Real input field with Gboard autocorrect / swipe / predictions. or Send flushes to stdin + a newline. Other keys still work mid-typing.</div>
</div>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
</script>
</body>
</html>