ui: enhance chat interface
Some checks failed
BotUI CI / build (push) Failing after 0s

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2026-04-12 10:27:27 -03:00
parent f903dd4918
commit 5753a7f912
2 changed files with 184 additions and 1 deletions

View file

@ -537,6 +537,64 @@ footer {
}
/* Suggestions */
/* Switchers Container - Response Format Modifiers */
.switchers-container {
display: flex;
align-items: center;
gap: 12px;
padding: 8px 16px;
flex-wrap: wrap;
background: rgba(0, 0, 0, 0.02);
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.switchers-label {
font-size: 13px;
font-weight: 600;
color: #666;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.switchers-chips {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.switcher-chip {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border-radius: 20px;
border: 2px solid transparent;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
background: rgba(0, 0, 0, 0.05);
color: #666;
user-select: none;
}
.switcher-chip:hover {
background: rgba(0, 0, 0, 0.08);
transform: translateY(-1px);
}
.switcher-chip.active {
border-color: currentColor;
background: currentColor;
color: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.switcher-chip-icon {
font-size: 14px;
}
/* Suggestions Container */
.suggestions-container {
display: flex;
flex-wrap: wrap;

View file

@ -16,6 +16,12 @@
<main id="messages"></main>
<footer>
<div class="switchers-container" id="switchers">
<div class="switchers-label">Formato:</div>
<div class="switchers-chips" id="switchersChips">
<!-- Switcher chips will be rendered here -->
</div>
</div>
<div class="suggestions-container" id="suggestions"></div>
<div class="mention-dropdown" id="mentionDropdown">
<div class="mention-header">
@ -913,6 +919,33 @@
input.focus();
}
// Prepend active switcher prompts
var enhancedContent = content;
if (activeSwitchers.size > 0) {
// Get prompts for active switchers from backend
var activePrompts = [];
activeSwitchers.forEach(function(id) {
// Backend has predefined prompts for each ID
// For now, use a simple mapping that will be enhanced by backend
var promptMap = {
'tables': 'REGRAS DE FORMATO: SEMPRE retorne suas respostas em formato de tabela HTML usando <table>, <thead>, <tbody>, <tr>, <th>, <td>. Cada dado deve ser uma célula. Use cabeçalhos claros na primeira linha. Se houver dados numéricos, alinhe à direita. Se houver texto, alinhe à esquerda. Use cores sutis em linhas alternadas (nth-child). NÃO use markdown tables, use HTML puro.',
'infographic': 'REGRAS DE FORMATO: Crie representações visuais HTML usando SVG, progress bars, stat cards, e elementos gráficos. Use elementos como: <svg> para gráficos, <div style="width:X%;background:color"> para barras de progresso, ícones emoji, badges coloridos. Organize informações visualmente com grids, flexbox, e espaçamento. Inclua legendas e rótulos visuais claros.',
'cards': 'REGRAS DE FORMATO: Retorne informações em formato de cards HTML. Cada card deve ter: <div class="card" style="border:1px solid #ddd;border-radius:8px;padding:16px;margin:8px;box-shadow:0 2px 4px rgba(0,0,0,0.1)">. Dentro do card use: título em <h3> ou <strong>, subtítulo em <p> style="color:#666", ícone emoji ou ícone SVG no topo, badges de status. Organize cards em grid usando display:grid ou flex-wrap.',
'list': 'REGRAS DE FORMATO: Use apenas listas HTML: <ul> para bullets e <ol> para números numerados. Cada item em <li>. Use sublistas aninhadas quando apropriado. NÃO use parágrafos de texto, converta tudo em itens de lista. Adicione ícones emoji no início de cada <li> quando possível. Use classes CSS para estilização: .list-item, .sub-list.',
'comparison': 'REGRAS DE FORMATO: Crie comparações lado a lado em HTML. Use grid de 2 colunas: <div style="display:grid;grid-template-columns:1fr 1fr;gap:20px">. Cada lado em uma <div class="comparison-side"> com borda colorida distinta. Use headers claros para cada lado. Adicione seção de "Diferenças Chave" com bullet points. Use cores contrastantes para cada lado (ex: azul vs laranja). Inclua tabela de comparação resumida no final.',
'timeline': 'REGRAS DE FORMATO: Organize eventos cronologicamente em formato de timeline HTML. Use <div class="timeline"> com border-left vertical. Cada evento em <div class="timeline-item"> com: data em <span class="timeline-date" style="font-weight:bold;color:#666">, título em <h3>, descrição em <p>. Adicione círculo indicador na timeline line. Ordene do mais antigo para o mais recente. Use espaçamento claro entre eventos.',
'markdown': 'REGRAS DE FORMATO: Use exclusivamente formato Markdown padrão. Sintaxe permitida: **negrito**, *itálico*, `inline code`, ```bloco de código```, # cabeçalhos, - bullets, 1. números, [links](url), ![alt](url), | tabela | markdown |. NÃO use HTML tags exceto para blocos de código. Siga estritamente a sintaxe CommonMark.',
'chart': 'REGRAS DE FORMATO: Crie gráficos e diagramas em HTML SVG. Use elementos SVG: <svg width="X" height="Y">, <line> para gráficos de linha, <rect> para gráficos de barra, <circle> para gráficos de pizza, <path> para gráficos de área. Inclua eixos com labels, grid lines, legendas. Use cores distintas para cada série de dados (ex: vermelho, azul, verde). Adicione tooltips com valores ao hover. Se o usuário pedir gráfico de pizza com "pizza vermelha", use fill="#FF0000" no SVG.'
};
activePrompts.push(promptMap[id] || "");
});
// Inject prompts before user message
if (activePrompts.length > 0) {
enhancedContent = activePrompts.join('\n\n') + '\n\n---\n\n' + content;
}
}
addMessage("user", content);
if (ws && ws.readyState === WebSocket.OPEN) {
@ -922,7 +955,7 @@
user_id: currentUserId,
session_id: currentSessionId,
channel: "web",
content: content,
content: enhancedContent,
message_type: MessageType.USER,
timestamp: new Date().toISOString(),
}),
@ -1283,6 +1316,9 @@
}
function proceedWithChatInit() {
// Render switchers on initialization
renderSwitchers();
var botName = window.__INITIAL_BOT_NAME__ || "default";
var sessionIdKey = "gb_session_" + botName;
@ -1360,6 +1396,95 @@
}
}
// Switcher Logic - Response Format Modifiers
var activeSwitchers = new Set();
var switcherDefinitions = [
{
id: 'tables',
label: 'Tabelas',
icon: '📊',
color: '#4CAF50'
},
{
id: 'infographic',
label: 'Infográfico',
icon: '📈',
color: '#2196F3'
},
{
id: 'cards',
label: 'Cards',
icon: '🃏',
color: '#FF9800'
},
{
id: 'list',
label: 'Lista',
icon: '📋',
color: '#9C27B0'
},
{
id: 'comparison',
label: 'Comparação',
icon: '⚖️',
color: '#E91E63'
},
{
id: 'timeline',
label: 'Timeline',
icon: '📅',
color: '#00BCD4'
},
{
id: 'markdown',
label: 'Markdown',
icon: '📝',
color: '#607D8B'
},
{
id: 'chart',
label: 'Gráfico',
icon: '📉',
color: '#F44336'
}
];
function renderSwitchers() {
var container = document.getElementById("switcherChips");
if (!container) return;
container.innerHTML = switcherDefinitions.map(function(sw) {
var isActive = activeSwitchers.has(sw.id);
return (
'<div class="switcher-chip' + (isActive ? ' active' : '') + '" ' +
'data-switch-id="' + sw.id + '" ' +
'style="--switcher-color: ' + sw.color + '; ' +
(isActive ? 'color: ' + sw.color + ' background: ' + sw.color + '; ' : '') +
'">' +
'<span class="switcher-chip-icon">' + sw.icon + '</span>' +
'<span>' + sw.label + '</span>' +
'</div>'
);
}).join('');
// Add click handlers
container.querySelectorAll('.switcher-chip').forEach(function(chip) {
chip.addEventListener('click', function() {
toggleSwitcher(this.getAttribute('data-switch-id'));
});
});
}
function toggleSwitcher(switcherId) {
if (activeSwitchers.has(switcherId)) {
activeSwitchers.delete(switcherId);
} else {
activeSwitchers.add(switcherId);
}
renderSwitchers();
}
function setupEventHandlers() {
var form = document.getElementById("chatForm");
var input = document.getElementById("messageInput");