Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9aa2b11
UI polish: one column, page titles, calmer metadata, firmer dark surf…
Nov 5, 2026
0d3836c
coder-checkpoint: turn 34
Nov 5, 2026
8101ece
UI polish: one accent, grouped lists, serif section heads, quieter ac…
Nov 5, 2026
a285539
UI polish: no duplicate titles, routine actions in a menu, readable s…
Nov 5, 2026
c7555e0
UI polish: stable header across tabs, one button edge, 12px minimum m…
Nov 5, 2026
533f588
UI polish: clear primary actions, flat account tiles, visible overflo…
Nov 5, 2026
b9e7ab4
UI polish: firmer dark cards, footnote helper text, accent send, key …
Nov 5, 2026
9305ddf
UI polish: accent primaries, one button height, hairline account tile…
Nov 5, 2026
7fc56f4
UI polish: visible dark card edges, one secondary button style, task-…
Nov 5, 2026
1b5057e
UI polish: account tiles on the page, flat templates, dotted memory m…
Nov 5, 2026
3cf5ed2
UI polish: a comfortable reading scale (14px text, 32px controls), on…
Nov 5, 2026
9aee52f
UI polish: one-line run details, quieter token arrow, fading day divider
Nov 5, 2026
23c4e33
UI polish: task-first routine rows, roomier run column, 32px chat search
Nov 5, 2026
b4185fb
UI polish: routine actions under the text on phones; no Tools heading…
Nov 5, 2026
849d9c1
UI polish: two-line routine rows, field groups off cards on the bot p…
Nov 5, 2026
516a0ff
UI polish: line chevrons on selects, 15px chat text, role as the bot'…
Nov 5, 2026
e320530
UI polish: stronger serif section heads, blue only for actions and on…
Nov 5, 2026
e6b1972
UI polish: serif wordmark, filled account tiles, visible light off-sw…
Nov 5, 2026
0e6d970
UI polish: primary action on every page's title line, filled template…
Nov 5, 2026
e6ea993
UI polish: underlined text actions placed last, title-line primary on…
Nov 5, 2026
751c6da
UI polish: one card type scale, visible link underlines, chip bot pic…
Nov 5, 2026
61b3b89
UI polish: link underlines actually render, ghost Run now, lighter se…
Nov 5, 2026
f5e7731
UI polish: sparkle for Tidy up, dimmed added library cards, two-line …
Nov 5, 2026
4dcf641
UI polish: one-line account tiles, quieter library offers, shorter in…
Nov 5, 2026
4c92a3d
UI polish: calmer routine meta, play glyph on Run now, one paragraph …
Nov 5, 2026
bfc79c2
UI polish: ghost toolbar actions, softer list toggles, denser memory …
Nov 5, 2026
9b26d8d
UI polish: one switch blue, eye for quiet routines, boxed Settings ic…
Nov 5, 2026
467ef4c
UI polish: private-chat glyph, Activity on the shared title column, h…
Nov 5, 2026
4cc831c
UI polish: card notes as footer rows, one-line library offers, cleare…
Nov 5, 2026
cf018bd
UI polish: added skills at full contrast, lighter note rules, firmer …
Nov 5, 2026
5826451
UI polish: one row-title token, unclamped helper measure, single note…
Nov 5, 2026
fa38f70
UI polish: true semibold titles, clearer dark tabs, tinted dark note …
Nov 5, 2026
feaf9ad
UI polish: one 16px trailing inset, quieter memory meta, lock for pri…
Nov 5, 2026
8594847
UI polish: one sidebar selection, plain header copy, search on the su…
Nov 5, 2026
473263b
UI polish: keep the AI account grid one column on phones
Nov 6, 2026
4926a27
UI polish: readable approval cards, section gaps in Needs you
Nov 6, 2026
0108c19
Merge origin/master into ui-polish
Nov 6, 2026
04846c4
UI polish: pad the new folder and rule input bars, fix the raw iMessa…
Nov 6, 2026
a4a9542
UI polish: wrap input bars and pad card notes on phones
Nov 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions scripts/ui-flows.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ await sw.click(); await p.waitForTimeout(800)
check('resume clears Paused', !(await p.locator('.routine').innerText()).includes('Paused'))
await p.locator('.routine').getByRole('button', { name: 'Run now' }).click()
check('run now finishes', await until(async () => (await p.locator('.routine').getByRole('button', { name: 'Run now' }).count()) > 0 && (await p.locator('.rh-dots .dot').count()) > 0, 20000))
await p.locator('.routine').getByRole('button', { name: 'Edit' }).click(); await p.waitForTimeout(400)
await p.locator('.routine').getByRole('button', { name: 'More for this routine' }).click(); await p.getByRole('menuitem', { name: 'Edit' }).click(); await p.waitForTimeout(400)
const prompt = p.locator('.routine-inline textarea').first()
await prompt.fill('Brief me on tech news, edited'); await p.locator('.routine-inline').getByRole('button', { name: /Save/ }).click(); await p.waitForTimeout(800)
check('edit saved', (await main()).includes('edited'))
await p.getByRole('button', { name: 'Delete routine' }).click(); await p.waitForTimeout(200)
await p.getByRole('button', { name: 'More for this routine' }).click(); await p.getByRole('menuitem', { name: 'Delete…' }).click(); await p.waitForTimeout(200)
await p.locator('.ask-box').getByRole('button', { name: 'Delete' }).click(); await p.waitForTimeout(800)
check('routine deleted', (await p.locator('.routine').count()) === 0)

Expand Down
23 changes: 11 additions & 12 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ function Main() {
// Clicking a bot opens a chat with it (on this computer); its settings are a right-click (or the gear by the
// composer's bot picker) away.
const talkTo = (id: number) => { setChatBot(id); setChatId(LOCAL); setIncognito(false); setViaBot(true); setView('chat'); setMenu(null) }
const botChat = viaBot && view === 'chat' && chat.chat_id === LOCAL
// Opened from a bot: it stays that bot's chat across the section tabs, so the header and sidebar don't jump.
const botChat = viaBot && inChat && chat.chat_id === LOCAL
// A bot's right-click menu, or pause choices (for one bot, or all of them: id null).
const [menu, setMenu] = useState<{ x: number; y: number; id: number | null; pick?: boolean } | null>(null)
// A bot file being read before it's added (from a file, or a bot's own for Duplicate).
Expand Down Expand Up @@ -258,7 +259,7 @@ function Main() {
<div className="brand"><img src="/logo.png" alt="" />Mimir{remoteServer() && <span className="where" title={remoteServer()!.url}>server</span>}</div>
<button className={'rail-item inbox-item' + (view === 'inbox' ? ' on' : '')} onClick={() => setView('inbox')}>
<span className="ri-glyph"><Icon name="inbox" size={15} /></span>
<span className="ri-text"><span className="ri-name">Needs you</span><span className="ri-sub">{needs ? 'Waiting for you' : 'All clear'}</span></span>
<span className="ri-text"><span className="ri-name">Needs you</span>{!needs && <span className="ri-sub">All clear</span>}</span>
{needs > 0 && <span className="badge count" key={needs}>{needs}</span>}
</button>
{inDesktop && (
Expand Down Expand Up @@ -338,18 +339,20 @@ function Main() {
</div>
<div className="rail-foot">
<button className={'rail-item' + (view === 'settings' ? ' on' : '')} onClick={() => setView('settings')} title={`Settings ${shortcut(',')}`}>
<Icon name="settings" /> <span className="ri-text"><span className="ri-name">Settings</span></span>
<span className="ri-glyph"><Icon name="settings" size={15} /></span><span className="ri-text"><span className="ri-name">Settings</span></span>
</button>
</div>
</aside>

<main className="main" style={{ '--dx': `${dx}px` } as React.CSSProperties}>
<header className="toolbar" data-tauri-drag-region>
{/* Pages outside a chat carry their own big title: the bar stays only as the window's drag area. */}
<header className={'toolbar' + (inChat ? '' : ' bare')} data-tauri-drag-region>
{inChat ? (
<>
<div className="toolbar-title" data-tauri-drag-region>
<span className="ri-glyph" style={{ width: 26, height: 26, borderRadius: 7, display: 'grid', placeItems: 'center', background: 'var(--hover)', color: 'var(--text-2)' }}><Icon name={ch.icon} size={14} /></span>
<span className="tt" data-tauri-drag-region><b>{botChat ? botOf(chatBot ?? botList[0]?.id ?? 1).name : chatName(chat)}</b><small>{ch.name} · {chat.memories} {chat.memories === 1 ? 'memory' : 'memories'}{household ? '' : ', shared by all your bots'}{chat.household && !household ? ' · reads the household' : ''}{!household && <GoalLine chatId={chat.chat_id} />}</small></span>
{botChat ? <Avatar id={chatBot ?? botList[0]?.id ?? 1} name={botOf(chatBot ?? botList[0]?.id ?? 1).name} size={26} still />
: <span className="ri-glyph" style={{ width: 26, height: 26, borderRadius: 7, display: 'grid', placeItems: 'center', background: 'var(--hover)', color: 'var(--text-2)' }}><Icon name={ch.icon} size={14} /></span>}
<span className="tt" data-tauri-drag-region><b>{botChat ? botOf(chatBot ?? botList[0]?.id ?? 1).name : chatName(chat)}</b><small title={household ? undefined : 'Memories here are shared by all your bots'}>{ch.name} · {chat.memories} {chat.memories === 1 ? 'memory' : 'memories'}{chat.household && !household ? ' + household memories' : ''}{!household && <GoalLine chatId={chat.chat_id} />}</small></span>
{!botChat && chat.chat_id !== LOCAL && !household && !chat.family && (
<button className={'btn btn-sm btn-ghost' + (chat.guest ? ' guest-on' : '')}
title={chat.guest ? 'Paired by someone else: bots here have their own memory, and none of your email, calendar, meetings, saved logins or tool servers. Click if this chat is yours.' : 'Click if someone else uses this chat (a partner, a housemate): bots here then get none of your email, calendar, meetings, saved logins or tool servers.'}
Expand Down Expand Up @@ -377,11 +380,7 @@ function Main() {
</div>
<Segmented label="Sections" value={view as Tab} onChange={setView} options={household ? TABS.filter(t => t.id === 'memory') : TABS} />
</>
) : (
<div className="toolbar-title" data-tauri-drag-region>
<span className="tt" data-tauri-drag-region><b>{view === 'settings' ? 'Settings' : view === 'inbox' ? 'Needs you' : view === 'computer' ? 'Computer' : view === 'meetings' ? 'Meetings' : botId === 0 ? 'New bot' : botOf(botId).name}</b></span>
</div>
)}
) : null}
</header>

{view !== 'inbox' && <Approvals list={approvals} chats={list} chatName={chatName} onDecided={inbox.reload} onOpen={() => setView('inbox')} />}
Expand All @@ -394,7 +393,7 @@ function Main() {
) : (
// Keyed: each view starts at the top (the scroller used to keep the last view's position).
<div className="page" key={`${view}-${chat.chat_id}-${botId}`}>
<div className={'col fade-in' + (view === 'activity' || view === 'computer' ? ' wide' : '')}>
<div className={'col fade-in' + (view === 'computer' ? ' wide' : '')}>
{view === 'memory' && <MemoryView chatId={chat.chat_id} onChange={chats.reload} />}
{view === 'skills' && <SkillsView chatId={chat.chat_id} />}
{view === 'routines' && <RoutinesView chatId={chat.chat_id} bots={botList} />}
Expand Down
Loading
Loading