mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 08:33:36 +00:00
Merge branch 'main' into feat/claude-usage-clean
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Palette } from "lucide-react";
|
||||
import { themeOptions } from "@/config/theme-options";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { Theme, Project } from "../shared/types";
|
||||
import { useState } from 'react';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Palette, Moon, Sun } from 'lucide-react';
|
||||
import { darkThemes, lightThemes } from '@/config/theme-options';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { Theme, Project } from '../shared/types';
|
||||
|
||||
interface AppearanceSectionProps {
|
||||
effectiveTheme: Theme;
|
||||
@@ -15,13 +16,17 @@ export function AppearanceSection({
|
||||
currentProject,
|
||||
onThemeChange,
|
||||
}: AppearanceSectionProps) {
|
||||
const [activeTab, setActiveTab] = useState<'dark' | 'light'>('dark');
|
||||
|
||||
const themesToShow = activeTab === 'dark' ? darkThemes : lightThemes;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-2xl overflow-hidden",
|
||||
"border border-border/50",
|
||||
"bg-gradient-to-br from-card/90 via-card/70 to-card/80 backdrop-blur-xl",
|
||||
"shadow-sm shadow-black/5"
|
||||
'rounded-2xl overflow-hidden',
|
||||
'border border-border/50',
|
||||
'bg-gradient-to-br from-card/90 via-card/70 to-card/80 backdrop-blur-xl',
|
||||
'shadow-sm shadow-black/5'
|
||||
)}
|
||||
>
|
||||
<div className="p-6 border-b border-border/50 bg-gradient-to-r from-transparent via-accent/5 to-transparent">
|
||||
@@ -37,43 +42,69 @@ export function AppearanceSection({
|
||||
</div>
|
||||
<div className="p-6 space-y-4">
|
||||
<div className="space-y-4">
|
||||
<Label className="text-foreground font-medium">
|
||||
Theme{" "}
|
||||
<span className="text-muted-foreground font-normal">
|
||||
{currentProject ? `(for ${currentProject.name})` : "(Global)"}
|
||||
</span>
|
||||
</Label>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-foreground font-medium">
|
||||
Theme{' '}
|
||||
<span className="text-muted-foreground font-normal">
|
||||
{currentProject ? `(for ${currentProject.name})` : '(Global)'}
|
||||
</span>
|
||||
</Label>
|
||||
{/* Dark/Light Tabs */}
|
||||
<div className="flex gap-1 p-1 rounded-lg bg-accent/30">
|
||||
<button
|
||||
onClick={() => setActiveTab('dark')}
|
||||
className={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200',
|
||||
activeTab === 'dark'
|
||||
? 'bg-brand-500 text-white shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<Moon className="w-3.5 h-3.5" />
|
||||
Dark
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('light')}
|
||||
className={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200',
|
||||
activeTab === 'light'
|
||||
? 'bg-brand-500 text-white shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<Sun className="w-3.5 h-3.5" />
|
||||
Light
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
{themeOptions.map(({ value, label, Icon, testId }) => {
|
||||
{themesToShow.map(({ value, label, Icon, testId, color }) => {
|
||||
const isActive = effectiveTheme === value;
|
||||
return (
|
||||
<button
|
||||
key={value}
|
||||
onClick={() => onThemeChange(value)}
|
||||
className={cn(
|
||||
"group flex items-center justify-center gap-2.5 px-4 py-3.5 rounded-xl",
|
||||
"text-sm font-medium transition-all duration-200 ease-out",
|
||||
'group flex items-center justify-center gap-2.5 px-4 py-3.5 rounded-xl',
|
||||
'text-sm font-medium transition-all duration-200 ease-out',
|
||||
isActive
|
||||
? [
|
||||
"bg-gradient-to-br from-brand-500/15 to-brand-600/10",
|
||||
"border-2 border-brand-500/40",
|
||||
"text-foreground",
|
||||
"shadow-md shadow-brand-500/10",
|
||||
'bg-gradient-to-br from-brand-500/15 to-brand-600/10',
|
||||
'border-2 border-brand-500/40',
|
||||
'text-foreground',
|
||||
'shadow-md shadow-brand-500/10',
|
||||
]
|
||||
: [
|
||||
"bg-accent/30 hover:bg-accent/50",
|
||||
"border border-border/50 hover:border-border",
|
||||
"text-muted-foreground hover:text-foreground",
|
||||
"hover:shadow-sm",
|
||||
'bg-accent/30 hover:bg-accent/50',
|
||||
'border border-border/50 hover:border-border',
|
||||
'text-muted-foreground hover:text-foreground',
|
||||
'hover:shadow-sm',
|
||||
],
|
||||
"hover:scale-[1.02] active:scale-[0.98]"
|
||||
'hover:scale-[1.02] active:scale-[0.98]'
|
||||
)}
|
||||
data-testid={testId}
|
||||
>
|
||||
<Icon className={cn(
|
||||
"w-4 h-4 transition-all duration-200",
|
||||
isActive ? "text-brand-500" : "group-hover:text-brand-400"
|
||||
)} />
|
||||
<Icon className="w-4 h-4 transition-all duration-200" style={{ color }} />
|
||||
<span>{label}</span>
|
||||
</button>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// Shared TypeScript types for settings view components
|
||||
// Theme type is now imported from the central theme-options config
|
||||
export { type Theme } from '@/config/theme-options';
|
||||
|
||||
export interface CliStatus {
|
||||
success: boolean;
|
||||
@@ -17,31 +19,13 @@ export interface CliStatus {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export type Theme =
|
||||
| "dark"
|
||||
| "light"
|
||||
| "retro"
|
||||
| "dracula"
|
||||
| "nord"
|
||||
| "monokai"
|
||||
| "tokyonight"
|
||||
| "solarized"
|
||||
| "gruvbox"
|
||||
| "catppuccin"
|
||||
| "onedark"
|
||||
| "synthwave"
|
||||
| "red"
|
||||
| "cream"
|
||||
| "sunset"
|
||||
| "gray";
|
||||
|
||||
export type KanbanDetailLevel = "minimal" | "standard" | "detailed";
|
||||
export type KanbanDetailLevel = 'minimal' | 'standard' | 'detailed';
|
||||
|
||||
export interface Project {
|
||||
id: string;
|
||||
name: string;
|
||||
path: string;
|
||||
theme?: Theme;
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
export interface ApiKeys {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ArrowRight, ArrowLeft, Check } from "lucide-react";
|
||||
import { themeOptions } from "@/config/theme-options";
|
||||
import { useAppStore } from "@/store/app-store";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ArrowRight, ArrowLeft, Check, Moon, Sun } from 'lucide-react';
|
||||
import { darkThemes, lightThemes } from '@/config/theme-options';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface ThemeStepProps {
|
||||
onNext: () => void;
|
||||
@@ -11,6 +12,7 @@ interface ThemeStepProps {
|
||||
|
||||
export function ThemeStep({ onNext, onBack }: ThemeStepProps) {
|
||||
const { theme, setTheme, setPreviewTheme } = useAppStore();
|
||||
const [activeTab, setActiveTab] = useState<'dark' | 'light'>('dark');
|
||||
|
||||
const handleThemeHover = (themeValue: string) => {
|
||||
setPreviewTheme(themeValue as typeof theme);
|
||||
@@ -25,19 +27,47 @@ export function ThemeStep({ onNext, onBack }: ThemeStepProps) {
|
||||
setPreviewTheme(null);
|
||||
};
|
||||
|
||||
const themesToShow = activeTab === 'dark' ? darkThemes : lightThemes;
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="text-center">
|
||||
<h2 className="text-3xl font-bold text-foreground mb-3">
|
||||
Choose Your Theme
|
||||
</h2>
|
||||
<h2 className="text-3xl font-bold text-foreground mb-3">Choose Your Theme</h2>
|
||||
<p className="text-muted-foreground max-w-md mx-auto">
|
||||
Pick a theme that suits your style. Hover to preview, click to select.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Dark/Light Tabs */}
|
||||
<div className="flex justify-center gap-2">
|
||||
<button
|
||||
onClick={() => setActiveTab('dark')}
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-6 py-2.5 rounded-lg font-medium transition-all duration-200',
|
||||
activeTab === 'dark'
|
||||
? 'bg-brand-500 text-white shadow-lg shadow-brand-500/25'
|
||||
: 'bg-accent/50 text-muted-foreground hover:bg-accent hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<Moon className="w-4 h-4" />
|
||||
Dark Themes
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('light')}
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-6 py-2.5 rounded-lg font-medium transition-all duration-200',
|
||||
activeTab === 'light'
|
||||
? 'bg-brand-500 text-white shadow-lg shadow-brand-500/25'
|
||||
: 'bg-accent/50 text-muted-foreground hover:bg-accent hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<Sun className="w-4 h-4" />
|
||||
Light Themes
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3">
|
||||
{themeOptions.map((option) => {
|
||||
{themesToShow.map((option) => {
|
||||
const Icon = option.Icon;
|
||||
const isSelected = theme === option.value;
|
||||
|
||||
@@ -49,11 +79,11 @@ export function ThemeStep({ onNext, onBack }: ThemeStepProps) {
|
||||
onMouseLeave={handleThemeLeave}
|
||||
onClick={() => handleThemeClick(option.value)}
|
||||
className={cn(
|
||||
"relative flex flex-col items-center gap-2 p-4 rounded-lg border-2 transition-all duration-200",
|
||||
"hover:scale-105 hover:shadow-lg",
|
||||
'relative flex flex-col items-center gap-2 p-4 rounded-lg border-2 transition-all duration-200',
|
||||
'hover:scale-105 hover:shadow-lg',
|
||||
isSelected
|
||||
? "border-brand-500 bg-brand-500/10"
|
||||
: "border-border hover:border-brand-400 bg-card"
|
||||
? 'border-brand-500 bg-brand-500/10'
|
||||
: 'border-border hover:border-brand-400 bg-card'
|
||||
)}
|
||||
>
|
||||
{isSelected && (
|
||||
@@ -61,10 +91,8 @@ export function ThemeStep({ onNext, onBack }: ThemeStepProps) {
|
||||
<Check className="w-4 h-4 text-brand-500" />
|
||||
</div>
|
||||
)}
|
||||
<Icon className="w-6 h-6 text-foreground" />
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
{option.label}
|
||||
</span>
|
||||
<Icon className="w-6 h-6" style={{ color: option.color }} />
|
||||
<span className="text-sm font-medium text-foreground">{option.label}</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user