refactor: streamline, refine and polish
This commit is contained in:
@@ -13,6 +13,7 @@ import { useColorInfo, useGeneratePalette, useGenerateGradient } from '@/lib/col
|
||||
import { Loader2, Share2, Palette, Plus, X, Layers } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -137,37 +138,36 @@ function PlaygroundContent() {
|
||||
title="Color"
|
||||
description="Interactive color manipulation and analysis tool"
|
||||
>
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-6">
|
||||
{/* Row 1: Workspace */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8 items-stretch">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 items-stretch">
|
||||
{/* Main Workspace: Color Picker and Information */}
|
||||
<div className="lg:col-span-2">
|
||||
<Card className="h-full">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0">
|
||||
<CardTitle>Color Picker</CardTitle>
|
||||
<Button onClick={handleShare} variant="outline" size="sm">
|
||||
<Share2 className="h-4 w-4 mr-2" />
|
||||
<Button onClick={handleShare} variant="outline" size="xs">
|
||||
<Share2 className="h-3 w-3 mr-1" />
|
||||
Share
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex flex-col md:flex-row gap-12">
|
||||
<div className="flex flex-col md:flex-row gap-8">
|
||||
<div className="flex-shrink-0 mx-auto md:mx-0">
|
||||
<ColorPicker color={color} onChange={setColor} />
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<h3 className="text-sm font-medium mb-4 text-muted-foreground uppercase tracking-wider">Color Information</h3>
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
{isLoading && (
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
||||
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isError && (
|
||||
<div className="p-4 bg-destructive/10 text-destructive rounded-lg">
|
||||
<div className="p-3 bg-destructive/10 text-destructive rounded-lg text-sm">
|
||||
<p className="font-medium">Error loading color information</p>
|
||||
<p className="text-sm mt-1">{error?.message || 'Unknown error'}</p>
|
||||
<p className="mt-1">{error?.message || 'Unknown error'}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -182,7 +182,7 @@ function PlaygroundContent() {
|
||||
<div className="lg:col-span-1">
|
||||
<Card className="h-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Color Manipulation</CardTitle>
|
||||
<CardTitle>Adjustments</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ManipulationPanel color={color} onColorChange={setColor} />
|
||||
@@ -192,15 +192,12 @@ function PlaygroundContent() {
|
||||
</div>
|
||||
|
||||
{/* Row 2: Harmony Generator */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8 items-stretch">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 items-stretch">
|
||||
{/* Harmony Controls */}
|
||||
<div className="lg:col-span-1">
|
||||
<Card className="h-full">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Palette className="h-5 w-5" />
|
||||
Harmony Type
|
||||
</CardTitle>
|
||||
<CardTitle>Harmony</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<Select
|
||||
@@ -219,7 +216,7 @@ function PlaygroundContent() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<p className="text-sm text-muted-foreground">
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{harmonyDescriptions[harmonyType]}
|
||||
</p>
|
||||
|
||||
@@ -230,14 +227,11 @@ function PlaygroundContent() {
|
||||
>
|
||||
{paletteMutation.isPending ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Generating..
|
||||
<Loader2 className="h-3.5 w-3.5 mr-1.5 animate-spin" />
|
||||
Generating...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Palette className="mr-2 h-4 w-4" />
|
||||
Generate Harmony
|
||||
</>
|
||||
'Generate'
|
||||
)}
|
||||
</Button>
|
||||
</CardContent>
|
||||
@@ -249,21 +243,21 @@ function PlaygroundContent() {
|
||||
<Card className="h-full">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Generated Palette {palette.length > 0 && `(${palette.length} colors)`}
|
||||
Palette {palette.length > 0 && <span className="text-muted-foreground font-normal text-sm ml-1">({palette.length})</span>}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{palette.length > 0 ? (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-5">
|
||||
<PaletteGrid colors={palette} onColorClick={setColor} />
|
||||
<div className="pt-4 border-t">
|
||||
<div className="pt-3 border-t">
|
||||
<ExportMenu colors={palette} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-12 text-center text-muted-foreground">
|
||||
<Palette className="h-12 w-12 mx-auto mb-4 opacity-50" />
|
||||
<p>Select a harmony type and click Generate to create your palette based on the current color</p>
|
||||
<div className="py-8 text-center text-muted-foreground text-xs">
|
||||
<Palette className="h-8 w-8 mx-auto mb-2 opacity-20" />
|
||||
<p>Generate a harmony palette from the current color</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
@@ -272,74 +266,72 @@ function PlaygroundContent() {
|
||||
</div>
|
||||
|
||||
{/* Row 3: Gradient Generator */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8 items-stretch">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 items-stretch">
|
||||
{/* Gradient Controls */}
|
||||
<div className="lg:col-span-1">
|
||||
<Card className="h-full">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Layers className="h-5 w-5" />
|
||||
Gradient Controls
|
||||
</CardTitle>
|
||||
<CardTitle>Gradient</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-3">
|
||||
<h4 className="text-sm font-medium text-muted-foreground uppercase tracking-wider">Color Stops</h4>
|
||||
{stops.map((stop, index) => (
|
||||
<div key={index} className="flex items-center gap-2">
|
||||
<div className="flex-1">
|
||||
<Input
|
||||
type="color"
|
||||
value={stop}
|
||||
onChange={(e) => updateStop(index, e.target.value)}
|
||||
className="h-10 w-full cursor-pointer p-1"
|
||||
/>
|
||||
</div>
|
||||
{index !== 0 && stops.length > 2 && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => removeStop(index)}
|
||||
className="shrink-0"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<Button onClick={addStop} variant="outline" size="sm" className="w-full">
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
Add Stop
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<h4 className="text-sm font-medium text-muted-foreground uppercase tracking-wider">Steps</h4>
|
||||
<Input
|
||||
type="number"
|
||||
min={2}
|
||||
max={100}
|
||||
value={gradientCount}
|
||||
onChange={(e) => setGradientCount(parseInt(e.target.value))}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
onClick={generateGradient}
|
||||
disabled={gradientMutation.isPending}
|
||||
className="w-full"
|
||||
>
|
||||
{gradientMutation.isPending ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Generating..
|
||||
</>
|
||||
) : (
|
||||
'Generate Gradient'
|
||||
)}
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs">Color Stops</Label>
|
||||
{stops.map((stop, index) => (
|
||||
<div key={index} className="flex items-center gap-2">
|
||||
<Input
|
||||
type="color"
|
||||
value={stop}
|
||||
onChange={(e) => updateStop(index, e.target.value)}
|
||||
className="w-9 h-9 p-1 shrink-0 cursor-pointer"
|
||||
/>
|
||||
<Input
|
||||
type="text"
|
||||
value={stop}
|
||||
onChange={(e) => updateStop(index, e.target.value)}
|
||||
className="font-mono text-xs flex-1"
|
||||
/>
|
||||
{index !== 0 && stops.length > 2 && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
onClick={() => removeStop(index)}
|
||||
>
|
||||
<X className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<Button onClick={addStop} variant="outline" size="sm" className="w-full">
|
||||
<Plus className="h-3.5 w-3.5 mr-1.5" />
|
||||
Add Stop
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs">Steps</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min={2}
|
||||
max={100}
|
||||
value={gradientCount}
|
||||
onChange={(e) => setGradientCount(parseInt(e.target.value))}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
onClick={generateGradient}
|
||||
disabled={gradientMutation.isPending}
|
||||
className="w-full"
|
||||
>
|
||||
{gradientMutation.isPending ? (
|
||||
<>
|
||||
<Loader2 className="h-3.5 w-3.5 mr-1.5 animate-spin" />
|
||||
Generating...
|
||||
</>
|
||||
) : (
|
||||
'Generate'
|
||||
)}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
@@ -349,27 +341,27 @@ function PlaygroundContent() {
|
||||
<Card className="h-full">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Generated Gradient {gradientResult.length > 0 && `(${gradientResult.length} colors)`}
|
||||
Gradient {gradientResult.length > 0 && <span className="text-muted-foreground font-normal text-sm ml-1">({gradientResult.length})</span>}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{gradientResult.length > 0 ? (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-5">
|
||||
<div
|
||||
className="h-24 w-full rounded-lg border shadow-inner"
|
||||
className="h-16 w-full rounded-lg border"
|
||||
style={{
|
||||
background: `linear-gradient(to right, ${gradientResult.join(', ')})`,
|
||||
}}
|
||||
/>
|
||||
<PaletteGrid colors={gradientResult} onColorClick={setColor} />
|
||||
<div className="pt-4 border-t">
|
||||
<div className="pt-3 border-t">
|
||||
<ExportMenu colors={gradientResult} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-12 text-center text-muted-foreground">
|
||||
<Layers className="h-12 w-12 mx-auto mb-4 opacity-50" />
|
||||
<p>Add color stops and click Generate to create your smooth gradient</p>
|
||||
<div className="py-8 text-center text-muted-foreground text-xs">
|
||||
<Layers className="h-8 w-8 mx-auto mb-2 opacity-20" />
|
||||
<p>Add color stops and generate a smooth gradient</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import * as React from 'react';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { FaviconGenerator } from '@/components/favicon/FaviconGenerator';
|
||||
import { Globe, Shield, Zap } from 'lucide-react';
|
||||
|
||||
export default function FaviconPage() {
|
||||
return (
|
||||
@@ -11,9 +10,7 @@ export default function FaviconPage() {
|
||||
title="Favicon Generator"
|
||||
description="Create a complete set of icons for your website including PWA manifest and HTML code."
|
||||
>
|
||||
<div className="w-full max-w-7xl mx-auto space-y-8 pb-12">
|
||||
<FaviconGenerator />
|
||||
</div>
|
||||
<FaviconGenerator />
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import BackToTop from '@/components/BackToTop';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="relative min-h-screen dark text-foreground">
|
||||
<main className="relative min-h-screen text-foreground">
|
||||
<AnimatedBackground />
|
||||
<BackToTop />
|
||||
<Hero />
|
||||
|
||||
Reference in New Issue
Block a user