159 lines
5.7 KiB
HTML
159 lines
5.7 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Chat - General Bots{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="chat-layout">
|
|
<!-- Session Sidebar -->
|
|
<aside class="chat-sidebar" id="chat-sidebar">
|
|
<div class="sidebar-header">
|
|
<h3>Sessions</h3>
|
|
<button class="btn-new-session"
|
|
hx-post="/api/chat/sessions/new"
|
|
hx-target="#sessions-list"
|
|
hx-swap="afterbegin">
|
|
+ New Chat
|
|
</button>
|
|
</div>
|
|
<div id="sessions-list" class="sessions-list"
|
|
hx-get="/api/chat/sessions"
|
|
hx-trigger="load"
|
|
hx-swap="innerHTML">
|
|
<!-- Sessions loaded here -->
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Chat Main -->
|
|
<div class="chat-main">
|
|
<!-- Connection Status -->
|
|
<div id="connection-status" class="connection-status"
|
|
hx-sse="connect:/api/chat/status swap:innerHTML">
|
|
<span class="status-dot"></span>
|
|
<span class="status-text">Connecting...</span>
|
|
</div>
|
|
|
|
<!-- Messages Container -->
|
|
<div id="messages" class="messages"
|
|
hx-get="/api/chat/messages?session_id={{ session_id }}"
|
|
hx-trigger="load"
|
|
hx-swap="innerHTML">
|
|
<!-- Messages loaded here -->
|
|
</div>
|
|
|
|
<!-- Typing Indicator -->
|
|
<div id="typing-indicator" class="typing-indicator hidden">
|
|
<div class="typing-dots">
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Suggestions -->
|
|
<div id="suggestions" class="suggestions"
|
|
hx-get="/api/chat/suggestions"
|
|
hx-trigger="load"
|
|
hx-swap="innerHTML">
|
|
<!-- Suggestions loaded here -->
|
|
</div>
|
|
|
|
<!-- Input Form -->
|
|
<form class="chat-input-container"
|
|
hx-post="/api/chat/send"
|
|
hx-target="#messages"
|
|
hx-swap="beforeend"
|
|
hx-ext="json-enc"
|
|
hx-on::before-request="document.getElementById('typing-indicator').classList.remove('hidden')"
|
|
hx-on::after-request="this.reset(); document.getElementById('typing-indicator').classList.add('hidden'); document.getElementById('message-input').focus()">
|
|
|
|
<input type="hidden" name="session_id" value="{{ session_id }}">
|
|
|
|
<div class="input-group">
|
|
<textarea
|
|
id="message-input"
|
|
name="content"
|
|
class="message-input"
|
|
placeholder="Type your message..."
|
|
rows="1"
|
|
required
|
|
autofocus
|
|
hx-trigger="keydown[key=='Enter' && !shiftKey] from:body"
|
|
hx-post="/api/chat/send"
|
|
hx-target="#messages"
|
|
hx-swap="beforeend"></textarea>
|
|
|
|
<!-- Voice Button -->
|
|
<button type="button"
|
|
class="btn-voice"
|
|
hx-post="/api/voice/toggle"
|
|
hx-swap="none"
|
|
title="Voice input">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
|
|
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
|
|
<line x1="12" y1="19" x2="12" y2="23"></line>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- Send Button -->
|
|
<button type="submit" class="btn-send" title="Send">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<line x1="22" y1="2" x2="11" y2="13"></line>
|
|
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Context Selector -->
|
|
<div class="context-selector"
|
|
hx-get="/api/chat/contexts"
|
|
hx-trigger="load"
|
|
hx-swap="innerHTML">
|
|
<!-- Contexts loaded here -->
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Scroll to Bottom -->
|
|
<button id="scroll-to-bottom" class="scroll-to-bottom hidden"
|
|
onclick="document.getElementById('messages').scrollTo(0, document.getElementById('messages').scrollHeight)">
|
|
↓
|
|
</button>
|
|
</div>
|
|
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
// Auto-resize textarea
|
|
const textarea = document.getElementById('message-input');
|
|
textarea.addEventListener('input', function() {
|
|
this.style.height = 'auto';
|
|
this.style.height = Math.min(this.scrollHeight, 120) + 'px';
|
|
});
|
|
|
|
// Monitor scroll position
|
|
const messages = document.getElementById('messages');
|
|
const scrollBtn = document.getElementById('scroll-to-bottom');
|
|
|
|
messages.addEventListener('scroll', function() {
|
|
const isAtBottom = this.scrollHeight - this.scrollTop <= this.clientHeight + 50;
|
|
scrollBtn.classList.toggle('hidden', isAtBottom);
|
|
});
|
|
|
|
// Auto-scroll on new messages
|
|
messages.addEventListener('htmx:afterSettle', function(event) {
|
|
if (event.detail.target === this) {
|
|
this.scrollTo(0, this.scrollHeight);
|
|
}
|
|
});
|
|
|
|
// Handle suggestion clicks
|
|
document.addEventListener('click', function(e) {
|
|
if (e.target.classList.contains('suggestion-chip')) {
|
|
textarea.value = e.target.textContent;
|
|
textarea.form.dispatchEvent(new Event('submit'));
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|