layers drag drope done
@@ -11,6 +11,9 @@
|
||||
"start": "next start --port 3333"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.1.0",
|
||||
"@dnd-kit/sortable": "^8.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@headlessui/react": "^1.7.17",
|
||||
"@next-auth/prisma-adapter": "^1.0.7",
|
||||
"@prisma/client": "^5.1.1",
|
||||
@@ -38,6 +41,7 @@
|
||||
"@trpc/react-query": "^10.37.1",
|
||||
"@trpc/server": "^10.37.1",
|
||||
"@types/uuid": "^9.0.3",
|
||||
"@uiw/react-color": "^2.0.3",
|
||||
"axios": "^1.5.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
|
||||
372
pnpm-lock.yaml
generated
@@ -5,6 +5,15 @@ settings:
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@dnd-kit/core':
|
||||
specifier: ^6.1.0
|
||||
version: 6.1.0(react-dom@18.2.0)(react@18.2.0)
|
||||
'@dnd-kit/sortable':
|
||||
specifier: ^8.0.0
|
||||
version: 8.0.0(@dnd-kit/core@6.1.0)(react@18.2.0)
|
||||
'@dnd-kit/utilities':
|
||||
specifier: ^3.2.2
|
||||
version: 3.2.2(react@18.2.0)
|
||||
'@headlessui/react':
|
||||
specifier: ^1.7.17
|
||||
version: 1.7.17(react-dom@18.2.0)(react@18.2.0)
|
||||
@@ -86,6 +95,9 @@ dependencies:
|
||||
'@types/uuid':
|
||||
specifier: ^9.0.3
|
||||
version: 9.0.6
|
||||
'@uiw/react-color':
|
||||
specifier: ^2.0.3
|
||||
version: 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
axios:
|
||||
specifier: ^1.5.1
|
||||
version: 1.5.1
|
||||
@@ -217,6 +229,49 @@ packages:
|
||||
dependencies:
|
||||
regenerator-runtime: 0.14.0
|
||||
|
||||
/@dnd-kit/accessibility@3.1.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-ea7IkhKvlJUv9iSHJOnxinBcoOI3ppGnnL+VDJ75O45Nss6HtZd8IdN8touXPDtASfeI2T2LImb8VOZcL47wjQ==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@dnd-kit/core@6.1.0(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-J3cQBClB4TVxwGo3KEjssGEXNJqGVWx17aRTZ1ob0FliR5IjYgTxl5YJbKTzA6IzrtelotH19v6y7uoIRUZPSg==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
dependencies:
|
||||
'@dnd-kit/accessibility': 3.1.0(react@18.2.0)
|
||||
'@dnd-kit/utilities': 3.2.2(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@dnd-kit/sortable@8.0.0(@dnd-kit/core@6.1.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-U3jk5ebVXe1Lr7c2wU7SBZjcWdQP+j7peHJfCspnA81enlu88Mgd7CC8Q+pub9ubP7eKVETzJW+IBAhsqbSu/g==}
|
||||
peerDependencies:
|
||||
'@dnd-kit/core': ^6.1.0
|
||||
react: '>=16.8.0'
|
||||
dependencies:
|
||||
'@dnd-kit/core': 6.1.0(react-dom@18.2.0)(react@18.2.0)
|
||||
'@dnd-kit/utilities': 3.2.2(react@18.2.0)
|
||||
react: 18.2.0
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@dnd-kit/utilities@3.2.2(react@18.2.0):
|
||||
resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@eslint-community/eslint-utils@4.4.0(eslint@8.52.0):
|
||||
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
@@ -2175,6 +2230,323 @@ packages:
|
||||
eslint-visitor-keys: 3.4.3
|
||||
dev: true
|
||||
|
||||
/@uiw/color-convert@2.0.3(@babel/runtime@7.23.2):
|
||||
resolution: {integrity: sha512-lP/dnZzaiUDMrn3F+WYAG/TLhIanoy5A0HAPEO6Z/s3Jv5AI0nOM2bVOm0HI+vNiHZkVTkE1oGP0k+endEA+9A==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-alpha@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-bTO0jMTT2fFZr8lGpDrOCbMSbidkgYMuCmyc6A8p6WfyCznKZvKG5WG9KukDOB2ReJUZKIaiR20CgUa6opS3Hw==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-drag-event-interactive': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-block@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-KDl4PBtv8/IAQ/HeonxsFka+9ppBTjKBhI7U/j6oxqvVPWuvqOZSGlAtr9oIGZnEG14CXZPg4xNVLkZQkfJ8vg==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-editable-input': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-swatch': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-chrome@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-qT9mdTf1wc1zTAb5K2sAs4VtNM9GwcR36ZeCbrLYLRMpovu4ynsZBAn0hR4RYc1xJJsedRZtelWPInAKLvwyEA==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-alpha': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input-hsla': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input-rgba': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-github': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-hue': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-saturation': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-circle@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-IBMzGOSVQvN/x5dAFk2j1bkGzWX/nWz9kmbcdETRhIQtBcP1AmrQHaRL3E+GX7oTB6cRMg2W20baxHgj97NQIQ==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-swatch': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-colorful@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-IjnvYyroW/Kmz1ICSwQ6HUpl7cs6Rkh2mVuFGvYd8FOxBjbQuAI/pfVi8I54rgkesn8uRVYlbvl4ROfAl3RrHw==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-alpha': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-hue': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-saturation': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-compact@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-xjPn46zuFZZ0RqEB8ZelSdtU0ySpp4Ekgw+Wu/W7ZZrUGBXypgFSbQqudggOq7ovhU+4qxGOGqrN4SGHqH36mg==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-editable-input': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input-rgba': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-swatch': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-editable-input-hsla@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-RwFgPlOv/OjAtegCYIsoIFbWHhAEE44SMT/44zGlRfYq6PX3KvXjEfHpM7F7EFJHYuRfKFpQRhikc1kSkOeWVw==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-editable-input-rgba': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-editable-input-rgba@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-ROz25EVr5F9XgNLG9p0RKMTgzg5ORh2RxMKC8Ch3vXrdTt4FL350Kq0N5KMHs7gyQAzcr4GQmuaCLlbEHHYAwA==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-editable-input': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-editable-input@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-Zy+BuvtQ5c2XcSPN+zgVQ0gnz4fl+1YB1kpKnTYNyZptL2HXWPygwz2OdfNB/bVNRR34s5/4x3jD/zNQTBe60w==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-github@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-pMv6lc76UmReAKtKlNSyHoFTpeeyD4z2Vr51uiiQqHS09wXisyPRX0KvpvWnGtBXXci9dkOx8kpohwhiKGpPHw==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-swatch': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-hue@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-Bi9/JkLH6FSxULC52y7kjLlunkRbL6TRuAzm5+BBs/4tSf+VL8Xp5Dr2gCPJG1vuA4ohDx9vl3P5QO4Rk9h8wQ==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-alpha': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-material@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-xgJ76LvF+LM+8emUby1EwcIwdtTLlA0JpQePwZi78J1DY3gQs9tTWHCaAkqZoprHiNlzXTHtqi8Wg/i0MIPLPw==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-editable-input': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input-rgba': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-saturation@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-+AZM3WemWv7w/uRGmSY5lXWdSJoKKysKMW+C7/qkWNQmN/WjG6YmC4ZtcEqPr7BbWFXSS2DJTn15fNBvxCFKDg==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-drag-event-interactive': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-shade-slider@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-TTxNkzExgurWKklC90+D1HbtRMD37wKoK9kOLOvLynEm3r5SgcifjvZLNIBC8CUTbQutazAKl1IXgQCST09ang==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-alpha': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-sketch@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-OS7nD7DlsYhtQJrSQOwM2kXcLrpqYzbLcY6dy55odmgMPx1ixbhhgXfDp8zAPOT5+guPAOdfy4PV4fpUGGYiSg==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-alpha': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input-rgba': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-hue': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-saturation': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-swatch': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-slider@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-ejIVLFVwNYGlGqesJOwOgw1DYBljeHB2pznJCQI/YZyVVq9pM/fjDCjpxFQ/BgU7k/Ezs/UW90QHIxOy+tct4g==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-alpha': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-swatch@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-xKUASrSB4wPQ+kmMV1Yr1gQ9BZvMzkdotr9o+CYFGvZNSLclEur0cIhu5RkBhZ6PGP6Vd54mod43amY/a905lw==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color-wheel@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-IEQ75777ZNvaA2dunTc/zD7OmcwbTjKeLGZ7Mo8ID+Em0rLF7SCC+9g2pF8G468MAc9HwyfRjv8K6Z69PWUyNg==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-drag-event-interactive': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-color@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-W2zin6cxq1clQAJoUSbFbp07SkMKtYaoCOK1dLGE0OUM/oYMEw9eXTa8VbvVCY1e3plkXnA+/HgiCFBm6tVsQg==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
'@uiw/color-convert': 2.0.3(@babel/runtime@7.23.2)
|
||||
'@uiw/react-color-alpha': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-block': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-chrome': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-circle': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-colorful': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-compact': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input-hsla': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-editable-input-rgba': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-github': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-hue': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-material': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-saturation': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-shade-slider': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-sketch': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-slider': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-swatch': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@uiw/react-color-wheel': 2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@uiw/react-drag-event-interactive@2.0.3(@babel/runtime@7.23.2)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-r9VQbvpk2z0ux3GenmT5K4BVQqT91eBSDQjYuR43Ya0kJaD2yJPuPe8JqvKTFR3/C9kldolJoWbxl0mbuu1X0w==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.19.0'
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.2
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@ungap/structured-clone@1.2.0:
|
||||
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
|
||||
dev: true
|
||||
|
||||
11
src/assets/12.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.9.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 595.28 841.89" style="enable-background:new 0 0 595.28 841.89;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CDA150;}
|
||||
.st1{font-family:'GaramondThree';}
|
||||
.st2{font-size:16px;}
|
||||
</style>
|
||||
<text transform="matrix(0.4439 0 0 1 283.2148 425.3496)" class="st0 st1 st2">12% vol.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 575 B |
27
src/assets/FE.svg
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.9.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 595.28 841.89" style="enable-background:new 0 0 595.28 841.89;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CDA150;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M296.14,421.35c-0.14-0.22-0.71-0.39-0.53-0.4c0.18-0.01,0.53-0.47,0.71-0.56c0.18-0.08,0.21,0,0.45,1.3
|
||||
c0,0.01,0,0.02,0.01,0.04C296.56,421.64,296.23,421.5,296.14,421.35z M296.45,417.75c0,0,0.2-0.01,0.22,0.1
|
||||
c0.01,0.11,0.01,0.57-0.25,0.67C296.42,418.52,296.27,417.96,296.45,417.75z M298.97,417.72c0.02-0.05,0.09-0.16,0.23-0.28
|
||||
c0.15-0.12,0.31-0.19,0.36-0.21C299.5,417.61,299.11,417.7,298.97,417.72z M300.03,421.44c0.15-0.06,0.54-2.56,0.56-2.76
|
||||
c0.01-0.19-0.08-0.32-0.11-0.5c-0.03-0.18-0.39-0.17-0.39-0.17s-0.52-0.85-0.52-0.84c-0.01,0-0.21,0.07-0.4,0.23
|
||||
c-0.19,0.16-0.25,0.31-0.25,0.32h0l0.67,0.72c-0.07,0.19,0.35,0.25,0.42,0.49c0.07,0.24-0.38,1.42-0.53,1.49
|
||||
c-0.15,0.07-1-0.91-1.18-1.14c-0.18-0.24-0.7-0.42-0.7-0.42c-0.1-0.14-0.11-0.4,0.03-0.61c0.14-0.21,0.4-0.11,0.63-0.14
|
||||
c0.22-0.03,0.08-0.45,0.07-0.57c-0.01-0.13,0.11-0.08,0.18-0.11c0.07-0.03-0.05-0.24-0.14-0.34c-0.08-0.1-0.1-0.27-0.13-0.61
|
||||
c-0.03-0.35-0.64-0.68-1.11-0.67c-0.47,0.01-0.71,0.25-0.86,0.49c-0.15,0.24-0.14,0.27-0.32,0.17c-0.18-0.1-0.24,0.55-0.42,0.77
|
||||
c-0.18,0.22-0.21,1.17-0.21,1.17l0.58,0.88c-0.6,0.4-1.35,1.53-1.44,1.73c-0.08,0.19-0.04,0.24,0.6,0.61
|
||||
c0.52,0.3,1.43,0.59,1.76,0.69c-0.07,0.88-0.61,1.36-0.69,1.68c-0.1,0.39,0.18,0.85,0.39,1.1c0.21,0.25,0.11,0.61,0.11,0.61
|
||||
l0.92,0.11l0.91-0.13l0.95-0.25c-0.14-0.24-0.06-0.68,0-1c0.06-0.32,0.78-0.64,0.84-1.39c0.05-0.75-0.99-1.85-0.99-1.85
|
||||
C299.38,421.42,299.87,421.5,300.03,421.44z"/>
|
||||
<path class="st0" d="M300.21,424.88l-5.92-8.32c0.85-0.63,1.9-1.01,3.04-1.01c2.82,0,5.11,2.29,5.11,5.11
|
||||
C302.43,422.41,301.55,423.96,300.21,424.88z M292.22,420.66c0-1.48,0.63-2.81,1.63-3.74l5.87,8.25c-0.72,0.38-1.53,0.6-2.4,0.6
|
||||
C294.51,425.77,292.22,423.48,292.22,420.66z M297.32,414.99c-3.13,0-5.67,2.54-5.67,5.67c0,3.13,2.54,5.67,5.67,5.67
|
||||
c3.13,0,5.67-2.54,5.67-5.67C302.99,417.54,300.45,414.99,297.32,414.99z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
11
src/assets/PRODUIT DE FRANCE.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.9.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 595.28 841.89" style="enable-background:new 0 0 595.28 841.89;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CDA150;}
|
||||
.st1{font-family:'Helvetica';}
|
||||
.st2{font-size:6px;}
|
||||
</style>
|
||||
<text transform="matrix(0.66 0 0 1 289.8221 375.1115)" class="st0 st1 st2">PRODUCE OF FRANCE</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 577 B |
11
src/assets/QUALITÉ.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.9.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 595.28 841.89" style="enable-background:new 0 0 595.28 841.89;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CDA150;}
|
||||
.st1{font-family:'Helvetica';}
|
||||
.st2{font-size:14px;}
|
||||
</style>
|
||||
<text transform="matrix(0.66 0 0 1 299.1375 375.1115)" class="st0 st1 st2">BRUT</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 565 B |
11
src/assets/centilitrage.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.9.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 595.28 841.89" style="enable-background:new 0 0 595.28 841.89;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CDA150;}
|
||||
.st1{font-family:'GaramondThree';}
|
||||
.st2{font-size:20px;}
|
||||
</style>
|
||||
<text transform="matrix(0.4084 0 0 1 283.9296 426.5225)" class="st0 st1 st2">750 ml</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 573 B |
11
src/assets/sulfites.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.9.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 595.28 841.89" style="enable-background:new 0 0 595.28 841.89;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CDA150;}
|
||||
.st1{font-family:'Helvetica';}
|
||||
.st2{font-size:6px;}
|
||||
</style>
|
||||
<text transform="matrix(0.66 0 0 1 286.9607 375.1115)" class="st0 st1 st2">Contient des sulfites</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 581 B |
11
src/assets/ÉLABORATION.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.9.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 595.28 841.89" style="enable-background:new 0 0 595.28 841.89;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CDA150;}
|
||||
.st1{font-family:'Helvetica';}
|
||||
.st2{font-size:6px;}
|
||||
</style>
|
||||
<text transform="matrix(0.66 0 0 1 254.2979 375.1115)" class="st0 st1 st2">ÉLABORÉ PAR ERAL CHARLES DELROCHE, 51200 ÉPERNAY, FRANCE - RM-00000-01</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 633 B |
@@ -12,6 +12,8 @@ import {
|
||||
import { useEffect, useState } from "react";
|
||||
import { Toolbar } from "@/components/toolbar";
|
||||
import TransformableText from "@/components/transformable-text";
|
||||
import LayerBorder from "@/components/layer-border";
|
||||
import { CANVAS_PADDING_X, CANVAS_PADDING_Y } from "@/consts/canvas-params";
|
||||
|
||||
const Canvas = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -33,7 +35,6 @@ const Canvas = () => {
|
||||
if (!clickedOnEmpty) {
|
||||
return;
|
||||
}
|
||||
console.log(target);
|
||||
dispatch(deselectItem());
|
||||
};
|
||||
|
||||
@@ -54,42 +55,6 @@ const Canvas = () => {
|
||||
setSelected(!isEditing);
|
||||
}
|
||||
|
||||
// function toggleTransforming() {
|
||||
// setIsTransforming(!isTransforming);
|
||||
// setSelected(!isTransforming);
|
||||
// }
|
||||
//
|
||||
// const handleWheel = (e: Konva.KonvaEventObject<WheelEvent>) => {
|
||||
// e.evt.preventDefault();
|
||||
//
|
||||
// const scaleBy = 1.02;
|
||||
// const targetStage = e.target.getStage()!;
|
||||
// const oldScale = targetStage.scaleX();
|
||||
//
|
||||
// const mousePointTo = {
|
||||
// x:
|
||||
// targetStage.getPointerPosition().x / oldScale -
|
||||
// targetStage.x() / oldScale,
|
||||
// y:
|
||||
// targetStage.getPointerPosition().y / oldScale -
|
||||
// targetStage.y() / oldScale,
|
||||
// };
|
||||
//
|
||||
// const newScale = e.evt.deltaY < 0 ? oldScale * scaleBy : oldScale / scaleBy;
|
||||
//
|
||||
// dispatch(
|
||||
// setStageScale({
|
||||
// scale: newScale,
|
||||
// x:
|
||||
// (targetStage.getPointerPosition().x / newScale - mousePointTo.x) *
|
||||
// newScale,
|
||||
// y:
|
||||
// (targetStage.getPointerPosition().y / newScale - mousePointTo.y) *
|
||||
// newScale,
|
||||
// }),
|
||||
// );
|
||||
// };
|
||||
|
||||
return (
|
||||
<div className="relative flex h-full w-full flex-col items-center">
|
||||
<Toolbar />
|
||||
@@ -112,7 +77,6 @@ const Canvas = () => {
|
||||
y={stage.y}
|
||||
scaleX={stage.scale}
|
||||
scaleY={stage.scale}
|
||||
// onWheel={handleWheel}
|
||||
>
|
||||
<Layer>
|
||||
{!!backgroundRect && (
|
||||
@@ -125,7 +89,14 @@ const Canvas = () => {
|
||||
id={backgroundId}
|
||||
/>
|
||||
)}
|
||||
{items.map((item) => {
|
||||
</Layer>
|
||||
<Layer
|
||||
clipX={CANVAS_PADDING_X}
|
||||
clipY={CANVAS_PADDING_Y}
|
||||
clipWidth={stage.width - 2 * CANVAS_PADDING_X}
|
||||
clipHeight={stage.height - 2 * CANVAS_PADDING_Y}
|
||||
>
|
||||
{items.toReversed().map((item) => {
|
||||
if (item.type === StageItemType.Image) {
|
||||
return (
|
||||
<TransformableImage
|
||||
@@ -158,24 +129,9 @@ const Canvas = () => {
|
||||
}
|
||||
})}
|
||||
</Layer>
|
||||
{/* <Layer>
|
||||
<Rect
|
||||
x={50}
|
||||
y={220}
|
||||
fontSize={48}
|
||||
width={100}
|
||||
height={100}
|
||||
fill="red"
|
||||
/>
|
||||
<Rect
|
||||
x={30}
|
||||
y={200}
|
||||
fontSize={48}
|
||||
width={100}
|
||||
height={100}
|
||||
fill="yellow"
|
||||
/>
|
||||
</Layer>*/}
|
||||
{/*<Legales />*/}
|
||||
|
||||
<LayerBorder />
|
||||
</Stage>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import React from "react";
|
||||
import { TbFlipHorizontal, TbFlipVertical } from "react-icons/tb";
|
||||
import { BsArrowsFullscreen } from "react-icons/Bs";
|
||||
import { Toggle } from "@/components/ui/toggle";
|
||||
import { useAppDispatch } from "@/hooks";
|
||||
import { useAppDispatch, useAppSelector } from "@/hooks";
|
||||
import { type StageImageItem, updateImage } from "@/store/app.slice";
|
||||
import ImageOpacityTool from "@/components/image-editing-tools/image-opacity-tool";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { CANVAS_PADDING_X, CANVAS_PADDING_Y } from "@/consts/canvas-params";
|
||||
|
||||
type Props = {
|
||||
selectedItemId: string;
|
||||
@@ -13,6 +15,9 @@ type Props = {
|
||||
|
||||
export function ImageToolbar({ selectedItemId, currentImage }: Props) {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const stageParams = useAppSelector((state) => state.app.stage);
|
||||
|
||||
const flipImageVerticaly = () => {
|
||||
const currentScale = currentImage.scaleY;
|
||||
let editOffsetY = currentImage.height;
|
||||
@@ -40,6 +45,19 @@ export function ImageToolbar({ selectedItemId, currentImage }: Props) {
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const setAsBackground = () => {
|
||||
dispatch(
|
||||
updateImage({
|
||||
id: selectedItemId,
|
||||
x: CANVAS_PADDING_X,
|
||||
y: CANVAS_PADDING_Y,
|
||||
width: stageParams.width - 2 * CANVAS_PADDING_X,
|
||||
height: stageParams.height - 2 * CANVAS_PADDING_Y,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Toggle onClick={() => flipImageHorizontaly()}>
|
||||
@@ -53,6 +71,9 @@ export function ImageToolbar({ selectedItemId, currentImage }: Props) {
|
||||
selectedItemId={selectedItemId}
|
||||
currentImage={currentImage}
|
||||
/>
|
||||
<Toggle onClick={() => setAsBackground()}>
|
||||
<BsArrowsFullscreen />
|
||||
</Toggle>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
63
src/components/layer-border.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import React from "react";
|
||||
import { Layer, Line } from "react-konva";
|
||||
import {
|
||||
CANVAS_PADDING_X,
|
||||
CANVAS_PADDING_Y,
|
||||
DASH_SPACING,
|
||||
DASH_STROKE_COLOR,
|
||||
DASH_STROKE_WIDTH,
|
||||
DASH_WIDTH,
|
||||
} from "@/consts/canvas-params";
|
||||
import { useAppSelector } from "@/hooks";
|
||||
|
||||
export default function LayerBorder() {
|
||||
const stage = useAppSelector((state) => state.app.stage);
|
||||
return (
|
||||
<Layer>
|
||||
<Line
|
||||
points={[
|
||||
CANVAS_PADDING_X,
|
||||
CANVAS_PADDING_Y,
|
||||
stage.width - CANVAS_PADDING_X,
|
||||
CANVAS_PADDING_Y,
|
||||
]}
|
||||
stroke={DASH_STROKE_COLOR}
|
||||
strokeWidth={DASH_STROKE_WIDTH}
|
||||
dash={[DASH_WIDTH, DASH_SPACING]}
|
||||
/>
|
||||
<Line
|
||||
points={[
|
||||
CANVAS_PADDING_X,
|
||||
CANVAS_PADDING_Y,
|
||||
CANVAS_PADDING_X,
|
||||
stage.height - CANVAS_PADDING_Y,
|
||||
]}
|
||||
stroke={DASH_STROKE_COLOR}
|
||||
strokeWidth={DASH_STROKE_WIDTH}
|
||||
dash={[DASH_WIDTH, DASH_SPACING]}
|
||||
/>
|
||||
<Line
|
||||
points={[
|
||||
CANVAS_PADDING_X,
|
||||
stage.height - CANVAS_PADDING_Y,
|
||||
stage.width - CANVAS_PADDING_X,
|
||||
stage.height - CANVAS_PADDING_Y,
|
||||
]}
|
||||
stroke={DASH_STROKE_COLOR}
|
||||
strokeWidth={DASH_STROKE_WIDTH}
|
||||
dash={[DASH_WIDTH, DASH_SPACING]}
|
||||
/>
|
||||
<Line
|
||||
points={[
|
||||
stage.width - CANVAS_PADDING_X,
|
||||
CANVAS_PADDING_Y,
|
||||
stage.width - CANVAS_PADDING_X,
|
||||
stage.height - CANVAS_PADDING_Y,
|
||||
]}
|
||||
stroke={DASH_STROKE_COLOR}
|
||||
strokeWidth={DASH_STROKE_WIDTH}
|
||||
dash={[DASH_WIDTH, DASH_SPACING]}
|
||||
/>
|
||||
</Layer>
|
||||
);
|
||||
}
|
||||
42
src/components/layer-item.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import React from "react";
|
||||
import { useSortable } from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
import { type StageItem, StageItemType } from "@/store/app.slice";
|
||||
import { useAppDispatch } from "@/hooks";
|
||||
|
||||
export default function LayerItem({ item }: { item: StageItem }) {
|
||||
const dispatch = useAppDispatch();
|
||||
const { attributes, listeners, setNodeRef, transform, transition } =
|
||||
useSortable({
|
||||
id: item.id,
|
||||
});
|
||||
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
};
|
||||
return (
|
||||
<div
|
||||
style={style}
|
||||
ref={setNodeRef}
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
className="m-2 flex items-center justify-between rounded-md border p-2 text-black"
|
||||
>
|
||||
{item.type === StageItemType.Text ? (
|
||||
item.params.text < 5 ? (
|
||||
item.params.text
|
||||
) : (
|
||||
item.params.text?.substring(0, 5) + "..."
|
||||
)
|
||||
) : (
|
||||
<img
|
||||
className="max-h-8 w-8"
|
||||
alt={item.params.imageUrl}
|
||||
src={item.params.imageUrl}
|
||||
/>
|
||||
)}
|
||||
<span className="">{item.type}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { UserNav } from "./user-nav";
|
||||
import Image from "next/image";
|
||||
import logo from "@/assets/logo.png";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
export const Navbar = () => {
|
||||
return (
|
||||
@@ -12,7 +13,7 @@ export const Navbar = () => {
|
||||
alt="Logo"
|
||||
layout="fill" // required
|
||||
objectFit="cover" // change as you like
|
||||
className="rounded-full" // you can use other classes here too
|
||||
className="rounded-full object-cover" // you can use other classes here too
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-auto flex items-center space-x-4">
|
||||
|
||||
@@ -8,12 +8,13 @@ import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { RxLayout } from "react-icons/rx";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useAppDispatch } from "@/hooks";
|
||||
import { useAppDispatch, useAppSelector } from "@/hooks";
|
||||
import { selectBackground } from "@/store/app.slice";
|
||||
|
||||
export const BackgroundSelect = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const [open, setOpen] = useState(false);
|
||||
const bgColor = useAppSelector((state) => state.app.background);
|
||||
|
||||
const handleBackgroundSelect = (color: string) => {
|
||||
dispatch(selectBackground(color));
|
||||
@@ -40,30 +41,17 @@ export const BackgroundSelect = () => {
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<div
|
||||
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary"
|
||||
onClick={() => handleBackgroundSelect("red")}
|
||||
>
|
||||
Red
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label
|
||||
htmlFor="paypal"
|
||||
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary"
|
||||
onClick={() => handleBackgroundSelect("blue")}
|
||||
>
|
||||
Blue
|
||||
</Label>
|
||||
</div>
|
||||
<div>
|
||||
<Label
|
||||
htmlFor="apple"
|
||||
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary"
|
||||
onClick={() => handleBackgroundSelect("green")}
|
||||
>
|
||||
Green
|
||||
<input
|
||||
className="m-2 "
|
||||
type="color"
|
||||
value={bgColor}
|
||||
onChange={(e) => handleBackgroundSelect(e.target.value)}
|
||||
/>
|
||||
</Label>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
@@ -8,19 +8,26 @@ import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { RxStack } from "react-icons/rx";
|
||||
import { useAppDispatch, useAppSelector } from "@/hooks";
|
||||
import { OrderDirection, updateItemOrder } from "@/store/app.slice";
|
||||
import { selectItem, setStageItems } from "@/store/app.slice";
|
||||
import { closestCenter, DndContext, type DragEndEvent } from "@dnd-kit/core";
|
||||
import {
|
||||
arrayMove,
|
||||
SortableContext,
|
||||
verticalListSortingStrategy,
|
||||
} from "@dnd-kit/sortable";
|
||||
import LayerItem from "@/components/layer-item";
|
||||
|
||||
export const Layers = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const items = useAppSelector((state) => state.app.items);
|
||||
|
||||
const updateImageLayer = (id: string, direction: OrderDirection) => {
|
||||
dispatch(
|
||||
updateItemOrder({
|
||||
id,
|
||||
direction,
|
||||
}),
|
||||
);
|
||||
const handleDragEnd = (e: DragEndEvent) => {
|
||||
const { active, over } = e;
|
||||
const oldIndex = items.findIndex((item) => item.id === active.id);
|
||||
const newIndex = items.findIndex((item) => item.id === over?.id);
|
||||
const result = arrayMove(items, oldIndex, newIndex);
|
||||
dispatch(setStageItems(result));
|
||||
dispatch(selectItem(active.id));
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -33,26 +40,22 @@ export const Layers = () => {
|
||||
<PopoverContent side="right">
|
||||
<Card className="p-2">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-center">Layer</CardTitle>
|
||||
<CardTitle className="text-center">Layers</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-2">
|
||||
{items.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-2 ">
|
||||
{item.id}
|
||||
<Button
|
||||
className="h-full"
|
||||
onClick={() => updateImageLayer(item.id, OrderDirection.Up)}
|
||||
>
|
||||
+
|
||||
</Button>
|
||||
<Button
|
||||
className="h-full"
|
||||
onClick={() => updateImageLayer(item.id, OrderDirection.Down)}
|
||||
>
|
||||
-
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
<CardContent className="grid items-center gap-2 p-2 ">
|
||||
<DndContext
|
||||
collisionDetection={closestCenter}
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={items}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
{items.map((item) => (
|
||||
<LayerItem item={item} key={item.id} />
|
||||
))}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</PopoverContent>
|
||||
|
||||
0
src/components/layout/sidebar/legacy.tsx
Normal file
@@ -1,33 +1,69 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { PiFrameCornersDuotone } from "react-icons/pi";
|
||||
import { useAppDispatch } from "@/hooks";
|
||||
import { Card, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { useAppDispatch } from "@/hooks";
|
||||
import { LuLayoutTemplate } from "react-icons/lu";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
|
||||
export function SelectTemplate() {
|
||||
export const SelectTemplate = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleSizeSelect = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
return (
|
||||
<Popover>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="secondary" className="text-xl">
|
||||
<PiFrameCornersDuotone />
|
||||
<Button
|
||||
onClick={() => setOpen(true)}
|
||||
variant="outline"
|
||||
className="text-xl"
|
||||
>
|
||||
<LuLayoutTemplate />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent side="right">
|
||||
{/*<Input type="file" onChange={handleImageUploaded} />*/}
|
||||
|
||||
<Card className="p-2">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-center">Cadre</CardTitle>
|
||||
<PopoverContent side="right" className="mt-4">
|
||||
<Card className="p-3">
|
||||
<CardHeader className="mb-2 p-2 text-center">
|
||||
<CardTitle>Template</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<ScrollArea>
|
||||
<div className="flex h-64 w-full flex-col items-center justify-between gap-4">
|
||||
<div className="rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary">
|
||||
Image
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary">
|
||||
Image
|
||||
</div>{" "}
|
||||
<div className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary">
|
||||
Image
|
||||
</div>{" "}
|
||||
<div className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary">
|
||||
Image
|
||||
</div>{" "}
|
||||
<div className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary">
|
||||
Image
|
||||
</div>{" "}
|
||||
<div className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary">
|
||||
Image
|
||||
</div>{" "}
|
||||
<div className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary">
|
||||
Image
|
||||
</div>{" "}
|
||||
<div className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-2 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary">
|
||||
Image
|
||||
</div>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</Card>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,6 +3,8 @@ import ImageInput from "@/components/layout/sidebar/image-input";
|
||||
import SizeSelect from "@/components/layout/sidebar/size-select";
|
||||
import { BackgroundSelect } from "@/components/layout/sidebar/background-select";
|
||||
import { Layers } from "@/components/layout/sidebar/layers";
|
||||
import { SelectTemplate } from "@/components/layout/sidebar/select-template";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
export function Sidebar() {
|
||||
return (
|
||||
@@ -10,7 +12,7 @@ export function Sidebar() {
|
||||
<SizeSelect />
|
||||
<TextInput />
|
||||
<ImageInput />
|
||||
{/*<SelectTemplate />*/}
|
||||
<SelectTemplate />
|
||||
<BackgroundSelect />
|
||||
<Layers />
|
||||
</div>
|
||||
|
||||
@@ -42,13 +42,13 @@ const SizeSelect = () => {
|
||||
</CardHeader>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button onClick={() => handleStageSizeSelect(350, 400)}>
|
||||
<Button onClick={() => handleStageSizeSelect(269.32, 165.87)}>
|
||||
Petit Format
|
||||
</Button>
|
||||
<Button onClick={() => handleStageSizeSelect(500, 500)}>
|
||||
<Button onClick={() => handleStageSizeSelect(323.15, 227)}>
|
||||
Moyen Format
|
||||
</Button>
|
||||
<Button onClick={() => handleStageSizeSelect(800, 600)}>
|
||||
<Button onClick={() => handleStageSizeSelect(410, 289)}>
|
||||
Grand Format
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
20
src/components/legales.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
import { Image, Layer } from "react-konva";
|
||||
import women from "../assets/logo.png";
|
||||
import useImage from "use-image";
|
||||
|
||||
export default function Legales() {
|
||||
const [test] = useImage(women);
|
||||
return (
|
||||
<Layer>
|
||||
<Image
|
||||
width={100}
|
||||
height={100}
|
||||
x={200}
|
||||
y={200}
|
||||
alt={women}
|
||||
image={test}
|
||||
/>
|
||||
</Layer>
|
||||
);
|
||||
}
|
||||
46
src/components/ui/scroll-area.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as React from "react";
|
||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
));
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
|
||||
|
||||
const ScrollBar = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" &&
|
||||
"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]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
));
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
|
||||
|
||||
export { ScrollArea, ScrollBar };
|
||||
27
src/components/ui/switch.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as React from "react"
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
|
||||
export { Switch }
|
||||
117
src/components/ui/table.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Table = React.forwardRef<
|
||||
HTMLTableElement,
|
||||
React.HTMLAttributes<HTMLTableElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="relative w-full overflow-auto">
|
||||
<table
|
||||
ref={ref}
|
||||
className={cn("w-full caption-bottom text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
Table.displayName = "Table"
|
||||
|
||||
const TableHeader = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
||||
))
|
||||
TableHeader.displayName = "TableHeader"
|
||||
|
||||
const TableBody = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tbody
|
||||
ref={ref}
|
||||
className={cn("[&_tr:last-child]:border-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableBody.displayName = "TableBody"
|
||||
|
||||
const TableFooter = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tfoot
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableFooter.displayName = "TableFooter"
|
||||
|
||||
const TableRow = React.forwardRef<
|
||||
HTMLTableRowElement,
|
||||
React.HTMLAttributes<HTMLTableRowElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tr
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableRow.displayName = "TableRow"
|
||||
|
||||
const TableHead = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.ThHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableHead.displayName = "TableHead"
|
||||
|
||||
const TableCell = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<td
|
||||
ref={ref}
|
||||
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableCell.displayName = "TableCell"
|
||||
|
||||
const TableCaption = React.forwardRef<
|
||||
HTMLTableCaptionElement,
|
||||
React.HTMLAttributes<HTMLTableCaptionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<caption
|
||||
ref={ref}
|
||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableCaption.displayName = "TableCaption"
|
||||
|
||||
export {
|
||||
Table,
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableCaption,
|
||||
}
|
||||
6
src/consts/canvas-params.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const CANVAS_PADDING_X = 20;
|
||||
export const CANVAS_PADDING_Y = 20;
|
||||
export const DASH_WIDTH = 5;
|
||||
export const DASH_SPACING = 3;
|
||||
export const DASH_STROKE_WIDTH = 1;
|
||||
export const DASH_STROKE_COLOR = "#c6a25e";
|
||||
@@ -13,7 +13,6 @@ export enum StageItemType {
|
||||
|
||||
type StageItemCommon = {
|
||||
id: string;
|
||||
order: number;
|
||||
};
|
||||
|
||||
export type StageTextItem = {
|
||||
@@ -28,7 +27,7 @@ export type StageImageItem = {
|
||||
|
||||
type StageItemSpecific = StageTextItem | StageImageItem;
|
||||
|
||||
type StageItem = StageItemCommon & StageItemSpecific;
|
||||
export type StageItem = StageItemCommon & StageItemSpecific;
|
||||
|
||||
const initialState = {
|
||||
stage: { width: 500, height: 500, scale: 1, x: 0, y: 0 },
|
||||
@@ -57,15 +56,13 @@ const defaultImageConfig = {
|
||||
scaleY: 1,
|
||||
};
|
||||
|
||||
export enum OrderDirection {
|
||||
Up = "up",
|
||||
Down = "down",
|
||||
}
|
||||
|
||||
export const appSlice = createSlice({
|
||||
name: "app",
|
||||
initialState,
|
||||
reducers: {
|
||||
setStageItems: (state, action: PayloadAction<StageItem[]>) => {
|
||||
state.items = action.payload;
|
||||
},
|
||||
setStageScale: (
|
||||
state,
|
||||
action: PayloadAction<{ x: number; y: number; scale: number }>,
|
||||
@@ -80,7 +77,6 @@ export const appSlice = createSlice({
|
||||
state.items.push({
|
||||
type: StageItemType.Text,
|
||||
id: textId,
|
||||
order: state.items.length + 1,
|
||||
params: {
|
||||
text: action.payload.initialValue,
|
||||
|
||||
@@ -102,7 +98,6 @@ export const appSlice = createSlice({
|
||||
state.items.push({
|
||||
type: StageItemType.Image,
|
||||
id: imageId,
|
||||
order: state.items.length + 1,
|
||||
params: {
|
||||
imageUrl: action.payload.imageUrl,
|
||||
width: action.payload.width,
|
||||
@@ -112,83 +107,6 @@ export const appSlice = createSlice({
|
||||
});
|
||||
},
|
||||
|
||||
updateImageOrder: (
|
||||
state,
|
||||
action: PayloadAction<{ id: string; direction: OrderDirection }>,
|
||||
) => {
|
||||
const imageToUpdateIndex = state.items.findIndex(
|
||||
(img) => img.id === action.payload.id,
|
||||
);
|
||||
const imageToUpdate = state.items[imageToUpdateIndex];
|
||||
|
||||
if (!imageToUpdate) return;
|
||||
const isLast = imageToUpdate.order === state.items.length;
|
||||
const isFirst = imageToUpdate.order === 1;
|
||||
|
||||
let newOrder = imageToUpdate.order;
|
||||
if (action.payload.direction === OrderDirection.Up && !isLast) {
|
||||
newOrder = imageToUpdate.order + 1;
|
||||
}
|
||||
if (action.payload.direction === OrderDirection.Down && !isFirst) {
|
||||
newOrder = imageToUpdate.order - 1;
|
||||
}
|
||||
|
||||
state.items[imageToUpdateIndex] = {
|
||||
...imageToUpdate,
|
||||
order: newOrder,
|
||||
};
|
||||
|
||||
state.items.sort((a, b) => {
|
||||
if (a === b) return 0;
|
||||
if (a < b) return 1;
|
||||
return -1;
|
||||
});
|
||||
},
|
||||
|
||||
updateItemOrder: (
|
||||
state,
|
||||
action: PayloadAction<{ id: string; direction: OrderDirection }>,
|
||||
) => {
|
||||
const itemToUpdateIndex = state.items.findIndex(
|
||||
(item) => item.id === action.payload.id,
|
||||
);
|
||||
const itemToUpdate = state.items[itemToUpdateIndex];
|
||||
|
||||
if (!itemToUpdate) return;
|
||||
const isLast = itemToUpdate.order === state.items.length;
|
||||
const isFirst = itemToUpdate.order === 1;
|
||||
|
||||
let newOrder = itemToUpdate.order;
|
||||
if (action.payload.direction === OrderDirection.Up && !isLast) {
|
||||
newOrder = itemToUpdate.order + 1;
|
||||
}
|
||||
if (action.payload.direction === OrderDirection.Down && !isFirst) {
|
||||
newOrder = itemToUpdate.order - 1;
|
||||
}
|
||||
const prevItemIndex = state.items.findIndex(
|
||||
(item) => item.order === newOrder,
|
||||
);
|
||||
const prevItem = state.items[prevItemIndex];
|
||||
|
||||
if (!prevItem) return;
|
||||
|
||||
state.items[prevItemIndex] = {
|
||||
...prevItem,
|
||||
order: itemToUpdate.order,
|
||||
};
|
||||
|
||||
state.items[itemToUpdateIndex] = {
|
||||
...itemToUpdate,
|
||||
order: newOrder,
|
||||
};
|
||||
|
||||
state.items.sort((a, b) => {
|
||||
if (a === b) return 0;
|
||||
if (a < b) return 1;
|
||||
return -1;
|
||||
});
|
||||
},
|
||||
|
||||
selectBackground: (state, action: PayloadAction<string>) => {
|
||||
state.background = {
|
||||
fill: action.payload,
|
||||
@@ -258,15 +176,14 @@ export const appSlice = createSlice({
|
||||
});
|
||||
|
||||
export const {
|
||||
setStageScale,
|
||||
addImage,
|
||||
addText,
|
||||
selectItem,
|
||||
deselectItem,
|
||||
updateText,
|
||||
updateImage,
|
||||
deleteStageItem,
|
||||
updateStage,
|
||||
selectBackground,
|
||||
updateItemOrder,
|
||||
setStageItems,
|
||||
selectItem,
|
||||
} = appSlice.actions;
|
||||
|
||||