546 lines
26 KiB
Plaintext
Executable File
546 lines
26 KiB
Plaintext
Executable File
<?php require_once __DIR__ . '/hamid-providers-config.php'; ?>
|
||
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>WEVAL MIND Widget - Assistant IA</title>
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
:root {
|
||
--primary: #22d3ee;
|
||
--primary-dark: #0891b2;
|
||
--secondary: #3b82f6;
|
||
--bg-dark: #0f172a;
|
||
--bg-medium: #1e293b;
|
||
--bg-light: #334155;
|
||
--text-primary: #f1f5f9;
|
||
--text-secondary: #94a3b8;
|
||
--text-muted: #64748b;
|
||
--success: #22c55e;
|
||
--error: #ef4444;
|
||
--warning: #f59e0b;
|
||
--border: #475569;
|
||
}
|
||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: linear-gradient(135deg, var(--bg-dark) 0%, #1a1a2e 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px; }
|
||
|
||
/* Widget Container */
|
||
.widget-wrapper { position: relative; }
|
||
|
||
/* Floating Button */
|
||
.widget-btn { width: 70px; height: 70px; border-radius: 50%; background: linear-gradient(135deg, var(--primary), var(--secondary)); border: none; cursor: pointer; box-shadow: 0 8px 32px rgba(34,211,238,0.4); display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; position: fixed; bottom: 30px; right: 30px; z-index: 9998; }
|
||
.widget-btn:hover { transform: scale(1.1) rotate(10deg); box-shadow: 0 12px 40px rgba(34,211,238,0.6); }
|
||
.widget-btn img { width: 50px; height: 50px; border-radius: 50%; object-fit: cover; }
|
||
.widget-btn .pulse { position: absolute; width: 100%; height: 100%; border-radius: 50%; background: var(--primary); animation: pulse 2s infinite; opacity: 0.3; }
|
||
@keyframes pulse { 0%, 100% { transform: scale(1); opacity: 0.3; } 50% { transform: scale(1.2); opacity: 0; } }
|
||
|
||
/* Bubble */
|
||
.widget-bubble { position: fixed; bottom: 110px; right: 30px; background: white; padding: 12px 18px; border-radius: 20px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); font-size: 14px; color: var(--bg-dark); animation: bubblePop 0.4s ease; z-index: 9997; }
|
||
.widget-bubble::after { content: ''; position: absolute; bottom: -8px; right: 30px; border: 8px solid transparent; border-top-color: white; }
|
||
@keyframes bubblePop { from { opacity: 0; transform: scale(0.8) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } }
|
||
|
||
/* Chat Window */
|
||
.widget-chat { position: fixed; bottom: 110px; right: 30px; width: 400px; height: 600px; background: var(--bg-dark); border-radius: 24px; box-shadow: 0 25px 80px rgba(0,0,0,0.5); display: none; flex-direction: column; overflow: hidden; z-index: 9999; animation: slideUp 0.3s ease; }
|
||
.widget-chat.open { display: flex; }
|
||
@keyframes slideUp { from { opacity: 0; transform: translateY(30px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
|
||
|
||
/* Header */
|
||
.widget-header { background: linear-gradient(135deg, var(--primary), var(--secondary)); padding: 20px; display: flex; align-items: center; gap: 14px; }
|
||
.widget-header .avatar { width: 50px; height: 50px; border-radius: 14px; background: rgba(255,255,255,0.2); display: flex; align-items: center; justify-content: center; font-size: 28px; }
|
||
.widget-header .info { flex: 1; color: white; }
|
||
.widget-header .title { font-size: 18px; font-weight: 600; }
|
||
.widget-header .status { font-size: 13px; opacity: 0.9; display: flex; align-items: center; gap: 6px; }
|
||
.widget-header .status .dot { width: 8px; height: 8px; background: #4ade80; border-radius: 50%; animation: blink 2s infinite; }
|
||
@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
|
||
.widget-header .close-btn { background: rgba(255,255,255,0.2); border: none; width: 36px; height: 36px; border-radius: 10px; color: white; font-size: 20px; cursor: pointer; transition: all 0.2s; }
|
||
.widget-header .close-btn:hover { background: rgba(255,255,255,0.3); }
|
||
|
||
/* Provider Select */
|
||
.provider-bar { background: var(--bg-medium); padding: 10px 16px; display: flex; align-items: center; gap: 10px; border-bottom: 1px solid var(--border); }
|
||
.provider-bar label { font-size: 12px; color: var(--text-muted); }
|
||
.provider-bar select { flex: 1; background: var(--bg-light); border: 1px solid var(--border); color: var(--text-primary); padding: 8px 12px; border-radius: 8px; font-size: 13px; }
|
||
|
||
/* Messages */
|
||
.widget-messages { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 16px; }
|
||
.widget-messages::-webkit-scrollbar { width: 6px; }
|
||
.widget-messages::-webkit-scrollbar-track { background: transparent; }
|
||
.widget-messages::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
|
||
|
||
.message { display: flex; gap: 10px; animation: msgFade 0.3s ease; }
|
||
@keyframes msgFade { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
|
||
.message.user { flex-direction: row-reverse; }
|
||
.message .avatar { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; }
|
||
.message.bot .avatar { background: linear-gradient(135deg, var(--primary), var(--secondary)); }
|
||
.message.user .avatar { background: var(--bg-light); }
|
||
.message .bubble { max-width: 85%; padding: 14px 18px; border-radius: 18px; font-size: 14px; line-height: 1.5; }
|
||
.message.bot .bubble { background: var(--bg-medium); color: var(--text-primary); border-bottom-left-radius: 6px; }
|
||
.message.user .bubble { background: linear-gradient(135deg, var(--primary), var(--secondary)); color: white; border-bottom-right-radius: 6px; }
|
||
.message .time { font-size: 11px; color: var(--text-muted); margin-top: 6px; }
|
||
|
||
/* Thinking Box */
|
||
.thinking-box { background: linear-gradient(135deg, rgba(168,85,247,0.1), rgba(34,211,238,0.05)); border: 1px solid rgba(168,85,247,0.2); border-radius: 12px; margin: 8px 0; overflow: hidden; }
|
||
.thinking-header { padding: 10px 14px; cursor: pointer; display: flex; align-items: center; gap: 8px; font-size: 12px; color: #a855f7; }
|
||
.thinking-header .icon { animation: sparkle 2s linear infinite; }
|
||
@keyframes sparkle { 0%, 100% { opacity: 0.5; transform: rotate(0deg); } 50% { opacity: 1; transform: rotate(180deg); } }
|
||
.thinking-header .chevron { margin-left: auto; transition: transform 0.3s; font-size: 10px; }
|
||
.thinking-box.expanded .chevron { transform: rotate(180deg); }
|
||
.thinking-content { max-height: 0; overflow: hidden; transition: max-height 0.3s; }
|
||
.thinking-box.expanded .thinking-content { max-height: 150px; padding: 10px 14px; border-top: 1px solid rgba(168,85,247,0.15); font-size: 12px; color: var(--text-secondary); overflow-y: auto; }
|
||
|
||
/* Code Block */
|
||
.code-block { background: var(--bg-dark); border: 1px solid var(--border); border-radius: 10px; margin: 10px 0; overflow: hidden; }
|
||
.code-header { display: flex; justify-content: space-between; padding: 8px 12px; background: var(--bg-light); font-size: 11px; color: var(--text-muted); }
|
||
.code-header button { background: none; border: none; color: var(--primary); cursor: pointer; font-size: 11px; }
|
||
.code-content { padding: 12px; font-family: 'Fira Code', monospace; font-size: 12px; overflow-x: auto; color: var(--text-primary); }
|
||
|
||
/* Quick Actions */
|
||
.quick-actions { padding: 12px 16px; display: flex; gap: 8px; flex-wrap: wrap; border-bottom: 1px solid var(--border); }
|
||
.quick-btn { background: var(--bg-medium); border: 1px solid var(--border); color: var(--text-secondary); padding: 8px 14px; border-radius: 20px; font-size: 12px; cursor: pointer; transition: all 0.2s; }
|
||
.quick-btn:hover { border-color: var(--primary); color: var(--primary); }
|
||
|
||
/* Input Area */
|
||
.widget-input { padding: 16px; background: var(--bg-medium); border-top: 1px solid var(--border); }
|
||
.input-container { display: flex; gap: 10px; align-items: flex-end; }
|
||
.input-wrapper { flex: 1; background: var(--bg-light); border: 1px solid var(--border); border-radius: 16px; overflow: hidden; transition: border-color 0.3s; }
|
||
.input-wrapper:focus-within { border-color: var(--primary); }
|
||
.input-wrapper textarea { width: 100%; padding: 12px 16px; background: transparent; border: none; color: var(--text-primary); font-size: 14px; resize: none; outline: none; font-family: inherit; min-height: 44px; max-height: 100px; }
|
||
.input-wrapper textarea::placeholder { color: var(--text-muted); }
|
||
.input-toolbar { display: flex; padding: 8px 12px; gap: 8px; border-top: 1px solid var(--border); }
|
||
.input-toolbar button { background: none; border: none; color: var(--text-muted); cursor: pointer; padding: 4px; font-size: 16px; transition: color 0.2s; }
|
||
.input-toolbar button:hover { color: var(--primary); }
|
||
.send-btn { width: 48px; height: 48px; border-radius: 14px; background: linear-gradient(135deg, var(--primary), var(--secondary)); border: none; color: white; font-size: 20px; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; }
|
||
.send-btn:hover { transform: scale(1.05); box-shadow: 0 4px 20px rgba(34,211,238,0.4); }
|
||
.send-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
|
||
|
||
/* Typing Indicator */
|
||
.typing { display: flex; align-items: center; gap: 10px; padding: 14px 18px; }
|
||
.typing .dots { display: flex; gap: 4px; }
|
||
.typing .dots span { width: 8px; height: 8px; background: var(--primary); border-radius: 50%; animation: typing 1.4s infinite ease-in-out both; }
|
||
.typing .dots span:nth-child(1) { animation-delay: -0.32s; }
|
||
.typing .dots span:nth-child(2) { animation-delay: -0.16s; }
|
||
@keyframes typing { 0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; } 40% { transform: scale(1); opacity: 1; } }
|
||
|
||
/* Responsive */
|
||
@media (max-width: 500px) {
|
||
.widget-chat { width: 100%; height: 100%; bottom: 0; right: 0; border-radius: 0; }
|
||
.widget-btn { bottom: 20px; right: 20px; }
|
||
}
|
||
|
||
/* Demo Mode Styles */
|
||
.demo-container { display: flex; flex-direction: column; align-items: center; gap: 30px; }
|
||
.demo-title { color: var(--text-primary); font-size: 24px; font-weight: 600; text-align: center; }
|
||
.demo-subtitle { color: var(--text-secondary); font-size: 14px; margin-top: -20px; }
|
||
.demo-widget { position: relative; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="demo-container">
|
||
<h1 class="demo-title">🔲 WEVAL MIND Widget</h1>
|
||
<p class="demo-subtitle">Widget IA intégrable sur n'importe quel site</p>
|
||
|
||
<div class="demo-widget">
|
||
<!-- Floating Button -->
|
||
<div class="widget-btn" onclick="toggleChat()" id="widgetBtn">
|
||
<div class="pulse"></div>
|
||
<span style="font-size:32px;">🤖</span>
|
||
</div>
|
||
|
||
<!-- Bubble -->
|
||
<div class="widget-bubble" id="bubble">Besoin d'aide? 💬</div>
|
||
|
||
<!-- Chat Window -->
|
||
<div class="widget-chat" id="chatWindow">
|
||
<div class="widget-header">
|
||
<div class="avatar">🤖</div>
|
||
<div class="info">
|
||
<div class="title">WEVAL MIND</div>
|
||
<div class="status"><span class="dot"></span> En ligne</div>
|
||
</div>
|
||
<button class="close-btn" onclick="toggleChat()">×</button>
|
||
</div>
|
||
|
||
<div class="provider-bar">
|
||
<label>Provider:</label>
|
||
<?php echo hamid_providers_dropdown("cerebras", "provider", ""); ?>
|
||
</div>
|
||
|
||
<div class="quick-actions">
|
||
<button class="quick-btn" onclick="quickMsg('Bonjour!')">👋 Saluer</button>
|
||
<button class="quick-btn" onclick="quickMsg('Aide moi avec mon code')">💻 Code</button>
|
||
<button class="quick-btn" onclick="quickMsg('Explique moi')">📖 Expliquer</button>
|
||
<button class="quick-btn" onclick="quickMsg('Résume')">📝 Résumer</button>
|
||
</div>
|
||
|
||
<div class="widget-messages" id="messages">
|
||
<div class="message bot">
|
||
<div class="avatar">🤖</div>
|
||
<div>
|
||
<div class="bubble">
|
||
Bonjour! 👋 Je suis <strong>WEVAL MIND</strong>, votre assistant IA.<br><br>
|
||
Comment puis-je vous aider aujourd'hui?
|
||
</div>
|
||
<div class="time">Maintenant</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="widget-input">
|
||
<div class="input-container">
|
||
<div class="input-wrapper">
|
||
<textarea id="input" placeholder="Écrivez votre message..." rows="1"></textarea>
|
||
<div class="input-toolbar">
|
||
<button title="Pièce jointe">📎</button>
|
||
<button title="Emoji">😊</button>
|
||
<button title="Microphone">🎤</button>
|
||
</div>
|
||
</div>
|
||
<button class="send-btn" onclick="sendMessage()" id="sendBtn">➤</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const messagesEl = document.getElementById('messages');
|
||
const inputEl = document.getElementById('input');
|
||
const providerSelect = document.getElementById('provider');
|
||
const chatWindow = document.getElementById('chatWindow');
|
||
const bubble = document.getElementById('bubble');
|
||
const sendBtn = document.getElementById('sendBtn');
|
||
|
||
let sessionId = 'widget_' + Date.now();
|
||
let isOpen = false;
|
||
|
||
// Toggle chat
|
||
function toggleChat() {
|
||
isOpen = !isOpen;
|
||
chatWindow.classList.toggle('open', isOpen);
|
||
bubble.style.display = isOpen ? 'none' : 'block';
|
||
if (isOpen) inputEl.focus();
|
||
}
|
||
|
||
// Quick message
|
||
function quickMsg(text) {
|
||
inputEl.value = text;
|
||
sendMessage();
|
||
}
|
||
|
||
// Input handling
|
||
inputEl.addEventListener('keydown', e => {
|
||
if (e.key === 'Enter' && !e.shiftKey) {
|
||
e.preventDefault();
|
||
sendMessage();
|
||
}
|
||
});
|
||
|
||
inputEl.addEventListener('input', () => {
|
||
inputEl.style.height = 'auto';
|
||
inputEl.style.height = Math.min(inputEl.scrollHeight, 100) + 'px';
|
||
});
|
||
|
||
function addMessage(content, isUser = false) {
|
||
const div = document.createElement('div');
|
||
div.className = 'message ' + (isUser ? 'user' : 'bot');
|
||
const time = new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' });
|
||
|
||
div.innerHTML = `
|
||
<div class="avatar">${isUser ? '👤' : '🤖'}</div>
|
||
<div>
|
||
<div class="bubble">${formatContent(content)}</div>
|
||
<div class="time">${time}</div>
|
||
</div>
|
||
`;
|
||
|
||
messagesEl.appendChild(div);
|
||
messagesEl.scrollTop = messagesEl.scrollHeight;
|
||
}
|
||
|
||
function formatContent(text) {
|
||
// Code blocks
|
||
text = text.replace(/```(\w+)?\n?([\s\S]*?)```/g, (_, lang, code) => {
|
||
return `<div class="code-block">
|
||
<div class="code-header"><span>${lang || 'code'}</span><button onclick="copyCode(this)">📋 Copier</button></div>
|
||
<div class="code-content"><pre>${escapeHtml(code.trim())}</pre></div>
|
||
</div>`;
|
||
});
|
||
text = text.replace(/`([^`]+)`/g, '<code style="background:var(--bg-light);padding:2px 6px;border-radius:4px;">$1</code>');
|
||
text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
||
text = text.replace(/\n/g, '<br>');
|
||
return text;
|
||
}
|
||
|
||
function escapeHtml(text) {
|
||
const div = document.createElement('div');
|
||
div.textContent = text;
|
||
return div.innerHTML;
|
||
}
|
||
|
||
function copyCode(btn) {
|
||
const code = btn.closest('.code-block').querySelector('pre').textContent;
|
||
navigator.clipboard.writeText(code);
|
||
btn.textContent = '✅ Copié!';
|
||
setTimeout(() => btn.textContent = '📋 Copier', 2000);
|
||
}
|
||
|
||
function addThinking(text) {
|
||
const div = document.createElement('div');
|
||
div.className = 'thinking-box';
|
||
div.innerHTML = `
|
||
<div class="thinking-header" onclick="this.parentElement.classList.toggle('expanded')">
|
||
<span class="icon">✨</span> Réflexion <span class="chevron">▼</span>
|
||
</div>
|
||
<div class="thinking-content">${text}</div>
|
||
`;
|
||
messagesEl.appendChild(div);
|
||
}
|
||
|
||
function addTyping() {
|
||
const div = document.createElement('div');
|
||
div.className = 'message bot';
|
||
div.id = 'typing';
|
||
div.innerHTML = `
|
||
<div class="avatar">🤖</div>
|
||
<div class="typing">
|
||
<div class="dots"><span></span><span></span><span></span></div>
|
||
</div>
|
||
`;
|
||
messagesEl.appendChild(div);
|
||
messagesEl.scrollTop = messagesEl.scrollHeight;
|
||
}
|
||
|
||
function removeTyping() {
|
||
const el = document.getElementById('typing');
|
||
if (el) el.remove();
|
||
}
|
||
|
||
async function sendMessage() {
|
||
const message = inputEl.value.trim();
|
||
if (!message) return;
|
||
|
||
addMessage(message, true);
|
||
inputEl.value = '';
|
||
inputEl.style.height = 'auto';
|
||
sendBtn.disabled = true;
|
||
|
||
addTyping();
|
||
|
||
try {
|
||
const res = await fetch('/hamid-api.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
message: message,
|
||
provider: providerSelect.value,
|
||
session_id: sessionId
|
||
})
|
||
});
|
||
|
||
const data = await res.json();
|
||
removeTyping();
|
||
|
||
if (data.error) {
|
||
addMessage('❌ ' + data.error);
|
||
} else {
|
||
if (data.thinking) addThinking(data.thinking);
|
||
addMessage(data.response);
|
||
}
|
||
} catch (e) {
|
||
removeTyping();
|
||
addMessage('❌ Erreur de connexion');
|
||
}
|
||
|
||
sendBtn.disabled = false;
|
||
}
|
||
|
||
// Auto-hide bubble after 5s
|
||
setTimeout(() => { bubble.style.display = 'none'; }, 5000);
|
||
</script>
|
||
</body>
|
||
</html>
|
||
|
||
<!-- FEATURES ADDITIONNELLES -->
|
||
<script>
|
||
// Export conversation
|
||
function exportConversation() {
|
||
const msgs = document.querySelectorAll('.message');
|
||
let content = 'WEVAL MIND - Conversation Export\n';
|
||
content += '================================\n\n';
|
||
msgs.forEach(m => {
|
||
const isUser = m.classList.contains('user');
|
||
const text = m.querySelector('.bubble').textContent;
|
||
content += (isUser ? 'USER: ' : 'BOT: ') + text + '\n\n';
|
||
});
|
||
const blob = new Blob([content], { type: 'text/plain' });
|
||
const a = document.createElement('a');
|
||
a.href = URL.createObjectURL(blob);
|
||
a.download = 'weval-conversation-' + Date.now() + '.txt';
|
||
a.click();
|
||
}
|
||
|
||
// Voice input
|
||
let recognition = null;
|
||
function toggleVoiceInput() {
|
||
if (!('webkitSpeechRecognition' in window)) {
|
||
alert('Voice input not supported in this browser');
|
||
return;
|
||
}
|
||
if (!recognition) {
|
||
recognition = new webkitSpeechRecognition();
|
||
recognition.lang = 'fr-FR';
|
||
recognition.continuous = false;
|
||
recognition.onresult = e => {
|
||
inputEl.value = e.results[0][0].transcript;
|
||
sendMessage();
|
||
};
|
||
}
|
||
recognition.start();
|
||
}
|
||
|
||
// Keyboard shortcuts
|
||
document.addEventListener('keydown', e => {
|
||
if (e.key === 'Escape' && isOpen) toggleChat();
|
||
if (e.ctrlKey && e.key === 'k') { toggleChat(); e.preventDefault(); }
|
||
});
|
||
|
||
// Notification sound
|
||
function playNotification() {
|
||
const ctx = new (window.AudioContext || window.webkitAudioContext)();
|
||
const osc = ctx.createOscillator();
|
||
const gain = ctx.createGain();
|
||
osc.connect(gain);
|
||
gain.connect(ctx.destination);
|
||
osc.frequency.value = 800;
|
||
gain.gain.value = 0.1;
|
||
osc.start();
|
||
setTimeout(() => osc.stop(), 100);
|
||
}
|
||
|
||
// Auto-save conversation to localStorage
|
||
function saveConversation() {
|
||
const msgs = [];
|
||
document.querySelectorAll('.message').forEach(m => {
|
||
msgs.push({
|
||
isUser: m.classList.contains('user'),
|
||
content: m.querySelector('.bubble').innerHTML,
|
||
time: m.querySelector('.time')?.textContent || ''
|
||
});
|
||
});
|
||
localStorage.setItem('weval_widget_msgs_' + sessionId, JSON.stringify(msgs));
|
||
}
|
||
|
||
// Load saved conversation
|
||
function loadConversation() {
|
||
const saved = localStorage.getItem('weval_widget_msgs_' + sessionId);
|
||
if (saved) {
|
||
try {
|
||
const msgs = JSON.parse(saved);
|
||
msgs.forEach(m => {
|
||
const div = document.createElement('div');
|
||
div.className = 'message ' + (m.isUser ? 'user' : 'bot');
|
||
div.innerHTML = `
|
||
<div class="avatar">${m.isUser ? '👤' : '🤖'}</div>
|
||
<div>
|
||
<div class="bubble">${m.content}</div>
|
||
<div class="time">${m.time}</div>
|
||
</div>
|
||
`;
|
||
messagesEl.appendChild(div);
|
||
});
|
||
} catch(e) {}
|
||
}
|
||
}
|
||
|
||
// Typing indicator with random messages
|
||
const typingMessages = [
|
||
'Réflexion en cours...',
|
||
'Analyse de votre demande...',
|
||
'Consultation de la base de connaissances...',
|
||
'Génération de la réponse...'
|
||
];
|
||
|
||
function getRandomTypingMessage() {
|
||
return typingMessages[Math.floor(Math.random() * typingMessages.length)];
|
||
}
|
||
|
||
// Enhanced addTyping with message
|
||
function addTypingEnhanced() {
|
||
const div = document.createElement('div');
|
||
div.className = 'message bot';
|
||
div.id = 'typing';
|
||
div.innerHTML = `
|
||
<div class="avatar">🤖</div>
|
||
<div class="typing">
|
||
<span style="font-size:11px;color:var(--text-muted);margin-right:8px;">${getRandomTypingMessage()}</span>
|
||
<div class="dots"><span></span><span></span><span></span></div>
|
||
</div>
|
||
`;
|
||
messagesEl.appendChild(div);
|
||
messagesEl.scrollTop = messagesEl.scrollHeight;
|
||
}
|
||
|
||
// Clear chat with confirmation
|
||
function clearChatConfirm() {
|
||
if (confirm('Effacer toute la conversation ?')) {
|
||
messagesEl.innerHTML = '';
|
||
localStorage.removeItem('weval_widget_msgs_' + sessionId);
|
||
addMessage('Conversation effacée. Comment puis-je vous aider ?', false);
|
||
}
|
||
}
|
||
|
||
// Feedback system
|
||
function sendFeedback(msgId, isPositive) {
|
||
console.log('Feedback:', msgId, isPositive ? 'positive' : 'negative');
|
||
// TODO: Send to API
|
||
}
|
||
|
||
// Theme toggle
|
||
let isDarkTheme = true;
|
||
function toggleTheme() {
|
||
isDarkTheme = !isDarkTheme;
|
||
document.body.style.setProperty('--bg-dark', isDarkTheme ? '#0f172a' : '#f8fafc');
|
||
document.body.style.setProperty('--text-primary', isDarkTheme ? '#f1f5f9' : '#1e293b');
|
||
}
|
||
|
||
// Window resize handler
|
||
window.addEventListener('resize', () => {
|
||
if (window.innerWidth < 500 && isOpen) {
|
||
chatWindow.style.width = '100%';
|
||
chatWindow.style.height = '100%';
|
||
chatWindow.style.borderRadius = '0';
|
||
}
|
||
});
|
||
|
||
// Initialize
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
// Show bubble after 2s
|
||
setTimeout(() => { bubble.style.display = 'block'; }, 2000);
|
||
// Hide bubble after 8s
|
||
setTimeout(() => { bubble.style.display = 'none'; }, 8000);
|
||
});
|
||
</script>
|
||
|
||
<style>
|
||
/* Additional styles for enhanced features */
|
||
.feedback-btns { display: flex; gap: 8px; margin-top: 8px; }
|
||
.feedback-btn { background: none; border: 1px solid var(--border); padding: 4px 8px; border-radius: 12px; cursor: pointer; font-size: 12px; color: var(--text-muted); transition: all 0.2s; }
|
||
.feedback-btn:hover { border-color: var(--primary); color: var(--primary); }
|
||
.feedback-btn.active { background: var(--primary); color: white; border-color: var(--primary); }
|
||
|
||
/* Tooltip */
|
||
.tooltip { position: relative; }
|
||
.tooltip::after { content: attr(data-tooltip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: var(--bg-light); color: var(--text-primary); padding: 6px 10px; border-radius: 6px; font-size: 11px; white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity 0.2s; }
|
||
.tooltip:hover::after { opacity: 1; }
|
||
|
||
/* Animations */
|
||
@keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }
|
||
.shake { animation: shake 0.5s ease; }
|
||
|
||
/* Minimized state */
|
||
.widget-chat.minimized { height: 60px; }
|
||
.widget-chat.minimized .widget-messages,
|
||
.widget-chat.minimized .widget-input,
|
||
.widget-chat.minimized .quick-actions,
|
||
.widget-chat.minimized .provider-bar { display: none; }
|
||
</style>
|