Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 2 additions & 14 deletions app/(tools)/background-snippets/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import BackgroundSnippetsGenerator from "@/components/view/background-snippets";
import { siteConfig } from "@/lib/utils";
import type { Metadata } from "next";
import React from "react";
import { ToolPlaygroundShell } from "@/components/common/tool-playground-shell";
export const metadata: Metadata = {
title: "Background Snippets Generator",
description:
Expand Down Expand Up @@ -57,18 +56,7 @@ export const metadata: Metadata = {
},
};
function page() {
return (
<ToolPlaygroundShell
title="Background Snippets Generator"
description="Generate modern CSS snippets for patterned backgrounds."
examples={["Noise", "Grid", "Dots", "Stripes"]}
docs="Use Playground for live editing, Examples to load quick presets, and Export to copy production-ready output."
exportLabel="CSS"
exportCode={`/* export output from active tool */`}
>
<BackgroundSnippetsGenerator />
</ToolPlaygroundShell>
);
return <BackgroundSnippetsGenerator />;
}

export default page;
export default page;
34 changes: 3 additions & 31 deletions app/(tools)/color-lab/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import ClipPathGenerator from "@/components/view/clip-path";
import ColorConverter from "@/components/view/colors";
import { siteConfig } from "@/lib/utils";
import type { Metadata } from "next";
import React, { Suspense } from "react";
import { ToolPlaygroundShell } from "@/components/common/tool-playground-shell";
import React from "react";
export const metadata: Metadata = {
title:
"Color Lab – Generate Color Palettes, Convert Codes & Build Shadcn Themes",
Expand Down Expand Up @@ -69,34 +67,8 @@ export const metadata: Metadata = {
creator: "@naymur_dev",
},
};
const PageLoading = () => {
return (
<>
<div className="mx-auto h-28 w-[50%] animate-pulse rounded-lg border bg-card-bg" />
<div className="mx-auto grid w-[70%] grid-cols-3 gap-5 pt-10 md:grid-cols-6">
{Array.from({ length: 18 }).map((_, index) => (
<div
key={index}
className="h-36 w-full animate-pulse rounded-lg border bg-card-bg"
/>
))}
</div>
</>
);
};
function page() {
return (
<ToolPlaygroundShell
title="Color Lab"
description="Convert HEX/RGB/HSL and generate scales, contrast, and tokens."
examples={["Brand blue", "Sunset orange", "Mint", "Slate"]}
docs="Use Playground for live editing, Examples to load quick presets, and Export to copy production-ready output."
exportLabel="CSS Variables"
exportCode={`/* export output from active tool */`}
>
<ColorConverter />
</ToolPlaygroundShell>
);
return <ColorConverter />;
}

export default page;
export default page;
5 changes: 4 additions & 1 deletion app/(tools)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ function Toolslayout({ children }: { children: React.ReactNode }) {
const isFullPlayground =
pathname === "/svg-line-draw" ||
pathname === "/shadows" ||
pathname === "/clip-paths";
pathname === "/clip-paths" ||
pathname === "/mesh-gradients" ||
pathname === "/background-snippets" ||
pathname === "/color-lab";

return (
<div className="h-screen overflow-hidden bg-white text-black dark:bg-black dark:text-white">
Expand Down
16 changes: 2 additions & 14 deletions app/(tools)/mesh-gradients/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ShaderGradientGenerator } from "@/components/view/mesh-gradient";
import { siteConfig } from "@/lib/utils";
import type { Metadata } from "next";
import React from "react";
import { ToolPlaygroundShell } from "@/components/common/tool-playground-shell";
export const metadata: Metadata = {
title: "Mesh-Gradient Generator",
description:
Expand Down Expand Up @@ -52,18 +51,7 @@ export const metadata: Metadata = {
};

function page() {
return (
<ToolPlaygroundShell
title="Mesh Gradient Generator"
description="Build fluid mesh gradients with draggable color points."
examples={["Aurora", "Sunset", "Neon", "Pastel"]}
docs="Use Playground for live editing, Examples to load quick presets, and Export to copy production-ready output."
exportLabel="CSS"
exportCode={`/* export output from active tool */`}
>
<ShaderGradientGenerator />
</ToolPlaygroundShell>
);
return <ShaderGradientGenerator />;
}

export default page;
export default page;
127 changes: 46 additions & 81 deletions components/view/background-snippets/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@

import { useState } from "react";

import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Switch } from "@/components/ui/switch";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { useMediaQuery } from "@/components/ui/use-media-query";
import ThemeSwitch from "@/components/theme-switcher";
import { useGradientStops } from "@/hooks/use-gradient-stops";
import { cn } from "@/lib/utils";
import { ChevronsDown } from "lucide-react";
import { Bookmark, PanelsTopLeft, Settings2, SidebarClose, SidebarOpen } from "lucide-react";
import { usePathname, useRouter } from "next/navigation";
import { CodeDisplay } from "./code-output/code-display";
import { getFullCode } from "./code-output/code-generator";
import { ColorPickerPopover } from "./color-pickers/color-picker-popover";
import { GradientControls } from "./gradient-controls/gradient-controls";
import { MaskControls } from "./mask-controls/mask-controls";
import { PatternControls } from "./pattern-controls/pattern-controls";
import { type IPreset, presets } from "./preset/data";
import { PresetCard, PresetGallery } from "./preset/preset-gallery";
import type { IPreset } from "./preset/data";
import { PresetGallery } from "./preset/preset-gallery";
import { BackgroundPreview } from "./preview/background-preview";

export default function BackgroundPatternGenerator() {
const isMobile = useMediaQuery("(max-width:1024px)");
const [viewAll, setViewAll] = useState(false);
const [activeSidebarTab, setActiveSidebarTab] = useState<"presets" | "settings" | "saved">("settings");
const [isSidebarExpanded, setIsSidebarExpanded] = useState(true);
const pathname = usePathname();
const router = useRouter();
const [patternType, setPatternType] = useState("grid");
const [bgColor, setBgColor] = useState("#000000");

Expand Down Expand Up @@ -220,68 +226,34 @@ export default function BackgroundPatternGenerator() {

return (
<>
<article className="space-y-3 pb-8">
<h1 className="text-center font-medium text-2xl capitalize sm:text-3xl md:text-5xl">
Experiment with beautiful <br /> background Snippets.
</h1>

<div className="mx-auto flex w-fit items-center justify-center gap-2 font-semibold">
<div className="flex gap-2 rounded-md border bg-card-bg p-2 shadow-[0px_1px_0px_0px_rgba(17,17,26,0.1)] dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0">
Expand
<Switch
id="view-all-switch"
checked={viewAll}
onCheckedChange={setViewAll}
className="bg-main"
/>
</div>
<a
href="#editor"
className="group flex cursor-pointer gap-1 rounded-md border bg-card-bg p-2 text-primary shadow-[0px_1px_0px_0px_rgba(17,17,26,0.1)] hover:bg-accent dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0"
>
Click to Editor
<ChevronsDown />
</a>
</div>
</article>

<div
className={cn(
"xl:overflow-none relative mx-auto grid w-[80%] max-w-screen-lg grid-cols-3 gap-2 overflow-hidden pb-10 sm:gap-4 lg:grid-cols-4 lg:gap-8 lg:pb-10 xl:max-w-screen-xl xl:grid-cols-5 2xl:gap-10",
viewAll ? "h-full" : "h-[28rem]",
)}
>
{!viewAll && (
<div className="absolute bottom-0 left-0 z-10 grid h-60 w-full place-content-center bg-gradient-to-t from-42% from-white dark:from-black" />
)}
{(viewAll ? presets : presets.slice(0, 10)).map((preset) => (
<PresetCard
key={preset.id}
preset={preset}
cardClassName={cn(
" w-full",
viewAll ? "h-28 2xl:h-36" : "h-full 2xl:h-full",
)}
hideName={true}
className="border-0 bg-card-bg p-2 shadow-[0px_1px_0px_0px_rgba(17,17,26,0.1)] lg:p-5 dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)]"
onSelect={handleSelectPreset}
isActive={preset.id === activePresetId}
/>
))}
</div>
{isMobile && (
<p className="pb-2 text-center text-primary/60">
Please use a desktop/laptop to view the Editor.
</p>
)}
<div
className=" mx-auto gap-4 px-3 pb-8 lg:container lg:grid lg:grid-cols-12 lg:px-0 xl:grid-cols-4"
id="editor"
>
{!isMobile && (
<ScrollArea className="inset-shadow-[0_1px_rgb(0_0_0/0.10)] max-h-[95vh] rounded-xl border bg-card-bg p-3 lg:col-span-4 xl:col-span-1 dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0 ">
<div className="h-full w-full overflow-hidden p-3" id="editor">
<div className={cn("relative grid h-full min-h-0 gap-3", isMobile ? "grid-cols-1" : isSidebarExpanded ? "lg:grid-cols-[70px_320px_minmax(0,1fr)]" : "lg:grid-cols-[70px_0px_minmax(0,1fr)]")}>
{!isMobile && <div className="inset-shadow-[0_1px_rgb(0_0_0/0.10)] hidden h-full min-h-0 rounded-lg border bg-card-bg p-2 lg:flex lg:flex-col lg:justify-between dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0">
<div className="space-y-2">{[{ key: "presets", label: "Presets", icon: PanelsTopLeft }, { key: "settings", label: "Settings", icon: Settings2 }, { key: "saved", label: "Saved", icon: Bookmark }].map((item)=><button type="button" key={item.key} onClick={()=>{setIsSidebarExpanded(true);setActiveSidebarTab(item.key as "presets"|"settings"|"saved");}} className={cn("grid h-16 w-full place-items-center rounded-md border px-1 py-1 font-semibold text-[11px]",activeSidebarTab===item.key?"border-primary bg-primary text-primary-foreground":"bg-main")}><item.icon className="h-4 w-4"/><span>{item.label}</span></button>)}</div>
<div className="space-y-2">
<ThemeSwitch className="w-full rounded-lg border bg-white dark:bg-black" />
<Button
type="button"
variant="outline"
size="icon"
className="h-9 w-full shadow-none"
onClick={() => setIsSidebarExpanded((prev) => !prev)}
>
{isSidebarExpanded ? (
<SidebarClose className="h-4 w-4" />
) : (
<SidebarOpen className="h-4 w-4" />
)}
</Button>
<Select value={pathname} onValueChange={(value)=>router.push(value)}>
<SelectTrigger className="h-9 px-2 text-[10px]"><SelectValue placeholder="Go to editor..." /></SelectTrigger>
<SelectContent><SelectItem value="/background-snippets">Background Snippets</SelectItem><SelectItem value="/mesh-gradients">Mesh Gradients</SelectItem><SelectItem value="/color-lab">Color Lab</SelectItem></SelectContent>
</Select>
</div>
</div>}
{!isMobile && <ScrollArea className={cn("inset-shadow-[0_1px_rgb(0_0_0/0.10)] max-h-[95vh] rounded-xl border bg-card-bg p-3 dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0", !isSidebarExpanded && "pointer-events-none w-0 overflow-hidden border-0 p-0 opacity-0")}>
<div className="space-y-3">
<div className="space-y-2 rounded-lg border bg-main p-3">
{activeSidebarTab === "settings" && <div className="space-y-2 rounded-lg border bg-main p-3">
<ColorPickerPopover
color={bgColor}
onChange={setBgColor}
Expand Down Expand Up @@ -338,8 +310,8 @@ export default function BackgroundPatternGenerator() {
maskFade={maskFade}
setMaskFade={setMaskFade}
/>
</div>
<div className="rounded-lg border bg-main">
</div>}
{activeSidebarTab === "settings" && <div className="rounded-lg border bg-main">
<GradientControls
useGradient={useGradient}
setUseGradient={setUseGradient}
Expand All @@ -364,15 +336,13 @@ export default function BackgroundPatternGenerator() {
setDragIndex={setDragIndex}
dragIndex={dragIndex}
/>
</div>
{/* <div className="bg-main rounded-lg border">

</div> */}
</div>}
{activeSidebarTab === "presets" && <PresetGallery onSelectPreset={handleSelectPreset} activePresetId={activePresetId} />}
{activeSidebarTab === "saved" && <p className="text-primary/60 text-sm">Saved snippets will appear here.</p>}
</div>
</ScrollArea>
)}
</ScrollArea>}

<div className="relative flex h-full flex-col gap-2 lg:col-span-8 lg:h-[95vh] xl:col-span-3 ">
<div className="relative col-span-12 h-full min-h-0 lg:col-auto"><div className="relative flex h-full flex-col gap-2 lg:h-[95vh]">
<div className="relative inset-shadow-[0_1px_rgb(0_0_0/0.10)] h-96 flex-grow rounded-xl border border-t-0 bg-card-bg p-2 lg:h-auto dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)]">
<BackgroundPreview
bgColor={bgColor}
Expand Down Expand Up @@ -444,12 +414,7 @@ export default function BackgroundPatternGenerator() {
maskFade={maskFade}
/>
</div>
<div className="inset-shadow-[0_1px_rgb(0_0_0/0.10)] flex h-44 w-full gap-2 rounded-xl border border-t-0 bg-card-bg p-2 2xl:h-60 dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0">
<PresetGallery
onSelectPreset={handleSelectPreset}
activePresetId={activePresetId}
/>
</div>
</div></div>
</div>
</div>
</>
Expand Down
55 changes: 26 additions & 29 deletions components/view/colors/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import {
parseRgba,
rgbToHex,
} from "@/lib/color-utils";
import { ChevronsDown, Pipette } from "lucide-react";
import { Pipette } from "lucide-react";
import { Bookmark, PanelsTopLeft, Settings2 } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { cn } from "@/lib/utils";
import { usePathname, useRouter } from "next/navigation";
import { useState } from "react";
import { AllColorFormats } from "./all-color-formats";
import { ColorPaletteSection } from "./color-palette-section";
Expand All @@ -40,6 +44,10 @@ import { ThemeGenerator } from "./theme-generator";

export default function ColorConverter() {
const [showPalette, setShowPalette] = useState(true); // Show palette by default
const [activeSidebarTab, setActiveSidebarTab] = useState<"presets" | "settings" | "saved">("settings");
const [isSidebarExpanded, setIsSidebarExpanded] = useState(true);
const pathname = usePathname();
const router = useRouter();

const {
hexValue,
Expand Down Expand Up @@ -300,33 +308,21 @@ export default function ColorConverter() {

return (
<>
<div className="container mx-auto w-full pb-10">
<article className="space-y-3 pb-14">
<h1 className="text-center font-medium text-2xl capitalize sm:text-3xl md:text-5xl">
Play, Pick, Convert and <br /> Generate New Colors 🎨
</h1>

<div className="mx-auto flex w-fit items-center justify-center gap-2">
{/* <div className="flex gap-2 rounded-md border bg-card-bg p-2 shadow-[0px_1px_0px_0px_rgba(17,17,26,0.1)] dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0">
Expand
<Switch
id="view-all-switch"
checked={viewAll}
onCheckedChange={setViewAll}
className="bg-main"
/>
</div> */}
<a
href="#shadcn-theme"
className="group flex cursor-pointer gap-1 rounded-md border bg-card-bg p-2 font-semibold text-primary shadow-[0px_1px_0px_0px_rgba(17,17,26,0.1)] hover:bg-accent dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0"
>
Shadcn/ui theme
<ChevronsDown />
</a>
<div className="h-full w-full overflow-hidden p-3">
<div className={cn("relative grid h-full min-h-0 gap-3", isSidebarExpanded ? "lg:grid-cols-[70px_320px_minmax(0,1fr)]" : "lg:grid-cols-[70px_0px_minmax(0,1fr)]")}>
<div className="inset-shadow-[0_1px_rgb(0_0_0/0.10)] hidden h-full min-h-0 rounded-lg border bg-card-bg p-2 lg:flex lg:flex-col lg:justify-between dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0">
<div className="space-y-2">{[{ key: "presets", label: "Presets", icon: PanelsTopLeft }, { key: "settings", label: "Settings", icon: Settings2 }, { key: "saved", label: "Saved", icon: Bookmark }].map((item)=><button type="button" key={item.key} onClick={()=>{setIsSidebarExpanded(true);setActiveSidebarTab(item.key as "presets"|"settings"|"saved");}} className={cn("grid h-16 w-full place-items-center rounded-md border px-1 py-1 font-semibold text-[11px]",activeSidebarTab===item.key?"border-primary bg-primary text-primary-foreground":"bg-main")}><item.icon className="h-4 w-4"/><span>{item.label}</span></button>)}</div>
<Select value={pathname} onValueChange={(value)=>router.push(value)}><SelectTrigger className="h-9 px-2 text-[10px]"><SelectValue placeholder="Go to editor..." /></SelectTrigger><SelectContent><SelectItem value="/color-lab">Color</SelectItem><SelectItem value="/mesh-gradients">Mesh</SelectItem><SelectItem value="/background-snippets">BG</SelectItem></SelectContent></Select>
</div>
<div className={cn("inset-shadow-[0_1px_rgb(0_0_0/0.10)] hidden h-full min-h-0 rounded-lg border bg-card-bg p-3 lg:block dark:inset-shadow-[0_1px_rgb(255_255_255/0.15)] dark:border-0", !isSidebarExpanded && "pointer-events-none w-0 overflow-hidden border-0 p-0 opacity-0")}>
{activeSidebarTab === "settings" && <SimplifiedColorPicker
hexValue={hexValue} rgbValues={rgbValues} hslValues={hslValues} colorName={colorName} handleHexChange={handleHexChange} handleRgbChange={handleRgbChange} handleHslChange={handleHslChange} handleColorPicker={handleColorPicker} setHexValue={setHexValue}
/>}
{activeSidebarTab === "presets" && <ColorPaletteSection showPalette={showPalette} setShowPalette={setShowPalette} palette={palette} setHexValue={setHexValue} />}
{activeSidebarTab === "saved" && <HistoryFavorites history={history} setHexValue={setHexValue} />}
</div>
</article>
<div className="space-y-6 ">
<div className="grid gap-10 px-4 sm:px-0 lg:grid-cols-2">
<div className="space-y-6">
<div className="grid gap-10 px-4 sm:px-0 lg:grid-cols-2">
<div className="space-y-4">
{/* Main Color Picker */}
<SimplifiedColorPicker
Expand Down Expand Up @@ -360,9 +356,10 @@ export default function ColorConverter() {
{/* History and Favorites */}
<HistoryFavorites history={history} setHexValue={setHexValue} />
</div>
</div>
{/* Theme Generator Section */}
<ThemeGenerator hexValue={hexValue} />
</div>
{/* Theme Generator Section */}
<ThemeGenerator hexValue={hexValue} />
</div>
</div>
</>
Expand Down
Loading