fix: make TodoPanel respect themes and clear on disconnect

- Replace all hardcoded colours with CSS theme variables
- TodoPanel now respects user's theme (Dark, Light, Trans Pride, etc.)
- Clear todos when user disconnects (stop)
- Preserve todos during reconnects (permission prompts, interrupts)
- Only clear on real disconnect (when skipNextGreeting is false)
This commit is contained in:
2026-02-07 14:55:02 -08:00
committed by Naomi Carrigan
parent 3194a3cca5
commit 70af6a6b72
2 changed files with 25 additions and 21 deletions
+21 -21
View File
@@ -15,12 +15,12 @@
</script> </script>
<div <div
class="fixed top-0 right-0 h-full w-96 bg-gray-900 border-l border-pink-500/30 shadow-2xl flex flex-col z-50" class="fixed top-0 right-0 h-full w-96 bg-[var(--bg-primary)] border-l border-[var(--accent-primary)]/30 shadow-2xl flex flex-col z-50"
> >
<!-- Header --> <!-- Header -->
<div class="flex items-center justify-between p-4 border-b border-pink-500/30"> <div class="flex items-center justify-between p-4 border-b border-[var(--accent-primary)]/30">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<div class="text-pink-400"> <div class="text-[var(--accent-primary)]">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6" class="h-6 w-6"
@@ -37,9 +37,9 @@
</svg> </svg>
</div> </div>
<div> <div>
<h2 class="text-lg font-semibold text-white">Hikari's Todo List</h2> <h2 class="text-lg font-semibold text-[var(--text-primary)]">Hikari's Todo List</h2>
{#if hasTodos} {#if hasTodos}
<p class="text-xs text-gray-400"> <p class="text-xs text-[var(--text-secondary)]">
{completedCount} of {totalCount} completed {completedCount} of {totalCount} completed
</p> </p>
{/if} {/if}
@@ -47,7 +47,7 @@
</div> </div>
<button <button
onclick={onClose} onclick={onClose}
class="text-gray-400 hover:text-white transition-colors p-1 rounded-lg hover:bg-gray-800" class="text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition-colors p-1 rounded-lg hover:bg-[var(--bg-secondary)]"
aria-label="Close todo panel" aria-label="Close todo panel"
> >
<svg <svg
@@ -68,7 +68,7 @@
<!-- Content --> <!-- Content -->
<div class="flex-1 overflow-y-auto p-4"> <div class="flex-1 overflow-y-auto p-4">
{#if !hasTodos} {#if !hasTodos}
<div class="flex flex-col items-center justify-center h-full text-gray-500"> <div class="flex flex-col items-center justify-center h-full text-[var(--text-secondary)]">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="h-16 w-16 mb-4 opacity-50" class="h-16 w-16 mb-4 opacity-50"
@@ -90,18 +90,18 @@
<div class="space-y-2"> <div class="space-y-2">
{#each currentTodos as todo (todo.content)} {#each currentTodos as todo (todo.content)}
<div <div
class="group bg-gray-800/50 rounded-lg p-3 border border-gray-700 hover:border-pink-500/50 transition-all" class="group bg-[var(--bg-secondary)]/50 rounded-lg p-3 border border-[var(--border-color)] hover:border-[var(--accent-primary)]/50 transition-all"
class:opacity-60={todo.status === "completed"} class:opacity-60={todo.status === "completed"}
> >
<div class="flex items-start gap-3"> <div class="flex items-start gap-3">
<!-- Status Icon --> <!-- Status Icon -->
<div class="mt-0.5 flex-shrink-0"> <div class="mt-0.5 flex-shrink-0">
{#if todo.status === "completed"} {#if todo.status === "completed"}
<CheckCircle class="w-5 h-5 text-green-400" /> <CheckCircle class="w-5 h-5 text-[var(--success-color)]" />
{:else if todo.status === "in_progress"} {:else if todo.status === "in_progress"}
<Loader class="w-5 h-5 text-pink-400 animate-spin" /> <Loader class="w-5 h-5 text-[var(--accent-primary)] animate-spin" />
{:else} {:else}
<Circle class="w-5 h-5 text-gray-500" /> <Circle class="w-5 h-5 text-[var(--text-secondary)]" />
{/if} {/if}
</div> </div>
@@ -109,9 +109,9 @@
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<p <p
class="text-sm font-medium" class="text-sm font-medium"
class:text-gray-400={todo.status === "completed"} class:text-[var(--text-secondary)]={todo.status === "completed"}
class:line-through={todo.status === "completed"} class:line-through={todo.status === "completed"}
class:text-white={todo.status !== "completed"} class:text-[var(--text-primary)]={todo.status !== "completed"}
> >
{todo.status === "in_progress" ? todo.activeForm : todo.content} {todo.status === "in_progress" ? todo.activeForm : todo.content}
</p> </p>
@@ -120,19 +120,19 @@
<div class="mt-1"> <div class="mt-1">
{#if todo.status === "completed"} {#if todo.status === "completed"}
<span <span
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-900/30 text-green-400 border border-green-500/30" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-[var(--success-color)]/20 text-[var(--success-color)] border border-[var(--success-color)]/30"
> >
✓ Completed ✓ Completed
</span> </span>
{:else if todo.status === "in_progress"} {:else if todo.status === "in_progress"}
<span <span
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-pink-900/30 text-pink-400 border border-pink-500/30 animate-pulse" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-[var(--accent-primary)]/20 text-[var(--accent-primary)] border border-[var(--accent-primary)]/30 animate-pulse"
> >
⚡ In Progress ⚡ In Progress
</span> </span>
{:else} {:else}
<span <span
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-700/30 text-gray-400 border border-gray-600/30" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-[var(--bg-secondary)] text-[var(--text-secondary)] border border-[var(--border-color)]"
> >
○ Pending ○ Pending
</span> </span>
@@ -148,16 +148,16 @@
<!-- Footer with Progress Bar --> <!-- Footer with Progress Bar -->
{#if hasTodos} {#if hasTodos}
<div class="border-t border-pink-500/30 p-4 bg-gray-800/50"> <div class="border-t border-[var(--accent-primary)]/30 p-4 bg-[var(--bg-secondary)]/50">
<div class="flex items-center justify-between mb-2"> <div class="flex items-center justify-between mb-2">
<span class="text-xs font-medium text-gray-400">Progress</span> <span class="text-xs font-medium text-[var(--text-secondary)]">Progress</span>
<span class="text-xs font-medium text-pink-400"> <span class="text-xs font-medium text-[var(--accent-primary)]">
{Math.round((completedCount / totalCount) * 100)}% {Math.round((completedCount / totalCount) * 100)}%
</span> </span>
</div> </div>
<div class="w-full bg-gray-700 rounded-full h-2 overflow-hidden"> <div class="w-full bg-[var(--bg-secondary)] rounded-full h-2 overflow-hidden">
<div <div
class="bg-gradient-to-r from-pink-500 to-purple-500 h-2 rounded-full transition-all duration-500 ease-out" class="bg-gradient-to-r from-[var(--accent-primary)] to-[var(--accent-secondary)] h-2 rounded-full transition-all duration-500 ease-out"
style="width: {(completedCount / totalCount) * 100}%" style="width: {(completedCount / totalCount) * 100}%"
></div> ></div>
</div> </div>
+4
View File
@@ -14,6 +14,7 @@ import type {
import type { CharacterState } from "$lib/types/states"; import type { CharacterState } from "$lib/types/states";
import type { AgentStartPayload, AgentEndPayload } from "$lib/types/agents"; import type { AgentStartPayload, AgentEndPayload } from "$lib/types/agents";
import { agentStore } from "$lib/stores/agents"; import { agentStore } from "$lib/stores/agents";
import { todos } from "$lib/stores/todos";
import { import {
initializeNotificationRules, initializeNotificationRules,
cleanupNotificationRules, cleanupNotificationRules,
@@ -196,6 +197,9 @@ export async function initializeTauriListeners() {
"system", "system",
"Disconnected from Claude Code" "Disconnected from Claude Code"
); );
// Clear todos on real disconnect (not on reconnects for permissions)
todos.clear();
} }
// Update character state for this conversation // Update character state for this conversation