Files
OpenQode/web/index.html
2025-12-14 00:40:14 +04:00

553 lines
28 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenQode IDE - AI-Powered Coding Assistant</title>
<meta name="description"
content="OpenQode IDE - A free AI-powered coding assistant with Qwen integration. 2000 daily requests, real-time chat, and full IDE capabilities.">
<link rel="stylesheet" href="styles.css">
</head>
<body class="vscode-body">
<div class="vscode-shell">
<!-- Top Header Bar -->
<header class="top-bar">
<div class="top-left">
<div class="logo-cell">
<span>OQ</span>
</div>
<div>
<strong>OpenQode IDE</strong>
<p>Local AI Coding Assistant</p>
</div>
</div>
<div class="top-actions">
<div class="auth-pill">
<span id="auth-status">Auth Status</span>
<span id="auth-status-text">Not authenticated</span>
</div>
<a id="hero-local-preview" href="#" class="preview-pill" target="_blank">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
<polyline points="15 3 21 3 21 9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg>
Open Preview
</a>
</div>
</header>
<!-- Main Three-Column Layout -->
<div class="main-grid">
<!-- Left Panel: Explorer & Files -->
<aside class="left-panel">
<div class="section-title">
<span>Explorer</span>
<button id="refresh-tree-btn" class="ghost-btn mini" title="Refresh file tree">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<polyline points="23 4 23 10 17 10"></polyline>
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
</svg>
Refresh
</button>
</div>
<!-- Sessions List -->
<div class="section-subtitle"
style="padding: 12px 0 8px 0; font-size: 11px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em;">
Last Chats
</div>
<div id="sessions-list" class="session-list" style="max-height: 200px; overflow-y: auto;">
<div class="session-pill active">
<span class="session-icon">📁</span>
<span>Current workspace</span>
</div>
</div>
<button id="new-project-btn" class="primary-btn full" style="margin-top: 8px; margin-bottom: 8px;"
onclick="window.openQodeApp.startNewProjectFlow()">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path
d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z">
</path>
<polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
<line x1="12" y1="22.08" x2="12" y2="12"></line>
</svg>
New Project
</button>
<button id="new-session-btn" class="ghost-btn full" onclick="window.openQodeApp.createNewSession()">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
New Session
</button>
<button id="deploy-btn" class="ghost-btn full" style="margin-top: 8px;"
onclick="window.openQodeApp.deployToVercel()">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="17 8 12 3 7 8"></polyline>
<line x1="12" y1="3" x2="12" y2="15"></line>
</svg>
Deploy to Vercel
</button>
<button id="preview-btn" class="ghost-btn full" style="margin-top: 8px;"
onclick="window.openQodeApp.startLocalPreview()">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polygon points="5 3 19 12 5 21 5 3"></polygon>
</svg>
Local Preview
</button>
<div class="section-title">
<span>Files</span>
</div>
<!-- File Tree -->
<div id="file-tree" class="file-tree">
<div class="file-tree-placeholder">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5">
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z">
</path>
</svg>
<p>Authenticate to view files</p>
</div>
</div>
<!-- File Actions -->
<div class="file-actions">
<button id="new-file-btn" class="ghost-btn mini" title="Create new file or folder">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="12" y1="18" x2="12" y2="12"></line>
<line x1="9" y1="15" x2="15" y2="15"></line>
</svg>
New
</button>
<button id="save-file-btn" class="ghost-btn mini" title="Save current file (Ctrl+S)">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path>
<polyline points="17 21 17 13 7 13 7 21"></polyline>
<polyline points="7 3 7 8 15 8"></polyline>
</svg>
Save
</button>
</div>
<!-- Authentication Section -->
<div class="auth-section">
<button id="auth-btn" class="primary-btn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
Authenticate Qwen
</button>
<button id="reauth-btn" class="ghost-btn full">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<polyline points="23 4 23 10 17 10"></polyline>
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
</svg>
Re-authenticate
</button>
</div>
</aside>
<!-- Center Panel: Chat & Editor -->
<section class="center-panel">
<!-- Chat Header with View Toggle -->
<div class="chat-header">
<div>
<p class="chat-title">Studio Chat</p>
<p class="chat-sub">AI-powered coding assistant</p>
</div>
<div class="mode-toggle">
<button id="gui-view-btn" class="mode-btn active">GUI Chat</button>
<button id="tui-view-btn" class="mode-btn">TUI Chat</button>
</div>
</div>
<!-- Chat Layer (GUI & TUI Views) -->
<div class="chat-layer">
<!-- GUI Chat View -->
<section id="gui-view" class="chat-window active">
<!-- Model Status Bar -->
<div class="chat-note">
<div class="chat-note-left">
<span class="tag">Model</span>
<strong id="model-status">Qwen Coder</strong>
</div>
<div class="chat-note-meta">
<span class="status-badge online">Online</span>
<span class="status-badge">Streaming</span>
</div>
</div>
<!-- Message Feed -->
<div id="chat-messages" class="message-feed">
<div class="message-placeholder welcome-message">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
<h3>Welcome to OpenQode</h3>
<p>Ask anything and get AI-powered code assistance</p>
</div>
</div>
<!-- Chat Input -->
<div class="chat-input">
<textarea id="message-input" class="message-input"
placeholder="Ask OpenQode anything... (Enter to send, Shift+Enter for new line)"
rows="3"></textarea>
<div class="input-controls">
<button id="attach-btn" class="ghost-btn circle" title="Attach file or code context">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<path
d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48">
</path>
</svg>
</button>
<button id="send-btn" class="primary-btn">
<svg width="16" height="16" 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>
Send
</button>
</div>
</div>
</section>
<!-- TUI Chat View -->
<section id="tui-view" class="chat-window tui-window">
<!-- TUI will be injected here by tui.js -->
<div class="tui-placeholder">
<p>TUI Chat mode - Terminal-style interface</p>
</div>
</section>
</div>
<!-- Editor Shell -->
<div class="editor-shell">
<div class="editor-toolbar">
<div>
<strong>Workspace Editor</strong>
<p class="muted" id="current-file-path">Select a file to edit</p>
</div>
<div class="workspace-controls">
<button id="rename-file-btn" class="ghost-btn mini" title="Rename current file">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
</svg>
Rename
</button>
<button id="delete-file-btn" class="ghost-btn mini" title="Delete current file">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<polyline points="3 6 5 6 21 6"></polyline>
<path
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2">
</path>
</svg>
Delete
</button>
<button id="show-diff-btn" class="ghost-btn mini" title="Show changes diff">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>
Diff
</button>
</div>
</div>
<!-- Editor Tabs -->
<div id="editor-tabs" class="editor-tabs"></div>
<!-- Code Editor -->
<textarea id="editor-textarea" class="editor-textarea"
placeholder="// Select a file from the explorer to start editing..."></textarea>
<!-- Terminal -->
<div class="terminal-mini">
<div class="terminal-heading">
<span>Terminal</span>
<button id="terminal-run-btn" class="ghost-btn mini">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<polygon points="5 3 19 12 5 21 5 3"></polygon>
</svg>
Run
</button>
</div>
<div id="terminal-output" class="terminal-output"></div>
<div class="terminal-input-row">
<span class="terminal-prompt">PS&gt;</span>
<input id="terminal-input" class="terminal-input" placeholder="Enter command...">
<span class="terminal-hint">Enter to run</span>
</div>
</div>
</div>
</section>
<!-- Right Panel: Settings & Configuration -->
<aside class="right-panel">
<div class="panel-title">
<span>Settings</span>
<button id="settings-btn" class="ghost-btn mini">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<circle cx="12" cy="12" r="3"></circle>
<path
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z">
</path>
</svg>
More
</button>
</div>
<!-- Model Selection -->
<div class="panel-section">
<label for="model-select">AI Model</label>
<select id="model-select">
<option value="qwen/coder-model">Qwen Coder (Default)</option>
<option value="qwen/vision-model">Qwen Vision</option>
<option value="gpt-4">OpenAI GPT-4</option>
</select>
</div>
<!-- Feature Toggles -->
<div class="panel-section">
<label>Features</label>
<label class="switch">
<input type="checkbox" id="lakeview-mode">
<span class="switch-slider"></span>
<span class="switch-label">Lakeview Mode</span>
</label>
<label class="switch">
<input type="checkbox" id="sequential-thinking">
<span class="switch-slider"></span>
<span class="switch-label">Sequential Thinking</span>
</label>
</div>
<!-- System Info -->
<div class="panel-section">
<label>System</label>
<p class="muted">Local-first prompts with private context. All data stays on your machine.</p>
</div>
<!-- Temperature Slider -->
<div class="panel-section">
<label>Temperature</label>
<div class="slider-container">
<input type="range" id="temperature-slider" min="0" max="1" step="0.1" value="0.7">
<span class="slider-value">0.7</span>
</div>
</div>
<!-- Active Tools -->
<div class="panel-section">
<label>Active Tools</label>
<div class="panel-tags">
<span class="panel-tag active">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="12"></line>
<line x1="12" y1="16" x2="12.01" y2="16"></line>
</svg>
Thinking
</span>
<span class="panel-tag active">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<polygon points="5 3 19 12 5 21 5 3"></polygon>
</svg>
Code Exec
</span>
<span class="panel-tag">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
</svg>
File Ops
</span>
</div>
</div>
<!-- Keyboard Shortcuts -->
<div class="panel-section shortcuts-section">
<label>Shortcuts</label>
<div class="shortcut-list">
<div class="shortcut-item">
<kbd>Ctrl</kbd> + <kbd>S</kbd>
<span>Save file</span>
</div>
<div class="shortcut-item">
<kbd>Ctrl</kbd> + <kbd>Enter</kbd>
<span>Send message</span>
</div>
<div class="shortcut-item">
<kbd>Shift</kbd> + <kbd>Click</kbd>
<span>Select files</span>
</div>
</div>
</div>
</aside>
</div>
<!-- Status Bar -->
<footer class="status-bar">
<div class="status-left">
<span class="status-item">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
</svg>
OpenQode v1.01
</span>
<span class="status-item">Running locally</span>
</div>
<div class="status-actions">
<span class="status-item">Sessions: auto-save</span>
<button id="apply-diff-btn" class="ghost-btn mini">Apply Changes</button>
</div>
</footer>
</div>
<!-- Diff Modal -->
<div id="diff-modal" class="hidden-modal">
<div class="diff-panel">
<div class="diff-header">
<span>📊 Diff Preview</span>
<button id="close-diff" class="ghost-btn mini">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
Close
</button>
</div>
<div id="diff-content" class="diff-content"></div>
<div class="diff-footer">
<button class="ghost-btn" id="cancel-diff-btn">Cancel</button>
<button class="primary-btn" id="apply-diff-btn-panel">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
Apply Changes
</button>
</div>
</div>
</div>
<!-- Settings Modal -->
<div id="settings-modal" class="hidden-modal">
<div class="settings-panel">
<div class="settings-header">
<strong>⚙️ Settings</strong>
<button id="close-settings" class="ghost-btn mini">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
Close
</button>
</div>
<div class="settings-body">
<div class="settings-row">
<span>Authentication Status</span>
<span id="settings-auth-status" class="status-badge">Unknown</span>
</div>
<div class="settings-row">
<span>Workspace Root</span>
<span class="muted">Local directory</span>
</div>
<div class="settings-row">
<span>API Endpoint</span>
<span class="muted">localhost:16400</span>
</div>
<hr class="settings-divider">
<button id="reauth-btn-panel" class="primary-btn full">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="23 4 23 10 17 10"></polyline>
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
</svg>
Re-authenticate with Qwen
</button>
</div>
</div>
</div>
<!-- Loading Overlay -->
<div id="loading-overlay" class="loading-overlay">
<div class="loader"></div>
<p>Connecting to OpenQode...</p>
</div>
<!-- New Project Wizard Modal -->
<div id="new-project-modal" class="modal-overlay hidden">
<div class="modal-content">
<div class="modal-header">
<h3>✨ New Project Wizard</h3>
<button id="close-wizard-btn" class="icon-btn" onclick="window.openQodeApp.closeNewProjectWizard()">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="project-name">Project Name</label>
<input type="text" id="project-name" placeholder="e.g. My Awesome App" class="modal-input"
oninput="window.openQodeApp.autoFillProjectPath(this.value)">
</div>
<div class="form-group">
<label for="project-path">Location</label>
<input type="text" id="project-path" placeholder="e.g. projects/my-awesome-app" class="modal-input">
</div>
<div class="form-group">
<label for="project-requirements">What do you want to build?</label>
<textarea id="project-requirements" rows="4"
placeholder="Describe your app in detail... e.g. A React todo app with dark mode"
class="modal-input"></textarea>
</div>
</div>
<div class="modal-footer">
<button id="cancel-wizard-btn" class="ghost-btn"
onclick="window.openQodeApp.closeNewProjectWizard()">Cancel</button>
<button id="create-project-confirm-btn" class="primary-btn"
onclick="window.openQodeApp.confirmNewProject()">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
class="mr-2">
<path d="M5 12h14M12 5l7 7-7 7" />
</svg>
Start Agentic Build
</button>
</div>
</div>
</div>
<script src="app.js"></script>
<script src="tui.js"></script>
</body>
</html>