624 lines
20 KiB
HTML
624 lines
20 KiB
HTML
<style>
|
|
/* CRITICAL: Overriding default Tailwind resets that break the layout */
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
font-family: "Fira Code", "Fira Sans", Arial, sans-serif !important;
|
|
background: var(--bg) !important;
|
|
overflow: hidden !important;
|
|
height: 100vh !important;
|
|
width: 100vw !important;
|
|
display: flex !important;
|
|
}
|
|
|
|
/* Core Layout replicating BUILD V3 screenshot styling */
|
|
.build-container {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: 1000;
|
|
background: var(--bg);
|
|
}
|
|
|
|
/* Left Sidebar */
|
|
.sidebar {
|
|
width: 51px;
|
|
height: 100%;
|
|
background: var(--surface);
|
|
border-right: 1px solid var(--border);
|
|
display: flex;
|
|
flex-direction: column;
|
|
z-index: 100;
|
|
}
|
|
|
|
.sidebar-item {
|
|
width: 51px;
|
|
height: 50px;
|
|
border-bottom: 1px solid var(--border);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
transition: all 0.15s ease;
|
|
position: relative;
|
|
}
|
|
|
|
.sidebar-item:hover {
|
|
background: var(--surface-hover, #ffffff);
|
|
}
|
|
|
|
.sidebar-item.active {
|
|
background: var(--surface-hover, #ffffff);
|
|
border-left: 3px solid var(--accent);
|
|
}
|
|
|
|
.sidebar-icon {
|
|
width: 30px;
|
|
height: 30px;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
.sidebar-item:hover .sidebar-icon {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* Main Content wrapper */
|
|
.main-wrapper {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
|
|
/* Top Navigation Tabs - Removed (already in Vibe) */
|
|
|
|
/* Workspace (Where windows float) */
|
|
.workspace {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
background: var(--bg);
|
|
position: relative;
|
|
z-index: 10;
|
|
}
|
|
|
|
/* The Panel Grid (Desktop Icons) */
|
|
.panel-section {
|
|
flex: 1;
|
|
padding: 26px 33px;
|
|
overflow-y: auto;
|
|
z-index: 10;
|
|
position: absolute;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.panel-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 20px;
|
|
max-width: 1200px;
|
|
pointer-events: auto;
|
|
}
|
|
|
|
/* Interactive Desktop Icons triggering HTMX */
|
|
.desktop-icon {
|
|
background: var(--bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 8px;
|
|
height: 67px;
|
|
padding: 10px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: flex-end;
|
|
align-items: flex-start;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
position: relative;
|
|
width: 100%;
|
|
}
|
|
|
|
.desktop-icon:hover {
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
transform: translateY(-2px);
|
|
border-color: var(--accent);
|
|
}
|
|
|
|
.panel-card-icon {
|
|
position: absolute;
|
|
top: -20px;
|
|
left: 10px;
|
|
width: 42px;
|
|
height: 42px;
|
|
}
|
|
|
|
.panel-card-label {
|
|
font-family: "Fira Code", monospace;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
color: var(--text);
|
|
margin-top: auto;
|
|
}
|
|
|
|
.bg-grid {
|
|
display: none;
|
|
}
|
|
|
|
.bg-svg {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Bottom Taskbar */
|
|
.toolbar {
|
|
height: 50px;
|
|
background: var(--bg);
|
|
border-top: 1px solid var(--border);
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 8px;
|
|
z-index: 100;
|
|
position: relative;
|
|
}
|
|
|
|
#taskbar-apps {
|
|
display: flex;
|
|
flex: 1;
|
|
height: 100%;
|
|
align-items: center;
|
|
gap: 0px;
|
|
}
|
|
|
|
.toolbar-time {
|
|
font-family: "Fira Code", monospace;
|
|
font-size: 14px;
|
|
color: var(--text);
|
|
text-align: right;
|
|
line-height: 1.4;
|
|
padding: 0 10px;
|
|
margin-left: auto;
|
|
}
|
|
|
|
/* Taskbar Items generated by WindowManager */
|
|
.taskbar-item {
|
|
width: 40px;
|
|
height: 40px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
transition: all 0.15s ease;
|
|
border-bottom: 2px solid transparent;
|
|
}
|
|
|
|
.taskbar-item:hover {
|
|
background: var(--surface);
|
|
}
|
|
|
|
.taskbar-item.active {
|
|
border-bottom-color: var(--accent);
|
|
background: linear-gradient(
|
|
to bottom,
|
|
transparent 50%,
|
|
var(--accent-light, rgba(132, 214, 105, 0.1)) 100%
|
|
);
|
|
}
|
|
|
|
/* Utility */
|
|
svg {
|
|
display: block;
|
|
}
|
|
</style>
|
|
|
|
<div class="build-container">
|
|
<!-- Left Sidebar -->
|
|
<aside class="sidebar">
|
|
<div class="sidebar-item active" title="Home">
|
|
<svg
|
|
class="sidebar-icon"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
>
|
|
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
|
|
<polyline points="9 22 9 12 15 12 15 22"></polyline>
|
|
</svg>
|
|
</div>
|
|
<div class="sidebar-item" title="Terminal">
|
|
<svg
|
|
class="sidebar-icon"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
>
|
|
<polyline points="4 17 10 11 4 5"></polyline>
|
|
<line x1="12" y1="19" x2="20" y2="19"></line>
|
|
</svg>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Main Wrapper -->
|
|
<div class="main-wrapper">
|
|
<!-- Top Navigation Tabs - Removed (already in Vibe) -->
|
|
|
|
<!-- Workspace container where WindowManager operates -->
|
|
<div class="workspace" id="desktop-content-inner">
|
|
<!-- Background Pattern -->
|
|
|
|
<div class="panel-section">
|
|
<div class="panel-grid">
|
|
<!-- HTMX Enabled Desktop Icons that WindowManager catches -->
|
|
<div
|
|
class="desktop-icon"
|
|
data-app-id="chat"
|
|
data-app-title="Chat"
|
|
hx-get="/suite/partials/chat.html"
|
|
hx-swap="none"
|
|
>
|
|
<svg
|
|
class="panel-card-icon"
|
|
viewBox="0 0 42 42"
|
|
fill="none"
|
|
>
|
|
<circle
|
|
cx="21"
|
|
cy="21"
|
|
r="20"
|
|
stroke="var(--accent)"
|
|
stroke-width="2"
|
|
/>
|
|
<path
|
|
d="M14 21h14M21 14v14"
|
|
stroke="var(--accent)"
|
|
stroke-width="2"
|
|
/>
|
|
</svg>
|
|
<div class="panel-card-label">Chat</div>
|
|
</div>
|
|
|
|
<div
|
|
class="desktop-icon"
|
|
data-app-id="vibe"
|
|
data-app-title="Vibe"
|
|
hx-get="/suite/partials/vibe.html"
|
|
hx-swap="none"
|
|
>
|
|
<svg
|
|
class="panel-card-icon"
|
|
viewBox="0 0 42 42"
|
|
fill="none"
|
|
>
|
|
<circle
|
|
cx="21"
|
|
cy="21"
|
|
r="20"
|
|
stroke="var(--accent)"
|
|
stroke-width="2"
|
|
/>
|
|
<path
|
|
d="M12 14l8 7-8 7"
|
|
stroke="var(--accent)"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
/>
|
|
<line
|
|
x1="22"
|
|
y1="28"
|
|
x2="32"
|
|
y2="28"
|
|
stroke="var(--accent)"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
/>
|
|
</svg>
|
|
<div class="panel-card-label">Vibe</div>
|
|
</div>
|
|
|
|
<div
|
|
class="desktop-icon"
|
|
data-app-id="tasks"
|
|
data-app-title="Tasks"
|
|
hx-get="/suite/tasks/task-window.html"
|
|
hx-swap="none"
|
|
>
|
|
<svg
|
|
class="panel-card-icon"
|
|
viewBox="0 0 42 42"
|
|
fill="none"
|
|
>
|
|
<rect
|
|
x="2"
|
|
y="2"
|
|
width="38"
|
|
height="38"
|
|
rx="4"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="12"
|
|
y1="12"
|
|
x2="30"
|
|
y2="12"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="12"
|
|
y1="21"
|
|
x2="30"
|
|
y2="21"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="12"
|
|
y1="30"
|
|
x2="24"
|
|
y2="30"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
</svg>
|
|
<div class="panel-card-label">Tasks</div>
|
|
</div>
|
|
|
|
<div
|
|
class="desktop-icon"
|
|
data-app-id="terminal"
|
|
data-app-title="Terminal"
|
|
hx-get="/suite/partials/terminal.html"
|
|
hx-swap="none"
|
|
>
|
|
<svg
|
|
class="panel-card-icon"
|
|
viewBox="0 0 42 42"
|
|
fill="none"
|
|
>
|
|
<rect
|
|
x="2"
|
|
y="4"
|
|
width="38"
|
|
height="34"
|
|
rx="4"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="10"
|
|
y1="14"
|
|
x2="32"
|
|
y2="14"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="10"
|
|
y1="22"
|
|
x2="28"
|
|
y2="22"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="10"
|
|
y1="30"
|
|
x2="24"
|
|
y2="30"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
</svg>
|
|
<div class="panel-card-label">Terminal</div>
|
|
</div>
|
|
|
|
<div
|
|
class="desktop-icon"
|
|
data-app-id="explorer"
|
|
data-app-title="Explorer"
|
|
hx-get="/suite/partials/explorer.html"
|
|
hx-swap="none"
|
|
>
|
|
<svg
|
|
class="panel-card-icon"
|
|
viewBox="0 0 42 42"
|
|
fill="none"
|
|
>
|
|
<rect
|
|
x="2"
|
|
y="2"
|
|
width="38"
|
|
height="38"
|
|
rx="4"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="10"
|
|
y1="10"
|
|
x2="32"
|
|
y2="10"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="10"
|
|
y1="18"
|
|
x2="28"
|
|
y2="18"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="10"
|
|
y1="26"
|
|
x2="32"
|
|
y2="26"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="10"
|
|
y1="34"
|
|
x2="24"
|
|
y2="34"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
</svg>
|
|
<div class="panel-card-label">Explorer</div>
|
|
</div>
|
|
|
|
<div
|
|
class="desktop-icon"
|
|
data-app-id="editor"
|
|
data-app-title="Editor"
|
|
hx-get="/suite/partials/editor.html"
|
|
hx-swap="none"
|
|
>
|
|
<svg
|
|
class="panel-card-icon"
|
|
viewBox="0 0 42 42"
|
|
fill="none"
|
|
>
|
|
<polyline
|
|
points="4 8 12 2 20 8"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="12"
|
|
y1="2"
|
|
x2="12"
|
|
y2="24"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<polyline
|
|
points="22 16 30 10 38 16"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<line
|
|
x1="30"
|
|
y1="10"
|
|
x2="30"
|
|
y2="32"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
</svg>
|
|
<div class="panel-card-label">Editor</div>
|
|
</div>
|
|
|
|
<div
|
|
class="desktop-icon"
|
|
data-app-id="browser"
|
|
data-app-title="Browser"
|
|
hx-get="/suite/partials/browser.html"
|
|
hx-swap="none"
|
|
>
|
|
<svg
|
|
class="panel-card-icon"
|
|
viewBox="0 0 42 42"
|
|
fill="none"
|
|
>
|
|
<rect
|
|
x="2"
|
|
y="4"
|
|
width="38"
|
|
height="34"
|
|
rx="4"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<circle
|
|
cx="14"
|
|
cy="16"
|
|
r="4"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
<path
|
|
d="M6 34a6 6 0 0 1 6-6h10a6 6 0 0 1 6 6v2H6v-2z"
|
|
stroke="var(--text)"
|
|
stroke-width="2"
|
|
/>
|
|
</svg>
|
|
<div class="panel-card-label">Browser</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bottom Taskbar -->
|
|
<footer class="toolbar" id="taskbar">
|
|
<div id="taskbar-apps">
|
|
<!-- Taskbar items populated automatically by window-manager.js -->
|
|
</div>
|
|
<div
|
|
class="toolbar-time"
|
|
style="display: flex; align-items: center; gap: 15px"
|
|
>
|
|
<div id="themeSelectorContainer"></div>
|
|
<div style="text-align: right">
|
|
<div id="clock-time">00:00</div>
|
|
<div id="clock-date">01/01/2026</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- HTMX Intercepts and WindowManager Init as described in UI.md Phase 3 -->
|
|
<script>
|
|
// Auto-open Chat window maximized on desktop load
|
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
// Initialize WindowManager reference
|
|
if (typeof window.WindowManager !== "undefined") {
|
|
window.wm = window.WindowManager;
|
|
}
|
|
|
|
// Auto-open Chat window maximized
|
|
if (window.wm) {
|
|
try {
|
|
const response = await fetch("/suite/partials/chat.html");
|
|
if (response.ok) {
|
|
const htmlContent = await response.text();
|
|
window.wm.open("chat", "Chat", htmlContent);
|
|
// Maximize the chat window after opening
|
|
setTimeout(() => {
|
|
window.wm.toggleMaximize("chat");
|
|
}, 100);
|
|
}
|
|
} catch (err) {
|
|
console.error("Failed to auto-open chat:", err);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Simple Clock implementation matching the screenshot bottom right corner
|
|
setInterval(() => {
|
|
const now = new Date();
|
|
const timeEl = document.getElementById("clock-time");
|
|
const dateEl = document.getElementById("clock-date");
|
|
if (timeEl)
|
|
timeEl.textContent = now.toLocaleTimeString([], {
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
});
|
|
if (dateEl) dateEl.textContent = now.toLocaleDateString();
|
|
}, 1000);
|
|
</script>
|