"use client"; import React, { useState, useMemo } from "react"; import ToolLayout from "@/components/ToolLayout"; interface ColorStop { id: string; color: string; stop: number; } type GradientType = "linear" | "radial"; interface Preset { name: string; type: GradientType; angle?: number; shape?: "circle" | "ellipse"; position?: string; stops: { color: string; stop: number }[]; } const PRESETS: Preset[] = [ { name: "Ocean Blue", type: "linear", angle: 135, stops: [ { color: "#2563eb", stop: 0 }, { color: "#06b6d4", stop: 100 }, ], }, { name: "Sunset Glow", type: "linear", angle: 135, stops: [ { color: "#f97316", stop: 0 }, { color: "#ec4899", stop: 100 }, ], }, { name: "Purple Haze", type: "linear", angle: 135, stops: [ { color: "#6366f1", stop: 0 }, { color: "#a855f7", stop: 50 }, { color: "#ec4899", stop: 100 }, ], }, { name: "Emerald Forest", type: "linear", angle: 135, stops: [ { color: "#059669", stop: 0 }, { color: "#10b981", stop: 50 }, { color: "#6ee7b7", stop: 100 }, ], }, { name: "Neon Cyber", type: "linear", angle: 90, stops: [ { color: "#00f2fe", stop: 0 }, { color: "#4facfe", stop: 100 }, ], }, { name: "Flame", type: "linear", angle: 45, stops: [ { color: "#f12711", stop: 0 }, { color: "#f5af19", stop: 100 }, ], }, { name: "Radial Glow", type: "radial", shape: "circle", position: "center", stops: [ { color: "#3b82f6", stop: 0 }, { color: "#1e1b4b", stop: 100 }, ], }, { name: "Midnight Aura", type: "radial", shape: "circle", position: "center", stops: [ { color: "#8b5cf6", stop: 0 }, { color: "#0f172a", stop: 100 }, ], }, ]; const LINEAR_DIRECTIONS = [ { label: "→ Right", angle: 90, cssDir: "to right" }, { label: "← Left", angle: 270, cssDir: "to left" }, { label: "↓ Bottom", angle: 180, cssDir: "to bottom" }, { label: "↑ Top", angle: 0, cssDir: "to top" }, { label: "↗ Top Right", angle: 45, cssDir: "to top right" }, { label: "↘ Bottom Right", angle: 135, cssDir: "to bottom right" }, { label: "↙ Bottom Left", angle: 225, cssDir: "to bottom left" }, { label: "↖ Top Left", angle: 315, cssDir: "to top left" }, ]; const RADIAL_POSITIONS = [ { label: "Center", value: "center" }, { label: "Top", value: "top center" }, { label: "Bottom", value: "bottom center" }, { label: "Left", value: "center left" }, { label: "Right", value: "center right" }, { label: "Top Left", value: "top left" }, { label: "Top Right", value: "top right" }, { label: "Bottom Left", value: "bottom left" }, { label: "Bottom Right", value: "bottom right" }, ]; export default function CssGradientGeneratorPage() { const [gradientType, setGradientType] = useState("linear"); const [angle, setAngle] = useState(135); const [radialShape, setRadialShape] = useState<"circle" | "ellipse">("circle"); const [radialPosition, setRadialPosition] = useState("center"); const [colorStops, setColorStops] = useState([ { id: "1", color: "#3b82f6", stop: 0 }, { id: "2", color: "#8b5cf6", stop: 100 }, ]); const [copied, setCopied] = useState(false); const [previewText, setPreviewText] = useState(true); const [codeFormat, setCodeFormat] = useState<"standard" | "full" | "tailwind">("standard"); // Sort stops for rendering CSS const sortedStops = useMemo(() => { return [...colorStops].sort((a, b) => a.stop - b.stop); }, [colorStops]); // Construct CSS gradient value const gradientValue = useMemo(() => { const stopsString = sortedStops .map((s) => `${s.color} ${s.stop}%`) .join(", "); if (gradientType === "linear") { return `linear-gradient(${angle}deg, ${stopsString})`; } else { return `radial-gradient(${radialShape} at ${radialPosition}, ${stopsString})`; } }, [gradientType, angle, radialShape, radialPosition, sortedStops]); // Output CSS code block const generatedCode = useMemo(() => { const fallbackColor = sortedStops[0]?.color || "#3b82f6"; if (codeFormat === "tailwind") { return `className="bg-[${gradientValue}]"`; } if (codeFormat === "full") { return `/* Fallback for older browsers */\nbackground-color: ${fallbackColor};\n\n/* Modern CSS Gradient */\nbackground: ${gradientValue};`; } return `background: ${gradientValue};`; }, [gradientValue, sortedStops, codeFormat]); const handleCopy = async () => { try { await navigator.clipboard.writeText(generatedCode); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch { // Fallback const textArea = document.createElement("textarea"); textArea.value = generatedCode; document.body.appendChild(textArea); textArea.select(); document.execCommand("copy"); document.body.removeChild(textArea); setCopied(true); setTimeout(() => setCopied(false), 2000); } }; const updateStopColor = (id: string, newColor: string) => { setColorStops((prev) => prev.map((stop) => (stop.id === id ? { ...stop, color: newColor } : stop)) ); }; const updateStopPosition = (id: string, newStop: number) => { const clamped = Math.max(0, Math.min(100, isNaN(newStop) ? 0 : newStop)); setColorStops((prev) => prev.map((stop) => (stop.id === id ? { ...stop, stop: clamped } : stop)) ); }; const addColorStop = () => { if (colorStops.length >= 6) return; // Pick a midpoint or random color const newId = Date.now().toString(); if (colorStops.length === 2) { // Add a nice middle color const middleColor = "#ec4899"; setColorStops([ colorStops[0], { id: newId, color: middleColor, stop: 50 }, colorStops[1], ]); } else { const lastStop = colorStops[colorStops.length - 1]; const secondLast = colorStops[colorStops.length - 2]; const midPosition = Math.round((lastStop.stop + (secondLast?.stop ?? 0)) / 2); setColorStops((prev) => [ ...prev, { id: newId, color: "#10b981", stop: midPosition }, ]); } }; const removeColorStop = (id: string) => { if (colorStops.length <= 2) return; setColorStops((prev) => prev.filter((stop) => stop.id !== id)); }; const reverseColors = () => { setColorStops((prev) => { const reversed = [...prev].reverse(); return reversed.map((stop, idx) => ({ ...stop, stop: prev[idx].stop, })); }); }; const generateRandomGradient = () => { const randomHex = () => "#" + Math.floor(Math.random() * 16777215) .toString(16) .padStart(6, "0"); const count = colorStops.length; const newStops = colorStops.map((stop, idx) => ({ ...stop, color: randomHex(), stop: Math.round((idx / (count - 1)) * 100), })); setColorStops(newStops); if (gradientType === "linear") { setAngle(Math.floor(Math.random() * 360)); } }; const applyPreset = (preset: Preset) => { setGradientType(preset.type); if (preset.angle !== undefined) setAngle(preset.angle); if (preset.shape) setRadialShape(preset.shape); if (preset.position) setRadialPosition(preset.position); setColorStops( preset.stops.map((s, idx) => ({ id: (idx + 1).toString(), color: s.color, stop: s.stop, })) ); }; return (
{/* Live Preview Area */}

Live Preview

{previewText && (

CSS Gradient Preview

{gradientType === "linear" ? `${angle}° Linear` : `Radial ${radialShape}`}

)}
{/* Presets Gallery */}

Quick Presets

{PRESETS.map((preset) => { const bgString = preset.type === "linear" ? `linear-gradient(${preset.angle}deg, ${preset.stops.map((s) => `${s.color} ${s.stop}%`).join(", ")})` : `radial-gradient(${preset.shape} at ${preset.position}, ${preset.stops.map((s) => `${s.color} ${s.stop}%`).join(", ")})`; return ( ); })}
{/* Editor Controls Grid */}
{/* Left Column: Type & Direction Settings */}
{/* Gradient Type */}
{/* Linear Direction Options */} {gradientType === "linear" && (
setAngle(Number(e.target.value) % 361)} className="w-20 px-2 py-1 text-sm font-mono text-right rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:outline-none" />
setAngle(Number(e.target.value))} className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700 accent-blue-600" />
{/* Quick Direction Selector */}
{LINEAR_DIRECTIONS.map((dir) => ( ))}
)} {/* Radial Options */} {gradientType === "radial" && (
)}
{/* Right Column: Color Stops */}

Color Stops ({colorStops.length})

Customize start, middle, and end colors with position stops.

{/* Stops List */}
{colorStops.map((stop, index) => { const label = index === 0 ? "Start Color" : index === colorStops.length - 1 ? "End Color" : `Stop ${index + 1} (Middle)`; return (
{label}
{colorStops.length > 2 && ( )}
{/* Color Picker and Hex Input */}
updateStopColor(stop.id, e.target.value)} className="absolute -top-2 -left-2 w-14 h-14 cursor-pointer border-0" />
updateStopColor(stop.id, e.target.value)} className="w-full px-2.5 py-1.5 text-xs font-mono rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:outline-none uppercase" placeholder="#000000" />
{/* Position Slider and Input */}
updateStopPosition(stop.id, Number(e.target.value))} className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700 accent-blue-600" />
updateStopPosition(stop.id, Number(e.target.value))} className="w-14 px-1.5 py-1 text-xs font-mono text-right rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:outline-none" /> %
); })}
{/* Generated CSS Output Block */}

Generated CSS

              {generatedCode}
            
); }