feat: implement light/dark theme toggle with CSS custom properties
- Add CSS custom properties for theme colors (:root and .dark) - Create utility classes: bg-theme-*, text-theme-*, border-theme-* - Update +layout.svelte main containers - Update Sidenav with theme-aware navigation links - Update TopNav header and action buttons - Update ChatWindow main area and input section - Update ChatInput with themed input container - Update MessageItem with theme-aware message bubbles - Update EmptyState with themed welcome cards Theme colors automatically switch between light and dark mode when clicking the theme toggle button in the top navigation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,10 +2,69 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* Theme colors using CSS custom properties */
|
||||
:root {
|
||||
/* Light mode (default) */
|
||||
--color-bg-primary: theme('colors.slate.50');
|
||||
--color-bg-secondary: theme('colors.slate.100');
|
||||
--color-bg-tertiary: theme('colors.slate.200');
|
||||
--color-bg-sidenav: theme('colors.slate.100');
|
||||
--color-bg-topnav: theme('colors.white');
|
||||
--color-bg-input: theme('colors.white');
|
||||
--color-bg-hover: theme('colors.slate.200');
|
||||
--color-bg-message-user: theme('colors.slate.200');
|
||||
--color-bg-message-assistant: transparent;
|
||||
--color-text-primary: theme('colors.slate.900');
|
||||
--color-text-secondary: theme('colors.slate.600');
|
||||
--color-text-muted: theme('colors.slate.500');
|
||||
--color-text-placeholder: theme('colors.slate.400');
|
||||
--color-border: theme('colors.slate.300');
|
||||
--color-border-subtle: theme('colors.slate.200');
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* Dark mode */
|
||||
--color-bg-primary: theme('colors.slate.900');
|
||||
--color-bg-secondary: theme('colors.slate.800');
|
||||
--color-bg-tertiary: theme('colors.slate.700');
|
||||
--color-bg-sidenav: theme('colors.slate.950');
|
||||
--color-bg-topnav: theme('colors.slate.900');
|
||||
--color-bg-input: theme('colors.slate.800');
|
||||
--color-bg-hover: theme('colors.slate.700');
|
||||
--color-bg-message-user: theme('colors.slate.700');
|
||||
--color-bg-message-assistant: transparent;
|
||||
--color-text-primary: theme('colors.slate.100');
|
||||
--color-text-secondary: theme('colors.slate.300');
|
||||
--color-text-muted: theme('colors.slate.400');
|
||||
--color-text-placeholder: theme('colors.slate.500');
|
||||
--color-border: theme('colors.slate.700');
|
||||
--color-border-subtle: theme('colors.slate.800');
|
||||
}
|
||||
|
||||
/* Utility classes for theme colors */
|
||||
.bg-theme-primary { background-color: var(--color-bg-primary); }
|
||||
.bg-theme-secondary { background-color: var(--color-bg-secondary); }
|
||||
.bg-theme-tertiary { background-color: var(--color-bg-tertiary); }
|
||||
.bg-theme-sidenav { background-color: var(--color-bg-sidenav); }
|
||||
.bg-theme-topnav { background-color: var(--color-bg-topnav); }
|
||||
.bg-theme-input { background-color: var(--color-bg-input); }
|
||||
.bg-theme-hover { background-color: var(--color-bg-hover); }
|
||||
.bg-theme-message-user { background-color: var(--color-bg-message-user); }
|
||||
.text-theme-primary { color: var(--color-text-primary); }
|
||||
.text-theme-secondary { color: var(--color-text-secondary); }
|
||||
.text-theme-muted { color: var(--color-text-muted); }
|
||||
.text-theme-placeholder { color: var(--color-text-placeholder); }
|
||||
.border-theme { border-color: var(--color-border); }
|
||||
.border-theme-subtle { border-color: var(--color-border-subtle); }
|
||||
.hover\:bg-theme-hover:hover { background-color: var(--color-bg-hover); }
|
||||
.placeholder-theme-placeholder::placeholder { color: var(--color-text-placeholder); }
|
||||
|
||||
/* Base styles */
|
||||
html,
|
||||
body {
|
||||
@apply h-full;
|
||||
background-color: var(--color-bg-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
/* Text selection styling for dark theme */
|
||||
|
||||
@@ -258,8 +258,8 @@
|
||||
|
||||
<!-- Full-screen drag overlay - shown when dragging files anywhere on the page -->
|
||||
{#if isDragOver}
|
||||
<div class="pointer-events-none fixed inset-0 z-[100] flex items-center justify-center bg-slate-900/80 backdrop-blur-sm">
|
||||
<div class="flex flex-col items-center gap-3 rounded-2xl border-2 border-dashed border-violet-500 bg-slate-800/90 p-8 text-violet-300">
|
||||
<div class="pointer-events-none fixed inset-0 z-[100] flex items-center justify-center bg-[var(--color-bg-primary)]/80 backdrop-blur-sm">
|
||||
<div class="flex flex-col items-center gap-3 rounded-2xl border-2 border-dashed border-violet-500 bg-theme-secondary p-8 text-violet-600 dark:text-violet-300">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="h-12 w-12">
|
||||
<path fill-rule="evenodd" d="M10.5 3.75a6 6 0 0 0-5.98 6.496A5.25 5.25 0 0 0 6.75 20.25H18a4.5 4.5 0 0 0 2.206-8.423 3.75 3.75 0 0 0-4.133-4.303A6.001 6.001 0 0 0 10.5 3.75Zm2.03 5.47a.75.75 0 0 0-1.06 0l-3 3a.75.75 0 1 0 1.06 1.06l1.72-1.72v4.19a.75.75 0 0 0 1.5 0v-4.19l1.72 1.72a.75.75 0 1 0 1.06-1.06l-3-3Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
@@ -270,7 +270,7 @@
|
||||
Drop files here
|
||||
{/if}
|
||||
</span>
|
||||
<span class="text-sm text-slate-400">
|
||||
<span class="text-sm text-theme-muted">
|
||||
{#if isVisionModel}
|
||||
Images, text files, and PDFs supported
|
||||
{:else}
|
||||
@@ -295,7 +295,7 @@
|
||||
/>
|
||||
|
||||
<div
|
||||
class="flex items-end gap-3 rounded-2xl border border-slate-700/50 bg-slate-800/80 p-3 backdrop-blur transition-all focus-within:border-slate-600 focus-within:bg-slate-800"
|
||||
class="flex items-end gap-3 rounded-2xl border border-theme bg-theme-input p-3 backdrop-blur transition-all focus-within:border-theme-subtle"
|
||||
>
|
||||
<!-- Attachment indicators -->
|
||||
{#if pendingImages.length > 0 || pendingAttachments.length > 0}
|
||||
@@ -346,7 +346,7 @@
|
||||
{placeholder}
|
||||
{disabled}
|
||||
rows="1"
|
||||
class="max-h-[200px] min-h-[40px] flex-1 resize-none bg-transparent px-1 py-1.5 text-slate-100 placeholder-slate-500 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
||||
class="max-h-[200px] min-h-[40px] flex-1 resize-none bg-transparent px-1 py-1.5 text-theme-primary placeholder-theme-placeholder focus:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
||||
aria-label="Message input"
|
||||
data-chat-input
|
||||
></textarea>
|
||||
@@ -379,7 +379,7 @@
|
||||
disabled={!canSend}
|
||||
class="flex h-9 w-9 items-center justify-center rounded-xl transition-colors focus:outline-none focus:ring-2 focus:ring-violet-500/50 {canSend
|
||||
? 'bg-violet-500/20 text-violet-400 hover:bg-violet-500/30 hover:text-violet-300'
|
||||
: 'text-slate-600 cursor-not-allowed'}"
|
||||
: 'text-theme-muted cursor-not-allowed'}"
|
||||
aria-label="Send message"
|
||||
title="Send message"
|
||||
>
|
||||
@@ -397,19 +397,19 @@
|
||||
</div>
|
||||
|
||||
<!-- Subtle helper text -->
|
||||
<p class="text-center text-[11px] text-slate-600">
|
||||
<kbd class="rounded bg-slate-800 px-1 py-0.5 font-mono">Enter</kbd> send
|
||||
<span class="mx-1.5 text-slate-700">·</span>
|
||||
<kbd class="rounded bg-slate-800 px-1 py-0.5 font-mono">Shift+Enter</kbd> new line
|
||||
<span class="mx-1.5 text-slate-700">·</span>
|
||||
<p class="text-center text-[11px] text-theme-muted">
|
||||
<kbd class="rounded bg-theme-secondary px-1 py-0.5 font-mono">Enter</kbd> send
|
||||
<span class="mx-1.5 opacity-50">·</span>
|
||||
<kbd class="rounded bg-theme-secondary px-1 py-0.5 font-mono">Shift+Enter</kbd> new line
|
||||
<span class="mx-1.5 opacity-50">·</span>
|
||||
{#if isVisionModel}
|
||||
<span class="text-violet-500/70">images</span>
|
||||
<span class="mx-1 text-slate-700">+</span>
|
||||
<span class="text-violet-500 dark:text-violet-500/70">images</span>
|
||||
<span class="mx-1 opacity-50">+</span>
|
||||
{/if}
|
||||
<span class="text-slate-500">files supported</span>
|
||||
<span class="text-theme-muted">files supported</span>
|
||||
{#if showTokenCount}
|
||||
<span class="mx-1.5 text-slate-700">·</span>
|
||||
<span class="text-slate-500" title="{tokenEstimate.textTokens} text + {tokenEstimate.imageTokens} image tokens">
|
||||
<span class="mx-1.5 opacity-50">·</span>
|
||||
<span class="text-theme-muted" title="{tokenEstimate.textTokens} text + {tokenEstimate.imageTokens} image tokens">
|
||||
~{formatTokenCount(tokenEstimate.totalTokens)} tokens
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
@@ -807,7 +807,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex h-full flex-col bg-slate-900">
|
||||
<div class="flex h-full flex-col bg-theme-primary">
|
||||
{#if hasMessages}
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<MessageList
|
||||
@@ -825,9 +825,9 @@
|
||||
<!-- Input area with subtle gradient fade -->
|
||||
<div class="relative">
|
||||
<!-- Gradient fade at top -->
|
||||
<div class="pointer-events-none absolute -top-8 left-0 right-0 h-8 bg-gradient-to-t from-slate-900 to-transparent"></div>
|
||||
<div class="pointer-events-none absolute -top-8 left-0 right-0 h-8 bg-gradient-to-t from-[var(--color-bg-primary)] to-transparent"></div>
|
||||
|
||||
<div class="border-t border-slate-800/50 bg-slate-900/95 backdrop-blur-sm">
|
||||
<div class="border-t border-theme bg-theme-primary/95 backdrop-blur-sm">
|
||||
<!-- Summary recommendation banner -->
|
||||
<SummaryBanner onSummarize={handleSummarize} isLoading={isSummarizing} />
|
||||
|
||||
@@ -850,8 +850,8 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => settingsState.togglePanel()}
|
||||
class="flex items-center gap-1.5 rounded px-2 py-1 text-xs text-slate-400 transition-colors hover:bg-slate-800 hover:text-slate-200"
|
||||
class:bg-slate-800={settingsState.isPanelOpen}
|
||||
class="flex items-center gap-1.5 rounded px-2 py-1 text-xs text-theme-muted transition-colors hover:bg-theme-hover hover:text-theme-primary"
|
||||
class:bg-theme-secondary={settingsState.isPanelOpen}
|
||||
class:text-sky-400={settingsState.isPanelOpen || settingsState.useCustomParameters}
|
||||
aria-label="Toggle model parameters"
|
||||
aria-expanded={settingsState.isPanelOpen}
|
||||
@@ -881,7 +881,7 @@
|
||||
|
||||
<!-- Right side: Thinking mode toggle -->
|
||||
{#if supportsThinking}
|
||||
<label class="flex cursor-pointer items-center gap-2 text-xs text-slate-400">
|
||||
<label class="flex cursor-pointer items-center gap-2 text-xs text-theme-muted">
|
||||
<span class="flex items-center gap-1">
|
||||
<span class="text-amber-400">🧠</span>
|
||||
Thinking mode
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Welcome text -->
|
||||
<h2 class="mb-2 text-xl font-medium text-slate-100">
|
||||
<h2 class="mb-2 text-xl font-medium text-theme-primary">
|
||||
{#if hasModel}
|
||||
Start a conversation
|
||||
{:else}
|
||||
@@ -97,9 +97,9 @@
|
||||
{/if}
|
||||
</h2>
|
||||
|
||||
<p class="mb-8 max-w-md text-sm text-slate-500">
|
||||
<p class="mb-8 max-w-md text-sm text-theme-muted">
|
||||
{#if hasModel && selectedModel}
|
||||
Chatting with <span class="font-medium text-slate-300">{selectedModel.name}</span>
|
||||
Chatting with <span class="font-medium text-theme-secondary">{selectedModel.name}</span>
|
||||
{:else}
|
||||
Select a model from the sidebar to start chatting
|
||||
{/if}
|
||||
@@ -155,9 +155,9 @@
|
||||
onclick={() => selectPrompt(props.type)}
|
||||
class="flex items-start gap-3 rounded-xl border p-3 text-left transition-all {active
|
||||
? 'border-violet-500/50 bg-violet-500/10'
|
||||
: 'border-slate-800/50 bg-slate-800/30 hover:border-slate-700 hover:bg-slate-800/60'}"
|
||||
: 'border-theme hover:border-theme-subtle bg-theme-secondary/30 hover:bg-theme-secondary/60'}"
|
||||
>
|
||||
<div class="flex-shrink-0 {active ? 'text-violet-400' : 'text-slate-500'}">
|
||||
<div class="flex-shrink-0 {active ? 'text-violet-400' : 'text-theme-muted'}">
|
||||
{#if props.icon === 'lightbulb'}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="h-4 w-4">
|
||||
<path d="M10 1a6 6 0 00-3.815 10.631C7.237 12.5 8 13.443 8 14.456v.644a.75.75 0 00.572.729 6.016 6.016 0 002.856 0A.75.75 0 0012 15.1v-.644c0-1.013.762-1.957 1.815-2.825A6 6 0 0010 1zM8.863 17.414a.75.75 0 00-.226 1.483 9.066 9.066 0 002.726 0 .75.75 0 00-.226-1.483 7.553 7.553 0 01-2.274 0z" />
|
||||
@@ -177,8 +177,8 @@
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-medium {active ? 'text-violet-200' : 'text-slate-200'}">{props.title}</h3>
|
||||
<p class="text-xs {active ? 'text-violet-400/70' : 'text-slate-500'}">{props.description}</p>
|
||||
<h3 class="text-sm font-medium {active ? 'text-violet-200 dark:text-violet-200' : 'text-theme-primary'}">{props.title}</h3>
|
||||
<p class="text-xs {active ? 'text-violet-400/70' : 'text-theme-muted'}">{props.description}</p>
|
||||
</div>
|
||||
</button>
|
||||
{/snippet}
|
||||
|
||||
@@ -123,10 +123,10 @@
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="mb-1 flex items-center gap-2">
|
||||
<span class="text-xs font-medium text-amber-400">Conversation Summary</span>
|
||||
<span class="text-xs text-slate-500">Earlier messages compressed</span>
|
||||
<span class="text-xs font-medium text-amber-500 dark:text-amber-400">Conversation Summary</span>
|
||||
<span class="text-xs text-theme-muted">Earlier messages compressed</span>
|
||||
</div>
|
||||
<div class="prose prose-sm prose-invert max-w-none text-slate-300">
|
||||
<div class="prose prose-sm dark:prose-invert max-w-none text-theme-secondary">
|
||||
<MessageContent
|
||||
content={node.message.content.replace('[Previous conversation summary]\n\n', '')}
|
||||
{isStreaming}
|
||||
@@ -185,9 +185,9 @@
|
||||
<!-- Message bubble with branch navigator -->
|
||||
<div
|
||||
class="relative rounded-2xl px-4 py-3 {isUser
|
||||
? 'bg-slate-700 text-slate-100'
|
||||
? 'bg-theme-message-user text-theme-primary'
|
||||
: isToolMessage
|
||||
? 'bg-slate-800/50 border-l-2 border-teal-500/50'
|
||||
? 'bg-theme-secondary border-l-2 border-teal-500/50'
|
||||
: 'bg-transparent'}"
|
||||
>
|
||||
{#if isEditing}
|
||||
@@ -275,7 +275,7 @@
|
||||
<!-- Avatar for user -->
|
||||
{#if isUser}
|
||||
<div
|
||||
class="flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-xl bg-slate-600 text-slate-300"
|
||||
class="flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-xl bg-theme-tertiary text-theme-secondary"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<svg
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
<!-- Sidenav container -->
|
||||
<aside
|
||||
class="fixed left-0 top-0 z-50 flex h-full flex-col overflow-hidden bg-slate-950 transition-all duration-300 ease-in-out"
|
||||
class="fixed left-0 top-0 z-50 flex h-full flex-col overflow-hidden bg-theme-sidenav transition-all duration-300 ease-in-out"
|
||||
class:w-[280px]={uiState.sidenavOpen}
|
||||
class:w-0={!uiState.sidenavOpen}
|
||||
class:shadow-xl={uiState.sidenavOpen}
|
||||
@@ -48,11 +48,11 @@
|
||||
</div>
|
||||
|
||||
<!-- Footer / Navigation links -->
|
||||
<div class="border-t border-slate-700/50 p-3 space-y-1">
|
||||
<div class="border-t border-theme p-3 space-y-1">
|
||||
<!-- Model Browser link -->
|
||||
<a
|
||||
href="/models"
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors {isActive('/models') ? 'bg-cyan-900/30 text-cyan-400' : 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'}"
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors {isActive('/models') ? 'bg-cyan-500/20 text-cyan-600 dark:bg-cyan-900/30 dark:text-cyan-400' : 'text-theme-muted hover:bg-theme-hover hover:text-theme-primary'}"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -74,7 +74,7 @@
|
||||
<!-- Knowledge Base link -->
|
||||
<a
|
||||
href="/knowledge"
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors {isActive('/knowledge') ? 'bg-blue-900/30 text-blue-400' : 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'}"
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors {isActive('/knowledge') ? 'bg-blue-500/20 text-blue-600 dark:bg-blue-900/30 dark:text-blue-400' : 'text-theme-muted hover:bg-theme-hover hover:text-theme-primary'}"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -96,7 +96,7 @@
|
||||
<!-- Tools link -->
|
||||
<a
|
||||
href="/tools"
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors {isActive('/tools') ? 'bg-emerald-900/30 text-emerald-400' : 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'}"
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors {isActive('/tools') ? 'bg-emerald-500/20 text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400' : 'text-theme-muted hover:bg-theme-hover hover:text-theme-primary'}"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -118,7 +118,7 @@
|
||||
<!-- Prompts link -->
|
||||
<a
|
||||
href="/prompts"
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors {isActive('/prompts') ? 'bg-purple-900/30 text-purple-400' : 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'}"
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors {isActive('/prompts') ? 'bg-purple-500/20 text-purple-600 dark:bg-purple-900/30 dark:text-purple-400' : 'text-theme-muted hover:bg-theme-hover hover:text-theme-primary'}"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -141,7 +141,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (settingsOpen = true)}
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm text-slate-400 transition-colors hover:bg-slate-800 hover:text-slate-200"
|
||||
class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm text-theme-muted transition-colors hover:bg-theme-hover hover:text-theme-primary"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
</script>
|
||||
|
||||
<header
|
||||
class="flex h-16 items-center border-b border-slate-800 bg-slate-950/90 backdrop-blur-sm"
|
||||
class="flex h-16 items-center border-b border-theme bg-theme-topnav backdrop-blur-sm"
|
||||
>
|
||||
<div class="flex h-full w-full items-center justify-between px-4">
|
||||
<!-- Left section: Hamburger menu + Model select -->
|
||||
@@ -110,7 +110,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => uiState.toggleSidenav()}
|
||||
class="rounded-lg p-2 text-slate-400 transition-colors hover:bg-slate-800 hover:text-slate-200"
|
||||
class="rounded-lg p-2 text-theme-muted transition-colors hover:bg-theme-hover hover:text-theme-primary"
|
||||
aria-label={uiState.sidenavOpen ? 'Close sidebar' : 'Open sidebar'}
|
||||
>
|
||||
{#if uiState.sidenavOpen}
|
||||
@@ -159,7 +159,7 @@
|
||||
<div class="hidden flex-1 items-center justify-center gap-4 sm:flex">
|
||||
<!-- Conversation title -->
|
||||
{#if currentConversation}
|
||||
<h1 class="max-w-[300px] truncate text-sm font-medium text-slate-300" title={currentConversation.title}>
|
||||
<h1 class="max-w-[300px] truncate text-sm font-medium text-theme-secondary" title={currentConversation.title}>
|
||||
{currentConversation.title}
|
||||
</h1>
|
||||
{/if}
|
||||
@@ -173,7 +173,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => uiState.toggleDarkMode()}
|
||||
class="rounded-lg p-2 text-slate-400 transition-colors hover:bg-slate-800 hover:text-slate-200"
|
||||
class="rounded-lg p-2 text-theme-muted transition-colors hover:bg-theme-hover hover:text-theme-primary"
|
||||
aria-label={uiState.darkMode ? 'Switch to light mode' : 'Switch to dark mode'}
|
||||
title={uiState.darkMode ? 'Light mode' : 'Dark mode'}
|
||||
>
|
||||
@@ -217,7 +217,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={handleExport}
|
||||
class="rounded-lg p-2 text-slate-400 transition-colors hover:bg-slate-800 hover:text-slate-200"
|
||||
class="rounded-lg p-2 text-theme-muted transition-colors hover:bg-theme-hover hover:text-theme-primary"
|
||||
aria-label="Export conversation"
|
||||
title="Export"
|
||||
>
|
||||
@@ -241,7 +241,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={handlePin}
|
||||
class="rounded-lg p-2 transition-colors hover:bg-slate-800 {currentConversation?.isPinned ? 'text-emerald-500 hover:text-emerald-400' : 'text-slate-400 hover:text-slate-200'}"
|
||||
class="rounded-lg p-2 transition-colors hover:bg-theme-hover {currentConversation?.isPinned ? 'text-emerald-500 hover:text-emerald-400' : 'text-theme-muted hover:text-theme-primary'}"
|
||||
aria-label={currentConversation?.isPinned ? 'Unpin conversation' : 'Pin conversation'}
|
||||
title={currentConversation?.isPinned ? 'Unpin' : 'Pin'}
|
||||
>
|
||||
@@ -265,7 +265,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={handleArchive}
|
||||
class="rounded-lg p-2 transition-colors hover:bg-slate-800 {currentConversation?.isArchived ? 'text-amber-500 hover:text-amber-400' : 'text-slate-400 hover:text-slate-200'}"
|
||||
class="rounded-lg p-2 transition-colors hover:bg-theme-hover {currentConversation?.isArchived ? 'text-amber-500 hover:text-amber-400' : 'text-theme-muted hover:text-theme-primary'}"
|
||||
aria-label={currentConversation?.isArchived ? 'Unarchive conversation' : 'Archive conversation'}
|
||||
title={currentConversation?.isArchived ? 'Unarchive' : 'Archive'}
|
||||
>
|
||||
@@ -289,7 +289,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={handleDeleteClick}
|
||||
class="rounded-lg p-2 text-slate-400 transition-colors hover:bg-red-900/30 hover:text-red-400"
|
||||
class="rounded-lg p-2 text-theme-muted transition-colors hover:bg-red-500/20 hover:text-red-500 dark:hover:bg-red-900/30 dark:hover:text-red-400"
|
||||
aria-label="Delete conversation"
|
||||
title="Delete"
|
||||
>
|
||||
|
||||
@@ -144,13 +144,13 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="h-screen w-full overflow-hidden bg-slate-900">
|
||||
<div class="h-screen w-full overflow-hidden bg-theme-primary">
|
||||
<!-- Sidenav - fixed position -->
|
||||
<Sidenav />
|
||||
|
||||
<!-- Main content wrapper - shifts right when sidenav is open on desktop -->
|
||||
<div
|
||||
class="flex h-full flex-col bg-slate-900 transition-[margin-left] duration-300 ease-in-out"
|
||||
class="flex h-full flex-col bg-theme-primary transition-[margin-left] duration-300 ease-in-out"
|
||||
style="margin-left: {!uiState.isMobile && uiState.sidenavOpen ? SIDENAV_WIDTH : 0}px"
|
||||
>
|
||||
<!-- Top navigation - fixed at top of content area -->
|
||||
|
||||
Reference in New Issue
Block a user