/**
* Enhanced Chat Interface - Similar to chat.z.ai
* Features: Better input, chat history, session resumption, smooth animations
*/
// ============================================
// Enhanced Chat Input Experience
// ============================================
// Auto-focus chat input when switching to chat view
function focusChatInput() {
setTimeout(() => {
const input = document.getElementById('chat-input');
if (input) {
input.focus();
// Move cursor to end
input.setSelectionRange(input.value.length, input.value.length);
}
}, 100);
}
// Smooth textarea resize with animation
function enhanceChatInput() {
const input = document.getElementById('chat-input');
if (!input) return;
// Auto-resize with smooth transition
input.style.transition = 'height 0.2s ease';
input.addEventListener('input', function() {
this.style.height = 'auto';
const newHeight = Math.min(this.scrollHeight, 200);
this.style.height = newHeight + 'px';
});
// Focus animation
input.addEventListener('focus', function() {
this.parentElement.classList.add('input-focused');
});
input.addEventListener('blur', function() {
this.parentElement.classList.remove('input-focused');
});
}
// ============================================
// Chat History & Session Management
// ============================================
// Auto-load chat history when page loads
(async function loadChatHistoryOnLoad() {
try {
const res = await fetch('/claude/api/claude/sessions');
const data = await res.json();
const historyList = document.getElementById('chat-history-list');
if (!historyList) return;
// Combine active and historical sessions
const allSessions = [
...(data.active || []).map(s => ({...s, status: 'active'})),
...(data.historical || []).map(s => ({...s, status: 'historical'}))
];
// Sort by creation date (newest first)
allSessions.sort((a, b) => new Date(b.createdAt || b.created_at) - new Date(a.createdAt || a.created_at));
if (allSessions.length === 0) {
historyList.innerHTML = '
${session.status === 'historical' ? 'đ' : 'đŦ'}
${title}
${date}
${session.status === 'historical' ? 'Historical' : 'Active'}
${session.status === 'historical' ? '
Resume' : ''}
`;
}).join('');
} catch (error) {
console.error('[loadChatHistoryOnLoad] Error loading chat history:', error);
}
})();
// Resume historical session
async function resumeSession(sessionId) {
console.log('Resuming historical session:', sessionId);
// Show loading message
if (typeof appendSystemMessage === 'function') {
appendSystemMessage('đ Loading historical session...');
}
try {
// Load the historical session
const res = await fetch('/claude/api/claude/sessions/' + sessionId);
// Check if response is OK
if (!res.ok) {
const errorText = await res.text();
console.error('Session fetch error:', res.status, errorText);
// Handle 404 - session not found
if (res.status === 404) {
if (typeof appendSystemMessage === 'function') {
appendSystemMessage('â Session not found. It may have been deleted or the ID is incorrect.');
}
return;
}
throw new Error(`HTTP ${res.status}: ${errorText}`);
}
// Parse JSON with error handling
let data;
try {
data = await res.json();
} catch (jsonError) {
const responseText = await res.text();
console.error('JSON parse error:', jsonError);
console.error('Response text:', responseText);
throw new Error('Invalid JSON response from server');
}
if (data.session) {
if (typeof attachToSession === 'function') {
attachToSession(sessionId);
}
// Update UI
const sessionIdEl = document.getElementById('current-session-id');
if (sessionIdEl) sessionIdEl.textContent = sessionId;
// Load session messages
if (typeof clearChatDisplay === 'function') {
clearChatDisplay();
}
// Add historical messages
if (data.session.outputBuffer && data.session.outputBuffer.length > 0) {
data.session.outputBuffer.forEach(entry => {
if (typeof appendMessage === 'function') {
appendMessage('assistant', entry.content, false);
}
});
}
// Show resume message
const sessionDate = new Date(data.session.createdAt || data.session.created_at);
if (typeof appendSystemMessage === 'function') {
appendSystemMessage('â
Resumed historical session from ' + sessionDate.toLocaleString());
appendSystemMessage('âšī¸ This is a read-only historical session. Start a new chat to continue working.');
}
// Update active state in sidebar
if (typeof loadChatHistory === 'function') {
loadChatHistory();
}
// Subscribe to session (for any future updates)
if (typeof subscribeToSession === 'function') {
subscribeToSession(sessionId);
}
} else {
throw new Error('No session data in response');
}
} catch (error) {
console.error('Error resuming session:', error);
if (typeof appendSystemMessage === 'function') {
appendSystemMessage('â Failed to resume session: ' + error.message);
// Remove the loading message
const messagesContainer = document.getElementById('chat-messages');
if (messagesContainer) {
const loadingMessages = messagesContainer.querySelectorAll('.chat-system');
loadingMessages.forEach(msg => {
if (msg.textContent.includes('Loading historical session')) {
msg.remove();
}
});
}
}
}
}
// ============================================
// Enhanced Message Rendering
// ============================================
// Enhanced append with animations
function appendMessageWithAnimation(role, content, animate = true) {
const messagesContainer = document.getElementById('chat-messages');
if (!messagesContainer) return;
const messageDiv = document.createElement('div');
messageDiv.className = `chat-message chat-message-${role} ${animate ? 'message-appear' : ''}`;
const avatar = role === 'user' ? 'đ¤' : 'đ¤';
const label = role === 'user' ? 'You' : 'Claude';
// Strip dyad tags for display
const displayContent = stripDyadTags(content);
messageDiv.innerHTML = `
${formatMessageText(displayContent)}
`;
messagesContainer.appendChild(messageDiv);
// Scroll to bottom
messagesContainer.scrollTop = messagesContainer.scrollHeight;
// Update token usage
if (typeof updateTokenUsage === 'function') {
updateTokenUsage(content.length);
}
}
// Strip dyad tags from message for display
function stripDyadTags(content) {
let stripped = content;
// Remove dyad-write tags and replace with placeholder
stripped = stripped.replace(/