M4+: mirror the desktop design language onto mobile (Home/Projects/To-Dos/Sessions)

Design system: Palette (teal accent + the Mac's categorical status colors, status→color
refined by turn disposition), StatusStyle glyphs/labels, a card surface modifier, app-wide
teal tint.

Fixes the reported bug: Sessions now hides archived chats and uses disposition to split
NEEDS YOU from DONE (a finished-the-work turn no longer shows as needing you). Rows gain
status dots, favorite star, approval-count badge, diffstat; swipe to favorite/archive/delete.

New surfaces, full control-scope parity with the Mac:
- Home: greeting + day-streak flame, GitHub-style activity grid, stat cards, quick to-dos,
  and a start-chat composer (project picker + Auto).
- Projects: per-project session counts → project detail with a scoped composer.
- To-dos: capture, group by project, complete/dispatch/delete.
- Session detail: a control menu (rename, favorite, interrupt, integrate merge/squash/rebase,
  archive, delete).

RemoteStore handles the dashboard event + exposes all control intents; claims control scope.
A NUCLEIC_DEMO/NUCLEIC_TAB env seam seeds mock state for offline UI preview.

iOS app builds for the iOS 27 simulator; Home + Sessions verified rendering via screenshots.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
2026-06-13 02:20:53 -07:00
co-authored by Claude Opus 4.8
parent c907333df2
commit a70b21cd3e
11 changed files with 822 additions and 92 deletions
@@ -15,18 +15,29 @@ struct NucleicRemoteApp: App {
struct RootView: View {
@EnvironmentObject var store: RemoteStore
// Initial tab; overridable via NUCLEIC_TAB for offline UI previews.
@State private var tab = Int(ProcessInfo.processInfo.environment["NUCLEIC_TAB"] ?? "") ?? 0
var body: some View {
if store.isPaired {
TabView {
SessionsView()
.tabItem { Label("Sessions", systemImage: "square.stack.3d.up") }
.badge(store.needsYouCount)
SettingsView()
.tabItem { Label("Settings", systemImage: "gearshape") }
Group {
if store.isPaired {
TabView(selection: $tab) {
HomeView()
.tabItem { Label("Home", systemImage: "house") }.tag(0)
SessionsView()
.tabItem { Label("Sessions", systemImage: "square.stack.3d.up") }
.badge(store.needsYouCount).tag(1)
ProjectsView()
.tabItem { Label("Projects", systemImage: "folder") }.tag(2)
TodosView()
.tabItem { Label("To-dos", systemImage: "checklist") }.tag(3)
SettingsView()
.tabItem { Label("Settings", systemImage: "gearshape") }.tag(4)
}
} else {
PairingIntroView()
}
} else {
PairingIntroView()
}
.tint(Palette.accent)
}
}