botui/ui/suite/partials/vibe.html

247 lines
No EOL
10 KiB
HTML

<!-- Vibe Window — APP_CREATE Canvas + Agents IDE (Phase 7) -->
<link rel="stylesheet" href="/suite/vibe/agents-sidebar.css" />
<div class="vibe-container" id="vibeWindow">
<!-- Pipeline Tabs -->
<div class="vibe-pipeline">
<button class="vibe-pipeline-tab" data-stage="plan">// PLAN</button>
<button class="vibe-pipeline-tab active" data-stage="build">// BUILD</button>
<button class="vibe-pipeline-tab" data-stage="review">// REVIEW</button>
<button class="vibe-pipeline-tab" data-stage="deploy">// DEPLOY</button>
<button class="vibe-pipeline-tab" data-stage="monitor">// MONITOR</button>
</div>
<!-- Main Content: Canvas + Sidebar -->
<div class="vibe-body">
<!-- Canvas Area -->
<div class="vibe-canvas" id="vibeCanvas">
<div class="vibe-canvas-empty" id="vibeCanvasEmpty">
<div class="vibe-canvas-icon">🎨</div>
<h3>Vibe — App Builder</h3>
<p>Describe what you want to build. An agent will generate the entire application.</p>
<div class="vibe-canvas-prompt">
<input type="text" class="vibe-prompt-input" id="vibePromptInput"
placeholder="e.g. 'Create a CRM for my clinic'" />
<button class="vibe-prompt-btn" id="vibePromptBtn" type="button">Build</button>
</div>
</div>
<!-- Generated Steps (populated dynamically) -->
<div class="vibe-steps" id="vibeSteps" style="display:none;"></div>
<!-- Preview Panel -->
<div class="vibe-preview" id="vibePreview" style="display:none;">
<div class="vibe-preview-header">
<span>// PREVIEW</span>
<input type="text" class="vibe-preview-url" id="vibePreviewUrl" value="" readonly />
</div>
<div class="vibe-preview-content" id="vibePreviewContent"></div>
</div>
</div>
<!-- Agents & Workspaces Sidebar (collapsible) -->
<aside class="agents-sidebar" id="agentsSidebar">
<div class="as-section">
<div class="as-section-header">
<h3>Agents</h3>
<button class="as-collapse-btn" id="agentsSidebarCollapse" type="button"></button>
</div>
<div class="as-agent-list" id="asAgentList">
<div class="as-agent-empty">
<p style="padding: 1rem; text-align: center; color: var(--text-tertiary); font-size: 0.8rem;">
No active agents attached.<br><br>
Click "Build" and BotServer will automatically attach necessary agents (Architect,
Fullstack, DBA) to your workspace.
</p>
</div>
</div>
<button class="as-create-btn" id="createAgentBtn" type="button">+ Create a New Agent</button>
</div>
<div class="as-section">
<div class="as-section-header">
<h3>Workspaces</h3>
</div>
<div class="as-workspace-list" id="asWorkspaceList">
<div class="as-workspace-item">
<button class="as-workspace-toggle" type="button">
<span class="as-workspace-arrow"></span>
<span>Production</span>
<span class="as-workspace-count">2</span>
</button>
<div class="as-workspace-body" style="display:none;">
<div class="as-workspace-agent">Agent #1</div>
<div class="as-workspace-agent">Agent #2</div>
<div class="as-workspace-dropzone" data-workspace="production">
Drag an Agent to Include
</div>
</div>
</div>
<div class="as-workspace-item">
<button class="as-workspace-toggle" type="button">
<span class="as-workspace-arrow"></span>
<span>Staging</span>
<span class="as-workspace-count">0</span>
</button>
<div class="as-workspace-body" style="display:none;">
<div class="as-workspace-dropzone" data-workspace="staging">
Drag an Agent to Include
</div>
</div>
</div>
</div>
</div>
</aside>
</div>
</div>
<script>
(function () {
"use strict";
function initVibe() {
setupPipelineTabs();
setupPrompt();
setupSidebarCollapse();
setupWorkspaceAccordions();
setupDragAndDrop();
}
function setupPipelineTabs() {
var container = document.querySelector(".vibe-pipeline");
if (!container) return;
container.addEventListener("click", function (e) {
var tab = e.target.closest(".vibe-pipeline-tab");
if (!tab) return;
container.querySelectorAll(".vibe-pipeline-tab").forEach(function (t) {
t.classList.remove("active");
});
tab.classList.add("active");
});
}
function setupPrompt() {
var input = document.getElementById("vibePromptInput");
var btn = document.getElementById("vibePromptBtn");
if (!input || !btn) return;
function submit() {
var text = input.value.trim();
if (!text) return;
btn.disabled = true;
btn.textContent = "Building...";
fetch("/api/autotask/classify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ intent: text })
})
.then(function (r) { return r.json(); })
.then(function (data) {
btn.disabled = false;
btn.textContent = "Build";
if (data.result && data.result.app_url) {
showPreview(data.result.app_url);
} else if (data.app_url) {
showPreview(data.app_url);
} else if (data.error) {
alert("Error: " + data.error);
}
})
.catch(function () {
btn.disabled = false;
btn.textContent = "Build";
});
}
btn.addEventListener("click", submit);
input.addEventListener("keydown", function (e) {
if (e.key === "Enter") { e.preventDefault(); submit(); }
});
}
function showPreview(url) {
var preview = document.getElementById("vibePreview");
var urlBar = document.getElementById("vibePreviewUrl");
var content = document.getElementById("vibePreviewContent");
var empty = document.getElementById("vibeCanvasEmpty");
if (empty) empty.style.display = "none";
if (preview) preview.style.display = "";
if (urlBar) urlBar.value = url;
if (content) content.innerHTML = '<iframe src="' + url + '"></iframe>';
}
function setupSidebarCollapse() {
var btn = document.getElementById("agentsSidebarCollapse");
var sidebar = document.getElementById("agentsSidebar");
if (!btn || !sidebar) return;
btn.addEventListener("click", function () {
sidebar.classList.toggle("collapsed");
btn.textContent = sidebar.classList.contains("collapsed") ? "▶" : "◀";
});
}
function setupWorkspaceAccordions() {
var toggles = document.querySelectorAll(".as-workspace-toggle");
toggles.forEach(function (toggle) {
toggle.addEventListener("click", function () {
var body = this.nextElementSibling;
var arrow = this.querySelector(".as-workspace-arrow");
if (body) {
var isOpen = body.style.display !== "none";
body.style.display = isOpen ? "none" : "";
if (arrow) arrow.textContent = isOpen ? "▶" : "▼";
}
});
});
}
function setupDragAndDrop() {
var cards = document.querySelectorAll(".as-agent-card");
cards.forEach(function (card) {
card.addEventListener("dragstart", function (e) {
e.dataTransfer.setData("text/plain", card.getAttribute("data-agent-id"));
card.classList.add("dragging");
});
card.addEventListener("dragend", function () {
card.classList.remove("dragging");
});
});
var dropzones = document.querySelectorAll(".as-workspace-dropzone");
dropzones.forEach(function (zone) {
zone.addEventListener("dragover", function (e) {
e.preventDefault();
zone.classList.add("drag-over");
});
zone.addEventListener("dragleave", function () {
zone.classList.remove("drag-over");
});
zone.addEventListener("drop", function (e) {
e.preventDefault();
zone.classList.remove("drag-over");
var agentId = e.dataTransfer.getData("text/plain");
var agentEl = document.createElement("div");
agentEl.className = "as-workspace-agent";
agentEl.textContent = "Agent #" + agentId;
zone.parentNode.insertBefore(agentEl, zone);
});
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initVibe);
} else {
initVibe();
}
})();
</script>