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.
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
<!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> </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> </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> </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 "wire up compose bar"" />
|
||||
<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>
|
||||
Reference in New Issue
Block a user