gradients, colorpicker tabs

This commit is contained in:
Siddharth
2025-10-18 12:02:20 -07:00
parent 5eaa43c247
commit adf22a1408
4 changed files with 197 additions and 30 deletions
+111
View File
@@ -12,6 +12,7 @@
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13",
"@uiw/react-color-colorful": "^2.9.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.545.0",
@@ -309,6 +310,16 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/runtime": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
@@ -2600,6 +2611,106 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@uiw/color-convert": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@uiw/color-convert/-/color-convert-2.9.0.tgz",
"integrity": "sha512-tFm6iac8iN3VL9IIAXKAVpBX6ZQH7ucCvb+EgZNM5y8prRWlk53cERnP4RycE3wnYb/HUKW0lrngoygQnEWAHg==",
"license": "MIT",
"funding": {
"url": "https://jaywcjlove.github.io/#/sponsor"
},
"peerDependencies": {
"@babel/runtime": ">=7.19.0"
}
},
"node_modules/@uiw/react-color-alpha": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@uiw/react-color-alpha/-/react-color-alpha-2.9.0.tgz",
"integrity": "sha512-tP9zs2KUPzIGvdtTBTNlDEdwHWcNJ3Ju/nnpPTsKERRJF2vzucb3v18JzihX0ACiOXU9+JVqgpAVgvoZXMeITA==",
"license": "MIT",
"dependencies": {
"@uiw/color-convert": "2.9.0",
"@uiw/react-drag-event-interactive": "2.9.0"
},
"funding": {
"url": "https://jaywcjlove.github.io/#/sponsor"
},
"peerDependencies": {
"@babel/runtime": ">=7.19.0",
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/@uiw/react-color-colorful": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@uiw/react-color-colorful/-/react-color-colorful-2.9.0.tgz",
"integrity": "sha512-qw7zhgX9J4aydK0hKKLroXMYp0tw3ASNuZM1fQNwXXIpOkEW4zO+PHTkzUBpbII68wGS8tAxsZessTWNpAVi0w==",
"license": "MIT",
"dependencies": {
"@uiw/color-convert": "2.9.0",
"@uiw/react-color-alpha": "2.9.0",
"@uiw/react-color-hue": "2.9.0",
"@uiw/react-color-saturation": "2.9.0"
},
"funding": {
"url": "https://jaywcjlove.github.io/#/sponsor"
},
"peerDependencies": {
"@babel/runtime": ">=7.19.0",
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/@uiw/react-color-hue": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@uiw/react-color-hue/-/react-color-hue-2.9.0.tgz",
"integrity": "sha512-2Ix027ref3ppiVq+OQkbyKr6O8fLTH+n0wEW4xhHfa3kV8mBa2bEu8jAjrkSwO6uElaE6OJcuqYe2llyKRlIFg==",
"license": "MIT",
"dependencies": {
"@uiw/color-convert": "2.9.0",
"@uiw/react-color-alpha": "2.9.0"
},
"funding": {
"url": "https://jaywcjlove.github.io/#/sponsor"
},
"peerDependencies": {
"@babel/runtime": ">=7.19.0",
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/@uiw/react-color-saturation": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@uiw/react-color-saturation/-/react-color-saturation-2.9.0.tgz",
"integrity": "sha512-tBARqsW0ap+gwByGKSid1nYaGJd6dw2MTMwCABF9rebPQHtYbN/YgBjl9dNnp6XDGd+VBhH4RbpM38WV7J1F4g==",
"license": "MIT",
"dependencies": {
"@uiw/color-convert": "2.9.0",
"@uiw/react-drag-event-interactive": "2.9.0"
},
"funding": {
"url": "https://jaywcjlove.github.io/#/sponsor"
},
"peerDependencies": {
"@babel/runtime": ">=7.19.0",
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/@uiw/react-drag-event-interactive": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@uiw/react-drag-event-interactive/-/react-drag-event-interactive-2.9.0.tgz",
"integrity": "sha512-oBqrClsSuYA3IjkSHp4uHOBLgPkR98KeKeheqCRltF8w/a1CPaFCl43pyKyxwXaTV6qM6cb3VkT3JRCHMNqTzA==",
"license": "MIT",
"funding": {
"url": "https://jaywcjlove.github.io/#/sponsor"
},
"peerDependencies": {
"@babel/runtime": ">=7.19.0",
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/@ungap/structured-clone": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
+1
View File
@@ -14,6 +14,7 @@
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13",
"@uiw/react-color-colorful": "^2.9.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.545.0",
+79 -29
View File
@@ -1,50 +1,100 @@
import { cn } from "@/lib/utils";
import { Switch } from "@/components/ui/switch";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useState } from "react";
import Colorful from '@uiw/react-color-colorful';
import { hsvaToHex } from '@uiw/color-convert';
const WALLPAPER_COUNT = 12;
const WALLPAPER_PATHS = Array.from({ length: WALLPAPER_COUNT }, (_, i) => `/wallpapers/wallpaper${i + 1}.jpg`);
const GRADIENTS = [
"linear-gradient( 111.6deg, rgba(114,167,232,1) 9.4%, rgba(253,129,82,1) 43.9%, rgba(253,129,82,1) 54.8%, rgba(249,202,86,1) 86.3% )",
"linear-gradient(120deg, #d4fc79 0%, #96e6a1 100%)",
"radial-gradient( circle farthest-corner at 3.2% 49.6%, rgba(80,12,139,0.87) 0%, rgba(161,10,144,0.72) 83.6% )",
"linear-gradient( 111.6deg, rgba(0,56,68,1) 0%, rgba(163,217,185,1) 51.5%, rgba(231, 148, 6, 1) 88.6% )",
"linear-gradient( 107.7deg, rgba(235,230,44,0.55) 8.4%, rgba(252,152,15,1) 90.3% )",
"linear-gradient( 91deg, rgba(72,154,78,1) 5.2%, rgba(251,206,70,1) 95.9% )",
"radial-gradient( circle farthest-corner at 10% 20%, rgba(2,37,78,1) 0%, rgba(4,56,126,1) 19.7%, rgba(85,245,221,1) 100.2% )",
"linear-gradient( 109.6deg, rgba(15,2,2,1) 11.2%, rgba(36,163,190,1) 91.1% )",
"linear-gradient(135deg, #FBC8B4, #2447B1)",
"linear-gradient(109.6deg, #F635A6, #36D860)",
"linear-gradient(90deg, #FF0101, #4DFF01)",
"linear-gradient(315deg, #EC0101, #5044A9)",
];
interface SettingsPanelProps {
selected: string;
onWallpaperChange: (path: string) => void;
shadowEnabled: boolean;
onShadowChange: (enabled: boolean) => void;
}
export default function SettingsPanel({ selected, onWallpaperChange, shadowEnabled, onShadowChange }: SettingsPanelProps) {
export default function SettingsPanel({ selected, onWallpaperChange }: SettingsPanelProps) {
const [hsva, setHsva] = useState({ h: 0, s: 0, v: 68, a: 1 });
const [gradient, setGradient] = useState<string>(GRADIENTS[0]);
return (
<div className="flex-[3] min-w-0 bg-card border border-border rounded-xl p-8 flex flex-col shadow-sm">
<div className="mb-6">
<div className="flex items-center gap-2 mb-4">
<Switch checked={shadowEnabled} onCheckedChange={onShadowChange} />
<Switch/>
<div className="text-sm">Shadow</div>
</div>
</div>
<div className="mb-6">
<div className="text-lg mb-2">Choose Background</div>
<div className="grid grid-cols-6 gap-3">
{WALLPAPER_PATHS.map((path, idx) => (
<div
key={path}
className={cn(
"aspect-square rounded-lg border-2 overflow-hidden cursor-pointer transition-all w-16 h-16",
selected === path
? "border-primary/40 ring-1 ring-primary/40 scale-105"
: "border-border hover:border-primary/60 hover:scale-105"
)}
style={{ backgroundImage: `url(${path})`, backgroundSize: "cover", backgroundPosition: "center" }}
aria-label={`Wallpaper ${idx + 1}`}
tabIndex={0}
onClick={() => onWallpaperChange(path)}
onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') onWallpaperChange(path); }}
role="button"
/>
))}
</div>
</div>
<div className="flex-1 w-full flex items-center justify-center text-muted-foreground text-base">
Settings
</div>
<Tabs defaultValue="image" className="mb-6">
<TabsList className="mb-4">
<TabsTrigger value="image">Image</TabsTrigger>
<TabsTrigger value="color">Color</TabsTrigger>
<TabsTrigger value="gradient">Gradient</TabsTrigger>
</TabsList>
<TabsContent value="image">
<div className="grid grid-cols-6 gap-3">
{WALLPAPER_PATHS.map((path, idx) => (
<div
key={path}
className={cn(
"aspect-square rounded-lg border-2 overflow-hidden cursor-pointer transition-all w-16 h-16",
selected === path
? "border-primary/40 ring-1 ring-primary/40 scale-105"
: "border-border hover:border-primary/60 hover:scale-105"
)}
style={{ backgroundImage: `url(${path})`, backgroundSize: "cover", backgroundPosition: "center" }}
aria-label={`Wallpaper ${idx + 1}`}
onClick={() => onWallpaperChange(path)}
role="button"
/>
))}
</div>
</TabsContent>
<TabsContent value="color">
<Colorful
color={hsva}
disableAlpha={true}
onChange={(color) => {
setHsva(color.hsva);
onWallpaperChange(hsvaToHex(color.hsva));
}}
/>
</TabsContent>
<TabsContent value="gradient">
<div className="grid grid-cols-6 gap-3">
{GRADIENTS.map((g, idx) => (
<div
key={g}
className={cn(
"aspect-square rounded-lg border-2 overflow-hidden cursor-pointer transition-all w-16 h-16",
gradient === g ? "border-primary ring-1 ring-primary/40 scale-105" : "border-border hover:border-primary/60 hover:scale-105"
)}
style={{ background: g }}
aria-label={`Gradient ${idx + 1}`}
onClick={() => { setGradient(g); onWallpaperChange(g); }}
role="button"
/>
))}
</div>
</TabsContent>
</Tabs>
</div>
);
}
@@ -112,10 +112,15 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
}
};
const isImageUrl = wallpaper?.startsWith('/wallpapers/') || wallpaper?.startsWith('http');
const backgroundStyle = isImageUrl
? { backgroundImage: `url(${wallpaper || '/wallpapers/wallpaper1.jpg'})` }
: { background: wallpaper || '/wallpapers/wallpaper1.jpg' };
return (
<div
className="w-full aspect-video rounded-sm p-12 flex items-center justify-center overflow-hidden bg-cover bg-center"
style={{ backgroundImage: `url(${wallpaper || '/wallpapers/wallpaper1.jpg'})` }}
style={backgroundStyle}
>
<canvas
ref={canvasRef}