chore: add project docs, readme, and UI mockup
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>signal.el — UI screens</title>
|
||||
<style>
|
||||
:root{
|
||||
--page:#15171c;
|
||||
--bg:#282c34;
|
||||
--bg-dim:#21252b;
|
||||
--fg:#bbc2cf;
|
||||
--fg-dim:#5b6268;
|
||||
--fg-faint:#3f4450;
|
||||
--modeline-bg:#1c1f24;
|
||||
--modeline-fg:#9da5b4;
|
||||
--modeline-inactive:#5b6268;
|
||||
--hl-line:#2c323c;
|
||||
--blue:#3a76f0; /* Signal blue: prompt, matches, selection */
|
||||
--blue-soft:#6f9bf5;
|
||||
--green:#98be65; /* delivered, e2e */
|
||||
--yellow:#ecbe7b; /* unread */
|
||||
--red:#ff6c6b;
|
||||
--mono:"Iosevka","JetBrains Mono","Fira Code",ui-monospace,"SF Mono",Menlo,Consolas,monospace;
|
||||
}
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{
|
||||
background:var(--page);
|
||||
color:var(--fg);
|
||||
font-family:var(--mono);
|
||||
font-size:14px;
|
||||
line-height:1.5;
|
||||
padding:56px 20px 96px;
|
||||
}
|
||||
.wrap{max-width:900px;margin:0 auto}
|
||||
|
||||
header.page{margin-bottom:56px}
|
||||
header.page h1{
|
||||
font-size:15px;font-weight:600;letter-spacing:.04em;color:var(--fg);
|
||||
}
|
||||
header.page h1 .ext{color:var(--blue-soft)}
|
||||
header.page p{
|
||||
margin-top:6px;color:var(--fg-dim);font-size:13px;max-width:62ch;
|
||||
}
|
||||
kbd{
|
||||
color:var(--blue-soft);
|
||||
font-family:inherit;font-size:inherit;
|
||||
}
|
||||
|
||||
section.screen{margin-bottom:72px}
|
||||
.caption{
|
||||
display:flex;align-items:baseline;gap:14px;margin-bottom:12px;
|
||||
}
|
||||
.caption h2{
|
||||
font-size:12px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
|
||||
color:var(--modeline-fg);
|
||||
}
|
||||
.caption span{font-size:12px;color:var(--fg-dim)}
|
||||
|
||||
/* ——— the Emacs frame ——— */
|
||||
.frame{
|
||||
background:var(--bg);
|
||||
border:1px solid #0c0d10;
|
||||
border-radius:6px;
|
||||
overflow:hidden;
|
||||
box-shadow:0 14px 40px rgba(0,0,0,.45);
|
||||
}
|
||||
.buffer{
|
||||
padding:10px 0 14px;
|
||||
min-height:330px;
|
||||
white-space:pre;
|
||||
overflow-x:auto;
|
||||
tab-size:4;
|
||||
}
|
||||
.ln{padding:0 16px 0 22px;position:relative}
|
||||
.fringe{position:absolute;left:8px;color:var(--yellow)}
|
||||
.hl{background:var(--hl-line)}
|
||||
.header-line{
|
||||
background:var(--bg-dim);
|
||||
color:var(--fg-dim);
|
||||
padding:2px 16px 2px 22px;
|
||||
border-bottom:1px solid #1a1d22;
|
||||
white-space:pre;overflow-x:auto;
|
||||
}
|
||||
.dim{color:var(--fg-dim)}
|
||||
.faint{color:var(--fg-faint)}
|
||||
.name{color:var(--fg);font-weight:600}
|
||||
.unread{color:var(--yellow);font-weight:600}
|
||||
.blue{color:var(--blue-soft)}
|
||||
.green{color:var(--green)}
|
||||
.me{color:var(--blue-soft);font-weight:600}
|
||||
.sep{color:var(--fg-faint)}
|
||||
|
||||
.modeline{
|
||||
background:var(--modeline-bg);
|
||||
color:var(--modeline-fg);
|
||||
padding:2px 16px;
|
||||
white-space:pre;overflow-x:auto;
|
||||
border-top:1px solid #14161a;
|
||||
}
|
||||
.modeline .mode{color:var(--blue-soft)}
|
||||
.modeline .e2e{color:var(--green)}
|
||||
.echo{
|
||||
background:var(--bg);
|
||||
color:var(--fg-dim);
|
||||
padding:3px 16px 5px;
|
||||
white-space:pre;overflow-x:auto;
|
||||
}
|
||||
.echo kbd{color:var(--blue-soft)}
|
||||
|
||||
.cursor{
|
||||
display:inline-block;width:.62em;height:1.25em;
|
||||
background:var(--fg);vertical-align:text-bottom;
|
||||
animation:blink 1.1s steps(1) infinite;
|
||||
}
|
||||
@media (prefers-reduced-motion:reduce){.cursor{animation:none}}
|
||||
@keyframes blink{50%{opacity:0}}
|
||||
|
||||
/* minibuffer completion (vertico-style) */
|
||||
.dimmed{opacity:.38}
|
||||
.mini{
|
||||
background:var(--bg);
|
||||
border-top:1px solid #14161a;
|
||||
padding:4px 0 6px;
|
||||
white-space:pre;overflow-x:auto;
|
||||
}
|
||||
.cand{padding:0 16px 0 22px}
|
||||
.cand.sel{background:var(--hl-line)}
|
||||
.cand .m{color:var(--blue-soft);font-weight:700}
|
||||
.cand .ann{color:var(--fg-faint)}
|
||||
.prompt{padding:2px 16px 0 22px}
|
||||
.prompt .p{color:var(--blue-soft);font-weight:600}
|
||||
.prompt .count{color:var(--fg-dim)}
|
||||
|
||||
/* which-key panel */
|
||||
.whichkey{
|
||||
background:var(--bg-dim);
|
||||
border-top:1px solid #14161a;
|
||||
padding:8px 0 10px;
|
||||
white-space:pre;overflow-x:auto;
|
||||
}
|
||||
.wk{padding:0 16px 0 22px}
|
||||
.wk kbd{color:var(--blue-soft);font-weight:600}
|
||||
.wk .arr{color:var(--fg-faint)}
|
||||
|
||||
@media (max-width:560px){
|
||||
body{font-size:12px;padding:32px 8px 64px}
|
||||
.buffer{min-height:240px}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<header class="page">
|
||||
<h1>signal<span class="ext">.el</span> — screens</h1>
|
||||
<p>Four frames. No mouse targets, no chrome. Every action is a binding; conversation switching is a minibuffer completion, never a sidebar.</p>
|
||||
</header>
|
||||
|
||||
<!-- ============ SCREEN 1: chat list ============ -->
|
||||
<section class="screen">
|
||||
<div class="caption"><h2>Chat list</h2><span>*signal* — ibuffer-style root buffer, <kbd>n</kbd>/<kbd>p</kbd> to move, <kbd>RET</kbd> to open</span></div>
|
||||
<div class="frame">
|
||||
<div class="header-line"> U Name Last message When</div>
|
||||
<div class="buffer"><div class="ln"><span class="fringe">●</span><span class="unread"> 3</span> <span class="name">Family</span> <span class="dim">Dad: see you sunday then</span> <span class="faint">09:41</span></div><div class="ln hl"><span class="fringe">●</span><span class="unread"> 1</span> <span class="name">Sarah</span> <span class="dim">photo: IMG_2041.jpg</span> <span class="faint">09:12</span></div><div class="ln"> <span class="name">Mark Okafor</span> <span class="dim">me: merged, cutting the release now</span> <span class="faint">08:55</span></div><div class="ln"> <span class="name">cycling crew</span> <span class="dim">Priya: saturday 7am, usual spot?</span> <span class="faint">Mon</span></div><div class="ln"> <span class="name">Hawat alerts</span> <span class="dim">backup completed: zendo (4.2 GiB)</span> <span class="faint">Mon</span></div><div class="ln"> <span class="name">Elena V.</span> <span class="dim">thanks! that fixed it</span> <span class="faint">Sun</span></div><div class="ln"> <span class="name">school parents</span> <span class="dim">Reminder: early pickup friday</span> <span class="faint">Sun</span></div><div class="ln"> <span class="name">Tom</span> <span class="dim">me: voice message (0:42)</span> <span class="faint">Jun 5</span></div><div class="ln"> <span class="name">Note to Self</span> <span class="dim">uv pip compile --universal</span> <span class="faint">Jun 4</span></div></div>
|
||||
<div class="modeline"> <span class="e2e">⌁</span> <b>*signal*</b> 9 chats · 4 unread <span class="mode">(Signal Chats)</span> ─ U:%%- ─ Top ────────────</div>
|
||||
<div class="echo"><kbd>C-x b</kbd> switch chat <kbd>RET</kbd> open <kbd>m</kbd> mark read <kbd>g</kbd> refresh <kbd>/</kbd> filter</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ SCREEN 2: conversation buffer ============ -->
|
||||
<section class="screen">
|
||||
<div class="caption"><h2>Conversation</h2><span>*signal:Sarah* — compose inline at the prompt, <kbd>RET</kbd> sends, <kbd>M-RET</kbd> newline</span></div>
|
||||
<div class="frame">
|
||||
<div class="buffer"><div class="ln"><span class="sep">───────────────────────────── Tue, Jun 9 ─────────────────────────────</span></div>
|
||||
<div class="ln"><span class="faint">[08:58]</span> <span class="name">Sarah</span><span class="dim">></span> are you taking the girls to the pool after school?</div><div class="ln"><span class="faint">[09:02]</span> <span class="me">me</span><span class="dim">></span> yeah, leaving around 4. want me to grab dinner on the way back? <span class="green">✓✓</span></div><div class="ln"><span class="faint">[09:03]</span> <span class="name">Sarah</span><span class="dim">></span> yes please. thai?</div><div class="ln"><span class="faint">[09:10]</span> <span class="me">me</span><span class="dim">></span> done. ordering the usual <span class="green">✓✓</span></div><div class="ln"><span class="faint">[09:12]</span> <span class="name">Sarah</span><span class="dim">></span> <span class="blue">[photo: IMG_2041.jpg — RET to view]</span></div><div class="ln"> </div><div class="ln"><span class="sep">───────────────────────────────────────────────────────────────────────</span></div><div class="ln"><span class="blue">></span> looks great. see you toni<span class="cursor"></span></div></div>
|
||||
<div class="modeline"> <span class="e2e">⌁ E2E</span> <b>*signal:Sarah*</b> Sarah is typing… <span class="mode">(Signal Chat Fill)</span> ─ U:%%- ─ Bot ───</div>
|
||||
<div class="echo"><kbd>RET</kbd> send <kbd>C-c C-a</kbd> attach <kbd>C-c C-r</kbd> reply-to <kbd>C-c C-e</kbd> emoji react <kbd>M-p</kbd> edit last</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ SCREEN 3: minibuffer switcher ============ -->
|
||||
<section class="screen">
|
||||
<div class="caption"><h2>Minibuffer switcher</h2><span>the core interaction — <kbd>C-x b</kbd> from anywhere, fuzzy narrowing, <kbd>C-n</kbd>/<kbd>C-p</kbd>, <kbd>RET</kbd></span></div>
|
||||
<div class="frame">
|
||||
<div class="dimmed">
|
||||
<div class="buffer" style="min-height:200px"><div class="ln"><span class="faint">[09:10]</span> <span class="me">me</span><span class="dim">></span> done. ordering the usual <span class="green">✓✓</span></div><div class="ln"><span class="faint">[09:12]</span> <span class="name">Sarah</span><span class="dim">></span> <span class="blue">[photo: IMG_2041.jpg — RET to view]</span></div><div class="ln"> </div><div class="ln"><span class="sep">───────────────────────────────────────────────────────────────────────</span></div><div class="ln"><span class="blue">></span> </div></div>
|
||||
<div class="modeline"> <span class="e2e">⌁ E2E</span> <b>*signal:Sarah*</b> <span class="mode">(Signal Chat Fill)</span> ─ U:%%- ─ Bot ───</div>
|
||||
</div>
|
||||
<div class="mini"><div class="cand sel"><span class="name"><span class="m">s</span><span class="m">a</span><span class="m">r</span>ah</span> <span class="ann">direct · 1 unread · 09:12</span></div><div class="cand">school parent<span class="m">s</span> <span class="m">a</span>nd ca<span class="m">r</span>pool <span class="ann">group · Sun</span></div><div class="cand"><span class="m">S</span>amir D<span class="m">a</span><span class="m">r</span>wish <span class="ann">direct · May 30</span></div><div class="prompt"><span class="p">Switch to chat</span> <span class="count">(3/47)</span><span class="p">:</span> sar<span class="cursor"></span></div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ SCREEN 4: which-key ============ -->
|
||||
<section class="screen">
|
||||
<div class="caption"><h2>Discoverability</h2><span>which-key panel after <kbd>C-c s</kbd> — the keymap is the menu</span></div>
|
||||
<div class="frame">
|
||||
<div class="dimmed">
|
||||
<div class="buffer" style="min-height:170px"><div class="ln"><span class="faint">[09:03]</span> <span class="name">Sarah</span><span class="dim">></span> yes please. thai?</div><div class="ln"><span class="faint">[09:10]</span> <span class="me">me</span><span class="dim">></span> done. ordering the usual <span class="green">✓✓</span></div><div class="ln"> </div><div class="ln"><span class="sep">───────────────────────────────────────────────────────────────────────</span></div><div class="ln"><span class="blue">></span> </div></div>
|
||||
<div class="modeline"> <span class="e2e">⌁ E2E</span> <b>*signal:Sarah*</b> <span class="mode">(Signal Chat Fill)</span> ─ U:%%- ─ Bot ───</div>
|
||||
</div>
|
||||
<div class="whichkey"><div class="wk"><kbd>C-c s</kbd></div><div class="wk"> </div><div class="wk"><kbd>a</kbd> <span class="arr">→</span> attach file <kbd>m</kbd> <span class="arr">→</span> mute chat <kbd>v</kbd> <span class="arr">→</span> verify safety number</div><div class="wk"><kbd>d</kbd> <span class="arr">→</span> disappearing msgs <kbd>n</kbd> <span class="arr">→</span> new chat <kbd>x</kbd> <span class="arr">→</span> delete message</div><div class="wk"><kbd>g</kbd> <span class="arr">→</span> new group <kbd>p</kbd> <span class="arr">→</span> pin chat <kbd>/</kbd> <span class="arr">→</span> search in chat</div><div class="wk"><kbd>i</kbd> <span class="arr">→</span> chat info <kbd>r</kbd> <span class="arr">→</span> mark all read <kbd>?</kbd> <span class="arr">→</span> describe bindings</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user