diff --git a/public/app.js b/public/app.js
index 39599dd..c141528 100644
--- a/public/app.js
+++ b/public/app.js
@@ -74,11 +74,21 @@ document.addEventListener('DOMContentLoaded', () => {
const historyItems = document.getElementById('historyItems');
const btnLogout = document.getElementById('btnLogout');
const suggestionCards = document.querySelectorAll('.suggestion-card');
+ const searchInput = document.getElementById('searchInput');
+ const searchClear = document.getElementById('searchClear');
+ const searchResultsHeader = document.getElementById('searchResultsHeader');
+ const searchResultsCount = document.getElementById('searchResultsCount');
+ const searchClearAll = document.getElementById('searchClearAll');
+ const sidebarTags = document.getElementById('sidebarTags');
// Variáveis de Estado
let chats = JSON.parse(localStorage.getItem('camila_chats')) || [];
+ // Migração: adicionar campos tags e pinned a chats antigos
+ chats = chats.map(c => ({ ...c, tags: c.tags || [], pinned: c.pinned || false }));
let currentChatId = localStorage.getItem('camila_current_chat_id') || null;
let isGenerating = false;
+ let searchQuery = '';
+ let activeTag = 'all';
// ==========================================================================
// CONTROLES DE INTERFACE & SIDEBAR
@@ -115,8 +125,39 @@ document.addEventListener('DOMContentLoaded', () => {
}
});
+ // Busca no histórico
+ searchInput.addEventListener('input', () => {
+ searchQuery = searchInput.value;
+ searchClear.style.display = searchQuery ? 'flex' : 'none';
+ renderHistory();
+ });
+
+ searchClear.addEventListener('click', () => {
+ searchInput.value = '';
+ searchQuery = '';
+ searchClear.style.display = 'none';
+ renderHistory();
+ });
+
+ searchClearAll.addEventListener('click', () => {
+ searchInput.value = '';
+ searchQuery = '';
+ searchClear.style.display = 'none';
+ renderHistory();
+ });
+
+ // Filtro por tags
+ sidebarTags.addEventListener('click', (e) => {
+ const tagBtn = e.target.closest('.tag-filter');
+ if (!tagBtn) return;
+ document.querySelectorAll('.tag-filter').forEach(b => b.classList.remove('active'));
+ tagBtn.classList.add('active');
+ activeTag = tagBtn.dataset.tag;
+ renderHistory();
+ });
+
// ==========================================================================
- // HISTÓRICO DE CHATS (LOCALSTORAGE)
+ // HISTÓRICO DE CHATS (LOCALSTORAGE) — VERSÃO COMPLETA COM PINNED, TAGS, BUSCA
// ==========================================================================
const saveChats = () => {
@@ -128,46 +169,189 @@ document.addEventListener('DOMContentLoaded', () => {
}
};
+ // Agrupamento por data
+ const getDateGroup = (timestamp) => {
+ const now = new Date();
+ const date = new Date(timestamp);
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+ const yesterday = new Date(today);
+ yesterday.setDate(yesterday.getDate() - 1);
+ const weekAgo = new Date(today);
+ weekAgo.setDate(weekAgo.getDate() - 7);
+ const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
+
+ const dateOnly = new Date(date.getFullYear(), date.getMonth(), date.getDate());
+
+ if (dateOnly.getTime() === today.getTime()) return 'Hoje';
+ if (dateOnly.getTime() === yesterday.getTime()) return 'Ontem';
+ if (dateOnly >= weekAgo) return 'Esta Semana';
+ if (dateOnly >= monthStart) return 'Este Mês';
+ return 'Mais Antigas';
+ };
+
+ // Filtrar chats por tag
+ const filterByTag = (chatList) => {
+ if (activeTag === 'all') return chatList;
+ return chatList.filter(chat => chat.tags && chat.tags.includes(activeTag));
+ };
+
+ // Filtrar chats por busca
+ const filterBySearch = (chatList) => {
+ if (!searchQuery.trim()) return chatList;
+ const q = searchQuery.toLowerCase();
+ return chatList.filter(chat => {
+ if (chat.title.toLowerCase().includes(q)) return true;
+ return chat.messages.some(msg => msg.content.toLowerCase().includes(q));
+ });
+ };
+
+ // Renderizar um item de chat
+ const createHistoryItem = (chat) => {
+ const item = document.createElement('div');
+ item.className = `history-item ${chat.id === currentChatId ? 'active' : ''} ${chat.pinned ? 'pinned' : ''}`;
+ item.dataset.id = chat.id;
+
+ const pinIcon = chat.pinned
+ ? ``
+ : '';
+
+ const tagBadges = (chat.tags || []).map(tag =>
+ `${getTagEmoji(tag)}`
+ ).join('');
+
+ item.innerHTML = `
+
+ ${pinIcon}
+
${escapeHtml(chat.title)}
+ ${tagBadges ? `
${tagBadges}
` : ''}
+
+
-
-
-
Hoje
-
diff --git a/public/style.css b/public/style.css
index 578fc8e..a1c7216 100644
--- a/public/style.css
+++ b/public/style.css
@@ -391,6 +391,138 @@ body {
background-color: rgba(255, 255, 255, 0.15);
}
+/* Busca no Histórico */
+.sidebar-search {
+ padding: 12px 16px 0;
+}
+
+.sidebar-search-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ background-color: var(--bg-tertiary);
+ border: 1px solid var(--border-light);
+ border-radius: 10px;
+ padding: 8px 12px;
+ transition: border-color var(--transition-fast);
+}
+
+.sidebar-search-wrapper:focus-within {
+ border-color: var(--border-focus);
+}
+
+.search-icon {
+ width: 16px;
+ height: 16px;
+ color: var(--text-muted);
+ flex-shrink: 0;
+}
+
+.search-input {
+ flex: 1;
+ background: none;
+ border: none;
+ outline: none;
+ color: var(--text-primary);
+ font-size: 13px;
+ font-family: var(--font-sans);
+ min-width: 0;
+}
+
+.search-input::placeholder {
+ color: var(--text-muted);
+}
+
+.search-clear {
+ background: none;
+ border: none;
+ color: var(--text-muted);
+ cursor: pointer;
+ padding: 2px;
+ display: flex;
+ align-items: center;
+ border-radius: 4px;
+ flex-shrink: 0;
+ transition: color var(--transition-fast), background-color var(--transition-fast);
+}
+
+.search-clear:hover {
+ color: var(--text-primary);
+ background-color: rgba(255,255,255,0.05);
+}
+
+.search-clear svg {
+ width: 14px;
+ height: 14px;
+}
+
+/* Tags de filtro */
+.sidebar-tags {
+ display: flex;
+ gap: 6px;
+ padding: 10px 16px 0;
+ overflow-x: auto;
+ scrollbar-width: none;
+}
+
+.sidebar-tags::-webkit-scrollbar {
+ display: none;
+}
+
+.tag-filter {
+ background-color: var(--bg-tertiary);
+ border: 1px solid var(--border-light);
+ border-radius: 20px;
+ color: var(--text-secondary);
+ font-size: 11.5px;
+ font-weight: 500;
+ padding: 5px 10px;
+ cursor: pointer;
+ white-space: nowrap;
+ transition: all var(--transition-fast);
+ font-family: var(--font-sans);
+}
+
+.tag-filter:hover {
+ background-color: var(--bg-accent);
+ color: var(--text-primary);
+}
+
+.tag-filter.active {
+ background-color: var(--brand-green);
+ border-color: var(--brand-green);
+ color: white;
+}
+
+/* Busca results header */
+.search-results-header {
+ padding-bottom: 8px;
+}
+
+.search-results-info {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 12px;
+ color: var(--text-muted);
+}
+
+.search-clear-all {
+ background: none;
+ border: none;
+ color: var(--brand-green);
+ cursor: pointer;
+ font-size: 12px;
+ font-family: var(--font-sans);
+ padding: 2px 6px;
+ border-radius: 4px;
+ transition: background-color var(--transition-fast);
+}
+
+.search-clear-all:hover {
+ background-color: var(--brand-glow);
+}
+
.history-group h3 {
font-size: 11px;
font-weight: 600;
@@ -416,7 +548,7 @@ body {
cursor: pointer;
color: var(--text-primary);
font-size: 13.5px;
- gap: 10px;
+ gap: 8px;
text-decoration: none;
position: relative;
transition: background-color var(--transition-fast);
@@ -432,11 +564,42 @@ body {
font-weight: 500;
}
+.history-item.pinned {
+ border-left: 2px solid var(--brand-green);
+ padding-left: 8px;
+}
+
+.history-item-content {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ min-width: 0;
+ flex: 1;
+}
+
.history-item-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
+ min-width: 0;
+}
+
+.pin-icon {
+ width: 12px;
+ height: 12px;
+ color: var(--brand-green);
+ flex-shrink: 0;
+}
+
+.history-item-tags {
+ display: flex;
+ gap: 2px;
+ flex-shrink: 0;
+}
+
+.history-tag-badge {
+ font-size: 10px;
}
.history-item-actions {
@@ -794,6 +957,53 @@ body {
line-height: 1.6;
}
+.message-content-wrapper {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ min-width: 0;
+}
+
+/* Ações de mensagem (copiar) */
+.message-actions {
+ display: flex;
+ gap: 4px;
+ opacity: 0;
+ transition: opacity var(--transition-fast);
+ margin-top: 4px;
+}
+
+.message-row:hover .message-actions {
+ opacity: 1;
+}
+
+.msg-action-btn {
+ background: none;
+ border: 1px solid var(--border-light);
+ border-radius: 6px;
+ color: var(--text-muted);
+ cursor: pointer;
+ padding: 4px 8px;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 12px;
+ font-family: var(--font-sans);
+ transition: all var(--transition-fast);
+}
+
+.msg-action-btn:hover {
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ border-color: rgba(255,255,255,0.15);
+}
+
+.msg-action-btn svg {
+ width: 14px;
+ height: 14px;
+}
+
.message-content p {
margin-bottom: 12px;
}