rnd panel fixed for mobile devices

This commit is contained in:
Saimon8420 2024-12-30 13:36:14 +06:00
parent 9707f31094
commit 5b3d96c7eb
7 changed files with 233 additions and 168 deletions

View file

@ -1,7 +1,6 @@
import { useEffect, useCallback, useContext } from 'react';
import CanvasContext from './Context/canvasContext/CanvasContext';
import ActiveObjectContext from './Context/activeObject/ObjectContext';
import { Rnd } from 'react-rnd';
import OpenContext from './Context/openContext/OpenContext';
import CanvasSetting from './CanvasSetting';
import { EditPanel } from './EditPanel';
@ -79,21 +78,9 @@ const Canvas = () => {
return (
<div className='flex flex-col items-center relative w-full h-full overflow-hidden'>
{openSetting && (
<Rnd
className='z-[1000]'
default={{
x: 0,
y: 20,
}}
minWidth={220}
maxWidth={250}
minHeight={150}
bounds='parent'
>
<CanvasSetting />
</Rnd>
)}
{openSetting &&
<CanvasSetting />
}
{
openPanel &&

View file

@ -5,9 +5,9 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button';
import { Card, CardHeader, CardTitle } from './ui/card';
import { Rnd } from 'react-rnd';
import { X } from 'lucide-react';
import { Separator } from './ui/separator';
import RndComponent from './Layouts/RndComponent';
const resolutions = [
{ value: '720p', label: 'HD (1280x720)', width: 1280, height: 720 },
@ -73,28 +73,33 @@ const CanvasCapture = () => {
};
};
const rndValue = {
valueX: 0,
valueY: 20,
width: 250,
height: 150,
minWidth: 250,
maxWidth: 300,
minHeight: 150,
maxHeight: 300,
bound: "parent"
}
return (
<>
{captureOpen && (
<Rnd
className='z-[1000]'
default={{ x: 0, y: 20 }}
minWidth={250}
maxWidth={300}
minHeight={150}
bounds='parent'
>
<RndComponent value={rndValue}>
<Card className='space-y-2 p-2'>
<CardHeader className='p-0'>
<div className='flex items-center justify-between'>
<Button variant={'ghost'} onClick={() => setCaptureOpen(false)}>
<Button className="rnd-escape" variant={'ghost'} onClick={() => setCaptureOpen(false)}>
<X className='cursor-pointer' />
</Button>
<CardTitle className='text-lg mr-1'>Capture Panel</CardTitle>
</div>
</CardHeader>
<Separator />
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4 rnd-escape'>
<div className='space-y-2'>
<Label htmlFor='resolution'>Resolution</Label>
<Select onValueChange={setResolution} defaultValue={resolution}>
@ -126,11 +131,11 @@ const CanvasCapture = () => {
</Select>
</div>
</div>
<Button onClick={captureImage} className='w-full'>
<Button onClick={captureImage} className='w-full rnd-escape'>
Capture Canvas
</Button>
</Card>
</Rnd>
</RndComponent>
)}
</>
);

View file

@ -10,6 +10,8 @@ import { Input } from './ui/input';
import { Slider } from './ui/slider';
import { fabric } from 'fabric';
import OpenContext from './Context/openContext/OpenContext';
import { ScrollArea } from './ui/scroll-area';
import RndComponent from './Layouts/RndComponent';
const CanvasSetting = () => {
const { canvas } = useContext(CanvasContext);
@ -155,104 +157,120 @@ const CanvasSetting = () => {
}
};
const rndValue = {
valueX: 0,
valueY: 20,
width: 250,
height: 0,
minWidth: 250,
maxWidth: 300,
minHeight: 0,
maxHeight: 400,
bound: "parent"
}
return (
<Card className="px-2 py-2">
<CardTitle className="flex items-center flex-wrap justify-between gap-1">Canvas Setting <Button variant="secondary" onClick={() => setOpenSetting(false)}><X /></Button> </CardTitle>
<Separator className="mt-4" />
<div>
<ColorComponent />
<div className='flex flex-col my-2 gap-2'>
<div>
<Label>Background:</Label>
<div className='flex items-center w-fit gap-2 flex-wrap relative'>
<Button className="top-0 absolute flex items-center w-[30px]">
<UploadIcon className="cursor-pointer" />
<Input
ref={bgImgRef}
className="absolute top-0 opacity-0"
type="file"
accept="image/*"
onChange={setBackgroundImage}
/>
</Button>
<Button variant="secondary" className="ml-[35px]" onClick={removeBackgroundImage}><Trash2 /></Button>
</div>
</div>
<div>
<Label>Background Overlay:</Label>
<div className='flex items-center w-fit gap-2 flex-wrap relative'>
<Button className="top-0 absolute flex items-center w-[30px]">
<UploadIcon className="cursor-pointer" />
<Input
className="absolute top-0 opacity-0"
type="file"
accept="image/*"
onChange={setBackgroundOverlayImage}
/>
</Button>
<Button variant="secondary" className="ml-[35px]" onClick={removeBackgroundOverlayImage}><Trash2 /></Button>
</div>
</div>
<Separator className="mt-4" />
<div className='flex flex-col gap-2'>
<Label>
Adjust Opacity:
</Label>
<Slider
defaultValue={[1.0]} // Default value, you can set it to 0.0 or another value
min={0.0}
max={1.0}
step={0.01} // Step size for fine control
onValueChange={(value) => {
const newOpacity = value[0]; // Extract slider value
adjustBackgroundOpacity(newOpacity); // Adjust Fabric.js background opacity
}}
/>
</div>
</div>
<RndComponent value={rndValue}>
<Card className="px-2 py-2">
<CardTitle className="flex items-center flex-wrap justify-between gap-1">Canvas Setting <Button className="rnd-escape" variant="secondary" onClick={() => setOpenSetting(false)}><X /></Button> </CardTitle>
<Separator className="mt-4" />
<ScrollArea className="h-[400px] xl:h-fit lg:h-fit md:h-fit">
<div className='rnd-escape'>
<div className='flex gap-2 my-2'>
<div className='flex flex-col gap-2'>
<Label>
Width:
</Label>
<Input
type="number"
value={canvasSettings.width}
onChange={(e) => {
if (canvasSettings?.width > parseInt(e.target.value)) {
handleChange('width', parseInt(e.target.value, 10));
}
}}
/>
</div>
<ColorComponent />
<div className='flex flex-col gap-2'>
<Label>
Height:
</Label>
<Input
type="number"
value={canvasSettings.height}
onChange={(e) => {
if (canvasSettings?.height > parseInt(e.target.value)) {
handleChange('height', parseInt(e.target.value, 10));
}
}}
/>
<div className='flex flex-col my-2 gap-2 rnd-escape'>
<div>
<Label>Background:</Label>
<div className='flex items-center w-fit gap-2 flex-wrap relative'>
<Button className="top-0 absolute flex items-center w-[30px]">
<UploadIcon className="cursor-pointer" />
<Input
ref={bgImgRef}
className="absolute top-0 opacity-0"
type="file"
accept="image/*"
onChange={setBackgroundImage}
/>
</Button>
<Button variant="secondary" className="ml-[35px]" onClick={removeBackgroundImage}><Trash2 /></Button>
</div>
</div>
<div>
<Label>Background Overlay:</Label>
<div className='flex items-center w-fit gap-2 flex-wrap relative'>
<Button className="top-0 absolute flex items-center w-[30px]">
<UploadIcon className="cursor-pointer" />
<Input
className="absolute top-0 opacity-0"
type="file"
accept="image/*"
onChange={setBackgroundOverlayImage}
/>
</Button>
<Button variant="secondary" className="ml-[35px]" onClick={removeBackgroundOverlayImage}><Trash2 /></Button>
</div>
</div>
<Separator className="mt-4" />
<div className='flex flex-col gap-2 rnd-escape'>
<Label>
Adjust Opacity:
</Label>
<Slider
defaultValue={[1.0]} // Default value, you can set it to 0.0 or another value
min={0.0}
max={1.0}
step={0.01} // Step size for fine control
onValueChange={(value) => {
const newOpacity = value[0]; // Extract slider value
adjustBackgroundOpacity(newOpacity); // Adjust Fabric.js background opacity
}}
/>
</div>
</div>
<Separator className="mt-4" />
<div className='flex gap-2 my-2'>
<div className='flex flex-col gap-2'>
<Label>
Width:
</Label>
<Input
type="number"
value={canvasSettings.width}
onChange={(e) => {
if (canvasSettings?.width > parseInt(e.target.value)) {
handleChange('width', parseInt(e.target.value, 10));
}
}}
/>
</div>
<div className='flex flex-col gap-2'>
<Label>
Height:
</Label>
<Input
type="number"
value={canvasSettings.height}
onChange={(e) => {
if (canvasSettings?.height > parseInt(e.target.value)) {
handleChange('height', parseInt(e.target.value, 10));
}
}}
/>
</div>
</div>
</div>
</div>
</div>
</Card>
</ScrollArea>
</Card>
</RndComponent>
)
}

View file

@ -1,4 +1,3 @@
import { Rnd } from 'react-rnd';
import { useCallback, useContext, useState } from "react"
import { Card, CardContent, CardHeader, CardTitle } from './ui/card';
import { Button } from './ui/button';
@ -10,6 +9,7 @@ import OpenContext from './Context/openContext/OpenContext';
import CanvasContext from './Context/canvasContext/CanvasContext';
import ActiveObjectContext from './Context/activeObject/ObjectContext';
import { fabric } from 'fabric';
import RndComponent from './Layouts/RndComponent';
export function EditPanel() {
const [isCollapsed, setIsCollapsed] = useState(false);
@ -189,31 +189,31 @@ export function EditPanel() {
}
};
const rndValue = {
valueX: 0,
valueY: 20,
width: 250,
height: 0,
minWidth: 250,
maxWidth: 300,
minHeight: 0,
maxHeight: 0,
bound: "parent"
}
return (
<Rnd
default={{
x: 0,
y: 20,
width: 300,
height: 'auto',
}}
minWidth={200}
maxWidth={300}
bounds="parent"
enableResizing={{ right: true }}
className="z-[1000]"
>
<RndComponent value={rndValue}>
<Card className="w-full shadow-lg">
<CardHeader className="p-1 mr-12">
<div className="flex items-center justify-between">
<Button variant={"ghost"} onClick={() => setOpenPanel(false)}><X /></Button>
<Button className="rnd-escape" variant={"ghost"} onClick={() => setOpenPanel(false)}><X /></Button>
<CardTitle className="text-lg">Edit Panel</CardTitle>
</div>
</CardHeader>
<Collapsible open={!isCollapsed} onOpenChange={(open) => setIsCollapsed(!open)}>
<CollapsibleTrigger asChild>
<Button variant="ghost" size="sm" className="absolute top-1 right-2">
<Button variant="ghost" size="sm" className="absolute top-1 right-2 rnd-escape">
{isCollapsed ? <ChevronDown className="h-4 w-4" /> : <ChevronUp className="h-4 w-4" />}
</Button>
</CollapsibleTrigger>
@ -373,7 +373,7 @@ export function EditPanel() {
</CollapsibleContent>
</Collapsible>
</Card>
</Rnd>
</RndComponent>
)
}

View file

@ -0,0 +1,28 @@
import { Rnd } from 'react-rnd';
const RndComponent = ({ children, value }) => {
const { valueX, valueY, width, height, minWidth, maxWidth, minHeight, maxHeight, bound } = value;
return (
<Rnd
default={{
x: valueX,
y: valueY,
width: width,
height: 'auto',
}}
minWidth={minWidth}
maxWidth={maxWidth}
maxHeight={maxHeight}
bounds={bound}
className="z-[1000]"
cancel=".rnd-escape"
>
{children}
</Rnd>
)
}
export default RndComponent

View file

@ -1,10 +1,9 @@
import { Button } from './ui/button'
import { Card, CardContent, CardHeader, CardTitle } from './ui/card'
import { Card, CardHeader, CardTitle } from './ui/card'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/collapsible'
import { Tabs, TabsContent, TabsList, TabsTrigger } from './ui/tabs'
import { useContext, useState } from 'react'
import { PencilRuler, Shapes, Store, Upload, ChevronDown, ChevronUp, X } from 'lucide-react';
import { Rnd } from 'react-rnd';
import OpenContext from './Context/openContext/OpenContext';
import AllIconsPage from './EachComponent/Icons/AllIcons'
import { Separator } from './ui/separator'
@ -12,34 +11,35 @@ import { ScrollArea } from './ui/scroll-area'
import AddShapes from './Layouts/AddShapes'
import UploadImage from './EachComponent/UploadImage'
import CustomizeShape from './EachComponent/CustomizeShape'
import RndComponent from './Layouts/RndComponent'
const ObjectPanel = () => {
const [isCollapsed, setIsCollapsed] = useState(false);
const { tabValue, setTabValue, setOpenObjectPanel } = useContext(OpenContext);
const rndValue = {
valueX: 0,
valueY: 20,
width: 250,
height: 0,
minWidth: 250,
maxWidth: 300,
minHeight: 0,
maxHeight: 400,
bound: "parent"
}
return (
<Rnd
default={{
x: 0,
y: 20,
width: 300,
height: 'auto',
}}
minWidth={270}
maxWidth={300}
maxHeight={500}
bounds="parent"
enableResizing={{ right: true }}
className="z-40"
>
<RndComponent value={rndValue}>
<Card className="w-full shadow-lg">
<CardHeader className="p-1 mr-12">
<div className="flex items-center justify-between">
<Button variant={"ghost"} size={"sm"} onClick={() => setOpenObjectPanel(false)}><X /></Button>
<Button className="rnd-escape" variant={"ghost"} size={"sm"} onClick={() => setOpenObjectPanel(false)}><X /></Button>
<CardTitle className="text-lg">Object Panel</CardTitle>
</div>
</CardHeader>
<Collapsible open={!isCollapsed} onOpenChange={(open) => setIsCollapsed(!open)}>
<Collapsible className="rnd-escape" open={!isCollapsed} onOpenChange={(open) => setIsCollapsed(!open)}>
<CollapsibleTrigger asChild>
<Button variant="ghost" size="sm" className="absolute top-1 right-2">
@ -48,21 +48,48 @@ const ObjectPanel = () => {
</CollapsibleTrigger>
<CollapsibleContent>
<CardContent className="p-2">
<ScrollArea className="h-[400px] xl:h-fit lg:h-fit md:h-fit">
<Tabs className="w-full h-fit"
value={tabValue}
onValueChange={(value) => setTabValue(value)} // Sync tab state with context
>
<TabsList className="grid w-full grid-cols-4 h-fit gap-1">
<TabsTrigger value="icons" className="flex flex-col gap-1 text-xs" onClick={() => setTabValue("icons")}>
<Store className="h-4 w-4" />Icons
<TabsTrigger
value="icons"
className="flex flex-col gap-1 text-xs"
onClick={() => setTabValue("icons")}
>
<Store className="h-4 w-4" />
<span className="hidden sm:block">Icons</span>
</TabsTrigger>
<TabsTrigger value="shapes" className="flex flex-wrap gap-1 text-xs" onClick={() => setTabValue("shapes")}><Shapes className="h-4 w-4" />Shapes</TabsTrigger>
<TabsTrigger value="images" className="flex flex-wrap gap-1 text-xs" onClick={() => setTabValue("images")}><Upload className="h-4 w-4" />Images</TabsTrigger>
<TabsTrigger
value="shapes"
className="flex flex-col gap-1 text-xs"
onClick={() => setTabValue("shapes")}
>
<Shapes className="h-4 w-4" />
<span className="hidden sm:block">Shapes</span>
</TabsTrigger>
<TabsTrigger value="customize" className="flex flex-wrap gap-1 text-xs" onClick={() => setTabValue("customize")}><PencilRuler className="h-4 w-4" />Customize</TabsTrigger>
<TabsTrigger
value="images"
className="flex flex-col gap-1 text-xs"
onClick={() => setTabValue("images")}
>
<Upload className="h-4 w-4" />
<span className="hidden sm:block">Images</span>
</TabsTrigger>
<TabsTrigger
value="customize"
className="flex flex-col gap-1 text-xs"
onClick={() => setTabValue("customize")}
>
<PencilRuler className="h-4 w-4" />
<span className="hidden sm:block">Customize</span>
</TabsTrigger>
</TabsList>
{/* All icons */}
@ -109,7 +136,7 @@ const ObjectPanel = () => {
</Tabs>
</CardContent>
</ScrollArea>
</CollapsibleContent>
@ -117,7 +144,7 @@ const ObjectPanel = () => {
</Card>
</Rnd>
</RndComponent>
)
}

View file

@ -8,7 +8,7 @@ const ScrollArea = React.forwardRef(({ className, children, ...props }, ref) =>
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit] p-1">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
@ -24,9 +24,9 @@ const ScrollBar = React.forwardRef(({ className, orientation = "vertical", ...pr
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
className
)}
{...props}>