agent-drawer.html
118 lines1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<!-- Agent Drawer -->
<div id="agent-drawer" class="fixed top-0 right-0 h-full w-full sm:w-[420px] z-[60] translate-x-full transition-all duration-300 ease-[cubic-bezier(0.16,1,0.3,1)]">
<div class="flex flex-col h-full bg-white/95 backdrop-blur-xl border-l border-slate-200/40 shadow-2xl shadow-indigo-900/10">
<!-- Header -->
<div class="flex items-center justify-between px-4 py-3 border-b border-slate-100/80 bg-gradient-to-r from-white/80 to-indigo-50/30">
<div class="flex items-center gap-2.5">
<div class="w-7 h-7 rounded-lg bg-gradient-to-br from-indigo-500 to-violet-600 flex items-center justify-center shadow-sm shadow-indigo-500/20">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.455 2.456L21.75 6l-1.036.259a3.375 3.375 0 00-2.455 2.456z" /></svg>
</div>
<h3 class="text-sm font-semibold text-slate-700">Agent</h3>
</div>
<div class="flex items-center gap-1">
<div class="dropdown dropdown-end">
<div tabindex="0" role="button" class="inline-flex items-center justify-center w-7 h-7 rounded-md text-slate-400 hover:bg-slate-100 transition-colors" title="History">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
</div>
<div tabindex="0" class="dropdown-content menu bg-white rounded-lg z-[1] w-56 p-1.5 shadow-lg border border-slate-200 max-h-72 overflow-y-auto">
<button class="btn btn-ghost btn-xs w-full mb-1 text-indigo-600 font-medium" hx-post="/agent/conversations/new" hx-target="body">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" /></svg>
New Chat
</button>
{{range $conv := dashboard.Conversations}}
<div class="flex items-center group">
<a class="flex-1 min-w-0 rounded px-2.5 py-1.5 text-xs text-slate-500 hover:bg-slate-50 hover:text-slate-700 truncate cursor-pointer"
hx-get="/agent/conversations/{{$conv.ID}}" hx-target="#drawer-messages" hx-swap="innerHTML">
{{$conv.Title}}
</a>
<button class="shrink-0 w-5 h-5 inline-flex items-center justify-center rounded text-slate-300 hover:text-red-400 hover:bg-red-50 opacity-0 group-hover:opacity-100 transition-all"
hx-post="/agent/conversations/{{$conv.ID}}/delete" hx-confirm="Delete this conversation?" hx-target="body" title="Delete">
<svg xmlns="http://www.w3.org/2000/svg" class="w-2.5 h-2.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
</button>
</div>
{{end}}
{{if not dashboard.Conversations}}
<p class="text-[10px] text-slate-300 text-center py-2">No conversations yet</p>
{{end}}
</div>
</div>
<button class="inline-flex items-center justify-center w-7 h-7 rounded-md text-slate-400 hover:bg-slate-100 transition-colors" onclick="document.body.classList.remove('has-drawer')" title="Close (Esc)">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
</button>
</div>
</div>
{{if not dashboard.HasAgent}}
<div class="flex-1 flex items-center justify-center p-6">
<div class="text-center">
<div class="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-amber-50 mb-4">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" /></svg>
</div>
<p class="text-sm text-slate-600 mb-1.5 font-medium">Claude Code not authenticated</p>
<p class="text-xs text-slate-400 leading-relaxed">Open the IDE terminal and run <code class="text-[11px] bg-slate-100 text-indigo-600 px-1.5 py-0.5 rounded font-mono">claude</code> to sign in</p>
</div>
</div>
{{else}}
<div id="drawer-messages" class="flex-1 overflow-y-auto px-4 py-4 space-y-3 bg-gradient-to-b from-white/0 to-indigo-50/20">
<div class="text-center py-16">
<div class="inline-flex items-center justify-center w-12 h-12 rounded-2xl bg-gradient-to-br from-indigo-50 to-violet-50 mb-3 shadow-sm shadow-indigo-100/50">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-indigo-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" /></svg>
</div>
<p class="text-slate-500 text-xs font-medium mb-1">Ask the agent anything</p>
<p class="text-slate-300 text-[10px]">Manage services, edit code, deploy apps</p>
</div>
</div>
<div id="drawer-loading" class="hidden px-4 pb-2">
<div class="flex items-center gap-2.5 px-3 py-2 bg-indigo-50/50 rounded-xl">
<span class="loading loading-dots loading-xs text-indigo-400"></span>
<span class="text-xs text-indigo-400">Thinking...</span>
</div>
</div>
<div class="border-t border-slate-100/80 p-3 bg-white/80">
<form id="drawer-chat-form" hx-post="/agent/chat" hx-target="#drawer-messages" hx-swap="beforeend" class="flex gap-2">
<input type="hidden" name="conversation_id" id="drawer-conversation-id" value="" />
<textarea name="message" id="agent-input"
class="flex-1 min-h-[40px] max-h-24 resize-none text-sm bg-slate-50/80 border border-slate-200/60 rounded-xl px-3 py-2.5 focus:border-indigo-300 focus:ring-2 focus:ring-indigo-100 focus:outline-none transition-all placeholder:text-slate-300"
placeholder="Ask anything..."
rows="1"
onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();this.form.requestSubmit()}"
required></textarea>
<button type="submit" class="self-end w-9 h-9 rounded-xl bg-gradient-to-br from-indigo-500 to-indigo-600 hover:from-indigo-600 hover:to-indigo-700 text-white flex items-center justify-center shadow-sm shadow-indigo-500/20 transition-all btn-press shrink-0">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" /></svg>
</button>
</form>
<p class="text-[9px] text-slate-300 mt-1.5 text-center">Press <kbd class="font-mono bg-slate-100 px-1 rounded text-slate-400">/</kbd> to focus · Shift+Enter for newline</p>
</div>
{{end}}
</div>
</div>
<script>
document.addEventListener('htmx:beforeRequest', function(e) {
if (e.detail.elt.id === 'drawer-chat-form') {
var input = document.getElementById('agent-input');
var msg = input.value.trim();
if (msg) {
var messagesDiv = document.getElementById('drawer-messages');
var placeholder = messagesDiv.querySelector('.text-center');
if (placeholder) placeholder.remove();
messagesDiv.insertAdjacentHTML('beforeend',
'<div class="flex justify-end"><div class="max-w-[80%] user-bubble px-3.5 py-2.5 text-sm whitespace-pre-wrap">' +
msg.replace(/</g, '<').replace(/>/g, '>') +
'</div></div>');
document.getElementById('drawer-loading').classList.remove('hidden');
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
}
});
document.addEventListener('htmx:afterRequest', function(e) {
if (e.detail.elt.id === 'drawer-chat-form') {
document.getElementById('drawer-loading').classList.add('hidden');
document.getElementById('agent-input').value = '';
var messagesDiv = document.getElementById('drawer-messages');
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
});
</script>