Merge pull request #23 from josedario87/feat/chat-color-customization

Feat/chat color customization
This commit is contained in:
josedario87
2025-05-31 03:45:34 -06:00
committed by GitHub
3 changed files with 154 additions and 23 deletions

View File

@@ -1,11 +1,24 @@
<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,
'--chat-font-color': ui.chatFontColor,
'--chat-font-family': ui.chatFontFamily || 'inherit', // Fallback to inherit if empty
'--chat-font-size': ui.chatFontSize ? `${ui.chatFontSize}px` : 'inherit', // Fallback to inherit
}))
function scrollBottom () {
nextTick(() => list.value?.scrollTo({ top: list.value.scrollHeight, behavior: 'smooth' }))
}
@@ -40,16 +53,22 @@ 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">
<!-- mensaje de texto -->
<div :class="m.owner==='yo' ? 'flex justify-end' : 'flex justify-start'" v-if="m.type==='text'">
<div
class="max-w-lg px-4 py-2 shadow break-words rounded-lg"
:class="m.owner==='yo' ? 'text-white' : 'bg-white text-gray-900 dark:bg-gray-700 dark:text-gray-200'"
:style="m.owner==='yo' ? { backgroundColor: 'var(--accent-color-chat, #0D9488)' } : {}">
class="max-w-lg rounded-lg px-4 py-2 shadow break-words"
:class="m.owner === 'yo' ? '' : ''"
:style="{
backgroundColor: m.owner === 'yo' ? 'var(--chat-own-message-color)' : 'var(--chat-agent-message-color)',
color: 'var(--chat-font-color)',
fontFamily: 'var(--chat-font-family)',
fontSize: 'var(--chat-font-size)'
}">
{{ m.text }}
</div>
</div>
@@ -60,18 +79,24 @@ 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-md border border-gray-300 dark:border-gray-600 p-3 shadow-sm focus:outline-none focus:ring-2 focus:ring-[var(--accent-color-chat,#0D9488)] focus:border-[var(--accent-color-chat,#0D9488)] dark:bg-gray-700 dark:text-white 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)',
color: 'var(--chat-font-color)',
fontFamily: 'var(--chat-font-family)',
fontSize: 'var(--chat-font-size)'
}"
/>
<button
type="submit"
class="px-4 py-2 rounded-md text-white transition-colors duration-150 ease-in-out shadow-sm hover:brightness-90"
:style="{ backgroundColor: 'var(--accent-color-chat, #0D9488)' }">
<button type="submit" class="px-4 py-2 rounded-lg text-white transition" :style="{ backgroundColor: 'var(--chat-accent-color)' }">
</button>
</form>
@@ -92,16 +117,14 @@ watch(() => chat.items.length, scrollBottom)
}
.custom-scroll::-webkit-scrollbar { width: 8px; }
.custom-scroll::-webkit-scrollbar-track { background: transparent; }
.custom-scroll::-webkit-scrollbar-thumb {
background-color: var(--accent-color-chat-alpha-35, var(--accent-color-chat-alpha-35-fallback));
border-radius: 4px;
}
.custom-scroll:hover::-webkit-scrollbar-thumb {
background-color: var(--accent-color-chat-alpha-70, var(--accent-color-chat-alpha-70-fallback));
}
.custom-scroll {
scrollbar-width: thin;
scrollbar-color: var(--accent-color-chat-alpha-60, var(--accent-color-chat-alpha-60-fallback)) 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

@@ -32,7 +32,14 @@ const appearanceSettingKeys = [
'defaultViewAsistencias',
'defaultViewConfiguracion',
'transitionSpeed',
'backgroundColorChat',
'chatAgentMessageColor',
'chatOwnMessageColor',
'chatInputBoxColor',
'chatAccentColor',
'chatBackgroundColor',
'chatFontColor',
'chatFontFamily',
'chatFontSize',
]
@@ -111,6 +118,16 @@ 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',
// Chat UI fonts
chatFontColor: '#000000',
chatFontFamily: '',
chatFontSize: 14,
}
const loadedSettings = loadSettingsFromLocalStorage()
@@ -259,6 +276,42 @@ 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)
},
// Actions for chat UI fonts
setChatFontColor(color) {
this.chatFontColor = color
_saveAppearanceState(this)
},
setChatFontFamily(font) {
this.chatFontFamily = font
_saveAppearanceState(this)
},
setChatFontSize(size) {
this.chatFontSize = Number(size)
_saveAppearanceState(this)
},
},
})

View File

@@ -95,6 +95,61 @@
</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>
<!-- Chat Font Color -->
<div class="setting-item">
<label for="chatFontColor" class="block text-sm font-medium mb-1">Chat Font Color</label>
<input type="color" id="chatFontColor" v-model="ui.chatFontColor" @input="ui.setChatFontColor($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>
<!-- Chat Font Family -->
<div class="setting-item">
<label for="chatFontFamily" class="block text-sm font-medium mb-1">Chat Font Family</label>
<input type="text" id="chatFontFamily" v-model="ui.chatFontFamily" @input="ui.setChatFontFamily($event.target.value)"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]"
placeholder="e.g., Arial, sans-serif">
</div>
<!-- Chat Font Size -->
<div class="setting-item">
<label for="chatFontSize" class="block text-sm font-medium mb-1">Chat Font Size (px)</label>
<input type="number" id="chatFontSize" v-model.number="ui.chatFontSize" @input="ui.setChatFontSize(Number($event.target.value))"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]"
min="8" max="32" step="1">
</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>