mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
feat: Add accentForeground theme color for proper text contrast on accent backgrounds
- Add accentForeground color to all 16 themes for proper text contrast when rendering text on accent-colored backgrounds - Update UI components to use accentForeground instead of hardcoded white/dark colors for buttons and highlighted elements - Refresh Maestro's Choice and Dre Synth theme palettes - Add Save button to Batch Runner modal for persisting custom prompts - Fix sidebar resize not saving width correctly during drag - Queue custom AI commands when agent is busy (like regular messages) - Update search placeholder in Scratchpad to show correct shortcuts - Update docs to reflect 13 theme colors (was 12) Claude ID: ac8e7811-8742-4991-b9ce-9c03629b8288 Maestro ID: 5a166b38-b7e9-47f0-a8ff-0113c65f2682
This commit is contained in:
@@ -417,20 +417,21 @@ Themes defined in `src/renderer/constants/themes.ts`.
|
||||
interface Theme {
|
||||
id: ThemeId;
|
||||
name: string;
|
||||
mode: 'light' | 'dark';
|
||||
mode: 'light' | 'dark' | 'vibe';
|
||||
colors: {
|
||||
bgMain: string; // Main content background
|
||||
bgSidebar: string; // Sidebar background
|
||||
bgActivity: string; // Accent background
|
||||
border: string; // Border colors
|
||||
textMain: string; // Primary text
|
||||
textDim: string; // Secondary text
|
||||
accent: string; // Accent color
|
||||
accentDim: string; // Dimmed accent
|
||||
accentText: string; // Accent text color
|
||||
success: string; // Success state (green)
|
||||
warning: string; // Warning state (yellow)
|
||||
error: string; // Error state (red)
|
||||
bgMain: string; // Main content background
|
||||
bgSidebar: string; // Sidebar background
|
||||
bgActivity: string; // Accent background
|
||||
border: string; // Border colors
|
||||
textMain: string; // Primary text
|
||||
textDim: string; // Secondary text
|
||||
accent: string; // Accent color
|
||||
accentDim: string; // Dimmed accent
|
||||
accentText: string; // Accent text color
|
||||
accentForeground: string; // Text ON accent backgrounds (contrast)
|
||||
success: string; // Success state (green)
|
||||
warning: string; // Warning state (yellow)
|
||||
error: string; // Error state (red)
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
@@ -136,7 +136,7 @@ useEffect(() => {
|
||||
|
||||
### 5. Theme Colors
|
||||
|
||||
Themes have 12 required colors. Use inline styles for theme colors:
|
||||
Themes have 13 required colors. Use inline styles for theme colors:
|
||||
```typescript
|
||||
style={{ color: theme.colors.textMain }} // Correct
|
||||
className="text-gray-500" // Wrong for themed text
|
||||
|
||||
@@ -23,6 +23,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#6366f1',
|
||||
accentDim: 'rgba(99, 102, 241, 0.2)',
|
||||
accentText: '#a5b4fc',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#22c55e',
|
||||
warning: '#eab308',
|
||||
error: '#ef4444'
|
||||
@@ -42,6 +43,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#fd971f',
|
||||
accentDim: 'rgba(253, 151, 31, 0.2)',
|
||||
accentText: '#fdbf6f',
|
||||
accentForeground: '#1e1f1c',
|
||||
success: '#a6e22e',
|
||||
warning: '#e6db74',
|
||||
error: '#f92672'
|
||||
@@ -61,6 +63,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#88c0d0',
|
||||
accentDim: 'rgba(136, 192, 208, 0.2)',
|
||||
accentText: '#8fbcbb',
|
||||
accentForeground: '#2e3440',
|
||||
success: '#a3be8c',
|
||||
warning: '#ebcb8b',
|
||||
error: '#bf616a'
|
||||
@@ -80,6 +83,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#7aa2f7',
|
||||
accentDim: 'rgba(122, 162, 247, 0.2)',
|
||||
accentText: '#7dcfff',
|
||||
accentForeground: '#1a1b26',
|
||||
success: '#9ece6a',
|
||||
warning: '#e0af68',
|
||||
error: '#f7768e'
|
||||
@@ -99,6 +103,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#89b4fa',
|
||||
accentDim: 'rgba(137, 180, 250, 0.2)',
|
||||
accentText: '#89dceb',
|
||||
accentForeground: '#1e1e2e',
|
||||
success: '#a6e3a1',
|
||||
warning: '#f9e2af',
|
||||
error: '#f38ba8'
|
||||
@@ -118,6 +123,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#83a598',
|
||||
accentDim: 'rgba(131, 165, 152, 0.2)',
|
||||
accentText: '#8ec07c',
|
||||
accentForeground: '#1d2021',
|
||||
success: '#b8bb26',
|
||||
warning: '#fabd2f',
|
||||
error: '#fb4934'
|
||||
@@ -138,6 +144,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#0969da',
|
||||
accentDim: 'rgba(9, 105, 218, 0.1)',
|
||||
accentText: '#0969da',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#1a7f37',
|
||||
warning: '#9a6700',
|
||||
error: '#cf222e'
|
||||
@@ -157,6 +164,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#2aa198',
|
||||
accentDim: 'rgba(42, 161, 152, 0.1)',
|
||||
accentText: '#2aa198',
|
||||
accentForeground: '#fdf6e3',
|
||||
success: '#859900',
|
||||
warning: '#b58900',
|
||||
error: '#dc322f'
|
||||
@@ -176,6 +184,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#4078f2',
|
||||
accentDim: 'rgba(64, 120, 242, 0.1)',
|
||||
accentText: '#4078f2',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#50a14f',
|
||||
warning: '#c18401',
|
||||
error: '#e45649'
|
||||
@@ -195,6 +204,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#458588',
|
||||
accentDim: 'rgba(69, 133, 136, 0.1)',
|
||||
accentText: '#076678',
|
||||
accentForeground: '#fbf1c7',
|
||||
success: '#98971a',
|
||||
warning: '#d79921',
|
||||
error: '#cc241d'
|
||||
@@ -214,6 +224,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#1e66f5',
|
||||
accentDim: 'rgba(30, 102, 245, 0.1)',
|
||||
accentText: '#1e66f5',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#40a02b',
|
||||
warning: '#df8e1d',
|
||||
error: '#d20f39'
|
||||
@@ -233,6 +244,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#55b4d4',
|
||||
accentDim: 'rgba(85, 180, 212, 0.1)',
|
||||
accentText: '#399ee6',
|
||||
accentForeground: '#1a1a1a',
|
||||
success: '#86b300',
|
||||
warning: '#f2ae49',
|
||||
error: '#f07171'
|
||||
@@ -253,6 +265,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#ff69b4',
|
||||
accentDim: 'rgba(255, 105, 180, 0.25)',
|
||||
accentText: '#ff8dc7',
|
||||
accentForeground: '#1a0f24',
|
||||
success: '#7cb342',
|
||||
warning: '#d4af37',
|
||||
error: '#da70d6'
|
||||
@@ -263,18 +276,19 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
name: "Maestro's Choice",
|
||||
mode: 'vibe',
|
||||
colors: {
|
||||
bgMain: '#0a0a0f',
|
||||
bgSidebar: '#05050a',
|
||||
bgActivity: '#12121a',
|
||||
border: '#2a2a3a',
|
||||
textMain: '#f0e6d3',
|
||||
textDim: '#8a8078',
|
||||
accent: '#c9a227',
|
||||
accentDim: 'rgba(201, 162, 39, 0.2)',
|
||||
accentText: '#e6b830',
|
||||
success: '#4a9c6d',
|
||||
warning: '#c9a227',
|
||||
error: '#8b2942'
|
||||
bgMain: '#1a1a24',
|
||||
bgSidebar: '#141420',
|
||||
bgActivity: '#24243a',
|
||||
border: '#3a3a5a',
|
||||
textMain: '#fff8e8',
|
||||
textDim: '#a8a0a0',
|
||||
accent: '#f4c430',
|
||||
accentDim: 'rgba(244, 196, 48, 0.25)',
|
||||
accentText: '#ffd54f',
|
||||
accentForeground: '#1a1a24',
|
||||
success: '#66d9a0',
|
||||
warning: '#f4c430',
|
||||
error: '#e05070'
|
||||
}
|
||||
},
|
||||
'dre-synth': {
|
||||
@@ -285,14 +299,15 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
bgMain: '#0d0221',
|
||||
bgSidebar: '#0a0118',
|
||||
bgActivity: '#150530',
|
||||
border: '#2a1050',
|
||||
border: '#00d4aa',
|
||||
textMain: '#f0e6ff',
|
||||
textDim: '#9080b0',
|
||||
accent: '#ff2a6d',
|
||||
accentDim: 'rgba(255, 42, 109, 0.25)',
|
||||
accentText: '#ff6b9d',
|
||||
success: '#05ffa1',
|
||||
warning: '#00f5d4',
|
||||
textDim: '#60e0d0',
|
||||
accent: '#00ffcc',
|
||||
accentDim: 'rgba(0, 255, 204, 0.25)',
|
||||
accentText: '#40ffdd',
|
||||
accentForeground: '#0d0221',
|
||||
success: '#00ffcc',
|
||||
warning: '#ff2a6d',
|
||||
error: '#ff2a6d'
|
||||
}
|
||||
},
|
||||
@@ -310,6 +325,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#cc0033',
|
||||
accentDim: 'rgba(204, 0, 51, 0.25)',
|
||||
accentText: '#ff3355',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#f5f5f5',
|
||||
warning: '#cc0033',
|
||||
error: '#cc0033'
|
||||
|
||||
@@ -1349,8 +1349,6 @@ export default function MaestroConsole() {
|
||||
activeBatchSessionIds,
|
||||
startBatchRun,
|
||||
stopBatchRun,
|
||||
customPrompts,
|
||||
setCustomPrompt
|
||||
} = useBatchProcessor({
|
||||
sessions,
|
||||
onUpdateSession: (sessionId, updates) => {
|
||||
@@ -2432,6 +2430,30 @@ export default function MaestroConsole() {
|
||||
{ session: activeSession, gitBranch }
|
||||
);
|
||||
|
||||
// Queue the command if AI is busy (same as regular messages)
|
||||
if (activeSession.state === 'busy') {
|
||||
const queuedEntry: LogEntry = {
|
||||
id: generateId(),
|
||||
timestamp: Date.now(),
|
||||
source: 'user',
|
||||
text: substitutedPrompt,
|
||||
aiCommand: {
|
||||
command: matchingCustomCommand.command,
|
||||
description: matchingCustomCommand.description
|
||||
}
|
||||
};
|
||||
|
||||
setSessions(prev => prev.map(s => {
|
||||
if (s.id !== activeSessionId) return s;
|
||||
return {
|
||||
...s,
|
||||
messageQueue: [...s.messageQueue, queuedEntry],
|
||||
aiCommandHistory: Array.from(new Set([...(s.aiCommandHistory || []), commandText])).slice(-50),
|
||||
};
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
// Add user log showing the command with its interpolated prompt
|
||||
// Also track this command for automatic synopsis on completion
|
||||
setSessions(prev => prev.map(s => {
|
||||
@@ -4193,12 +4215,16 @@ export default function MaestroConsole() {
|
||||
theme={theme}
|
||||
onClose={() => setBatchRunnerModalOpen(false)}
|
||||
onGo={(prompt) => {
|
||||
// Save the custom prompt for this session
|
||||
setCustomPrompt(activeSession.id, prompt);
|
||||
// Start the batch run
|
||||
handleStartBatchRun(prompt);
|
||||
}}
|
||||
initialPrompt={customPrompts[activeSession.id] || ''}
|
||||
onSave={(prompt) => {
|
||||
// Save the custom prompt to the session (persisted across restarts)
|
||||
setSessions(prev => prev.map(s =>
|
||||
s.id === activeSession.id ? { ...s, batchRunnerPrompt: prompt } : s
|
||||
));
|
||||
}}
|
||||
initialPrompt={activeSession.batchRunnerPrompt || ''}
|
||||
showConfirmation={showConfirmation}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -152,7 +152,7 @@ export function AICommandsPanel({ theme, customAICommands, setCustomAICommands }
|
||||
className="flex items-center gap-2 px-4 py-2 rounded text-sm font-medium transition-all"
|
||||
style={{
|
||||
backgroundColor: theme.colors.accent,
|
||||
color: 'white'
|
||||
color: theme.colors.accentForeground
|
||||
}}
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
|
||||
@@ -179,7 +179,6 @@ export function AboutModal({ theme, sessions, onClose }: AboutModalProps) {
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<BarChart3 className="w-4 h-4" style={{ color: theme.colors.accent }} />
|
||||
<span className="text-sm font-bold" style={{ color: theme.colors.textMain }}>Global Statistics</span>
|
||||
<span className="text-[10px]" style={{ color: theme.colors.textDim }}>(all Claude projects)</span>
|
||||
</div>
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center py-4 gap-2">
|
||||
|
||||
@@ -337,7 +337,7 @@ export function AgentSessionsModal({
|
||||
className="flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm font-medium transition-colors"
|
||||
style={{
|
||||
backgroundColor: theme.colors.accent,
|
||||
color: theme.colors.accentText,
|
||||
color: theme.colors.accentForeground,
|
||||
}}
|
||||
>
|
||||
<Play className="w-4 h-4" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { X, RotateCcw, Play, Variable, ChevronDown, ChevronRight } from 'lucide-react';
|
||||
import { X, RotateCcw, Play, Variable, ChevronDown, ChevronRight, Save } from 'lucide-react';
|
||||
import type { Theme } from '../types';
|
||||
import { useLayerStack } from '../contexts/LayerStackContext';
|
||||
import { MODAL_PRIORITIES } from '../constants/modalPriorities';
|
||||
@@ -48,15 +48,17 @@ interface BatchRunnerModalProps {
|
||||
theme: Theme;
|
||||
onClose: () => void;
|
||||
onGo: (prompt: string) => void;
|
||||
onSave: (prompt: string) => void;
|
||||
initialPrompt?: string;
|
||||
showConfirmation: (message: string, onConfirm: () => void) => void;
|
||||
}
|
||||
|
||||
export function BatchRunnerModal(props: BatchRunnerModalProps) {
|
||||
const { theme, onClose, onGo, initialPrompt, showConfirmation } = props;
|
||||
const { theme, onClose, onGo, onSave, initialPrompt, showConfirmation } = props;
|
||||
|
||||
const [prompt, setPrompt] = useState(initialPrompt || DEFAULT_BATCH_PROMPT);
|
||||
const [variablesExpanded, setVariablesExpanded] = useState(false);
|
||||
const [savedPrompt, setSavedPrompt] = useState(initialPrompt || '');
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const { registerLayer, unregisterLayer, updateLayerHandler } = useLayerStack();
|
||||
@@ -103,12 +105,20 @@ export function BatchRunnerModal(props: BatchRunnerModalProps) {
|
||||
);
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
onSave(prompt);
|
||||
setSavedPrompt(prompt);
|
||||
};
|
||||
|
||||
const handleGo = () => {
|
||||
// Also save when running
|
||||
onSave(prompt);
|
||||
onGo(prompt);
|
||||
onClose();
|
||||
};
|
||||
|
||||
const isModified = prompt !== DEFAULT_BATCH_PROMPT;
|
||||
const hasUnsavedChanges = prompt !== savedPrompt && prompt !== DEFAULT_BATCH_PROMPT;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -232,6 +242,16 @@ export function BatchRunnerModal(props: BatchRunnerModalProps) {
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={!hasUnsavedChanges}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded border hover:bg-white/5 transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
|
||||
style={{ borderColor: theme.colors.border, color: theme.colors.success }}
|
||||
title={hasUnsavedChanges ? 'Save prompt for this session' : 'No unsaved changes'}
|
||||
>
|
||||
<Save className="w-4 h-4" />
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
onClick={handleGo}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded text-white font-bold"
|
||||
|
||||
@@ -218,8 +218,8 @@ export function CreateGroupModal(props: CreateGroupModalProps) {
|
||||
<button
|
||||
onClick={handleCreate}
|
||||
disabled={!groupName.trim()}
|
||||
className="px-4 py-2 rounded text-white disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
style={{ backgroundColor: theme.colors.accent }}
|
||||
className="px-4 py-2 rounded disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
style={{ backgroundColor: theme.colors.accent, color: theme.colors.accentForeground }}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
|
||||
@@ -740,7 +740,7 @@ export function FilePreview({ file, onClose, theme, markdownRawMode, setMarkdown
|
||||
className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 px-6 py-4 rounded-lg shadow-2xl text-base font-bold animate-in fade-in zoom-in-95 duration-200 z-50"
|
||||
style={{
|
||||
backgroundColor: theme.colors.accent,
|
||||
color: '#FFFFFF',
|
||||
color: theme.colors.accentForeground,
|
||||
textShadow: '0 1px 2px rgba(0, 0, 0, 0.3)'
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -355,7 +355,7 @@ export function HistoryDetailModal({
|
||||
className="px-4 py-2 rounded text-sm font-medium transition-colors hover:opacity-90"
|
||||
style={{
|
||||
backgroundColor: theme.colors.accent,
|
||||
color: 'white'
|
||||
color: theme.colors.accentForeground
|
||||
}}
|
||||
>
|
||||
Close
|
||||
|
||||
@@ -435,8 +435,8 @@ export function InputArea(props: InputAreaProps) {
|
||||
) : (
|
||||
<button
|
||||
onClick={processInput}
|
||||
className="p-2 rounded-md text-white shadow-sm transition-all hover:opacity-90"
|
||||
style={{ backgroundColor: theme.colors.accent }}
|
||||
className="p-2 rounded-md shadow-sm transition-all hover:opacity-90"
|
||||
style={{ backgroundColor: theme.colors.accent, color: theme.colors.accentForeground }}
|
||||
>
|
||||
<ArrowUp className="w-4 h-4" />
|
||||
</button>
|
||||
|
||||
@@ -1166,7 +1166,7 @@ export function MainPanel(props: MainPanelProps) {
|
||||
className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 px-6 py-4 rounded-lg shadow-2xl text-base font-bold animate-in fade-in zoom-in-95 duration-200 z-50"
|
||||
style={{
|
||||
backgroundColor: theme.colors.accent,
|
||||
color: '#FFFFFF',
|
||||
color: theme.colors.accentForeground,
|
||||
textShadow: '0 1px 2px rgba(0, 0, 0, 0.3)'
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -343,8 +343,8 @@ export function NewInstanceModal({ isOpen, onClose, onCreate, theme, defaultAgen
|
||||
<button
|
||||
onClick={handleCreate}
|
||||
disabled={!selectedAgent || !agents.find(a => a.id === selectedAgent)?.available}
|
||||
className="px-4 py-2 rounded text-white disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
style={{ backgroundColor: theme.colors.accent }}
|
||||
className="px-4 py-2 rounded disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
style={{ backgroundColor: theme.colors.accent, color: theme.colors.accentForeground }}
|
||||
>
|
||||
Create Agent
|
||||
</button>
|
||||
|
||||
@@ -360,7 +360,7 @@ export function QuickActionsModal(props: QuickActionsModalProps) {
|
||||
className={`w-full text-left px-4 py-3 flex items-center gap-3 hover:bg-opacity-10 ${i === selectedIndex ? 'bg-opacity-10' : ''}`}
|
||||
style={{
|
||||
backgroundColor: i === selectedIndex ? theme.colors.accent : 'transparent',
|
||||
color: theme.colors.textMain
|
||||
color: i === selectedIndex ? theme.colors.accentForeground : theme.colors.textMain
|
||||
}}
|
||||
>
|
||||
{showNumber ? (
|
||||
|
||||
@@ -182,8 +182,8 @@ export function RenameGroupModal(props: RenameGroupModalProps) {
|
||||
<button
|
||||
onClick={handleRename}
|
||||
disabled={!groupName.trim()}
|
||||
className="px-4 py-2 rounded text-white disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
style={{ backgroundColor: theme.colors.accent }}
|
||||
className="px-4 py-2 rounded disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
style={{ backgroundColor: theme.colors.accent, color: theme.colors.accentForeground }}
|
||||
>
|
||||
Rename
|
||||
</button>
|
||||
|
||||
@@ -105,8 +105,8 @@ export function RenameSessionModal(props: RenameSessionModalProps) {
|
||||
<button
|
||||
onClick={handleRename}
|
||||
disabled={!value.trim()}
|
||||
className="px-4 py-2 rounded text-white disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
style={{ backgroundColor: theme.colors.accent }}
|
||||
className="px-4 py-2 rounded disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
style={{ backgroundColor: theme.colors.accent, color: theme.colors.accentForeground }}
|
||||
>
|
||||
Rename
|
||||
</button>
|
||||
|
||||
@@ -120,15 +120,16 @@ export const RightPanel = forwardRef<RightPanelHandle, RightPanelProps>(function
|
||||
e.preventDefault();
|
||||
const startX = e.clientX;
|
||||
const startWidth = rightPanelWidth;
|
||||
let currentWidth = startWidth;
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const delta = startX - e.clientX; // Reversed for right panel
|
||||
const newWidth = Math.max(384, Math.min(800, startWidth + delta));
|
||||
setRightPanelWidthState(newWidth);
|
||||
currentWidth = Math.max(384, Math.min(800, startWidth + delta));
|
||||
setRightPanelWidthState(currentWidth);
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
window.maestro.settings.set('rightPanelWidth', rightPanelWidth);
|
||||
window.maestro.settings.set('rightPanelWidth', currentWidth);
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
};
|
||||
|
||||
@@ -808,7 +808,7 @@ export function Scratchpad({
|
||||
className={`flex items-center gap-2 px-3 py-1.5 rounded text-xs transition-colors ${isAgentBusy ? 'opacity-50 cursor-not-allowed' : 'hover:opacity-90'}`}
|
||||
style={{
|
||||
backgroundColor: theme.colors.accent,
|
||||
color: 'white',
|
||||
color: theme.colors.accentForeground,
|
||||
border: `1px solid ${theme.colors.accent}`
|
||||
}}
|
||||
title={isAgentBusy ? "Cannot run while agent is thinking" : "Run batch processing on scratchpad tasks"}
|
||||
@@ -888,7 +888,7 @@ export function Scratchpad({
|
||||
goToPrevMatch();
|
||||
}
|
||||
}}
|
||||
placeholder={mode === 'edit' ? "Search... (Enter: next, Shift+Enter: prev)" : "Search... (press '/' to open, Enter: next)"}
|
||||
placeholder={mode === 'edit' ? "Search... (⌘F to open, Enter: next, Shift+Enter: prev)" : "Search... (/ to open, Enter: next, Shift+Enter: prev)"}
|
||||
className="flex-1 bg-transparent outline-none text-sm"
|
||||
style={{ color: theme.colors.textMain }}
|
||||
autoFocus
|
||||
@@ -961,18 +961,12 @@ export function Scratchpad({
|
||||
e.stopPropagation();
|
||||
toggleMode();
|
||||
}
|
||||
// '/' to open search in preview mode
|
||||
// '/' to open search in preview mode (mutually exclusive with Cmd+F in edit mode)
|
||||
if (e.key === '/' && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
openSearch();
|
||||
}
|
||||
// CMD+F to open search
|
||||
if ((e.metaKey || e.ctrlKey) && e.key === 'f') {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
openSearch();
|
||||
}
|
||||
}}
|
||||
onScroll={handlePreviewScroll}
|
||||
style={{
|
||||
|
||||
@@ -265,15 +265,16 @@ export function SessionList(props: SessionListProps) {
|
||||
e.preventDefault();
|
||||
const startX = e.clientX;
|
||||
const startWidth = leftSidebarWidthState;
|
||||
let currentWidth = startWidth;
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const delta = e.clientX - startX;
|
||||
const newWidth = Math.max(256, Math.min(600, startWidth + delta));
|
||||
setLeftSidebarWidthState(newWidth);
|
||||
currentWidth = Math.max(256, Math.min(600, startWidth + delta));
|
||||
setLeftSidebarWidthState(currentWidth);
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
window.maestro.settings.set('leftSidebarWidth', leftSidebarWidthState);
|
||||
window.maestro.settings.set('leftSidebarWidth', currentWidth);
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
};
|
||||
@@ -354,7 +355,7 @@ export function SessionList(props: SessionListProps) {
|
||||
className="w-full py-2 rounded text-xs font-medium transition-colors hover:opacity-90 flex items-center justify-center gap-2"
|
||||
style={{
|
||||
backgroundColor: theme.colors.accent,
|
||||
color: 'white'
|
||||
color: theme.colors.accentForeground
|
||||
}}
|
||||
>
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
@@ -1272,7 +1273,7 @@ export function SessionList(props: SessionListProps) {
|
||||
</button>
|
||||
|
||||
{leftSidebarOpen && (
|
||||
<button onClick={addNewSession} className="flex-1 flex items-center justify-center gap-2 py-2 rounded text-xs font-bold transition-colors text-white" style={{ backgroundColor: theme.colors.accent }}>
|
||||
<button onClick={addNewSession} className="flex-1 flex items-center justify-center gap-2 py-2 rounded text-xs font-bold transition-colors" style={{ backgroundColor: theme.colors.accent, color: theme.colors.accentForeground }}>
|
||||
<Plus className="w-3 h-3" /> New Agent
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -716,7 +716,7 @@ export function SettingsModal(props: SettingsModalProps) {
|
||||
<button
|
||||
onClick={addCustomFont}
|
||||
className="px-3 py-2 rounded text-xs font-bold"
|
||||
style={{ backgroundColor: theme.colors.accent, color: 'white' }}
|
||||
style={{ backgroundColor: theme.colors.accent, color: theme.colors.accentForeground }}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
@@ -1229,7 +1229,7 @@ export function SettingsModal(props: SettingsModalProps) {
|
||||
className="w-full py-3 rounded-lg font-bold text-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
style={{
|
||||
backgroundColor: theme.colors.accent,
|
||||
color: 'white',
|
||||
color: theme.colors.accentForeground,
|
||||
}}
|
||||
>
|
||||
{testingLLM ? 'Testing Connection...' : 'Test Connection'}
|
||||
|
||||
@@ -1264,7 +1264,7 @@ export const TerminalOutput = forwardRef<HTMLDivElement, TerminalOutputProps>((p
|
||||
className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 px-6 py-4 rounded-lg shadow-2xl text-base font-bold animate-in fade-in zoom-in-95 duration-200 z-50"
|
||||
style={{
|
||||
backgroundColor: theme.colors.accent,
|
||||
color: '#FFFFFF',
|
||||
color: theme.colors.accentForeground,
|
||||
textShadow: '0 1px 2px rgba(0, 0, 0, 0.3)'
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -16,6 +16,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#6366f1',
|
||||
accentDim: 'rgba(99, 102, 241, 0.2)',
|
||||
accentText: '#a5b4fc',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#22c55e',
|
||||
warning: '#eab308',
|
||||
error: '#ef4444'
|
||||
@@ -35,6 +36,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#fd971f',
|
||||
accentDim: 'rgba(253, 151, 31, 0.2)',
|
||||
accentText: '#fdbf6f',
|
||||
accentForeground: '#1e1f1c',
|
||||
success: '#a6e22e',
|
||||
warning: '#e6db74',
|
||||
error: '#f92672'
|
||||
@@ -54,6 +56,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#88c0d0',
|
||||
accentDim: 'rgba(136, 192, 208, 0.2)',
|
||||
accentText: '#8fbcbb',
|
||||
accentForeground: '#2e3440',
|
||||
success: '#a3be8c',
|
||||
warning: '#ebcb8b',
|
||||
error: '#bf616a'
|
||||
@@ -73,6 +76,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#7aa2f7',
|
||||
accentDim: 'rgba(122, 162, 247, 0.2)',
|
||||
accentText: '#7dcfff',
|
||||
accentForeground: '#1a1b26',
|
||||
success: '#9ece6a',
|
||||
warning: '#e0af68',
|
||||
error: '#f7768e'
|
||||
@@ -92,6 +96,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#89b4fa',
|
||||
accentDim: 'rgba(137, 180, 250, 0.2)',
|
||||
accentText: '#89dceb',
|
||||
accentForeground: '#1e1e2e',
|
||||
success: '#a6e3a1',
|
||||
warning: '#f9e2af',
|
||||
error: '#f38ba8'
|
||||
@@ -111,6 +116,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#83a598',
|
||||
accentDim: 'rgba(131, 165, 152, 0.2)',
|
||||
accentText: '#8ec07c',
|
||||
accentForeground: '#1d2021',
|
||||
success: '#b8bb26',
|
||||
warning: '#fabd2f',
|
||||
error: '#fb4934'
|
||||
@@ -131,6 +137,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#0969da',
|
||||
accentDim: 'rgba(9, 105, 218, 0.1)',
|
||||
accentText: '#0969da',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#1a7f37',
|
||||
warning: '#9a6700',
|
||||
error: '#cf222e'
|
||||
@@ -150,6 +157,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#2aa198',
|
||||
accentDim: 'rgba(42, 161, 152, 0.1)',
|
||||
accentText: '#2aa198',
|
||||
accentForeground: '#fdf6e3',
|
||||
success: '#859900',
|
||||
warning: '#b58900',
|
||||
error: '#dc322f'
|
||||
@@ -169,6 +177,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#4078f2',
|
||||
accentDim: 'rgba(64, 120, 242, 0.1)',
|
||||
accentText: '#4078f2',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#50a14f',
|
||||
warning: '#c18401',
|
||||
error: '#e45649'
|
||||
@@ -188,6 +197,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#458588',
|
||||
accentDim: 'rgba(69, 133, 136, 0.1)',
|
||||
accentText: '#076678',
|
||||
accentForeground: '#fbf1c7',
|
||||
success: '#98971a',
|
||||
warning: '#d79921',
|
||||
error: '#cc241d'
|
||||
@@ -207,6 +217,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#1e66f5',
|
||||
accentDim: 'rgba(30, 102, 245, 0.1)',
|
||||
accentText: '#1e66f5',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#40a02b',
|
||||
warning: '#df8e1d',
|
||||
error: '#d20f39'
|
||||
@@ -226,6 +237,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#55b4d4',
|
||||
accentDim: 'rgba(85, 180, 212, 0.1)',
|
||||
accentText: '#399ee6',
|
||||
accentForeground: '#1a1a1a',
|
||||
success: '#86b300',
|
||||
warning: '#f2ae49',
|
||||
error: '#f07171'
|
||||
@@ -246,6 +258,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#ff69b4',
|
||||
accentDim: 'rgba(255, 105, 180, 0.25)',
|
||||
accentText: '#ff8dc7',
|
||||
accentForeground: '#1a0f24',
|
||||
success: '#7cb342',
|
||||
warning: '#d4af37',
|
||||
error: '#da70d6'
|
||||
@@ -265,6 +278,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#f4c430',
|
||||
accentDim: 'rgba(244, 196, 48, 0.25)',
|
||||
accentText: '#ffd54f',
|
||||
accentForeground: '#1a1a24',
|
||||
success: '#66d9a0',
|
||||
warning: '#f4c430',
|
||||
error: '#e05070'
|
||||
@@ -284,6 +298,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#00ffcc',
|
||||
accentDim: 'rgba(0, 255, 204, 0.25)',
|
||||
accentText: '#40ffdd',
|
||||
accentForeground: '#0d0221',
|
||||
success: '#00ffcc',
|
||||
warning: '#ff2a6d',
|
||||
error: '#ff2a6d'
|
||||
@@ -303,6 +318,7 @@ export const THEMES: Record<ThemeId, Theme> = {
|
||||
accent: '#cc0033',
|
||||
accentDim: 'rgba(204, 0, 51, 0.25)',
|
||||
accentText: '#ff3355',
|
||||
accentForeground: '#ffffff',
|
||||
success: '#f5f5f5',
|
||||
warning: '#cc0033',
|
||||
error: '#cc0033'
|
||||
|
||||
@@ -54,13 +54,13 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.splash-logo {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
border-radius: 1.5rem;
|
||||
border-radius: 24px;
|
||||
box-shadow: 0 25px 50px -12px rgba(139, 92, 246, 0.4);
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -74,7 +74,7 @@
|
||||
.splash-title {
|
||||
font-family: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace;
|
||||
font-weight: 700;
|
||||
font-size: 2.25rem;
|
||||
font-size: 36px;
|
||||
letter-spacing: 0.25em;
|
||||
color: #ffffff;
|
||||
text-shadow: 0 2px 10px rgba(139, 92, 246, 0.3);
|
||||
@@ -103,7 +103,7 @@
|
||||
|
||||
.splash-text {
|
||||
font-family: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace;
|
||||
font-size: 0.875rem;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0.05em;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
@@ -173,6 +173,8 @@ export interface Session {
|
||||
recentClaudeSessions?: RecentClaudeSession[];
|
||||
// Pending AI command that will trigger a synopsis on completion (e.g., '/commit')
|
||||
pendingAICommandForSynopsis?: string;
|
||||
// Custom batch runner prompt (persisted per session)
|
||||
batchRunnerPrompt?: string;
|
||||
}
|
||||
|
||||
export interface Group {
|
||||
|
||||
@@ -58,6 +58,8 @@ export interface ThemeColors {
|
||||
accentDim: string;
|
||||
/** Text color for accent contexts */
|
||||
accentText: string;
|
||||
/** Text color for use ON accent backgrounds (contrasting color) */
|
||||
accentForeground: string;
|
||||
/** Success state color (green tones) */
|
||||
success: string;
|
||||
/** Warning state color (yellow/orange tones) */
|
||||
|
||||
Reference in New Issue
Block a user