go to laast session

This commit is contained in:
2026-01-21 00:52:19 -05:00
parent a2e10688bf
commit 0b2d5cdd81
5 changed files with 74 additions and 2 deletions
+3
View File
@@ -43,3 +43,6 @@ client/dev-dist/
# Test results
e2e/test-results/
# Ideas/notes
ideas.md
+2
View File
@@ -1,5 +1,7 @@
# Spiceflow
The ~~spice~~ *tokens* must flow.
A mobile-friendly web app for controlling AI coding assistants (Claude Code, OpenCode) remotely.
```
@@ -5,6 +5,7 @@
export let autoScroll: boolean = true;
export let provider: 'claude' | 'opencode' | 'tmux' = 'claude';
export let showBigMode: boolean = false;
export let lastSessionId: string | null = null;
const dispatch = createEventDispatcher<{
toggleAutoAccept: boolean;
@@ -13,6 +14,7 @@
refresh: void;
eject: void;
bigMode: void;
goToLastSession: void;
}>();
function handleToggleAutoScroll() {
@@ -54,6 +56,11 @@
open = false;
}
function handleGoToLastSession() {
dispatch('goToLastSession');
open = false;
}
function handleClickOutside(event: MouseEvent) {
const target = event.target as HTMLElement;
if (!target.closest('.settings-dropdown')) {
@@ -140,6 +147,19 @@
<span class="text-sm text-zinc-200">Refresh</span>
</button>
<!-- Go to last session -->
{#if lastSessionId}
<button
on:click={handleGoToLastSession}
class="w-full flex items-center gap-3 px-3 py-2.5 hover:bg-zinc-700/50 transition-colors text-left"
>
<svg class="h-4 w-4 text-zinc-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
<span class="text-sm text-zinc-200">Last session</span>
</button>
{/if}
{#if provider !== 'tmux'}
<button
on:click={handleCondenseAll}
+15 -1
View File
@@ -6,8 +6,9 @@
export let sessionId: string;
export let autoScroll: boolean = true;
export let autoFocus: boolean = true;
export let lastSessionId: string | null = null;
const dispatch = createEventDispatcher<{ aliveChange: boolean }>();
const dispatch = createEventDispatcher<{ aliveChange: boolean; goToLastSession: void }>();
// ANSI to HTML converter for terminal colors
const ansiConverter = new AnsiToHtml({
@@ -588,6 +589,19 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3" />
</svg>
</button>
{#if lastSessionId}
<span class="w-px h-6 bg-zinc-700"></span>
<button
on:click={() => dispatch('goToLastSession')}
class="{btnBase} bg-spice-600/80 hover:bg-spice-600 text-white"
aria-label="Go to last session"
title="Go to last session"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
</button>
{/if}
</div>
<!-- Hidden input for keyboard capture (invisible but functional for mobile) -->
+34 -1
View File
@@ -24,6 +24,7 @@
let autoScroll = true;
let tmuxAlive = false;
let isMobile = false;
let lastSessionId: string | null = null;
// Load auto-scroll preference from localStorage and detect mobile
onMount(() => {
@@ -32,6 +33,8 @@
if (stored !== null) {
autoScroll = stored === 'true';
}
// Load last session from localStorage
lastSessionId = localStorage.getItem('spiceflow-last-session');
// Detect mobile (screen width < 640px or height < 450px)
const checkMobile = () => {
isMobile = window.innerWidth < 640 || window.innerHeight < 450;
@@ -42,11 +45,28 @@
}
});
// Track session history when navigating to a new session
let previousSessionId: string | null = null;
$: if (browser && sessionId && sessionId !== previousSessionId) {
// Save the previous session as "last session" before switching
if (previousSessionId) {
localStorage.setItem('spiceflow-last-session', previousSessionId);
lastSessionId = previousSessionId;
}
previousSessionId = sessionId;
}
// Load session when sessionId changes (handles client-side navigation)
$: if (sessionId) {
activeSession.load(sessionId);
}
function goToLastSession() {
if (lastSessionId) {
goto(`/session/${lastSessionId}`);
}
}
function handleToggleAutoScroll(event: CustomEvent<boolean>) {
autoScroll = event.detail;
if (browser) {
@@ -236,6 +256,7 @@
<SessionSettings
{autoAcceptEdits}
{autoScroll}
{lastSessionId}
provider={session.provider}
showBigMode={isTmuxSession && isMobile}
on:toggleAutoAccept={handleToggleAutoAccept}
@@ -244,6 +265,7 @@
on:refresh={handleRefresh}
on:eject={handleEject}
on:bigMode={handleBigMode}
on:goToLastSession={goToLastSession}
/>
<!-- Refresh button - desktop only -->
@@ -326,6 +348,17 @@
</svg>
Refresh
</button>
{#if lastSessionId}
<button
on:click={() => { menuOpen = false; goToLastSession(); }}
class="w-full px-3 py-2 text-left text-sm hover:bg-zinc-700 flex items-center gap-2 transition-colors"
>
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
Last session
</button>
{/if}
{#if !isTmuxSession}
<button
on:click={() => { menuOpen = false; messageList?.condenseAll(); }}
@@ -385,7 +418,7 @@
</div>
{:else if isTmuxSession}
<!-- Terminal view for tmux sessions -->
<TerminalView bind:this={terminalView} sessionId={sessionId || ''} {autoScroll} on:aliveChange={handleTmuxAliveChange} />
<TerminalView bind:this={terminalView} sessionId={sessionId || ''} {autoScroll} {lastSessionId} on:aliveChange={handleTmuxAliveChange} on:goToLastSession={goToLastSession} />
{:else}
<MessageList bind:this={messageList} messages={$activeSession.messages} streamingContent={$activeSession.streamingContent} isThinking={$activeSession.isThinking} provider={session?.provider} {autoScroll} />