mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 08:59:40 +02:00
feat: unified Run button with mode selector dropdown
Replace separate "Run Claude" and "Run OC" buttons with a single split button: [Run ▾] where the chevron opens a dropdown to switch between Claude Code and OpenCode modes. - Run button label shows "Run" (Claude) or "Run OC" (OpenCode) - Button color reflects selected mode (blue=Claude, green=OpenCode) - Mode persisted in localStorage across sessions - Ctrl+Enter uses the selected mode - Welcome screen simplified to single "Run" button - Removed standalone btn-claude, btn-opencode, welcome-btn-opencode CSS - Updated welcome tagline: "Manage AI in persistent tmux sessions" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+63
-1
@@ -2878,6 +2878,7 @@ class ClaudemanApp {
|
||||
// Share a single settings fetch between both consumers
|
||||
const settingsPromise = fetch('/api/settings').then(r => r.ok ? r.json() : null).catch(() => null);
|
||||
this.loadQuickStartCases(null, settingsPromise);
|
||||
this._initRunMode();
|
||||
this.setupEventListeners();
|
||||
// Mobile: ensure button taps register even when keyboard is visible.
|
||||
// On mobile, tapping a button while the soft keyboard is up causes the
|
||||
@@ -9286,10 +9287,71 @@ class ClaudemanApp {
|
||||
}
|
||||
|
||||
async quickStart() {
|
||||
// Alias for backward compatibility
|
||||
return this.run();
|
||||
}
|
||||
|
||||
/** Run using the selected mode (Claude Code or OpenCode) */
|
||||
async run() {
|
||||
const mode = this._runMode || 'claude';
|
||||
if (mode === 'opencode') {
|
||||
return this.runOpenCode();
|
||||
}
|
||||
return this.runClaude();
|
||||
}
|
||||
|
||||
/** Get/set the run mode, persisted in localStorage */
|
||||
get runMode() { return this._runMode || 'claude'; }
|
||||
|
||||
setRunMode(mode) {
|
||||
this._runMode = mode;
|
||||
try { localStorage.setItem('claudeman_runMode', mode); } catch {}
|
||||
this._applyRunMode();
|
||||
// Close menu
|
||||
document.getElementById('runModeMenu')?.classList.remove('active');
|
||||
}
|
||||
|
||||
toggleRunModeMenu(e) {
|
||||
e?.stopPropagation();
|
||||
const menu = document.getElementById('runModeMenu');
|
||||
if (!menu) return;
|
||||
menu.classList.toggle('active');
|
||||
// Update selected state
|
||||
menu.querySelectorAll('.run-mode-option').forEach(btn => {
|
||||
btn.classList.toggle('selected', btn.dataset.mode === this.runMode);
|
||||
});
|
||||
// Close on click outside
|
||||
if (menu.classList.contains('active')) {
|
||||
const close = (ev) => {
|
||||
if (!menu.contains(ev.target)) {
|
||||
menu.classList.remove('active');
|
||||
document.removeEventListener('click', close);
|
||||
}
|
||||
};
|
||||
setTimeout(() => document.addEventListener('click', close), 0);
|
||||
}
|
||||
}
|
||||
|
||||
_applyRunMode() {
|
||||
const mode = this.runMode;
|
||||
const runBtn = document.getElementById('runBtn');
|
||||
const gearBtn = runBtn?.nextElementSibling;
|
||||
const label = document.getElementById('runBtnLabel');
|
||||
if (runBtn) {
|
||||
runBtn.className = `btn-toolbar btn-run mode-${mode}`;
|
||||
}
|
||||
if (gearBtn) {
|
||||
gearBtn.className = `btn-toolbar btn-run-gear mode-${mode}`;
|
||||
}
|
||||
if (label) {
|
||||
label.textContent = mode === 'opencode' ? 'Run OC' : 'Run';
|
||||
}
|
||||
}
|
||||
|
||||
_initRunMode() {
|
||||
try { this._runMode = localStorage.getItem('claudeman_runMode') || 'claude'; } catch { this._runMode = 'claude'; }
|
||||
this._applyRunMode();
|
||||
}
|
||||
|
||||
// Tab count stepper functions
|
||||
incrementTabCount() {
|
||||
const input = document.getElementById('tabCount');
|
||||
|
||||
Reference in New Issue
Block a user