feat: Implement chat interface color customization

This commit introduces new UI settings to control the colors of various chat interface elements.

Key changes:

- Added new state variables and actions to `ui/src/stores/useUi.js` for:
    - Agent message color (`chatAgentMessageColor`)
    - Own message color (`chatOwnMessageColor`)
    - Input box color (`chatInputBoxColor`)
    - Accent color (`chatAccentColor`)
    - Background color (`chatBackgroundColor`)
- These settings are persisted in local storage.
- Added a new "Chat Interface Colors" section in `ui/src/views/SettingsView.vue` with color pickers for each new setting.
- Modified `ui/src/components/chat/CanvasChat.vue` to use these new color settings via CSS custom properties. The chat elements (agent messages, own messages, input box, send button, background) now reflect your configured colors.

The changes have been tested to ensure that colors are applied correctly, persist across sessions, and do not conflict with existing theme settings.
This commit is contained in:
google-labs-jules[bot]
2025-05-31 09:35:56 +00:00
parent d16a160e5e
commit a88ee998b5
3 changed files with 93 additions and 10 deletions

View File

@@ -1,11 +1,21 @@
<script setup>
import { ref, nextTick, onMounted, watch } from 'vue'
import { ref, nextTick, onMounted, watch, computed } from 'vue'
import { useChat } from '@/stores/useChat'
import { useUi } from '@/stores/useUi'
const chat = useChat()
const ui = useUi()
const msg = ref('')
const list = ref(null)
const chatStyleVariables = computed(() => ({
'--chat-agent-message-color': ui.chatAgentMessageColor,
'--chat-own-message-color': ui.chatOwnMessageColor,
'--chat-input-box-color': ui.chatInputBoxColor,
'--chat-accent-color': ui.chatAccentColor,
'--chat-background-color': ui.chatBackgroundColor,
}))
function scrollBottom () {
nextTick(() => list.value?.scrollTo({ top: list.value.scrollHeight, behavior: 'smooth' }))
}
@@ -40,7 +50,7 @@ watch(() => chat.items.length, scrollBottom)
<template>
<!-- se adapta al contenedor flex, sin superponer la sidebar -->
<div class="flex flex-col flex-1 min-h-0 bg-gray-50">
<div class="flex flex-col flex-1 min-h-0" :style="chatStyleVariables" style="background-color: var(--chat-background-color);">
<!-- historial -->
<div ref="list" class="flex-1 min-h-0 overflow-auto p-6 space-y-4 custom-scroll">
<template v-for="(m,i) in chat.items" :key="i">
@@ -48,7 +58,8 @@ watch(() => chat.items.length, scrollBottom)
<div :class="m.owner==='yo' ? 'flex justify-end' : 'flex justify-start'" v-if="m.type==='text'">
<div
class="max-w-lg rounded-lg px-4 py-2 shadow break-words"
:class="m.owner==='yo' ? 'bg-teal-600 text-white' : 'bg-white text-gray-900'">
:class="m.owner==='yo' ? 'text-white' : 'text-gray-900'"
:style="{ backgroundColor: m.owner === 'yo' ? 'var(--chat-own-message-color)' : 'var(--chat-agent-message-color)' }">
{{ m.text }}
</div>
</div>
@@ -59,15 +70,16 @@ watch(() => chat.items.length, scrollBottom)
</div>
<!-- input -->
<form @submit.prevent="send" class="border-t bg-white p-4 flex gap-2">
<form @submit.prevent="send" class="border-t p-4 flex gap-2" :style="{ backgroundColor: 'var(--chat-input-box-color)' }">
<textarea
v-model="msg"
@keydown="handleKey"
rows="1"
placeholder="Escribí un mensaje… (Enter para enviar, Shift+Enter salto)"
class="flex-1 resize-none rounded-lg border p-3 focus:outline-none focus:ring-2 focus:ring-teal-500 custom-scroll"
class="flex-1 resize-none rounded-lg border p-3 focus:outline-none focus:ring-2 custom-scroll"
:style="{ backgroundColor: 'var(--chat-input-box-color)', borderColor: 'var(--chat-accent-color)', '--tw-ring-color': 'var(--chat-accent-color)' }"
/>
<button type="submit" class="px-4 py-2 rounded-lg bg-teal-600 text-white hover:bg-teal-700 transition">
<button type="submit" class="px-4 py-2 rounded-lg text-white transition" :style="{ backgroundColor: 'var(--chat-accent-color)' }">
</button>
</form>
@@ -76,8 +88,14 @@ watch(() => chat.items.length, scrollBottom)
<style scoped>
.custom-scroll::-webkit-scrollbar { width: 8px; }
.custom-scroll::-webkit-scrollbar-track { background: transparent; }
.custom-scroll::-webkit-scrollbar-thumb { background-color: rgba(13,148,136,.35); border-radius: 4px; }
.custom-scroll:hover::-webkit-scrollbar-thumb { background-color: rgba(13,148,136,.7); }
.custom-scroll { scrollbar-width: thin; scrollbar-color: rgba(13,148,136,.6) transparent; }
.custom-scroll::-webkit-scrollbar-track { background: transparent; } /* Consider if track needs to adapt to --chat-background-color */
.custom-scroll::-webkit-scrollbar-thumb { background-color: var(--chat-accent-color); opacity: 0.35; border-radius: 4px; }
.custom-scroll:hover::-webkit-scrollbar-thumb { opacity: 0.7; }
/* For Firefox scrollbar, if needed, though limited styling capability compared to webkit */
.custom-scroll { scrollbar-width: thin; scrollbar-color: var(--chat-accent-color) transparent; }
/* Override Tailwind focus ring color if it doesn't pick up the CSS variable directly */
textarea:focus {
--tw-ring-color: var(--chat-accent-color);
}
</style>

View File

@@ -31,6 +31,11 @@ const appearanceSettingKeys = [
'defaultViewAsistencias',
'defaultViewConfiguracion',
'transitionSpeed',
'chatAgentMessageColor',
'chatOwnMessageColor',
'chatInputBoxColor',
'chatAccentColor',
'chatBackgroundColor',
]
const loadSettingsFromLocalStorage = () => {
@@ -106,6 +111,12 @@ export const useUi = defineStore('ui', {
'defaultViewAsistencias': 'table',
'defaultViewConfiguracion': 'table',
transitionSpeed: 1, // Default to normal speed
// Chat UI colors
chatAgentMessageColor: '#FFFFFF',
chatOwnMessageColor: '#D1E8FF',
chatInputBoxColor: '#FFFFFF',
chatAccentColor: '#1976D2',
chatBackgroundColor: '#F4F4F4',
}
const loadedSettings = loadSettingsFromLocalStorage()
@@ -246,6 +257,28 @@ export const useUi = defineStore('ui', {
this.transitionSpeed = Number(newSpeed) // Ensure it's a number
_saveAppearanceState(this)
},
// Actions for chat UI colors
setChatAgentMessageColor(color) {
this.chatAgentMessageColor = color
_saveAppearanceState(this)
},
setChatOwnMessageColor(color) {
this.chatOwnMessageColor = color
_saveAppearanceState(this)
},
setChatInputBoxColor(color) {
this.chatInputBoxColor = color
_saveAppearanceState(this)
},
setChatAccentColor(color) {
this.chatAccentColor = color
_saveAppearanceState(this)
},
setChatBackgroundColor(color) {
this.chatBackgroundColor = color
_saveAppearanceState(this)
},
},
})

View File

@@ -95,6 +95,38 @@
</div>
</section>
<!-- Chat Interface Colors Section -->
<section class="mb-10">
<h2 class="text-2xl font-semibold mb-6 text-[var(--primary-color)]">Chat Interface Colors</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
<div class="setting-item">
<label for="chatAgentMessageColor" class="block text-sm font-medium mb-1">Agent Message Color</label>
<input type="color" id="chatAgentMessageColor" v-model="ui.chatAgentMessageColor" @input="ui.setChatAgentMessageColor($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="chatOwnMessageColor" class="block text-sm font-medium mb-1">Own Message Color</label>
<input type="color" id="chatOwnMessageColor" v-model="ui.chatOwnMessageColor" @input="ui.setChatOwnMessageColor($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="chatInputBoxColor" class="block text-sm font-medium mb-1">Input Box Color</label>
<input type="color" id="chatInputBoxColor" v-model="ui.chatInputBoxColor" @input="ui.setChatInputBoxColor($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="chatAccentColor" class="block text-sm font-medium mb-1">Accent Color</label>
<input type="color" id="chatAccentColor" v-model="ui.chatAccentColor" @input="ui.setChatAccentColor($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="chatBackgroundColor" class="block text-sm font-medium mb-1">Background Color</label>
<input type="color" id="chatBackgroundColor" v-model="ui.chatBackgroundColor" @input="ui.setChatBackgroundColor($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
</div>
</section>
<!-- Per-Module Color Settings -->
<section class="mb-10 module-settings-group">
<h3 class="text-xl font-semibold mb-4 text-[var(--primary-color)] border-b border-[var(--secondary-color)] pb-2">Empleados Module</h3>