new design added

This commit is contained in:
Saimon8420 2025-02-08 18:01:37 +06:00
parent 2c0ab8b736
commit e2b8d7368f
10 changed files with 225 additions and 422 deletions

View file

@ -61,13 +61,15 @@ export const Home = () => {
{!isLoading && {!isLoading &&
<> <>
<Toaster /> <Toaster />
<div>
{
activeObject && <TopBar />
}
</div>
<div className="fixed z-[999] right-0"> {
activeObject &&
<div className="absolute left-[90px] right-[90px] z-[9999] rounded-md p-1 h-fit bg-white border-t border-gray-200 shadow-md my-1 w-[80%] mx-auto">
<TopBar />
</div>
}
<div className="absolute z-[9999] right-0 bottom-0 flex justify-center items-center h-20 bg-white border-t border-gray-200 shadow-md w-fit">
<ActionButtons /> <ActionButtons />
</div> </div>
@ -79,7 +81,7 @@ export const Home = () => {
<EditorPanel /> <EditorPanel />
</div> </div>
<div className="flex-1 flex flex-col h-full overflow-hidden"> <div className="flex-1 flex flex-col h-full overflow-hidden my-2">
<div className="flex-1 overflow-auto"> <div className="flex-1 overflow-auto">
<Canvas /> <Canvas />
</div> </div>

View file

@ -15,7 +15,6 @@ const aspectRatios = [
{ value: "4:3", label: "Standard (4:3)" }, { value: "4:3", label: "Standard (4:3)" },
{ value: "3:2", label: "Classic (3:2)" }, { value: "3:2", label: "Classic (3:2)" },
{ value: "16:9", label: "Widescreen (16:9)" }, { value: "16:9", label: "Widescreen (16:9)" },
{ value: "9:16", label: "Portrait (9:16)" },
{ value: "21:9", label: "Ultrawide (21:9)" }, { value: "21:9", label: "Ultrawide (21:9)" },
{ value: "32:9", label: "Super Ultrawide (32:9)" }, { value: "32:9", label: "Super Ultrawide (32:9)" },
{ value: "1.85:1", label: "Cinema Standard (1.85:1)" }, { value: "1.85:1", label: "Cinema Standard (1.85:1)" },
@ -24,7 +23,9 @@ const aspectRatios = [
{ value: "5:4", label: "Large Format (5:4)" }, { value: "5:4", label: "Large Format (5:4)" },
{ value: "7:5", label: "Artistic Format (7:5)" }, { value: "7:5", label: "Artistic Format (7:5)" },
{ value: "11:8.5", label: "Letter Size (11:8.5)" }, { value: "11:8.5", label: "Letter Size (11:8.5)" },
{ value: "3:4", label: "Portrait (3:4)" }, { value: "3:4", label: "Portrait (4:4)" },
{ value: "9:16", label: "Vertical (9:16)" },
{ value: "1.33:1", label: "Instagram Stories (1.33:1)" },
{ value: "1.91:1", label: "Facebook Ads (1.91:1)" }, { value: "1.91:1", label: "Facebook Ads (1.91:1)" },
]; ];

View file

@ -236,22 +236,9 @@ export default function Canvas() {
}, [canvas, setActiveObject]); }, [canvas, setActiveObject]);
return ( return (
<> <div>
{/* Zoom Controls */}
<div className="fixed bottom-4 right-4 flex items-center gap-4 bg-white p-3 rounded-lg shadow-lg z-50">
<span className="text-sm font-medium min-w-[45px]">{zoomLevel}%</span>
<Slider
value={[zoomLevel]}
onValueChange={(value) => handleZoom(value[0])}
min={0}
max={100}
step={1}
className="w-32"
/>
</div>
{/* Canvas Container */} {/* Canvas Container */}
<div className="w-full max-w-4xl mx-auto mt-20"> <div className="w-full max-w-2xl mx-auto mt-20">
<Card <Card
className={`w-full rounded-none flex-1 flex flex-col className={`w-full rounded-none flex-1 flex flex-col
mx-auto border-0 shadow-none bg-transparent mx-auto border-0 shadow-none bg-transparent
@ -282,6 +269,19 @@ export default function Canvas() {
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
</>
{/* Zoom Controls */}
<div className="flex my-2 mb-4 bg-white p-3 rounded-lg shadow-lg z-50 w-fit">
<span className="text-sm font-medium min-w-[45px]">{zoomLevel}%</span>
<Slider
value={[zoomLevel]}
onValueChange={(value) => handleZoom(value[0])}
min={0}
max={100}
step={1}
className="w-32"
/>
</div>
</div>
); );
} }

View file

@ -1,21 +0,0 @@
import { AlignLeft, AlignRight } from 'lucide-react';
import { useContext } from 'react';
import OpenContext from '../Context/openContext/OpenContext';
const Header = () => {
const { setRightPanelOpen, setLeftPanelOpen } = useContext(OpenContext);
return (
<div className='bg-[#f2e6f8] fixed top-0 w-[60px] z-[900] min-w-full flex items-center p-4 shadow-md'>
<p className='mr-auto flex-wrap gap-1 cursor-pointer text-xs items-center font-semibold xl:flex lg:flex md:flex hidden' onClick={() => setLeftPanelOpen(true)}><AlignLeft /><span className='hidden xl:block lg:block md:block sm:block'>Add Element</span></p>
<h1 className='font-semibold'>PlanPostAi Canvas</h1>
<p className='ml-auto flex-wrap gap-1 cursor-pointer text-xs items-center font-semibold xl:flex lg:flex md:flex hidden' onClick={() => setRightPanelOpen(true)}> <span className='hidden xl:block lg:block md:block sm:block'>Edit Panel</span><AlignRight /></p>
</div>
)
}
export default Header

View file

@ -281,7 +281,7 @@ export const ObjectShortcut = ({ value }) => {
<p>Change object position</p> <p>Change object position</p>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
<PopoverContent className="w-40 p-2"> <PopoverContent className="w-40 p-2 z-[9999]">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<Button <Button
variant="ghost" variant="ghost"
@ -340,7 +340,7 @@ function ActionButton({ icon, label, onClick, tooltipContent }) {
</div> </div>
</Button> </Button>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="bottom" align="center" className="max-w-xs"> <TooltipContent side="bottom" align="center" className="max-w-xs z-[9999]">
<p>{tooltipContent}</p> <p>{tooltipContent}</p>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>

View file

@ -8,7 +8,7 @@ import { deleteProject, getProjects } from '@/api/projectApi';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
import ActiveObjectContext from '../Context/activeObject/ObjectContext'; import ActiveObjectContext from '../Context/activeObject/ObjectContext';
import { FixedSizeList as List } from 'react-window'; // Import FixedSizeList from react-window import { FixedSizeList as List } from 'react-window';
export const ProjectPanel = () => { export const ProjectPanel = () => {
const { setSelectedPanel, canvas } = useContext(CanvasContext); const { setSelectedPanel, canvas } = useContext(CanvasContext);
@ -63,12 +63,11 @@ export const ProjectPanel = () => {
} }
}); });
// Row renderer for react-window
const Row = ({ index, style }) => { const Row = ({ index, style }) => {
const project = projects?.data?.[index]; // Get project by index const project = filteredProjects[index]; // Use filtered projects
return ( return (
<div key={project?.id} className='flex flex-col gap-1 bg-red-50 p-1 rounded-md' style={style}> <div key={project?.id} className='flex flex-col gap-1 bg-red-50 p-1 rounded-md border border-red-100' style={style}>
<div className='rounded-md flex p-1 flex-col gap-1 hover:bg-red-100 cursor-pointer transition-all' onClick={() => navigate(`/${project.id}`)}> <div className='rounded-md flex p-1 flex-col gap-1 hover:bg-red-100 cursor-pointer transition-all' onClick={() => navigate(`/${project.id}`)}>
<p className='font-bold text-sm truncate'>{project?.name}</p> <p className='font-bold text-sm truncate'>{project?.name}</p>
<p className='text-xs truncate'>{project?.description} </p> <p className='text-xs truncate'>{project?.description} </p>
@ -77,11 +76,16 @@ export const ProjectPanel = () => {
<Button <Button
disabled={deletePending} disabled={deletePending}
className="w-fit p-1 ml-auto" size="small" onClick={() => { projectDelete(project?.id) }}><Trash className="h-4 w-4" /></Button> className="w-fit p-1 ml-auto" size="small" onClick={() => { projectDelete(project?.id) }}>
<Trash className="h-4 w-4" />
</Button>
</div> </div>
); );
}; };
// Filter projects where preview_url is not empty or null
const filteredProjects = projects?.data?.filter(project => project?.preview_url) || [];
return ( return (
<div> <div>
<div className="flex justify-between items-center p-4 border-b"> <div className="flex justify-between items-center p-4 border-b">
@ -102,9 +106,9 @@ export const ProjectPanel = () => {
{ {
!projectLoading && projectSuccess && projects?.status === 200 && !projectLoading && projectSuccess && projects?.status === 200 &&
<List <List
height={500} // Set the height of the viewport height={400} // Set the height of the viewport
itemCount={projects?.data?.length} // Total number of items itemCount={filteredProjects.length} // Use length of filtered projects
itemSize={300} // Height of each row itemSize={280} // Height of each row
width="100%" // Full width of the container width="100%" // Full width of the container
> >
{Row} {Row}

View file

@ -21,220 +21,124 @@ export function TopBar() {
const activeObjectType = activeObject?.type; const activeObjectType = activeObject?.type;
const hasClipPath = !!activeObject?.clipPath; const hasClipPath = !!activeObject?.clipPath;
const customClipPath = activeObject?.isClipPath; const customClipPath = activeObject?.isClipPath;
const scrollContainerRef = useRef(null); // w - [calc(100 % -80px)] h - full
const [showScrollButtons, setShowScrollButtons] = useState(false);
const scroll = (direction) => {
const container = scrollContainerRef.current;
if (container) {
const scrollAmount = 200; // Adjust this value to change scroll distance
container.scrollBy({
left: direction * scrollAmount,
behavior: "smooth",
});
}
};
return ( return (
<div <div className="w-full h-full overflow-x-scroll p-1">
className={`!absolute top-2 -translate-x-1/2 z-40 ${selectedPanel !== "" <div className="flex item-center justify-center w-fit mx-auto">
? "md:w-[465px] left-[41%] lg:w-[700px] lg:left-[43%] mdxl:left-[45%] xl:w-[900px] xl:left-[46%] 2xl:left-[50%]" <div className="bg-white mx-auto flex justify-center items-center gap-2">
: "w-[500px] lg:w-[600px] xl:w-[900px] lg:left-[41%] xl:left-[50%]" <div className="flex-1">
}`} <TextCustomization />
onMouseEnter={() => setShowScrollButtons(true)} </div>
onMouseLeave={() => setShowScrollButtons(false)}
> <div className="flex items-center gap-4 px-2">
<div className="relative h-full hidden xl:block">
{showScrollButtons && (
<>
<Button <Button
className="absolute left-0 top-1/2 -translate-y-1/2 z-10 bg-accent" variant="outline"
onClick={() => scroll(-1)} className="flex items-center gap-2 border-dashed border-2 rounded-md hover:bg-gray-50"
variant="ghost" onClick={() => setSelectedPanel("image-insert")}
size="icon"
> >
<ChevronLeft className="h-4 w-4" /> <ImagePlus className="w-5 h-5" />
<span>Add image</span>
</Button> </Button>
<Button
className="absolute right-0 top-1/2 -translate-y-1/2 z-10 bg-accent" {/* Canvas settings */}
onClick={() => scroll(1)}
variant="ghost"
size="icon"
>
<ChevronRight className="h-4 w-4" />
</Button>
</>
)}
<div
ref={scrollContainerRef}
className="w-full h-full overflow-x-auto scrollbar-hide"
>
<div className="bg-white shadow-sm mx-auto px-4 xl:px-10 py-2 flex justify-start items-center gap-2 min-w-max h-full">
<div> <div>
<TextCustomization /> <a data-tooltip-id="canvas">
</div> <Button
<div className="flex items-center gap-4 px-2"> variant="ghost"
<Button size="icon"
variant="outline" className="w-10 h-10"
className="flex items-center gap-2 border-dashed border-2 rounded-md hover:bg-gray-50" onClick={() => setSelectedPanel("canvas")}
onClick={() => setSelectedPanel("image-insert")} >
> <svg
<ImagePlus className="w-5 h-5" /> width="100"
<span>Add image</span> height="100"
</Button> viewBox="0 0 24 24"
fill="none"
{/* canvas settings */} xmlns="http://www.w3.org/2000/svg"
<div>
<a data-tooltip-id="canvas">
<Button
variant="ghost"
size="icon"
className="w-10 h-10"
onClick={() => setSelectedPanel("canvas")}
> >
<svg <rect x="3" y="5" width="18" height="12" stroke="black" strokeWidth="2" fill="none" />
width="100" <path d="M14 14 L19 19" stroke="black" strokeWidth="2" />
height="100" <path d="M15 15 Q16 12, 19 11" stroke="black" strokeWidth="2" fill="none" />
viewBox="0 0 24 24" <line x1="3" y1="17" x2="7" y2="21" stroke="black" strokeWidth="2" />
fill="none" <line x1="21" y1="17" x2="17" y2="21" stroke="black" strokeWidth="2" />
xmlns="http://www.w3.org/2000/svg" </svg>
> </Button>
<rect </a>
x="3" <Tooltip id="canvas" content="Canvas Settings" place="bottom" />
y="5" </div>
width="18"
height="12"
stroke="black"
strokeWidth="2"
fill="none"
/>
<path d="M14 14 L19 19" stroke="black" strokeWidth="2" />
<path
d="M15 15 Q16 12, 19 11"
stroke="black"
strokeWidth="2"
fill="none"
/>
<line
x1="3"
y1="17"
x2="7"
y2="21"
stroke="black"
strokeWidth="2"
/>
<line
x1="21"
y1="17"
x2="17"
y2="21"
stroke="black"
strokeWidth="2"
/>
</svg>
</Button>
</a>
<Tooltip id="canvas" content="Canvas Settings" place="bottom" />
</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{activeObjectType !== "image" && {activeObjectType !== "image" &&
activeObject?.type !== "i-text" && activeObject?.type !== "i-text" &&
!hasClipPath && !hasClipPath &&
!customClipPath && ( !customClipPath && (
<a data-tooltip-id="color-gr"> <a data-tooltip-id="color-gr">
<Button
variant="ghost"
size="icon"
className="rounded-full"
onClick={() => setSelectedPanel("color")}
style={{ backgroundColor: textColor?.fill || "black" }}
></Button>
</a>
)}
<Tooltip id="color-gr" content="Color" place="bottom" />
{!customClipPath && (
<a data-tooltip-id="stroke">
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="w-10 h-10" className="rounded-full"
onClick={() => setSelectedPanel("stroke")} onClick={() => setSelectedPanel("color")}
> style={{ backgroundColor: textColor?.fill || "black" }}
<RxBorderWidth className="text-lg" /> ></Button>
</Button>
</a> </a>
)} )}
<Tooltip id="stroke" content="Stroke" place="bottom" /> <Tooltip id="color-gr" content="Color" place="bottom" />
{(activeObject || activeObject.type === "group") && (
<a data-tooltip-id="group-obj">
<Button
variant="ghost"
size="icon"
className="w-10 h-10"
onClick={() => setSelectedPanel("group-obj")}
>
<FaRegObjectGroup />
</Button>
</a>
)}
<Tooltip id="group-obj" content="Group Object" place="bottom" />
</div>
<div className="h-6 w-px bg-gray-200" /> {!customClipPath && (
<a data-tooltip-id="stroke">
<div className="flex items-center gap-2"> <Button variant="ghost" size="icon" className="w-10 h-10" onClick={() => setSelectedPanel("stroke")}>
<a data-tooltip-id="flip"> <RxBorderWidth className="text-lg" />
<Button
variant="ghost"
size="icon"
onClick={() => setSelectedPanel("flip")}
>
<LuFlipVertical />
</Button> </Button>
</a> </a>
)}
<Tooltip id="stroke" content="Stroke" place="bottom" />
<Tooltip id="flip" content="Object flip" place="bottom" /> {(activeObject || activeObject.type === "group") && (
{activeObject?.type !== "group" && ( <a data-tooltip-id="group-obj">
<a data-tooltip-id="position"> <Button variant="ghost" size="icon" className="w-10 h-10" onClick={() => setSelectedPanel("group-obj")}>
<Button <FaRegObjectGroup />
variant="ghost"
size="icon"
onClick={() => setSelectedPanel("position")}
>
<SlTarget />
</Button>
</a>
)}
<Tooltip
id="position"
content="Object position"
place="bottom"
/>
<a data-tooltip-id="shadow">
<Button
variant="ghost"
size="icon"
onClick={() => setSelectedPanel("shadow")}
>
<RiShadowLine />
</Button> </Button>
</a> </a>
<Tooltip id="shadow" content="Shadow color" place="bottom" /> )}
</div> <Tooltip id="group-obj" content="Group Object" place="bottom" />
</div> </div>
<OpacityCustomization />
<div className="h-4 w-px bg-border mx-2" />
<div> <div className="h-6 w-px bg-gray-200" />
<ObjectShortcut value="default" />
</div> <div className="flex items-center gap-2">
<div className="ml-4"> <a data-tooltip-id="flip">
<LockObject /> <Button variant="ghost" size="icon" onClick={() => setSelectedPanel("flip")}>
<LuFlipVertical />
</Button>
</a>
<Tooltip id="flip" content="Object flip" place="bottom" />
{activeObject?.type !== "group" && (
<a data-tooltip-id="position">
<Button variant="ghost" size="icon" onClick={() => setSelectedPanel("position")}>
<SlTarget />
</Button>
</a>
)}
<Tooltip id="position" content="Object position" place="bottom" />
<a data-tooltip-id="shadow">
<Button variant="ghost" size="icon" onClick={() => setSelectedPanel("shadow")}>
<RiShadowLine />
</Button>
</a>
<Tooltip id="shadow" content="Shadow color" place="bottom" />
</div> </div>
</div> </div>
<OpacityCustomization />
<div className="h-4 w-px bg-border mx-2" />
<div>
<ObjectShortcut value="default" />
</div>
<div className="ml-4">
<LockObject />
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,107 +0,0 @@
const loadCanvasState = (state) => {
if (!canvas2) {
console.error('Canvas2 is not initialized!');
return;
}
try {
const canvasData = typeof state === 'string' ? JSON.parse(state) : state;
// Clear the existing canvas
canvas2.clear();
// Set the background color if it exists
if (canvasData.backgroundColor) {
canvas2.set({ backgroundColor: canvasData.backgroundColor });
}
// Function to load background image
const loadBackgroundImage = () => {
return new Promise((resolve) => {
if (!canvasData.background) {
resolve();
return;
}
const imgElement = new Image();
imgElement.crossOrigin = 'anonymous'; // Handle CORS if needed
imgElement.onload = () => {
const imgInstance = new fabric.Image(imgElement, {
originX: canvasData.background.originX || 'left',
originY: canvasData.background.originY || 'top',
scaleX: canvasData.background.scaleX || canvas2.width / imgElement.width,
scaleY: canvasData.background.scaleY || canvas2.height / imgElement.height,
opacity: canvasData.background.opacity || 1,
});
// Set background image using the set method
canvas2.set({ backgroundImage: imgInstance });
resolve();
};
imgElement.onerror = () => {
console.error("Failed to load the background image");
resolve(); // Resolve anyway to continue loading objects
};
imgElement.src = canvasData.background.src;
});
};
// Function to load objects
const loadObjects = () => {
return new Promise((resolve) => {
canvas2.loadFromJSON({ objects: canvasData.objects }, () => {
resolve();
}, (obj, element) => {
return obj;
});
});
};
// Load background image and objects if they exist
const loadTasks = [];
if (canvasData.background || canvasData.objects?.length) {
if (canvasData.background) {
loadTasks.push(loadBackgroundImage());
}
if (canvasData.objects?.length) {
loadTasks.push(loadObjects());
}
Promise.all(loadTasks)
.then(() => {
canvas2.requestRenderAll(); // Ensure re-rendering
})
.catch((error) => {
console.error('Error during canvas loading:', error);
});
} else {
// If only background color exists
if (canvasData.backgroundColor) {
canvas2.requestRenderAll(); // Apply background color and render
}
}
} catch (error) {
console.error('Error loading canvas state:', error);
}
};
// for download image/canvas
const exportScaledCanvasImage = (scale = 2) => {
if (canvas) {
const imageBase64 = canvas.toDataURL({
format: 'png', // or 'jpeg'
quality: 1, // (0 to 1) for JPEG compression, ignored for PNG
multiplier: scale, // Scale the canvas size
});
// Download the scaled image
const link = document.createElement('a');
link.href = imageBase64;
link.download = `canvas-image-${scale}x.png`;
link.click();
}
};

View file

@ -153,3 +153,23 @@
@apply bg-[#f5f0ff] text-foreground; @apply bg-[#f5f0ff] text-foreground;
} }
} }
::-webkit-scrollbar {
width: 0px;
height: 5px;
border-radius: 5px;
cursor: pointer;
/* background-color: var(--primary-600); */
@apply bg-red-50
}
::-webkit-scrollbar-track {
background-color: var(--primary-500);
}
::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
width: 5px;
background-color: red;
border-radius: 5px;
}

View file

@ -3,71 +3,71 @@ import scrollbarHide from "tailwind-scrollbar-hide";
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
darkMode: ["class"], darkMode: ["class"],
content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"], content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"],
theme: { theme: {
extend: { extend: {
textColor: { textColor: {
primary: { primary: {
DEFAULT: 'hsl(var(--primary-text))', DEFAULT: 'hsl(var(--primary-text))',
foreground: 'hsl(var(--primary-foreground))' foreground: 'hsl(var(--primary-foreground))'
} }
}, },
screens: { screens: {
mdxl: '1100px' mdxl: '1100px'
}, },
colors: { colors: {
border: 'hsl(var(--border))', border: 'hsl(var(--border))',
input: 'hsl(var(--input))', input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))', ring: 'hsl(var(--ring))',
background: 'hsl(var(--background))', background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))', foreground: 'hsl(var(--foreground))',
selection: { selection: {
DEFAULT: 'hsl(var(--selection))', DEFAULT: 'hsl(var(--selection))',
foreground: 'hsl(var(--selection-foreground))' foreground: 'hsl(var(--selection-foreground))'
}, },
primary: { primary: {
DEFAULT: 'hsl(var(--primary))', DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))' foreground: 'hsl(var(--primary-foreground))'
}, },
secondary: { secondary: {
DEFAULT: 'hsl(var(--secondary))', DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))' foreground: 'hsl(var(--secondary-foreground))'
}, },
destructive: { destructive: {
DEFAULT: 'hsl(var(--destructive))', DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))' foreground: 'hsl(var(--destructive-foreground))'
}, },
muted: { muted: {
DEFAULT: 'hsl(var(--muted))', DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))' foreground: 'hsl(var(--muted-foreground))'
}, },
accent: { accent: {
DEFAULT: 'hsl(var(--accent))', DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))' foreground: 'hsl(var(--accent-foreground))'
}, },
popover: { popover: {
DEFAULT: 'hsl(var(--popover))', DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))' foreground: 'hsl(var(--popover-foreground))'
}, },
card: { card: {
DEFAULT: 'hsl(var(--card))', DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))' foreground: 'hsl(var(--card-foreground))'
}, },
chart: { chart: {
'1': 'hsl(var(--chart-1))', '1': 'hsl(var(--chart-1))',
'2': 'hsl(var(--chart-2))', '2': 'hsl(var(--chart-2))',
'3': 'hsl(var(--chart-3))', '3': 'hsl(var(--chart-3))',
'4': 'hsl(var(--chart-4))', '4': 'hsl(var(--chart-4))',
'5': 'hsl(var(--chart-5))' '5': 'hsl(var(--chart-5))'
} }
}, },
borderRadius: { borderRadius: {
lg: 'var(--radius)', lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)', md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)' sm: 'calc(var(--radius) - 4px)'
} }
} }
}, },
plugins: [scrollbar, scrollbarHide, require("tailwindcss-animate")], plugins: [scrollbar, scrollbarHide, require("tailwindcss-animate")],
}; };