Compare commits

..

2 Commits

Author SHA1 Message Date
03527e7dc4 style(frontend): refine chat theme accents
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-17 20:35:33 -04:00
bf3b308a05 chore: better colors
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-17 20:29:18 -04:00
3 changed files with 61 additions and 61 deletions

View File

@@ -69,7 +69,7 @@
></div> ></div>
<button <button
@click.stop="deleteChat($event, chat.id)" @click.stop="deleteChat($event, chat.id)"
class="opacity-0 group-hover:opacity-100 focus:opacity-100 shrink-0 p-1 -mr-1 text-primary-400 hover:text-tertiary-600 hover:bg-tertiary-100 rounded transition-opacity" class="opacity-0 group-hover:opacity-100 focus:opacity-100 shrink-0 p-1 -mr-1 text-primary-400 hover:text-tertiary-600 hover:bg-tertiary-100 rounded transition-opacity cursor-pointer"
title="Delete chat" title="Delete chat"
aria-label="Delete chat" aria-label="Delete chat"
> >
@@ -137,10 +137,10 @@
<template x-for="message in currentChatMessages" :key="message.id"> <template x-for="message in currentChatMessages" :key="message.id">
<div :class="['mb-4', message.role === 'user' ? 'text-right' : 'text-left']"> <div :class="['mb-4', message.role === 'user' ? 'text-right' : 'text-left']">
<div <div
:class="['inline-block px-4 py-3 text-left rounded-lg max-w-[95%] md:max-w-[85%]', :class="['inline-block px-4 py-3 text-left rounded-lg max-w-[95%] md:max-w-[85%] border shadow-sm',
message.role === 'user' message.role === 'user'
? 'bg-primary-100 text-primary-900 rounded-br-none' ? 'bg-primary-100/75 border-primary-300/30 text-primary-900 rounded-br-none'
: 'bg-primary-200 text-primary-900 rounded-bl-none' : 'bg-primary-200/65 border-primary-300/40 text-primary-900 rounded-bl-none'
]" ]"
> >
<div <div
@@ -155,30 +155,30 @@
<div <div
x-show="message.thinking" x-show="message.thinking"
x-data="{ expanded: false }" x-data="{ expanded: false }"
role="button"
tabindex="0"
@click="expanded = !expanded" @click="expanded = !expanded"
@keydown.enter.prevent="expanded = !expanded"
@keydown.space.prevent="expanded = !expanded"
class="mb-3 rounded-md border-l-2 border-secondary-500/60 bg-secondary-100/35 px-3 py-2 ring-1 ring-secondary-400/20 cursor-pointer"
> >
<div class="cursor-pointer rounded-lg overflow-hidden bg-primary-100 hover:bg-primary-50"> <div class="flex items-center gap-2 text-xs font-medium text-secondary-700 transition-colors">
<div class="flex justify-center w-full px-3 py-2 text-xs text-primary-700 flex items-center gap-2 transition-colors"> <span x-text="expanded ? '▾' : '▸'"></span>
<span x-text="expanded ? '▼' : '◀'"></span> <span>Reasoning</span>
<span class="font-medium">Reasoning</span>
<span x-text="expanded ? '▼' : '▶'"></span>
</div> </div>
<div <div
x-show="expanded" x-show="expanded"
class="prose p-4 max-w-none text-sm prose-p:my-1 prose-headings:my-2 prose-ul:my-1 prose-ol:my-1 prose-pre:p-0" class="prose mt-2 max-w-none text-xs text-secondary-700 opacity-90 prose-p:my-1 prose-headings:my-2 prose-ul:my-1 prose-ol:my-1 prose-pre:p-0"
x-html="renderMarkdown(message.thinking)" x-html="renderMarkdown(message.thinking)"
></div> ></div>
</div> </div>
</div>
<hr x-show="message.thinking" class="my-2 border-primary-400/50" />
<div <div
x-show="message.role === 'assistant' && message.status === 'streaming' && !message.thinking && !message.content" x-show="message.role === 'assistant' && message.status === 'streaming' && !message.thinking && !message.content"
class="flex items-center gap-2 py-1" class="flex items-center gap-2 py-1"
> >
<div class="h-4 w-4 animate-spin rounded-full border-2 border-primary-500 border-t-transparent"></div> <div class="h-4 w-4 animate-spin rounded-full border-2 border-secondary-500 border-t-transparent"></div>
<span class="text-xs text-primary-600">Thinking...</span> <span class="text-xs text-secondary-600">Thinking...</span>
</div> </div>
<div <div
@@ -191,8 +191,8 @@
<div class="text-[10px] opacity-60" x-text="new Date(message.created_at).toLocaleTimeString()"></div> <div class="text-[10px] opacity-60" x-text="new Date(message.created_at).toLocaleTimeString()"></div>
<div <div
x-show="message.role === 'assistant' && ['stopped', 'error', 'failed'].includes(message.status)" x-show="message.role === 'assistant' && ['stopped', 'error', 'failed'].includes(message.status)"
:class="message.status === 'stopped' ? 'bg-primary-300/50 text-primary-700' : 'bg-tertiary-100 text-tertiary-700'" :class="message.status === 'stopped' ? 'bg-red-500/15 text-red-700 ring-red-500/20' : 'bg-red-600 text-white ring-red-700/20'"
class="px-2 py-0.5 rounded-full text-[10px] font-medium" class="px-2 py-0.5 rounded-full text-[10px] font-medium ring-1"
x-text="message.status === 'stopped' ? 'Stopped' : 'Error'" x-text="message.status === 'stopped' ? 'Stopped' : 'Error'"
></div> ></div>
</div> </div>
@@ -200,11 +200,11 @@
<div <div
x-show="message.role === 'assistant' && message.stats" x-show="message.role === 'assistant' && message.stats"
class="flex items-center gap-1 py-2 flex-wrap justify-start text-primary-700" class="flex items-center gap-1 py-2 flex-wrap justify-start text-primary-600"
> >
<div <div
x-show="message.stats?.prompt_tokens || message.stats?.generated_tokens" x-show="message.stats?.prompt_tokens || message.stats?.generated_tokens"
class="group relative px-2 py-0.5 text-[10px] bg-primary-300/50 rounded-full cursor-help" class="group relative px-2 py-0.5 text-[10px] bg-primary-200/40 rounded-full cursor-help"
> >
<span x-text="`${(message.stats?.prompt_tokens || 0) + (message.stats?.generated_tokens || 0)} tokens`"></span> <span x-text="`${(message.stats?.prompt_tokens || 0) + (message.stats?.generated_tokens || 0)} tokens`"></span>
<div class="invisible group-hover:visible absolute bottom-full left-1/2 -translate-x-1/2 m-2 px-2 py-1 bg-gray-900 text-white text-[10px] rounded whitespace-nowrap pointer-events-none grid grid-cols-[auto_1fr] gap-x-2"> <div class="invisible group-hover:visible absolute bottom-full left-1/2 -translate-x-1/2 m-2 px-2 py-1 bg-gray-900 text-white text-[10px] rounded whitespace-nowrap pointer-events-none grid grid-cols-[auto_1fr] gap-x-2">
@@ -217,17 +217,17 @@
<span <span
x-show="message.stats?.prompt_per_second" x-show="message.stats?.prompt_per_second"
class="px-2 py-0.5 text-[10px] bg-primary-300/50 rounded-full" class="px-2 py-0.5 text-[10px] bg-primary-200/40 rounded-full"
x-text="`${message.stats?.prompt_per_second.toFixed(1)} ppt/s`" x-text="`${message.stats?.prompt_per_second.toFixed(1)} ppt/s`"
></span> ></span>
<span <span
x-show="message.stats?.generated_per_second" x-show="message.stats?.generated_per_second"
class="px-2 py-0.5 text-[10px] bg-primary-300/50 rounded-full" class="px-2 py-0.5 text-[10px] bg-primary-200/40 rounded-full"
x-text="`${message.stats?.generated_per_second.toFixed(1)} tgt/s`" x-text="`${message.stats?.generated_per_second.toFixed(1)} tgt/s`"
></span> ></span>
<span <span
x-show="message.stats?.time_to_first_token" x-show="message.stats?.time_to_first_token"
class="px-2 py-0.5 text-[10px] bg-primary-300/50 rounded-full" class="px-2 py-0.5 text-[10px] bg-primary-200/40 rounded-full"
x-text="`${(message.stats?.time_to_first_token / 1000).toFixed(2)}s TTFT`" x-text="`${(message.stats?.time_to_first_token / 1000).toFixed(2)}s TTFT`"
></span> ></span>
</div> </div>
@@ -237,12 +237,12 @@
<!-- Sticky Input Bar --> <!-- Sticky Input Bar -->
<div <div
class="sticky bottom-0 pt-2 bg-primary-50" class="sticky bottom-0 pt-2 bg-primary-50/95"
style="padding-bottom: max(0.5rem, env(safe-area-inset-bottom));" style="padding-bottom: max(0.5rem, env(safe-area-inset-bottom));"
> >
<form <form
@submit.prevent="sendMessage" @submit.prevent="sendMessage"
class="flex flex-col gap-2 p-3 bg-primary-50 rounded-2xl border border-primary-200" class="flex flex-col gap-2 p-3 bg-primary-100/35 rounded-2xl border border-primary-300/40 shadow-sm"
> >
<input <input
x-ref="fileInput" x-ref="fileInput"
@@ -285,7 +285,7 @@
></textarea> ></textarea>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="relative min-w-0 flex-shrink inline-flex items-center pl-7 pr-6 py-1 bg-primary-200/70 hover:bg-primary-300 border border-primary-200 rounded-full transition-colors"> <div class="relative min-w-0 flex-shrink inline-flex items-center pl-7 pr-6 py-1 bg-primary-100/60 hover:bg-primary-200/70 border border-primary-300/50 rounded-full transition-colors">
<span <span
class="text-primary-900 text-xs font-medium truncate pointer-events-none" class="text-primary-900 text-xs font-medium truncate pointer-events-none"
x-text="(models.find(m => m.id === selectedModel)?.name) || selectedModel || 'Select Model'" x-text="(models.find(m => m.id === selectedModel)?.name) || selectedModel || 'Select Model'"
@@ -312,9 +312,9 @@
type="button" type="button"
@click="thinkingEnabled = !thinkingEnabled" @click="thinkingEnabled = !thinkingEnabled"
:class="thinkingEnabled :class="thinkingEnabled
? 'bg-primary-600 text-white border-primary-600 hover:bg-primary-700' ? 'bg-secondary-600 text-white border-secondary-600 hover:bg-secondary-700'
: 'bg-transparent text-primary-500 border-primary-300 hover:bg-primary-200/70'" : 'bg-transparent text-secondary-500 border-secondary-300 hover:bg-secondary-200/70'"
class="relative h-7 w-7 rounded-full border transition-colors flex items-center justify-center flex-shrink-0" class="relative h-7 w-7 rounded-full border transition-colors flex items-center justify-center flex-shrink-0 cursor-pointer"
:title="thinkingEnabled ? 'Thinking on' : 'Thinking off'" :title="thinkingEnabled ? 'Thinking on' : 'Thinking off'"
:aria-pressed="thinkingEnabled ? 'true' : 'false'" :aria-pressed="thinkingEnabled ? 'true' : 'false'"
aria-label="Toggle thinking" aria-label="Toggle thinking"
@@ -345,7 +345,7 @@
<button <button
type="button" type="button"
@click="$refs.fileInput.click()" @click="$refs.fileInput.click()"
class="h-7 w-7 bg-primary-200/70 text-primary-700 rounded-full transition-colors flex items-center justify-center flex-shrink-0 hover:bg-primary-300" class="h-7 w-7 bg-primary-100/70 text-primary-700 border border-primary-300/50 rounded-full transition-colors flex items-center justify-center flex-shrink-0 hover:bg-primary-200/70"
title="Attach Image" title="Attach Image"
aria-label="Attach Image" aria-label="Attach Image"
> >
@@ -477,7 +477,7 @@
></div> ></div>
<button <button
@click.stop="deleteChat($event, chat.id)" @click.stop="deleteChat($event, chat.id)"
class="shrink-0 p-1 -mr-1 text-primary-400 hover:text-tertiary-600 hover:bg-tertiary-100 rounded transition-colors" class="shrink-0 p-1 -mr-1 text-primary-400 hover:text-tertiary-600 hover:bg-tertiary-100 rounded transition-colors cursor-pointer"
title="Delete chat" title="Delete chat"
aria-label="Delete chat" aria-label="Delete chat"
> >

View File

@@ -146,13 +146,13 @@
</div> </div>
<span <span
@click="clearMask" @click="clearMask"
class="mt-2 px-3 py-1 cursor-pointer bg-primary-200 text-primary-700 rounded hover:bg-primary-600 hover:text-white text-center transition-colors" class="mt-2 px-3 py-1 cursor-pointer bg-tertiary-100 text-tertiary-700 rounded hover:bg-tertiary-600 hover:text-white text-center transition-colors"
> >
Clear Mask Clear Mask
</span> </span>
<span <span
@click="cancelEdit" @click="cancelEdit"
class="mt-2 px-3 py-1 cursor-pointer bg-primary-200 text-primary-700 rounded hover:bg-primary-600 hover:text-white text-center transition-colors" class="mt-2 px-3 py-1 cursor-pointer bg-tertiary-100 text-tertiary-700 rounded hover:bg-tertiary-600 hover:text-white text-center transition-colors"
> >
Cancel Cancel
</span> </span>
@@ -164,7 +164,7 @@
type="submit" type="submit"
x-bind:disabled="loading || !selectedModel" x-bind:disabled="loading || !selectedModel"
:class="loading || !selectedModel ? 'cursor-not-allowed' : 'cursor-pointer'" :class="loading || !selectedModel ? 'cursor-not-allowed' : 'cursor-pointer'"
class="inline-flex justify-center items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-primary-50 bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 disabled:opacity-50 gap-2 transition-colors" class="inline-flex justify-center items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-primary-50 bg-secondary-600 hover:bg-secondary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-secondary-500 disabled:opacity-50 gap-2 transition-colors"
> >
<span <span
x-text="loading ? '' : editMode ? 'Edit Image' : 'Generate Image'" x-text="loading ? '' : editMode ? 'Edit Image' : 'Generate Image'"
@@ -200,7 +200,7 @@
> >
<template x-for="(image, index) in generatedImages" :key="index"> <template x-for="(image, index) in generatedImages" :key="index">
<div <div
class="flex flex-col gap-2 break-inside-avoid border border-primary-200 rounded-lg p-2 mb-2 h-full bg-primary-100 hover:border-primary-300 transition-colors shadow" class="flex flex-col gap-2 break-inside-avoid border border-secondary-200 rounded-lg p-2 mb-2 h-full bg-secondary-50/60 hover:border-secondary-300 transition-colors shadow"
> >
<button <button
@click="deleteImage(image.name)" @click="deleteImage(image.name)"
@@ -215,7 +215,7 @@
class="rounded-lg shadow-sm max-w-full h-auto cursor-pointer hover:opacity-90 transition-opacity" class="rounded-lg shadow-sm max-w-full h-auto cursor-pointer hover:opacity-90 transition-opacity"
/> />
<span <span
class="text-xs text-primary-500 bg-primary-200 px-2 py-1 rounded flex justify-center" class="text-xs text-secondary-700 bg-secondary-100 px-2 py-1 rounded flex justify-center"
x-text="image.date" x-text="image.date"
></span> ></span>
</div> </div>

View File

@@ -77,36 +77,36 @@ body {
@layer base { @layer base {
.dark { .dark {
/* Dark mode - dark backgrounds (50-300), light text (700-900) */ /* Dark mode - background and surface steps are intentionally lifted for a softer dark theme. */
--color-primary-50: oklch(15% 0.08 290); --color-primary-50: oklch(25% 0.08 290);
--color-primary-100: oklch(18% 0.1 290); --color-primary-100: oklch(31% 0.1 290);
--color-primary-200: oklch(22% 0.12 290); --color-primary-200: oklch(36% 0.12 290);
--color-primary-300: oklch(28% 0.15 290); --color-primary-300: oklch(48% 0.15 290);
--color-primary-400: oklch(36% 0.18 290); --color-primary-400: oklch(52% 0.18 290);
--color-primary-500: oklch(45% 0.2 290); --color-primary-500: oklch(58% 0.2 290);
--color-primary-600: oklch(55% 0.18 290); --color-primary-600: oklch(62% 0.18 290);
--color-primary-700: oklch(65% 0.15 290); --color-primary-700: oklch(65% 0.15 290);
--color-primary-800: oklch(75% 0.12 290); --color-primary-800: oklch(75% 0.12 290);
--color-primary-900: oklch(85% 0.08 290); --color-primary-900: oklch(85% 0.08 290);
--color-secondary-50: oklch(15% 0.05 180); --color-secondary-50: oklch(25% 0.05 180);
--color-secondary-100: oklch(18% 0.07 180); --color-secondary-100: oklch(31% 0.07 180);
--color-secondary-200: oklch(22% 0.09 180); --color-secondary-200: oklch(36% 0.09 180);
--color-secondary-300: oklch(28% 0.11 180); --color-secondary-300: oklch(48% 0.11 180);
--color-secondary-400: oklch(36% 0.13 180); --color-secondary-400: oklch(52% 0.13 180);
--color-secondary-500: oklch(45% 0.15 180); --color-secondary-500: oklch(58% 0.15 180);
--color-secondary-600: oklch(55% 0.14 180); --color-secondary-600: oklch(62% 0.14 180);
--color-secondary-700: oklch(65% 0.12 180); --color-secondary-700: oklch(65% 0.12 180);
--color-secondary-800: oklch(75% 0.09 180); --color-secondary-800: oklch(75% 0.09 180);
--color-secondary-900: oklch(85% 0.06 180); --color-secondary-900: oklch(85% 0.06 180);
--color-tertiary-50: oklch(15% 0.008 60); --color-tertiary-50: oklch(25% 0.008 60);
--color-tertiary-100: oklch(18% 0.01 60); --color-tertiary-100: oklch(31% 0.01 60);
--color-tertiary-200: oklch(22% 0.015 60); --color-tertiary-200: oklch(36% 0.015 60);
--color-tertiary-300: oklch(28% 0.02 60); --color-tertiary-300: oklch(48% 0.02 60);
--color-tertiary-400: oklch(36% 0.025 60); --color-tertiary-400: oklch(52% 0.025 60);
--color-tertiary-500: oklch(45% 0.03 60); --color-tertiary-500: oklch(58% 0.03 60);
--color-tertiary-600: oklch(55% 0.025 60); --color-tertiary-600: oklch(62% 0.025 60);
--color-tertiary-700: oklch(65% 0.02 60); --color-tertiary-700: oklch(65% 0.02 60);
--color-tertiary-800: oklch(75% 0.015 60); --color-tertiary-800: oklch(75% 0.015 60);
--color-tertiary-900: oklch(85% 0.01 60); --color-tertiary-900: oklch(85% 0.01 60);