refactor: externalize AppPage component and streamline all tool pages
This commit is contained in:
@@ -1,17 +1,13 @@
|
||||
import { FigletConverter } from '@/components/figlet/FigletConverter';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
|
||||
export default function FigletPage() {
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Figlet ASCII</h1>
|
||||
<p className="text-muted-foreground">
|
||||
ASCII Art Text Generator with 373 Fonts
|
||||
</p>
|
||||
</div>
|
||||
<AppPage
|
||||
title="Figlet ASCII"
|
||||
description="ASCII Art Text Generator with 373 Fonts"
|
||||
>
|
||||
<FigletConverter />
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import { FileConverter } from '@/components/media/FileConverter';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
|
||||
export default function MediaPage() {
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Media Converter</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Professional browser-based media conversion for video, audio, and images
|
||||
</p>
|
||||
</div>
|
||||
<AppPage
|
||||
title="Media Converter"
|
||||
description="Professional browser-based media conversion for video, audio, and images"
|
||||
>
|
||||
<FileConverter />
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { PaletteGrid } from '@/components/pastel/PaletteGrid';
|
||||
import { ExportMenu } from '@/components/pastel/ExportMenu';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { useLighten, useDarken, useSaturate, useDesaturate, useRotate } from '@/lib/pastel/api/queries';
|
||||
import { Loader2, Upload, Download } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -92,15 +93,10 @@ export default function BatchPage() {
|
||||
rotateMutation.isPending;
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Batch Operations</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Process multiple colors at once with manipulation operations
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AppPage
|
||||
title="Batch Operations"
|
||||
description="Process multiple colors at once with manipulation operations"
|
||||
>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* Input */}
|
||||
<div className="space-y-6">
|
||||
@@ -213,7 +209,6 @@ export default function BatchPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { useSimulateColorBlindness } from '@/lib/pastel/api/queries';
|
||||
import { Loader2, Eye, Plus, X } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -66,15 +67,10 @@ export default function ColorBlindPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Color Blindness Simulator</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Simulate how colors appear with different types of color blindness
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AppPage
|
||||
title="Color Blindness Simulator"
|
||||
description="Simulate how colors appear with different types of color blindness"
|
||||
>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* Controls */}
|
||||
<div className="space-y-6">
|
||||
@@ -229,7 +225,6 @@ export default function ColorBlindPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ColorPicker } from '@/components/pastel/ColorPicker';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { getContrastRatio, hexToRgb, checkWCAGCompliance } from '@/lib/pastel/utils/color';
|
||||
import { ArrowLeftRight, Check, X } from 'lucide-react';
|
||||
|
||||
@@ -57,15 +58,10 @@ export default function ContrastPage() {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Contrast Checker</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Test color combinations for WCAG 2.1 compliance
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AppPage
|
||||
title="Contrast Checker"
|
||||
description="Test color combinations for WCAG 2.1 compliance"
|
||||
>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* Color Pickers */}
|
||||
<div className="space-y-6">
|
||||
@@ -183,7 +179,6 @@ export default function ContrastPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { useGenerateDistinct } from '@/lib/pastel/api/queries';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -38,15 +39,10 @@ export default function DistinctPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Distinct Colors Generator</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Generate visually distinct colors using simulated annealing
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AppPage
|
||||
title="Distinct Colors Generator"
|
||||
description="Generate visually distinct colors using simulated annealing"
|
||||
>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Controls */}
|
||||
<div className="lg:col-span-1">
|
||||
@@ -137,7 +133,6 @@ export default function DistinctPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ExportMenu } from '@/components/pastel/ExportMenu';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { useGenerateGradient } from '@/lib/pastel/api/queries';
|
||||
import { Loader2, Plus, X } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -48,15 +49,10 @@ export default function GradientPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Gradient Creator</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Create smooth color gradients with multiple stops
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AppPage
|
||||
title="Gradient Creator"
|
||||
description="Create smooth color gradients with multiple stops"
|
||||
>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* Controls */}
|
||||
<div className="space-y-6">
|
||||
@@ -169,7 +165,6 @@ export default function GradientPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { useGeneratePalette } from '@/lib/pastel/api/queries';
|
||||
import { Loader2, Palette } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -59,15 +60,10 @@ export default function HarmonyPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Harmony Palette Generator</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Create color harmonies based on color theory principles
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AppPage
|
||||
title="Harmony Palette Generator"
|
||||
description="Create color harmonies based on color theory principles"
|
||||
>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* Controls */}
|
||||
<div className="space-y-6">
|
||||
@@ -160,7 +156,6 @@ export default function HarmonyPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { useNamedColors } from '@/lib/pastel/api/queries';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { parse_color } from '@valknarthing/pastel-wasm';
|
||||
@@ -44,15 +45,11 @@ export default function NamedColorsPage() {
|
||||
}, [data, search, sortBy]);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Named Colors</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Explore 148 CSS/X11 named colors
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AppPage
|
||||
title="Named Colors"
|
||||
description="Explore 148 CSS/X11 named colors"
|
||||
>
|
||||
<div className="space-y-8">
|
||||
{/* Search and Filters */}
|
||||
<div className="flex flex-col sm:flex-row gap-4">
|
||||
<div className="flex-1">
|
||||
@@ -120,6 +117,6 @@ export default function NamedColorsPage() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ColorDisplay } from '@/components/pastel/ColorDisplay';
|
||||
import { ColorInfo } from '@/components/pastel/ColorInfo';
|
||||
import { ManipulationPanel } from '@/components/pastel/ManipulationPanel';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { useColorInfo } from '@/lib/pastel/api/queries';
|
||||
import { useColorHistory } from '@/lib/pastel/stores/historyStore';
|
||||
import { Loader2, Share2, History, X } from 'lucide-react';
|
||||
@@ -73,15 +74,10 @@ function PlaygroundContent() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Pastel</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Interactive color manipulation and analysis tool
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AppPage
|
||||
title="Pastel"
|
||||
description="Interactive color manipulation and analysis tool"
|
||||
>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* Left Column: Color Picker and Display */}
|
||||
<div className="space-y-6">
|
||||
@@ -197,8 +193,7 @@ function PlaygroundContent() {
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ColorPicker } from '@/components/pastel/ColorPicker';
|
||||
import { ColorDisplay } from '@/components/pastel/ColorDisplay';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { useTextColor } from '@/lib/pastel/api/queries';
|
||||
import { Loader2, Palette, Plus, X, CheckCircle2, XCircle } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -55,15 +56,10 @@ export default function TextColorPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Text Color Optimizer</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Automatically find the best text color (black or white) for any background color
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<AppPage
|
||||
title="Text Color Optimizer"
|
||||
description="Automatically find the best text color (black or white) for any background color"
|
||||
>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* Input */}
|
||||
<div className="space-y-6">
|
||||
@@ -226,7 +222,6 @@ export default function TextColorPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import MainConverter from '@/components/units/MainConverter';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
|
||||
export default function UnitsPage() {
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Units Converter</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Smart unit converter with 187 units across 23 categories
|
||||
</p>
|
||||
</div>
|
||||
<AppPage
|
||||
title="Units Converter"
|
||||
description="Smart unit converter with 187 units across 23 categories"
|
||||
>
|
||||
<MainConverter />
|
||||
</div>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
29
components/layout/AppPage.tsx
Normal file
29
components/layout/AppPage.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface AppPageProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function AppPage({ title, description, children, className }: AppPageProps) {
|
||||
return (
|
||||
<div className={cn("min-h-screen py-12", className)}>
|
||||
<div className="max-w-7xl mx-auto px-8 space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">{title}</h1>
|
||||
{description && (
|
||||
<p className="text-muted-foreground">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user