feat: enhance theme customization and UI components

- Implemented a new color generation module to create CSS variables based on a single hue value, supporting both light and dark modes.
- Added unit tests for the color generation logic to ensure accuracy and robustness.
- Replaced dropdown location filter with tab navigation in RulesManagerPage and SkillsManagerPage for improved UX.
- Updated app store to manage custom theme hues and states, allowing for dynamic theme adjustments.
- Sanitized notification content before persisting to localStorage to prevent sensitive data exposure.
- Refactored memory retrieval logic to handle archived status more flexibly.
- Improved Tailwind CSS configuration with new gradient utilities and animations.
- Minor adjustments to SettingsPage layout for better visual consistency.
This commit is contained in:
catlog22
2026-02-04 17:20:40 +08:00
parent 88616224e0
commit e260a3f77b
30 changed files with 1377 additions and 388 deletions

View File

@@ -296,19 +296,35 @@ export function CliViewerPage() {
}
}, [lastMessage, invalidateActive]);
// Auto-add new executions as tabs when they appear
// Auto-add new executions as tabs, distributing across available panes
// Uses round-robin distribution to spread executions across panes side-by-side
const addedExecutionsRef = useRef<Set<string>>(new Set());
useEffect(() => {
if (!focusedPaneId) return;
for (const executionId of Object.keys(executions)) {
if (!addedExecutionsRef.current.has(executionId)) {
addedExecutionsRef.current.add(executionId);
const exec = executions[executionId];
const toolShort = exec.tool.split('-')[0];
addTab(focusedPaneId, executionId, `${toolShort} (${exec.mode})`);
}
}
}, [executions, focusedPaneId, addTab]);
// Get all pane IDs from the current layout
const paneIds = Object.keys(panes);
if (paneIds.length === 0) return;
// Get addTab from store directly to avoid dependency on reactive function
// This prevents infinite loop when addTab updates store state
const storeAddTab = useViewerStore.getState().addTab;
// Get new executions that haven't been added yet
const newExecutionIds = Object.keys(executions).filter(
(id) => !addedExecutionsRef.current.has(id)
);
if (newExecutionIds.length === 0) return;
// Distribute new executions across panes round-robin
newExecutionIds.forEach((executionId, index) => {
addedExecutionsRef.current.add(executionId);
const exec = executions[executionId];
const toolShort = exec.tool.split('-')[0];
// Round-robin pane selection
const targetPaneId = paneIds[index % paneIds.length];
storeAddTab(targetPaneId, executionId, `${toolShort} (${exec.mode})`);
});
}, [executions, panes]);
// Initialize layout if empty
useEffect(() => {