agent-drawer.html

99 lines
1 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
<!-- Agent Drawer -->
<div id="agent-drawer" class="fixed top-0 right-0 h-full w-full sm:w-[400px] z-[60] translate-x-full transition-all duration-200 ease-out">
    <div class="flex flex-col h-full bg-white border-l border-slate-200 shadow-xl">
        <!-- Header -->
        <div class="flex items-center justify-between px-4 py-3 border-b border-slate-100">
            <div class="flex items-center gap-2">
                <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 text-indigo-500" 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>
                <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" 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-52 p-1.5 shadow-lg border border-slate-200 max-h-64 overflow-y-auto">
                        <button class="btn btn-ghost btn-xs w-full mb-1 text-indigo-600" hx-post="/agent/conversations/new" hx-target="body">New Chat</button>
                        {{range $conv := dashboard.Conversations}}
                        <a class="block 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>
                        {{end}}
                    </div>
                </div>
                <button class="inline-flex items-center justify-center w-7 h-7 rounded-md text-slate-400 hover:bg-slate-100" onclick="document.body.classList.remove('has-drawer')" title="Close">
                    <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-12 h-12 rounded-xl bg-amber-50 mb-3">
                    <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 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 font-medium">Sign in to Claude</p>
                <p class="text-xs text-slate-400">Run <code class="text-[11px] bg-slate-100 px-1.5 py-0.5 rounded font-mono">claude</code> in the IDE terminal</p>
            </div>
        </div>
        {{else}}
        <div id="drawer-messages" class="flex-1 overflow-y-auto px-4 py-4 space-y-3">
            <div class="text-center py-12">
                <p class="text-slate-400 text-xs">Ask the agent to manage infrastructure</p>
            </div>
        </div>

        <div id="drawer-loading" class="hidden px-4 pb-2">
            <div class="flex items-center gap-2 px-3 py-2">
                <span class="loading loading-dots loading-xs text-indigo-400"></span>
                <span class="text-xs text-slate-400">Thinking...</span>
            </div>
        </div>

        <div class="border-t border-slate-100 p-3">
            <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="textarea textarea-bordered textarea-sm flex-1 min-h-[40px] max-h-24 resize-none text-sm"
                    placeholder="Ask anything..."
                    rows="1"
                    onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();this.form.requestSubmit()}"
                    required></textarea>
                <button type="submit" class="btn btn-primary btn-sm self-end">
                    <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>
        </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%] rounded-xl rounded-br-sm px-3 py-2 bg-indigo-50 text-sm text-slate-700">' +
                msg.replace(/</g, '&lt;').replace(/>/g, '&gt;') +
                '</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>