canvas-backend/src/components/ColorComponent.jsx

244 lines
10 KiB
JavaScript

import { useContext, useEffect, useState } from 'react'
import { Label } from '@/components/ui/label'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import ColorContext from './Context/colorContext/ColorContext'
import CanvasContext from './Context/canvasContext/CanvasContext'
import { fabric } from 'fabric'
const ColorComponent = () => {
const { canvas } = useContext(CanvasContext)
const { backgroundType, setBackgroundType, solidColor, gradientColors, setSolidColor, setGradientColors, gradientDirection, setGradientDirection, setDirectionCoords,
} = useContext(ColorContext)
const [previewBackgroundType, setPreviewBackgroundType] = useState(backgroundType)
const [previewSolidColor, setPreviewSolidColor] = useState(solidColor)
const [previewGradientColors, setPreviewGradientColors] = useState(gradientColors)
const [previewGradientDirection, setPreviewGradientDirection] = useState(gradientDirection)
useEffect(() => {
setPreviewBackgroundType(backgroundType)
setPreviewSolidColor(solidColor)
setPreviewGradientColors(gradientColors)
setPreviewGradientDirection(gradientDirection)
}, [backgroundType, solidColor, gradientColors, gradientDirection])
useEffect(() => {
if (previewBackgroundType === "gradient" && canvas) {
const width = canvas.width || 0
const height = canvas.height || 0
const linearCoords = {
"top-to-bottom": { x1: 0, y1: 0, x2: 0, y2: height },
"bottom-to-top": { x1: 0, y1: height, x2: 0, y2: 0 },
"left-to-right": { x1: 0, y1: 0, x2: width, y2: 0 },
"right-to-left": { x1: width, y1: 0, x2: 0, y2: 0 },
}
const coords = linearCoords[previewGradientDirection]
if (coords) {
setDirectionCoords(coords)
}
}
}, [previewBackgroundType, previewGradientDirection, canvas, setDirectionCoords])
const applyChanges = () => {
setBackgroundType(previewBackgroundType)
setSolidColor(previewSolidColor)
setGradientColors(previewGradientColors)
setGradientDirection(previewGradientDirection)
applyToCanvas()
}
const applyToCanvas = () => {
if (!canvas) return
if (previewBackgroundType === "color") {
canvas.backgroundColor = previewSolidColor
} else if (previewBackgroundType === "gradient") {
const width = canvas.width || 0
const height = canvas.height || 0
const linearCoords = {
"top-to-bottom": { x1: 0, y1: 0, x2: 0, y2: height },
"bottom-to-top": { x1: 0, y1: height, x2: 0, y2: 0 },
"left-to-right": { x1: 0, y1: 0, x2: width, y2: 0 },
"right-to-left": { x1: width, y1: 0, x2: 0, y2: 0 },
}
const coords = linearCoords[previewGradientDirection]
if (coords) {
setDirectionCoords(coords)
const gradient = new fabric.Gradient({
type: "linear",
gradientUnits: "pixels",
coords: coords,
colorStops: [
{ offset: 0, color: previewGradientColors.color1 },
{ offset: 1, color: previewGradientColors.color2 },
],
})
canvas.backgroundColor = gradient
}
} else if (previewBackgroundType === "radial") {
const gradient = new fabric.Gradient({
type: "radial",
gradientUnits: "pixels",
coords: {
x1: canvas.width / 2,
y1: canvas.height / 2,
r1: 0,
x2: canvas.width / 2,
y2: canvas.height / 2,
r2: Math.min(canvas.width, canvas.height) / 2,
},
colorStops: [
{ offset: 0, color: previewGradientColors.color1 },
{ offset: 1, color: previewGradientColors.color2 },
],
})
canvas.backgroundColor = gradient
}
canvas.renderAll()
}
const getPreviewStyle = () => {
if (previewBackgroundType === "color") {
return { backgroundColor: previewSolidColor }
} else if (previewBackgroundType === "gradient") {
const direction = {
'top-to-bottom': '180deg',
'bottom-to-top': '0deg',
'left-to-right': '90deg',
'right-to-left': '270deg'
}[previewGradientDirection]
return {
backgroundImage: `linear-gradient(${direction}, ${previewGradientColors.color1}, ${previewGradientColors.color2})`
}
} else if (previewBackgroundType === "radial") {
return {
backgroundImage: `radial-gradient(circle, ${previewGradientColors.color1}, ${previewGradientColors.color2})`
}
}
}
return (
<div className='flex flex-col gap-4 p-1'>
<div className='flex flex-col gap-2'>
<Label>Background Type:</Label>
<Select value={previewBackgroundType} onValueChange={setPreviewBackgroundType}>
<SelectTrigger>
<SelectValue placeholder="Select background type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="color">Solid Color</SelectItem>
<SelectItem value="gradient">Linear Gradient</SelectItem>
<SelectItem value="radial">Radial Gradient</SelectItem>
</SelectContent>
</Select>
</div>
{previewBackgroundType === "color" ? (
<div className='flex flex-col gap-2'>
<Label>Solid Color:</Label>
<Input
type="color"
value={previewSolidColor}
onChange={(e) => setPreviewSolidColor(e.target.value)}
/>
</div>
) : previewBackgroundType === "gradient" ? (
<div className='grid grid-cols-1 gap-2'>
<div className='flex flex-col gap-2'>
<Label>Direction:</Label>
<Select
value={previewGradientDirection}
onValueChange={setPreviewGradientDirection}
>
<SelectTrigger>
<SelectValue placeholder="Select direction" />
</SelectTrigger>
<SelectContent>
<SelectItem value="top-to-bottom">Top to Bottom</SelectItem>
<SelectItem value="bottom-to-top">Bottom to Top</SelectItem>
<SelectItem value="left-to-right">Left to Right</SelectItem>
<SelectItem value="right-to-left">Right to Left</SelectItem>
</SelectContent>
</Select>
</div>
<div className='flex flex-col gap-2'>
<Label>Color 1:</Label>
<Input
type="color"
value={previewGradientColors.color1}
onChange={(e) =>
setPreviewGradientColors((prev) => ({
...prev,
color1: e.target.value,
}))}
/>
</div>
<div className='flex flex-col gap-2'>
<Label>Color 2:</Label>
<Input
type="color"
value={previewGradientColors.color2}
onChange={(e) =>
setPreviewGradientColors((prev) => ({
...prev,
color2: e.target.value,
}))}
/>
</div>
</div>
) : (
<div className='grid grid-cols-1 gap-2'>
<div className='flex flex-col gap-2'>
<Label>Color 1:</Label>
<Input
type="color"
value={previewGradientColors.color1}
onChange={(e) =>
setPreviewGradientColors((prev) => ({
...prev,
color1: e.target.value,
}))}
/>
</div>
<div className='flex flex-col gap-2'>
<Label>Color 2:</Label>
<Input
type="color"
value={previewGradientColors.color2}
onChange={(e) =>
setPreviewGradientColors((prev) => ({
...prev,
color2: e.target.value,
}))}
/>
</div>
</div>
)}
<div>
<Label>Preview:</Label>
<div
className='w-full h-24 rounded-md mt-2'
style={getPreviewStyle()}
></div>
</div>
<Button onClick={applyChanges}>
Apply Changes
</Button>
</div>
)
}
export default ColorComponent