Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>PhD Scholar Assistant</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| academic: { | |
| blue: '#1a365d', | |
| gold: '#d4af37', | |
| gray: '#4a5568', | |
| } | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| /* Custom scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: #f1f1f1; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: #888; | |
| border-radius: 4px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: #555; | |
| } | |
| /* Chat bubble animation */ | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .chat-bubble { | |
| animation: fadeIn 0.3s ease-out; | |
| } | |
| /* Pulse animation for AI typing indicator */ | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0.5; } | |
| } | |
| .typing-dot { | |
| animation: pulse 1.5s infinite ease-in-out; | |
| } | |
| .typing-dot:nth-child(1) { | |
| animation-delay: 0s; | |
| } | |
| .typing-dot:nth-child(2) { | |
| animation-delay: 0.3s; | |
| } | |
| .typing-dot:nth-child(3) { | |
| animation-delay: 0.6s; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 font-sans"> | |
| <div class="container mx-auto max-w-6xl p-4"> | |
| <!-- Header --> | |
| <header class="bg-academic-blue text-white rounded-lg shadow-md p-6 mb-6"> | |
| <div class="flex justify-between items-center"> | |
| <div> | |
| <h1 class="text-3xl font-bold"><i class="fas fa-graduation-cap mr-3"></i>PhD Scholar Assistant</h1> | |
| <p class="mt-2 text-academic-gold">Your AI-powered research companion</p> | |
| </div> | |
| <div class="flex space-x-4"> | |
| <button id="save-chat-btn" class="bg-academic-gold hover:bg-yellow-600 text-academic-blue font-semibold py-2 px-4 rounded-lg flex items-center"> | |
| <i class="fas fa-save mr-2"></i> Save Chat | |
| </button> | |
| <button id="load-chat-btn" class="bg-white hover:bg-gray-200 text-academic-blue font-semibold py-2 px-4 rounded-lg flex items-center"> | |
| <i class="fas fa-folder-open mr-2"></i> Load Chat | |
| </button> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Main Content --> | |
| <div class="flex flex-col lg:flex-row gap-6"> | |
| <!-- Sidebar --> | |
| <div class="w-full lg:w-1/4 bg-white rounded-lg shadow-md p-4 h-fit"> | |
| <h2 class="text-xl font-semibold text-academic-blue mb-4 flex items-center"> | |
| <i class="fas fa-book mr-2"></i> Research Tools | |
| </h2> | |
| <div class="space-y-3"> | |
| <button class="quick-prompt-btn w-full bg-gray-100 hover:bg-gray-200 text-academic-gray p-3 rounded-lg text-left flex items-center" data-prompt="Help me structure my literature review"> | |
| <i class="fas fa-book-reader mr-3 text-academic-blue"></i> | |
| Literature Review | |
| </button> | |
| <button class="quick-prompt-btn w-full bg-gray-100 hover:bg-gray-200 text-academic-gray p-3 rounded-lg text-left flex items-center" data-prompt="Suggest methodologies for my research on [topic]"> | |
| <i class="fas fa-flask mr-3 text-academic-blue"></i> | |
| Methodology | |
| </button> | |
| <button class="quick-prompt-btn w-full bg-gray-100 hover:bg-gray-200 text-academic-gray p-3 rounded-lg text-left flex items-center" data-prompt="Help me analyze this data: [describe your data]"> | |
| <i class="fas fa-chart-bar mr-3 text-academic-blue"></i> | |
| Data Analysis | |
| </button> | |
| <button class="quick-prompt-btn w-full bg-gray-100 hover:bg-gray-200 text-academic-gray p-3 rounded-lg text-left flex items-center" data-prompt="Help me write an abstract for my paper on [topic]"> | |
| <i class="fas fa-file-alt mr-3 text-academic-blue"></i> | |
| Paper Writing | |
| </button> | |
| <button class="quick-prompt-btn w-full bg-gray-100 hover:bg-gray-200 text-academic-gray p-3 rounded-lg text-left flex items-center" data-prompt="Suggest academic conferences in [field] for 2024"> | |
| <i class="fas fa-users mr-3 text-academic-blue"></i> | |
| Conferences | |
| </button> | |
| </div> | |
| <div class="mt-6 pt-4 border-t border-gray-200"> | |
| <h3 class="font-semibold text-academic-blue mb-3 flex items-center"> | |
| <i class="fas fa-save mr-2"></i> Saved Chats | |
| </h3> | |
| <div id="saved-chats-list" class="space-y-2 max-h-60 overflow-y-auto"> | |
| <!-- Saved chats will appear here --> | |
| <div class="text-gray-500 italic text-center py-4">No saved chats yet</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Chat Container --> | |
| <div class="w-full lg:w-3/4 bg-white rounded-lg shadow-md overflow-hidden flex flex-col"> | |
| <!-- Chat Header --> | |
| <div class="bg-academic-blue text-white p-4 flex justify-between items-center"> | |
| <h2 class="text-xl font-semibold flex items-center"> | |
| <i class="fas fa-comments mr-2"></i> Research Assistant | |
| </h2> | |
| <div class="flex items-center space-x-2"> | |
| <span id="word-count" class="text-sm bg-academic-gold text-academic-blue px-2 py-1 rounded">0 words</span> | |
| <button id="clear-chat-btn" class="text-white hover:text-academic-gold"> | |
| <i class="fas fa-trash-alt"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Chat Messages --> | |
| <div id="chat-container" class="flex-1 p-4 overflow-y-auto max-h-[60vh]"> | |
| <!-- Welcome message --> | |
| <div class="chat-bubble mb-6"> | |
| <div class="flex items-start"> | |
| <div class="bg-academic-blue text-white rounded-full w-10 h-10 flex items-center justify-center mr-3"> | |
| <i class="fas fa-robot"></i> | |
| </div> | |
| <div class="bg-gray-100 rounded-lg p-4 max-w-[85%]"> | |
| <h3 class="font-semibold text-academic-blue mb-1">PhD Research Assistant</h3> | |
| <p class="text-gray-800">Hello! I'm your AI research assistant. How can I help you with your PhD journey today? I can assist with:</p> | |
| <ul class="list-disc pl-5 mt-2 space-y-1"> | |
| <li>Literature review guidance</li> | |
| <li>Research methodology suggestions</li> | |
| <li>Data analysis strategies</li> | |
| <li>Academic writing tips</li> | |
| <li>Citation and reference help</li> | |
| </ul> | |
| <p class="mt-2 text-gray-800">Try clicking one of the quick prompts on the left or type your question below.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Typing Indicator (hidden by default) --> | |
| <div id="typing-indicator" class="hidden px-4 pb-4"> | |
| <div class="flex items-start"> | |
| <div class="bg-academic-blue text-white rounded-full w-10 h-10 flex items-center justify-center mr-3"> | |
| <i class="fas fa-robot"></i> | |
| </div> | |
| <div class="bg-gray-100 rounded-lg p-4"> | |
| <div class="flex space-x-2"> | |
| <div class="typing-dot w-2 h-2 bg-gray-500 rounded-full"></div> | |
| <div class="typing-dot w-2 h-2 bg-gray-500 rounded-full"></div> | |
| <div class="typing-dot w-2 h-2 bg-gray-500 rounded-full"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Input Area --> | |
| <div class="border-t border-gray-200 p-4 bg-gray-50"> | |
| <form id="chat-form" class="flex space-x-2"> | |
| <div class="flex-1 relative"> | |
| <textarea id="user-input" rows="1" class="w-full border border-gray-300 rounded-lg p-3 pr-10 focus:outline-none focus:ring-2 focus:ring-academic-blue resize-none" placeholder="Ask your research question..."></textarea> | |
| <button type="button" id="voice-input-btn" class="absolute right-2 bottom-2 text-gray-500 hover:text-academic-blue"> | |
| <i class="fas fa-microphone"></i> | |
| </button> | |
| </div> | |
| <button type="submit" class="bg-academic-blue hover:bg-blue-800 text-white rounded-lg p-3 px-4"> | |
| <i class="fas fa-paper-plane"></i> | |
| </button> | |
| </form> | |
| <div class="mt-2 flex justify-between items-center text-xs text-gray-500"> | |
| <div> | |
| <button id="citation-btn" class="hover:text-academic-blue mr-3"> | |
| <i class="fas fa-quote-right mr-1"></i> Citation Help | |
| </button> | |
| <button id="format-btn" class="hover:text-academic-blue"> | |
| <i class="fas fa-align-left mr-1"></i> Format Text | |
| </button> | |
| </div> | |
| <div> | |
| <span id="char-count">0/1000</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Save Chat Modal --> | |
| <div id="save-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white rounded-lg p-6 w-full max-w-md"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-xl font-semibold text-academic-blue">Save Chat Session</h3> | |
| <button id="close-save-modal" class="text-gray-500 hover:text-gray-700"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="chat-title" class="block text-gray-700 mb-2">Title:</label> | |
| <input type="text" id="chat-title" class="w-full border border-gray-300 rounded-lg p-2 focus:outline-none focus:ring-2 focus:ring-academic-blue" placeholder="e.g., Literature Review Discussion"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="chat-tags" class="block text-gray-700 mb-2">Tags (comma separated):</label> | |
| <input type="text" id="chat-tags" class="w-full border border-gray-300 rounded-lg p-2 focus:outline-none focus:ring-2 focus:ring-academic-blue" placeholder="e.g., methodology, qualitative, interviews"> | |
| </div> | |
| <div class="flex justify-end space-x-3"> | |
| <button id="cancel-save" class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-semibold py-2 px-4 rounded-lg"> | |
| Cancel | |
| </button> | |
| <button id="confirm-save" class="bg-academic-blue hover:bg-blue-800 text-white font-semibold py-2 px-4 rounded-lg"> | |
| Save | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Load Chat Modal --> | |
| <div id="load-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white rounded-lg p-6 w-full max-w-2xl"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-xl font-semibold text-academic-blue">Load Saved Chat</h3> | |
| <button id="close-load-modal" class="text-gray-500 hover:text-gray-700"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="mb-4"> | |
| <input type="text" id="search-saved" class="w-full border border-gray-300 rounded-lg p-2 focus:outline-none focus:ring-2 focus:ring-academic-blue" placeholder="Search saved chats..."> | |
| </div> | |
| <div id="saved-chats-modal-list" class="max-h-96 overflow-y-auto"> | |
| <!-- Saved chats will appear here --> | |
| <div class="text-gray-500 italic text-center py-8">No saved chats found</div> | |
| </div> | |
| <div class="flex justify-end mt-4"> | |
| <button id="cancel-load" class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-semibold py-2 px-4 rounded-lg"> | |
| Close | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const chatForm = document.getElementById('chat-form'); | |
| const userInput = document.getElementById('user-input'); | |
| const chatContainer = document.getElementById('chat-container'); | |
| const typingIndicator = document.getElementById('typing-indicator'); | |
| const saveChatBtn = document.getElementById('save-chat-btn'); | |
| const loadChatBtn = document.getElementById('load-chat-btn'); | |
| const clearChatBtn = document.getElementById('clear-chat-btn'); | |
| const saveModal = document.getElementById('save-modal'); | |
| const loadModal = document.getElementById('load-modal'); | |
| const closeSaveModal = document.getElementById('close-save-modal'); | |
| const closeLoadModal = document.getElementById('close-load-modal'); | |
| const cancelSave = document.getElementById('cancel-save'); | |
| const confirmSave = document.getElementById('confirm-save'); | |
| const cancelLoad = document.getElementById('cancel-load'); | |
| const quickPromptBtns = document.querySelectorAll('.quick-prompt-btn'); | |
| const charCount = document.getElementById('char-count'); | |
| const wordCount = document.getElementById('word-count'); | |
| const voiceInputBtn = document.getElementById('voice-input-btn'); | |
| const citationBtn = document.getElementById('citation-btn'); | |
| const formatBtn = document.getElementById('format-btn'); | |
| // Sample saved chats data (in a real app, this would come from localStorage or a database) | |
| let savedChats = []; | |
| // Auto-resize textarea | |
| userInput.addEventListener('input', function() { | |
| this.style.height = 'auto'; | |
| this.style.height = (this.scrollHeight) + 'px'; | |
| // Update character count | |
| const currentLength = this.value.length; | |
| charCount.textContent = `${currentLength}/1000`; | |
| // Update word count (for the entire chat) | |
| updateWordCount(); | |
| }); | |
| // Update word count function | |
| function updateWordCount() { | |
| const text = chatContainer.textContent || ''; | |
| const words = text.trim() ? text.trim().split(/\s+/).length : 0; | |
| wordCount.textContent = `${words} words`; | |
| } | |
| // Chat form submission | |
| chatForm.addEventListener('submit', function(e) { | |
| e.preventDefault(); | |
| const message = userInput.value.trim(); | |
| if (message) { | |
| // Add user message to chat | |
| addMessageToChat('user', message); | |
| userInput.value = ''; | |
| userInput.style.height = 'auto'; | |
| charCount.textContent = '0/1000'; | |
| // Show typing indicator | |
| typingIndicator.classList.remove('hidden'); | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| // Simulate AI response after a delay | |
| setTimeout(() => { | |
| typingIndicator.classList.add('hidden'); | |
| const aiResponse = generateAIResponse(message); | |
| addMessageToChat('assistant', aiResponse); | |
| }, 1500); | |
| } | |
| }); | |
| // Add message to chat function | |
| function addMessageToChat(role, content) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'chat-bubble mb-6'; | |
| if (role === 'user') { | |
| messageDiv.innerHTML = ` | |
| <div class="flex items-start justify-end"> | |
| <div class="bg-academic-blue text-white rounded-lg p-4 max-w-[85%]"> | |
| <p class="text-white">${content}</p> | |
| </div> | |
| <div class="bg-academic-gold text-academic-blue rounded-full w-10 h-10 flex items-center justify-center ml-3"> | |
| <i class="fas fa-user-graduate"></i> | |
| </div> | |
| </div> | |
| `; | |
| } else { | |
| messageDiv.innerHTML = ` | |
| <div class="flex items-start"> | |
| <div class="bg-academic-blue text-white rounded-full w-10 h-10 flex items-center justify-center mr-3"> | |
| <i class="fas fa-robot"></i> | |
| </div> | |
| <div class="bg-gray-100 rounded-lg p-4 max-w-[85%]"> | |
| <h3 class="font-semibold text-academic-blue mb-1">PhD Research Assistant</h3> | |
| <p class="text-gray-800">${content}</p> | |
| <div class="mt-3 flex space-x-3 text-sm"> | |
| <button class="copy-btn text-academic-blue hover:text-blue-800 flex items-center"> | |
| <i class="fas fa-copy mr-1"></i> Copy | |
| </button> | |
| <button class="save-excerpt-btn text-academic-blue hover:text-blue-800 flex items-center"> | |
| <i class="fas fa-save mr-1"></i> Save Excerpt | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| chatContainer.appendChild(messageDiv); | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| updateWordCount(); | |
| // Add event listeners to new buttons | |
| if (role === 'assistant') { | |
| const copyBtn = messageDiv.querySelector('.copy-btn'); | |
| const saveExcerptBtn = messageDiv.querySelector('.save-excerpt-btn'); | |
| copyBtn.addEventListener('click', function() { | |
| navigator.clipboard.writeText(content); | |
| const originalText = copyBtn.innerHTML; | |
| copyBtn.innerHTML = '<i class="fas fa-check mr-1"></i> Copied!'; | |
| setTimeout(() => { | |
| copyBtn.innerHTML = originalText; | |
| }, 2000); | |
| }); | |
| saveExcerptBtn.addEventListener('click', function() { | |
| alert('Excerpt saved to your research notes!'); | |
| // In a real app, this would save to a database or localStorage | |
| }); | |
| } | |
| } | |
| // Generate AI response (simulated) | |
| function generateAIResponse(userMessage) { | |
| // In a real app, this would call an API | |
| const responses = { | |
| 'help me structure my literature review': `A well-structured literature review typically includes these sections: | |
| 1. Introduction: State your research question and the scope of the review | |
| 2. Theoretical Framework: Discuss key theories relevant to your study | |
| 3. Empirical Review: Summarize and critique previous studies | |
| 4. Gaps in Literature: Identify what hasn't been addressed | |
| 5. Conclusion: Synthesize findings and connect to your research | |
| Would you like me to elaborate on any of these sections or help you find sources for a specific part?`, | |
| 'suggest methodologies for my research on': `The methodology depends on your research questions and field. Here are some options: | |
| For qualitative research: | |
| - Case studies | |
| - Ethnography | |
| - Phenomenology | |
| - Grounded theory | |
| For quantitative research: | |
| - Surveys | |
| - Experiments | |
| - Longitudinal studies | |
| - Statistical modeling | |
| Mixed methods combine both approaches. Could you share more about your specific topic and research objectives so I can provide more tailored suggestions?`, | |
| 'help me analyze this data': `Data analysis requires careful planning. Here's a general approach: | |
| 1. Clean your data (remove outliers, handle missing values) | |
| 2. Choose appropriate analysis methods based on your data type | |
| 3. For qualitative data: thematic analysis, content analysis | |
| 4. For quantitative data: descriptive stats, regression, ANOVA | |
| 5. Interpret results in context of your research questions | |
| Would you like to share more details about your data type and research goals?`, | |
| 'help me write an abstract for my paper on': `A strong abstract typically includes: | |
| 1. Context/Background (1-2 sentences) | |
| 2. Research problem/gap (1 sentence) | |
| 3. Methods (1-2 sentences) | |
| 4. Key findings (1-2 sentences) | |
| 5. Significance/Implications (1 sentence) | |
| Example structure: | |
| "This study examines [topic] in the context of [field]. Despite [gap in literature], little research has addressed [specific aspect]. Using [methods], we analyze [data] to [research goal]. Findings suggest [key results], contributing to [field] by [significance]." | |
| Would you like me to generate a draft based on your specific details?`, | |
| 'suggest academic conferences in': `Here are some notable conferences in various fields for 2024: | |
| Humanities/Social Sciences: | |
| - International Congress of Qualitative Inquiry (May 2024) | |
| - Annual Meeting of the American Anthropological Association (November 2024) | |
| STEM: | |
| - IEEE International Conference (varies by specialty) | |
| - ACM SIGCHI Conference on Human Factors in Computing Systems (April 2024) | |
| Interdisciplinary: | |
| - International Conference on Interdisciplinary Social Sciences (July 2024) | |
| - World Congress of Humanities (August 2024) | |
| Would you like me to search for conferences in a specific discipline or region?` | |
| }; | |
| // Check for quick prompt matches | |
| const lowerMessage = userMessage.toLowerCase(); | |
| for (const [key, value] of Object.entries(responses)) { | |
| if (lowerMessage.includes(key.toLowerCase())) { | |
| return value; | |
| } | |
| } | |
| // Default response for unmatched queries | |
| return `Thank you for your question about "${userMessage}". As a PhD research assistant, I can help you with: | |
| 1. Breaking down complex research problems | |
| 2. Identifying relevant literature | |
| 3. Developing appropriate methodologies | |
| 4. Analyzing and interpreting data | |
| 5. Academic writing and editing | |
| Could you please provide more details about your specific needs regarding this topic? This will help me give you more targeted assistance.`; | |
| } | |
| // Quick prompt buttons | |
| quickPromptBtns.forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| const prompt = this.getAttribute('data-prompt'); | |
| userInput.value = prompt; | |
| userInput.focus(); | |
| }); | |
| }); | |
| // Save chat functionality | |
| saveChatBtn.addEventListener('click', function() { | |
| saveModal.classList.remove('hidden'); | |
| }); | |
| closeSaveModal.addEventListener('click', function() { | |
| saveModal.classList.add('hidden'); | |
| }); | |
| cancelSave.addEventListener('click', function() { | |
| saveModal.classList.add('hidden'); | |
| }); | |
| confirmSave.addEventListener('click', function() { | |
| const title = document.getElementById('chat-title').value.trim(); | |
| const tags = document.getElementById('chat-tags').value.trim(); | |
| if (!title) { | |
| alert('Please enter a title for your chat session'); | |
| return; | |
| } | |
| // Create chat object | |
| const chat = { | |
| id: Date.now(), | |
| title: title, | |
| tags: tags.split(',').map(tag => tag.trim()), | |
| date: new Date().toLocaleString(), | |
| content: chatContainer.innerHTML | |
| }; | |
| // Save to "database" | |
| savedChats.push(chat); | |
| updateSavedChatsList(); | |
| // Clear and close modal | |
| document.getElementById('chat-title').value = ''; | |
| document.getElementById('chat-tags').value = ''; | |
| saveModal.classList.add('hidden'); | |
| // Show success message | |
| alert('Chat session saved successfully!'); | |
| }); | |
| // Load chat functionality | |
| loadChatBtn.addEventListener('click', function() { | |
| loadModal.classList.remove('hidden'); | |
| updateSavedChatsModalList(); | |
| }); | |
| closeLoadModal.addEventListener('click', function() { | |
| loadModal.classList.add('hidden'); | |
| }); | |
| cancelLoad.addEventListener('click', function() { | |
| loadModal.classList.add('hidden'); | |
| }); | |
| // Update saved chats list in sidebar | |
| function updateSavedChatsList() { | |
| const savedChatsList = document.getElementById('saved-chats-list'); | |
| if (savedChats.length === 0) { | |
| savedChatsList.innerHTML = '<div class="text-gray-500 italic text-center py-4">No saved chats yet</div>'; | |
| return; | |
| } | |
| savedChatsList.innerHTML = ''; | |
| savedChats.slice().reverse().forEach(chat => { | |
| const chatElement = document.createElement('div'); | |
| chatElement.className = 'bg-gray-50 hover:bg-gray-100 rounded-lg p-3 cursor-pointer border border-gray-200'; | |
| chatElement.innerHTML = ` | |
| <div class="font-medium text-academic-blue truncate">${chat.title}</div> | |
| <div class="text-xs text-gray-500 mt-1 flex justify-between"> | |
| <span>${chat.date}</span> | |
| <span>${chat.tags.slice(0, 2).map(tag => `#${tag}`).join(' ')}</span> | |
| </div> | |
| `; | |
| chatElement.addEventListener('click', function() { | |
| if (confirm('Load this chat? Your current chat will be cleared.')) { | |
| chatContainer.innerHTML = chat.content; | |
| loadModal.classList.add('hidden'); | |
| updateWordCount(); | |
| // Reattach event listeners to all assistant messages | |
| document.querySelectorAll('.chat-bubble').forEach(bubble => { | |
| const assistantDiv = bubble.querySelector('.bg-gray-100'); | |
| if (assistantDiv) { | |
| const copyBtn = bubble.querySelector('.copy-btn'); | |
| const saveExcerptBtn = bubble.querySelector('.save-excerpt-btn'); | |
| if (copyBtn) { | |
| copyBtn.addEventListener('click', function() { | |
| const content = assistantDiv.querySelector('p').textContent; | |
| navigator.clipboard.writeText(content); | |
| const originalText = copyBtn.innerHTML; | |
| copyBtn.innerHTML = '<i class="fas fa-check mr-1"></i> Copied!'; | |
| setTimeout(() => { | |
| copyBtn.innerHTML = originalText; | |
| }, 2000); | |
| }); | |
| } | |
| if (saveExcerptBtn) { | |
| saveExcerptBtn.addEventListener('click', function() { | |
| alert('Excerpt saved to your research notes!'); | |
| }); | |
| } | |
| } | |
| }); | |
| } | |
| }); | |
| savedChatsList.appendChild(chatElement); | |
| }); | |
| } | |
| // Update saved chats list in modal | |
| function updateSavedChatsModalList() { | |
| const savedChatsModalList = document.getElementById('saved-chats-modal-list'); | |
| if (savedChats.length === 0) { | |
| savedChatsModalList.innerHTML = '<div class="text-gray-500 italic text-center py-8">No saved chats found</div>'; | |
| return; | |
| } | |
| savedChatsModalList.innerHTML = ''; | |
| savedChats.slice().reverse().forEach(chat => { | |
| const chatElement = document.createElement('div'); | |
| chatElement.className = 'border-b border-gray-200 py-4'; | |
| chat | |
| </html> |