mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-11 02:33:51 +08:00
feat: add gradient effects settings and enhance theme customization options
This commit is contained in:
@@ -20,7 +20,21 @@ import { generateThemeFromHue } from '@/lib/colorGenerator';
|
|||||||
*/
|
*/
|
||||||
export function ThemeSelector() {
|
export function ThemeSelector() {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const { colorScheme, resolvedTheme, customHue, isCustomTheme, setColorScheme, setTheme, setCustomHue } = useTheme();
|
const {
|
||||||
|
colorScheme,
|
||||||
|
resolvedTheme,
|
||||||
|
customHue,
|
||||||
|
isCustomTheme,
|
||||||
|
gradientLevel,
|
||||||
|
enableHoverGlow,
|
||||||
|
enableBackgroundAnimation,
|
||||||
|
setColorScheme,
|
||||||
|
setTheme,
|
||||||
|
setCustomHue,
|
||||||
|
setGradientLevel,
|
||||||
|
setEnableHoverGlow,
|
||||||
|
setEnableBackgroundAnimation,
|
||||||
|
} = useTheme();
|
||||||
|
|
||||||
// Local state for preview hue (uncommitted changes)
|
// Local state for preview hue (uncommitted changes)
|
||||||
const [previewHue, setPreviewHue] = useState<number | null>(customHue);
|
const [previewHue, setPreviewHue] = useState<number | null>(customHue);
|
||||||
@@ -251,6 +265,74 @@ export function ThemeSelector() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Gradient Effects Settings */}
|
||||||
|
<div>
|
||||||
|
<h3 className="text-sm font-medium text-text mb-3">
|
||||||
|
{formatMessage({ id: 'theme.gradient.title' })}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{/* Gradient Level Selection */}
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div
|
||||||
|
className="flex gap-2"
|
||||||
|
role="radiogroup"
|
||||||
|
aria-label={formatMessage({ id: 'theme.gradient.title' })}
|
||||||
|
>
|
||||||
|
{(['off', 'standard', 'enhanced'] as const).map((level) => (
|
||||||
|
<button
|
||||||
|
key={level}
|
||||||
|
onClick={() => setGradientLevel(level)}
|
||||||
|
role="radio"
|
||||||
|
aria-checked={gradientLevel === level}
|
||||||
|
className={`
|
||||||
|
flex-1 px-3 py-2 rounded-lg text-sm font-medium
|
||||||
|
transition-all duration-200 border-2
|
||||||
|
${gradientLevel === level
|
||||||
|
? 'border-accent bg-surface shadow-md'
|
||||||
|
: 'border-border bg-bg hover:bg-surface'
|
||||||
|
}
|
||||||
|
focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{formatMessage({ id: `theme.gradient.${level}` })}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Hover Glow Checkbox */}
|
||||||
|
<label className="flex items-center gap-3 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={enableHoverGlow}
|
||||||
|
onChange={(e) => setEnableHoverGlow(e.target.checked)}
|
||||||
|
className="
|
||||||
|
w-4 h-4 rounded border-border text-accent
|
||||||
|
focus:ring-2 focus:ring-accent focus:ring-offset-2
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<span className="text-sm text-text">
|
||||||
|
{formatMessage({ id: 'theme.gradient.hoverGlow' })}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{/* Background Animation Checkbox */}
|
||||||
|
<label className="flex items-center gap-3 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={enableBackgroundAnimation}
|
||||||
|
onChange={(e) => setEnableBackgroundAnimation(e.target.checked)}
|
||||||
|
className="
|
||||||
|
w-4 h-4 rounded border-border text-accent
|
||||||
|
focus:ring-2 focus:ring-accent focus:ring-offset-2
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<span className="text-sm text-text">
|
||||||
|
{formatMessage({ id: 'theme.gradient.bgAnimation' })}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Theme Mode Selection */}
|
{/* Theme Mode Selection */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-medium text-text mb-3">
|
<h3 className="text-sm font-medium text-text mb-3">
|
||||||
|
|||||||
@@ -4,8 +4,17 @@
|
|||||||
// Convenient hook for theme management with multi-color scheme support
|
// Convenient hook for theme management with multi-color scheme support
|
||||||
|
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useAppStore, selectTheme, selectResolvedTheme, selectCustomHue, selectIsCustomTheme } from '../stores/appStore';
|
import {
|
||||||
import type { Theme, ColorScheme } from '../types/store';
|
useAppStore,
|
||||||
|
selectTheme,
|
||||||
|
selectResolvedTheme,
|
||||||
|
selectCustomHue,
|
||||||
|
selectIsCustomTheme,
|
||||||
|
selectGradientLevel,
|
||||||
|
selectEnableHoverGlow,
|
||||||
|
selectEnableBackgroundAnimation,
|
||||||
|
} from '../stores/appStore';
|
||||||
|
import type { Theme, ColorScheme, GradientLevel } from '../types/store';
|
||||||
|
|
||||||
export interface UseThemeReturn {
|
export interface UseThemeReturn {
|
||||||
/** Current theme preference ('light', 'dark', 'system') */
|
/** Current theme preference ('light', 'dark', 'system') */
|
||||||
@@ -20,6 +29,12 @@ export interface UseThemeReturn {
|
|||||||
customHue: number | null;
|
customHue: number | null;
|
||||||
/** Whether the current theme is a custom theme */
|
/** Whether the current theme is a custom theme */
|
||||||
isCustomTheme: boolean;
|
isCustomTheme: boolean;
|
||||||
|
/** Gradient level: 'off', 'standard', or 'enhanced' */
|
||||||
|
gradientLevel: GradientLevel;
|
||||||
|
/** Whether hover glow effects are enabled */
|
||||||
|
enableHoverGlow: boolean;
|
||||||
|
/** Whether background gradient animation is enabled */
|
||||||
|
enableBackgroundAnimation: boolean;
|
||||||
/** Set theme preference */
|
/** Set theme preference */
|
||||||
setTheme: (theme: Theme) => void;
|
setTheme: (theme: Theme) => void;
|
||||||
/** Set color scheme */
|
/** Set color scheme */
|
||||||
@@ -28,6 +43,12 @@ export interface UseThemeReturn {
|
|||||||
setCustomHue: (hue: number | null) => void;
|
setCustomHue: (hue: number | null) => void;
|
||||||
/** Toggle between light and dark (ignores system) */
|
/** Toggle between light and dark (ignores system) */
|
||||||
toggleTheme: () => void;
|
toggleTheme: () => void;
|
||||||
|
/** Set gradient level */
|
||||||
|
setGradientLevel: (level: GradientLevel) => void;
|
||||||
|
/** Set hover glow enabled */
|
||||||
|
setEnableHoverGlow: (enabled: boolean) => void;
|
||||||
|
/** Set background animation enabled */
|
||||||
|
setEnableBackgroundAnimation: (enabled: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,10 +75,16 @@ export function useTheme(): UseThemeReturn {
|
|||||||
const colorScheme = useAppStore((state) => state.colorScheme);
|
const colorScheme = useAppStore((state) => state.colorScheme);
|
||||||
const customHue = useAppStore(selectCustomHue);
|
const customHue = useAppStore(selectCustomHue);
|
||||||
const isCustomTheme = useAppStore(selectIsCustomTheme);
|
const isCustomTheme = useAppStore(selectIsCustomTheme);
|
||||||
|
const gradientLevel = useAppStore(selectGradientLevel);
|
||||||
|
const enableHoverGlow = useAppStore(selectEnableHoverGlow);
|
||||||
|
const enableBackgroundAnimation = useAppStore(selectEnableBackgroundAnimation);
|
||||||
const setThemeAction = useAppStore((state) => state.setTheme);
|
const setThemeAction = useAppStore((state) => state.setTheme);
|
||||||
const setColorSchemeAction = useAppStore((state) => state.setColorScheme);
|
const setColorSchemeAction = useAppStore((state) => state.setColorScheme);
|
||||||
const setCustomHueAction = useAppStore((state) => state.setCustomHue);
|
const setCustomHueAction = useAppStore((state) => state.setCustomHue);
|
||||||
const toggleThemeAction = useAppStore((state) => state.toggleTheme);
|
const toggleThemeAction = useAppStore((state) => state.toggleTheme);
|
||||||
|
const setGradientLevelAction = useAppStore((state) => state.setGradientLevel);
|
||||||
|
const setEnableHoverGlowAction = useAppStore((state) => state.setEnableHoverGlow);
|
||||||
|
const setEnableBackgroundAnimationAction = useAppStore((state) => state.setEnableBackgroundAnimation);
|
||||||
|
|
||||||
const setTheme = useCallback(
|
const setTheme = useCallback(
|
||||||
(newTheme: Theme) => {
|
(newTheme: Theme) => {
|
||||||
@@ -84,6 +111,27 @@ export function useTheme(): UseThemeReturn {
|
|||||||
toggleThemeAction();
|
toggleThemeAction();
|
||||||
}, [toggleThemeAction]);
|
}, [toggleThemeAction]);
|
||||||
|
|
||||||
|
const setGradientLevel = useCallback(
|
||||||
|
(level: GradientLevel) => {
|
||||||
|
setGradientLevelAction(level);
|
||||||
|
},
|
||||||
|
[setGradientLevelAction]
|
||||||
|
);
|
||||||
|
|
||||||
|
const setEnableHoverGlow = useCallback(
|
||||||
|
(enabled: boolean) => {
|
||||||
|
setEnableHoverGlowAction(enabled);
|
||||||
|
},
|
||||||
|
[setEnableHoverGlowAction]
|
||||||
|
);
|
||||||
|
|
||||||
|
const setEnableBackgroundAnimation = useCallback(
|
||||||
|
(enabled: boolean) => {
|
||||||
|
setEnableBackgroundAnimationAction(enabled);
|
||||||
|
},
|
||||||
|
[setEnableBackgroundAnimationAction]
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
theme,
|
theme,
|
||||||
resolvedTheme,
|
resolvedTheme,
|
||||||
@@ -91,9 +139,15 @@ export function useTheme(): UseThemeReturn {
|
|||||||
colorScheme,
|
colorScheme,
|
||||||
customHue,
|
customHue,
|
||||||
isCustomTheme,
|
isCustomTheme,
|
||||||
|
gradientLevel,
|
||||||
|
enableHoverGlow,
|
||||||
|
enableBackgroundAnimation,
|
||||||
setTheme,
|
setTheme,
|
||||||
setColorScheme,
|
setColorScheme,
|
||||||
setCustomHue,
|
setCustomHue,
|
||||||
toggleTheme,
|
toggleTheme,
|
||||||
|
setGradientLevel,
|
||||||
|
setEnableHoverGlow,
|
||||||
|
setEnableBackgroundAnimation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -433,3 +433,105 @@
|
|||||||
.animate-spin {
|
.animate-spin {
|
||||||
animation: spin 1s linear infinite;
|
animation: spin 1s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Gradient Effects System
|
||||||
|
Conditional styles based on data attributes
|
||||||
|
=========================== */
|
||||||
|
|
||||||
|
/* Disable gradients when off */
|
||||||
|
[data-gradient="off"] .bg-gradient-primary,
|
||||||
|
[data-gradient="off"] .bg-gradient-brand,
|
||||||
|
[data-gradient="off"] .bg-gradient-accent {
|
||||||
|
background-image: none !important;
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-gradient="off"] .gradient-text {
|
||||||
|
background-image: none !important;
|
||||||
|
-webkit-background-clip: unset;
|
||||||
|
background-clip: unset;
|
||||||
|
-webkit-text-fill-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standard gradients (default) */
|
||||||
|
[data-gradient="standard"] .bg-gradient-primary {
|
||||||
|
background: linear-gradient(135deg, hsl(var(--primary)) 0%, hsl(var(--accent)) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-gradient="standard"] .bg-gradient-brand {
|
||||||
|
background: linear-gradient(135deg, hsl(var(--accent)) 0%, hsl(var(--primary)) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-gradient="standard"] .bg-gradient-accent {
|
||||||
|
background: linear-gradient(90deg, hsl(var(--accent)) 0%, hsl(var(--primary)) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enhanced gradients - more vibrant with multiple color stops */
|
||||||
|
[data-gradient="enhanced"] .bg-gradient-primary {
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
hsl(var(--primary)) 0%,
|
||||||
|
hsl(var(--accent)) 50%,
|
||||||
|
hsl(var(--secondary)) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-gradient="enhanced"] .bg-gradient-brand {
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
hsl(var(--accent)) 0%,
|
||||||
|
hsl(var(--primary)) 40%,
|
||||||
|
hsl(var(--secondary)) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-gradient="enhanced"] .bg-gradient-accent {
|
||||||
|
background: linear-gradient(90deg,
|
||||||
|
hsl(var(--accent)) 0%,
|
||||||
|
hsl(var(--primary)) 50%,
|
||||||
|
hsl(var(--accent)) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover glow effects - disabled when data-hover-glow="false" */
|
||||||
|
.hover-glow,
|
||||||
|
.hover-glow-primary {
|
||||||
|
transition: box-shadow 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-glow:hover {
|
||||||
|
box-shadow: 0 0 20px hsla(var(--accent), 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-glow-primary:hover {
|
||||||
|
box-shadow: 0 0 20px hsla(var(--primary), 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-hover-glow="false"] .hover-glow:hover,
|
||||||
|
[data-hover-glow="false"] .hover-glow-primary:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Background animation keyframes */
|
||||||
|
@keyframes slow-gradient {
|
||||||
|
0% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-position: 100% 50%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animated background gradient class */
|
||||||
|
.animate-slow-gradient {
|
||||||
|
background-size: 200% 200%;
|
||||||
|
animation: slow-gradient 15s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable background animation when data-bg-animation="false" */
|
||||||
|
[data-bg-animation="false"] .animate-slow-gradient {
|
||||||
|
animation: none;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,5 +26,13 @@
|
|||||||
"preview.surface": "Card",
|
"preview.surface": "Card",
|
||||||
"preview.accent": "Accent",
|
"preview.accent": "Accent",
|
||||||
"save": "Save Custom Theme",
|
"save": "Save Custom Theme",
|
||||||
"reset": "Reset to Preset"
|
"reset": "Reset to Preset",
|
||||||
|
"gradient": {
|
||||||
|
"title": "Gradient Effects",
|
||||||
|
"off": "Off",
|
||||||
|
"standard": "Standard",
|
||||||
|
"enhanced": "Enhanced",
|
||||||
|
"hoverGlow": "Enable hover glow effects",
|
||||||
|
"bgAnimation": "Enable background gradient animation"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,5 +26,13 @@
|
|||||||
"preview.surface": "卡片",
|
"preview.surface": "卡片",
|
||||||
"preview.accent": "强调色",
|
"preview.accent": "强调色",
|
||||||
"save": "保存自定义主题",
|
"save": "保存自定义主题",
|
||||||
"reset": "重置为预设"
|
"reset": "重置为预设",
|
||||||
|
"gradient": {
|
||||||
|
"title": "渐变效果",
|
||||||
|
"off": "关闭",
|
||||||
|
"standard": "标准",
|
||||||
|
"enhanced": "增强",
|
||||||
|
"hoverGlow": "启用悬停光晕效果",
|
||||||
|
"bgAnimation": "启用背景渐变动画"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist, devtools } from 'zustand/middleware';
|
import { persist, devtools } from 'zustand/middleware';
|
||||||
import type { AppStore, Theme, ColorScheme, Locale, ViewMode, SessionFilter, LiteTaskType, DashboardLayouts, WidgetConfig } from '../types/store';
|
import type { AppStore, Theme, ColorScheme, GradientLevel, Locale, ViewMode, SessionFilter, LiteTaskType, DashboardLayouts, WidgetConfig } from '../types/store';
|
||||||
import { DEFAULT_DASHBOARD_LAYOUT } from '../components/dashboard/defaultLayouts';
|
import { DEFAULT_DASHBOARD_LAYOUT } from '../components/dashboard/defaultLayouts';
|
||||||
import { getInitialLocale, updateIntl } from '../lib/i18n';
|
import { getInitialLocale, updateIntl } from '../lib/i18n';
|
||||||
import { getThemeId } from '../lib/theme';
|
import { getThemeId } from '../lib/theme';
|
||||||
@@ -41,7 +41,10 @@ const resolveTheme = (theme: Theme): 'light' | 'dark' => {
|
|||||||
const applyThemeToDocument = (
|
const applyThemeToDocument = (
|
||||||
resolvedTheme: 'light' | 'dark',
|
resolvedTheme: 'light' | 'dark',
|
||||||
colorScheme: ColorScheme,
|
colorScheme: ColorScheme,
|
||||||
customHue: number | null
|
customHue: number | null,
|
||||||
|
gradientLevel: GradientLevel = 'standard',
|
||||||
|
enableHoverGlow: boolean = true,
|
||||||
|
enableBackgroundAnimation: boolean = false
|
||||||
): void => {
|
): void => {
|
||||||
if (typeof document === 'undefined') return;
|
if (typeof document === 'undefined') return;
|
||||||
|
|
||||||
@@ -92,13 +95,16 @@ const applyThemeToDocument = (
|
|||||||
|
|
||||||
// Set color scheme attribute
|
// Set color scheme attribute
|
||||||
document.documentElement.setAttribute('data-color-scheme', colorScheme);
|
document.documentElement.setAttribute('data-color-scheme', colorScheme);
|
||||||
|
|
||||||
|
// Apply gradient settings
|
||||||
|
document.documentElement.setAttribute('data-gradient', gradientLevel);
|
||||||
|
document.documentElement.setAttribute('data-hover-glow', String(enableHoverGlow));
|
||||||
|
document.documentElement.setAttribute('data-bg-animation', String(enableBackgroundAnimation));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use View Transition API for smooth transitions (progressive enhancement)
|
// Use View Transition API for smooth transitions (progressive enhancement)
|
||||||
// @ts-expect-error - View Transition API not yet in TypeScript DOM types
|
if (typeof document !== 'undefined' && 'startViewTransition' in document) {
|
||||||
if (document.startViewTransition) {
|
(document as unknown as { startViewTransition: (callback: () => void) => void }).startViewTransition(performThemeUpdate);
|
||||||
// @ts-expect-error - View Transition API not yet in TypeScript DOM types
|
|
||||||
document.startViewTransition(performThemeUpdate);
|
|
||||||
} else {
|
} else {
|
||||||
// Fallback: apply immediately without transition
|
// Fallback: apply immediately without transition
|
||||||
performThemeUpdate();
|
performThemeUpdate();
|
||||||
@@ -114,6 +120,11 @@ const initialState = {
|
|||||||
customHue: null as number | null,
|
customHue: null as number | null,
|
||||||
isCustomTheme: false,
|
isCustomTheme: false,
|
||||||
|
|
||||||
|
// Gradient settings
|
||||||
|
gradientLevel: 'standard' as GradientLevel,
|
||||||
|
enableHoverGlow: true,
|
||||||
|
enableBackgroundAnimation: false,
|
||||||
|
|
||||||
// Locale
|
// Locale
|
||||||
locale: getInitialLocale() as Locale,
|
locale: getInitialLocale() as Locale,
|
||||||
|
|
||||||
@@ -150,31 +161,31 @@ export const useAppStore = create<AppStore>()(
|
|||||||
set({ theme, resolvedTheme: resolved }, false, 'setTheme');
|
set({ theme, resolvedTheme: resolved }, false, 'setTheme');
|
||||||
|
|
||||||
// Apply theme using helper (encapsulates DOM manipulation)
|
// Apply theme using helper (encapsulates DOM manipulation)
|
||||||
const { colorScheme, customHue } = get();
|
const { colorScheme, customHue, gradientLevel, enableHoverGlow, enableBackgroundAnimation } = get();
|
||||||
applyThemeToDocument(resolved, colorScheme, customHue);
|
applyThemeToDocument(resolved, colorScheme, customHue, gradientLevel, enableHoverGlow, enableBackgroundAnimation);
|
||||||
},
|
},
|
||||||
|
|
||||||
setColorScheme: (colorScheme: ColorScheme) => {
|
setColorScheme: (colorScheme: ColorScheme) => {
|
||||||
set({ colorScheme, customHue: null, isCustomTheme: false }, false, 'setColorScheme');
|
set({ colorScheme, customHue: null, isCustomTheme: false }, false, 'setColorScheme');
|
||||||
|
|
||||||
// Apply color scheme using helper (encapsulates DOM manipulation)
|
// Apply color scheme using helper (encapsulates DOM manipulation)
|
||||||
const { resolvedTheme } = get();
|
const { resolvedTheme, gradientLevel, enableHoverGlow, enableBackgroundAnimation } = get();
|
||||||
applyThemeToDocument(resolvedTheme, colorScheme, null);
|
applyThemeToDocument(resolvedTheme, colorScheme, null, gradientLevel, enableHoverGlow, enableBackgroundAnimation);
|
||||||
},
|
},
|
||||||
|
|
||||||
setCustomHue: (hue: number | null) => {
|
setCustomHue: (hue: number | null) => {
|
||||||
if (hue === null) {
|
if (hue === null) {
|
||||||
// Reset to preset theme
|
// Reset to preset theme
|
||||||
const { colorScheme, resolvedTheme } = get();
|
const { colorScheme, resolvedTheme, gradientLevel, enableHoverGlow, enableBackgroundAnimation } = get();
|
||||||
set({ customHue: null, isCustomTheme: false }, false, 'setCustomHue');
|
set({ customHue: null, isCustomTheme: false }, false, 'setCustomHue');
|
||||||
applyThemeToDocument(resolvedTheme, colorScheme, null);
|
applyThemeToDocument(resolvedTheme, colorScheme, null, gradientLevel, enableHoverGlow, enableBackgroundAnimation);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply custom hue
|
// Apply custom hue
|
||||||
set({ customHue: hue, isCustomTheme: true }, false, 'setCustomHue');
|
set({ customHue: hue, isCustomTheme: true }, false, 'setCustomHue');
|
||||||
const { resolvedTheme, colorScheme } = get();
|
const { resolvedTheme, colorScheme, gradientLevel, enableHoverGlow, enableBackgroundAnimation } = get();
|
||||||
applyThemeToDocument(resolvedTheme, colorScheme, hue);
|
applyThemeToDocument(resolvedTheme, colorScheme, hue, gradientLevel, enableHoverGlow, enableBackgroundAnimation);
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleTheme: () => {
|
toggleTheme: () => {
|
||||||
@@ -183,6 +194,26 @@ export const useAppStore = create<AppStore>()(
|
|||||||
get().setTheme(newTheme);
|
get().setTheme(newTheme);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ========== Gradient Settings Actions ==========
|
||||||
|
|
||||||
|
setGradientLevel: (level: GradientLevel) => {
|
||||||
|
set({ gradientLevel: level }, false, 'setGradientLevel');
|
||||||
|
const { resolvedTheme, colorScheme, customHue, enableHoverGlow, enableBackgroundAnimation } = get();
|
||||||
|
applyThemeToDocument(resolvedTheme, colorScheme, customHue, level, enableHoverGlow, enableBackgroundAnimation);
|
||||||
|
},
|
||||||
|
|
||||||
|
setEnableHoverGlow: (enabled: boolean) => {
|
||||||
|
set({ enableHoverGlow: enabled }, false, 'setEnableHoverGlow');
|
||||||
|
const { resolvedTheme, colorScheme, customHue, gradientLevel, enableBackgroundAnimation } = get();
|
||||||
|
applyThemeToDocument(resolvedTheme, colorScheme, customHue, gradientLevel, enabled, enableBackgroundAnimation);
|
||||||
|
},
|
||||||
|
|
||||||
|
setEnableBackgroundAnimation: (enabled: boolean) => {
|
||||||
|
set({ enableBackgroundAnimation: enabled }, false, 'setEnableBackgroundAnimation');
|
||||||
|
const { resolvedTheme, colorScheme, customHue, gradientLevel, enableHoverGlow } = get();
|
||||||
|
applyThemeToDocument(resolvedTheme, colorScheme, customHue, gradientLevel, enableHoverGlow, enabled);
|
||||||
|
},
|
||||||
|
|
||||||
// ========== Locale Actions ==========
|
// ========== Locale Actions ==========
|
||||||
|
|
||||||
setLocale: (locale: Locale) => {
|
setLocale: (locale: Locale) => {
|
||||||
@@ -279,6 +310,9 @@ export const useAppStore = create<AppStore>()(
|
|||||||
theme: state.theme,
|
theme: state.theme,
|
||||||
colorScheme: state.colorScheme,
|
colorScheme: state.colorScheme,
|
||||||
customHue: state.customHue,
|
customHue: state.customHue,
|
||||||
|
gradientLevel: state.gradientLevel,
|
||||||
|
enableHoverGlow: state.enableHoverGlow,
|
||||||
|
enableBackgroundAnimation: state.enableBackgroundAnimation,
|
||||||
locale: state.locale,
|
locale: state.locale,
|
||||||
sidebarCollapsed: state.sidebarCollapsed,
|
sidebarCollapsed: state.sidebarCollapsed,
|
||||||
expandedNavGroups: state.expandedNavGroups,
|
expandedNavGroups: state.expandedNavGroups,
|
||||||
@@ -291,7 +325,14 @@ export const useAppStore = create<AppStore>()(
|
|||||||
state.resolvedTheme = resolved;
|
state.resolvedTheme = resolved;
|
||||||
state.isCustomTheme = state.customHue !== null;
|
state.isCustomTheme = state.customHue !== null;
|
||||||
// Apply theme using helper (encapsulates DOM manipulation)
|
// Apply theme using helper (encapsulates DOM manipulation)
|
||||||
applyThemeToDocument(resolved, state.colorScheme, state.customHue);
|
applyThemeToDocument(
|
||||||
|
resolved,
|
||||||
|
state.colorScheme,
|
||||||
|
state.customHue,
|
||||||
|
state.gradientLevel ?? 'standard',
|
||||||
|
state.enableHoverGlow ?? true,
|
||||||
|
state.enableBackgroundAnimation ?? false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Apply locale on rehydration
|
// Apply locale on rehydration
|
||||||
if (state) {
|
if (state) {
|
||||||
@@ -313,7 +354,14 @@ if (typeof window !== 'undefined') {
|
|||||||
const resolved = getSystemTheme();
|
const resolved = getSystemTheme();
|
||||||
useAppStore.setState({ resolvedTheme: resolved });
|
useAppStore.setState({ resolvedTheme: resolved });
|
||||||
// Apply theme using helper (encapsulates DOM manipulation)
|
// Apply theme using helper (encapsulates DOM manipulation)
|
||||||
applyThemeToDocument(resolved, state.colorScheme, state.customHue);
|
applyThemeToDocument(
|
||||||
|
resolved,
|
||||||
|
state.colorScheme,
|
||||||
|
state.customHue,
|
||||||
|
state.gradientLevel,
|
||||||
|
state.enableHoverGlow,
|
||||||
|
state.enableBackgroundAnimation
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -324,6 +372,9 @@ export const selectResolvedTheme = (state: AppStore) => state.resolvedTheme;
|
|||||||
export const selectColorScheme = (state: AppStore) => state.colorScheme;
|
export const selectColorScheme = (state: AppStore) => state.colorScheme;
|
||||||
export const selectCustomHue = (state: AppStore) => state.customHue;
|
export const selectCustomHue = (state: AppStore) => state.customHue;
|
||||||
export const selectIsCustomTheme = (state: AppStore) => state.isCustomTheme;
|
export const selectIsCustomTheme = (state: AppStore) => state.isCustomTheme;
|
||||||
|
export const selectGradientLevel = (state: AppStore) => state.gradientLevel;
|
||||||
|
export const selectEnableHoverGlow = (state: AppStore) => state.enableHoverGlow;
|
||||||
|
export const selectEnableBackgroundAnimation = (state: AppStore) => state.enableBackgroundAnimation;
|
||||||
export const selectLocale = (state: AppStore) => state.locale;
|
export const selectLocale = (state: AppStore) => state.locale;
|
||||||
export const selectSidebarOpen = (state: AppStore) => state.sidebarOpen;
|
export const selectSidebarOpen = (state: AppStore) => state.sidebarOpen;
|
||||||
export const selectCurrentView = (state: AppStore) => state.currentView;
|
export const selectCurrentView = (state: AppStore) => state.currentView;
|
||||||
|
|||||||
@@ -266,3 +266,101 @@ export const NODE_TYPE_CONFIGS: Record<FlowNodeType, NodeTypeConfig> = {
|
|||||||
handles: { inputs: 1, outputs: 1 },
|
handles: { inputs: 1, outputs: 1 },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ========== Quick Templates ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quick template definition for common prompt patterns
|
||||||
|
*/
|
||||||
|
export interface QuickTemplate {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
icon: string;
|
||||||
|
color: string;
|
||||||
|
data: Partial<PromptTemplateNodeData>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predefined quick templates for common workflow patterns
|
||||||
|
* All use 'prompt-template' type with preset configurations
|
||||||
|
*/
|
||||||
|
export const QUICK_TEMPLATES: QuickTemplate[] = [
|
||||||
|
{
|
||||||
|
id: 'analysis',
|
||||||
|
label: 'Analysis',
|
||||||
|
description: 'Code review, architecture analysis',
|
||||||
|
icon: 'Search',
|
||||||
|
color: 'bg-emerald-500',
|
||||||
|
data: {
|
||||||
|
label: 'Analyze',
|
||||||
|
instruction: 'Analyze the code for:\n1. Architecture patterns\n2. Code quality\n3. Potential issues',
|
||||||
|
tool: 'gemini',
|
||||||
|
mode: 'analysis',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'implementation',
|
||||||
|
label: 'Implementation',
|
||||||
|
description: 'Write code, create files',
|
||||||
|
icon: 'Code',
|
||||||
|
color: 'bg-violet-500',
|
||||||
|
data: {
|
||||||
|
label: 'Implement',
|
||||||
|
instruction: 'Implement the following:\n\n[Describe what to implement]',
|
||||||
|
tool: 'codex',
|
||||||
|
mode: 'write',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'file-operation',
|
||||||
|
label: 'File Operation',
|
||||||
|
description: 'Save, read, or transform files',
|
||||||
|
icon: 'FileOutput',
|
||||||
|
color: 'bg-amber-500',
|
||||||
|
data: {
|
||||||
|
label: 'Save Output',
|
||||||
|
instruction: 'Save {{previous_output}} to ./output/result.md\n\nFormat as markdown with summary.',
|
||||||
|
mode: 'write',
|
||||||
|
contextRefs: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'conditional',
|
||||||
|
label: 'Conditional',
|
||||||
|
description: 'Branch based on condition',
|
||||||
|
icon: 'GitBranch',
|
||||||
|
color: 'bg-orange-500',
|
||||||
|
data: {
|
||||||
|
label: 'Decision',
|
||||||
|
instruction: 'If {{previous.status}} === "success":\n Continue to next step\nElse:\n Stop and report error',
|
||||||
|
mode: 'mainprocess',
|
||||||
|
contextRefs: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'parallel',
|
||||||
|
label: 'Parallel Start',
|
||||||
|
description: 'Fork into parallel branches',
|
||||||
|
icon: 'GitFork',
|
||||||
|
color: 'bg-cyan-500',
|
||||||
|
data: {
|
||||||
|
label: 'Parallel Tasks',
|
||||||
|
instruction: 'Execute the following tasks in parallel:\n1. [Task A]\n2. [Task B]\n3. [Task C]',
|
||||||
|
mode: 'mainprocess',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'merge',
|
||||||
|
label: 'Merge Results',
|
||||||
|
description: 'Combine parallel outputs',
|
||||||
|
icon: 'GitMerge',
|
||||||
|
color: 'bg-pink-500',
|
||||||
|
data: {
|
||||||
|
label: 'Merge',
|
||||||
|
instruction: 'Combine results from:\n- {{task_a}}\n- {{task_b}}\n- {{task_c}}\n\nGenerate unified summary.',
|
||||||
|
mode: 'analysis',
|
||||||
|
contextRefs: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
export type Theme = 'light' | 'dark' | 'system';
|
export type Theme = 'light' | 'dark' | 'system';
|
||||||
export type ColorScheme = 'blue' | 'green' | 'orange' | 'purple';
|
export type ColorScheme = 'blue' | 'green' | 'orange' | 'purple';
|
||||||
|
export type GradientLevel = 'off' | 'standard' | 'enhanced';
|
||||||
export type Locale = 'en' | 'zh';
|
export type Locale = 'en' | 'zh';
|
||||||
export type ViewMode = 'sessions' | 'liteTasks' | 'project-overview' | 'sessionDetail' | 'liteTaskDetail' | 'loop-monitor' | 'issue-manager' | 'orchestrator';
|
export type ViewMode = 'sessions' | 'liteTasks' | 'project-overview' | 'sessionDetail' | 'liteTaskDetail' | 'loop-monitor' | 'issue-manager' | 'orchestrator';
|
||||||
export type SessionFilter = 'all' | 'active' | 'archived';
|
export type SessionFilter = 'all' | 'active' | 'archived';
|
||||||
@@ -42,6 +43,11 @@ export interface AppState {
|
|||||||
customHue: number | null; // Custom hue value (0-360) for theme customization
|
customHue: number | null; // Custom hue value (0-360) for theme customization
|
||||||
isCustomTheme: boolean; // Indicates if custom theme is active
|
isCustomTheme: boolean; // Indicates if custom theme is active
|
||||||
|
|
||||||
|
// Gradient settings
|
||||||
|
gradientLevel: GradientLevel; // Gradient intensity: off, standard, enhanced
|
||||||
|
enableHoverGlow: boolean; // Enable hover glow effects
|
||||||
|
enableBackgroundAnimation: boolean; // Enable background gradient animation
|
||||||
|
|
||||||
// Locale
|
// Locale
|
||||||
locale: Locale;
|
locale: Locale;
|
||||||
|
|
||||||
@@ -72,6 +78,11 @@ export interface AppActions {
|
|||||||
setColorScheme: (scheme: ColorScheme) => void; // New: set color scheme
|
setColorScheme: (scheme: ColorScheme) => void; // New: set color scheme
|
||||||
setCustomHue: (hue: number | null) => void; // Set custom hue for theme customization
|
setCustomHue: (hue: number | null) => void; // Set custom hue for theme customization
|
||||||
|
|
||||||
|
// Gradient settings actions
|
||||||
|
setGradientLevel: (level: GradientLevel) => void;
|
||||||
|
setEnableHoverGlow: (enabled: boolean) => void;
|
||||||
|
setEnableBackgroundAnimation: (enabled: boolean) => void;
|
||||||
|
|
||||||
// Locale actions
|
// Locale actions
|
||||||
setLocale: (locale: Locale) => void;
|
setLocale: (locale: Locale) => void;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user