mirror of
https://github.com/r2r90/canvas-label.git
synced 2025-12-17 05:29:27 +00:00
work in progress
This commit is contained in:
@@ -11,8 +11,11 @@
|
|||||||
"start": "next start"
|
"start": "next start"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@headlessui/react": "^1.7.17",
|
||||||
"@next-auth/prisma-adapter": "^1.0.7",
|
"@next-auth/prisma-adapter": "^1.0.7",
|
||||||
"@prisma/client": "^5.1.1",
|
"@prisma/client": "^5.1.1",
|
||||||
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
|
"@reduxjs/toolkit": "^1.9.6",
|
||||||
"@t3-oss/env-nextjs": "^0.6.0",
|
"@t3-oss/env-nextjs": "^0.6.0",
|
||||||
"@tanstack/react-query": "^4.32.6",
|
"@tanstack/react-query": "^4.32.6",
|
||||||
"@trpc/client": "^10.37.1",
|
"@trpc/client": "^10.37.1",
|
||||||
@@ -23,11 +26,14 @@
|
|||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"konva": "^9.2.0",
|
"konva": "^9.2.0",
|
||||||
|
"lucide-react": "^0.279.0",
|
||||||
"next": "^13.4.19",
|
"next": "^13.4.19",
|
||||||
"next-auth": "^4.23.0",
|
"next-auth": "^4.23.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
"react-icons": "^4.11.0",
|
||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
|
"react-redux": "^8.1.3",
|
||||||
"superjson": "^1.13.1",
|
"superjson": "^1.13.1",
|
||||||
"tailwind-merge": "^1.14.0",
|
"tailwind-merge": "^1.14.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
|||||||
152
pnpm-lock.yaml
generated
152
pnpm-lock.yaml
generated
@@ -5,12 +5,21 @@ settings:
|
|||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@headlessui/react':
|
||||||
|
specifier: ^1.7.17
|
||||||
|
version: 1.7.17(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@next-auth/prisma-adapter':
|
'@next-auth/prisma-adapter':
|
||||||
specifier: ^1.0.7
|
specifier: ^1.0.7
|
||||||
version: 1.0.7(@prisma/client@5.2.0)(next-auth@4.23.1)
|
version: 1.0.7(@prisma/client@5.2.0)(next-auth@4.23.1)
|
||||||
'@prisma/client':
|
'@prisma/client':
|
||||||
specifier: ^5.1.1
|
specifier: ^5.1.1
|
||||||
version: 5.2.0(prisma@5.2.0)
|
version: 5.2.0(prisma@5.2.0)
|
||||||
|
'@radix-ui/react-icons':
|
||||||
|
specifier: ^1.3.0
|
||||||
|
version: 1.3.0(react@18.2.0)
|
||||||
|
'@reduxjs/toolkit':
|
||||||
|
specifier: ^1.9.6
|
||||||
|
version: 1.9.6(react-redux@8.1.3)(react@18.2.0)
|
||||||
'@t3-oss/env-nextjs':
|
'@t3-oss/env-nextjs':
|
||||||
specifier: ^0.6.0
|
specifier: ^0.6.0
|
||||||
version: 0.6.1(typescript@5.2.2)(zod@3.22.2)
|
version: 0.6.1(typescript@5.2.2)(zod@3.22.2)
|
||||||
@@ -41,6 +50,9 @@ dependencies:
|
|||||||
konva:
|
konva:
|
||||||
specifier: ^9.2.0
|
specifier: ^9.2.0
|
||||||
version: 9.2.0
|
version: 9.2.0
|
||||||
|
lucide-react:
|
||||||
|
specifier: ^0.279.0
|
||||||
|
version: 0.279.0(react@18.2.0)
|
||||||
next:
|
next:
|
||||||
specifier: ^13.4.19
|
specifier: ^13.4.19
|
||||||
version: 13.4.19(react-dom@18.2.0)(react@18.2.0)
|
version: 13.4.19(react-dom@18.2.0)(react@18.2.0)
|
||||||
@@ -53,9 +65,15 @@ dependencies:
|
|||||||
react-dom:
|
react-dom:
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0(react@18.2.0)
|
version: 18.2.0(react@18.2.0)
|
||||||
|
react-icons:
|
||||||
|
specifier: ^4.11.0
|
||||||
|
version: 4.11.0(react@18.2.0)
|
||||||
react-konva:
|
react-konva:
|
||||||
specifier: ^18.2.10
|
specifier: ^18.2.10
|
||||||
version: 18.2.10(konva@9.2.0)(react-dom@18.2.0)(react@18.2.0)
|
version: 18.2.10(konva@9.2.0)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
react-redux:
|
||||||
|
specifier: ^8.1.3
|
||||||
|
version: 8.1.3(@types/react-dom@18.2.7)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1)
|
||||||
superjson:
|
superjson:
|
||||||
specifier: ^1.13.1
|
specifier: ^1.13.1
|
||||||
version: 1.13.1
|
version: 1.13.1
|
||||||
@@ -176,6 +194,18 @@ packages:
|
|||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@headlessui/react@1.7.17(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-4am+tzvkqDSSgiwrsEpGWqgGo9dz8qU5M3znCkC4PgkpY4HcCZzEDEvozltGGGHIKl9jbXbZPSH5TWn4sWJdow==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16 || ^17 || ^18
|
||||||
|
react-dom: ^16 || ^17 || ^18
|
||||||
|
dependencies:
|
||||||
|
client-only: 0.0.1
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@humanwhocodes/config-array@0.11.11:
|
/@humanwhocodes/config-array@0.11.11:
|
||||||
resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==}
|
resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==}
|
||||||
engines: {node: '>=10.10.0'}
|
engines: {node: '>=10.10.0'}
|
||||||
@@ -366,6 +396,33 @@ packages:
|
|||||||
resolution: {integrity: sha512-dT7FOLUCdZmq+AunLqB1Iz+ZH/IIS1Fz2THmKZQ6aFONrQD/BQ5ecJ7g2wGS2OgyUFf4OaLam6/bxmgdOBDqig==}
|
resolution: {integrity: sha512-dT7FOLUCdZmq+AunLqB1Iz+ZH/IIS1Fz2THmKZQ6aFONrQD/BQ5ecJ7g2wGS2OgyUFf4OaLam6/bxmgdOBDqig==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
|
|
||||||
|
/@radix-ui/react-icons@1.3.0(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.x || ^17.x || ^18.x
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@reduxjs/toolkit@1.9.6(react-redux@8.1.3)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-Gc4ikl90ORF4viIdAkY06JNUnODjKfGxZRwATM30EdHq8hLSVoSrwXne5dd739yenP5bJxAX7tLuOWK5RPGtrw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.9.0 || ^17.0.0 || ^18
|
||||||
|
react-redux: ^7.2.1 || ^8.0.2
|
||||||
|
peerDependenciesMeta:
|
||||||
|
react:
|
||||||
|
optional: true
|
||||||
|
react-redux:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
immer: 9.0.21
|
||||||
|
react: 18.2.0
|
||||||
|
react-redux: 8.1.3(@types/react-dom@18.2.7)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1)
|
||||||
|
redux: 4.2.1
|
||||||
|
redux-thunk: 2.4.2(redux@4.2.1)
|
||||||
|
reselect: 4.1.8
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@rushstack/eslint-patch@1.3.3:
|
/@rushstack/eslint-patch@1.3.3:
|
||||||
resolution: {integrity: sha512-0xd7qez0AQ+MbHatZTlI1gu5vkG8r7MYRUJAHPAHJBmGLs16zpkrpAVLvjQKQOqaXPDUBwOiJzNc00znHSCVBw==}
|
resolution: {integrity: sha512-0xd7qez0AQ+MbHatZTlI1gu5vkG8r7MYRUJAHPAHJBmGLs16zpkrpAVLvjQKQOqaXPDUBwOiJzNc00znHSCVBw==}
|
||||||
dev: true
|
dev: true
|
||||||
@@ -479,6 +536,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==}
|
resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/hoist-non-react-statics@3.3.2:
|
||||||
|
resolution: {integrity: sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw==}
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.21
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/json-schema@7.0.12:
|
/@types/json-schema@7.0.12:
|
||||||
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
|
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
|
||||||
dev: true
|
dev: true
|
||||||
@@ -498,7 +562,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==}
|
resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 18.2.21
|
'@types/react': 18.2.21
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/react-reconciler@0.28.4:
|
/@types/react-reconciler@0.28.4:
|
||||||
resolution: {integrity: sha512-Xd55E2aLI9Q/ikDQEmfRzIwYJs4oO0h9ZHA3FZDakzt1WR6JMZcpqtCZlF97I72KVjoY4rHXU5TfvkRDOyr/rg==}
|
resolution: {integrity: sha512-Xd55E2aLI9Q/ikDQEmfRzIwYJs4oO0h9ZHA3FZDakzt1WR6JMZcpqtCZlF97I72KVjoY4rHXU5TfvkRDOyr/rg==}
|
||||||
@@ -520,6 +583,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==}
|
resolution: {integrity: sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/use-sync-external-store@0.0.3:
|
||||||
|
resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/uuid@9.0.3:
|
/@types/uuid@9.0.3:
|
||||||
resolution: {integrity: sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug==}
|
resolution: {integrity: sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -1677,11 +1744,21 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.1
|
function-bind: 1.1.1
|
||||||
|
|
||||||
|
/hoist-non-react-statics@3.3.2:
|
||||||
|
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
||||||
|
dependencies:
|
||||||
|
react-is: 16.13.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ignore@5.2.4:
|
/ignore@5.2.4:
|
||||||
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
|
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/immer@9.0.21:
|
||||||
|
resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/import-fresh@3.3.0:
|
/import-fresh@3.3.0:
|
||||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -2005,6 +2082,14 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist: 4.0.0
|
yallist: 4.0.0
|
||||||
|
|
||||||
|
/lucide-react@0.279.0(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-LJ8g66+Bxc3t3x9vKTeK3wn3xucrOQGfJ9ou9GsBwCt2offsrT2BB90XrTrIzE1noYYDe2O8jZaRHi6sAHXNxw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.5.1 || ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/merge2@1.4.1:
|
/merge2@1.4.1:
|
||||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -2484,9 +2569,20 @@ packages:
|
|||||||
scheduler: 0.23.0
|
scheduler: 0.23.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-icons@4.11.0(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '*'
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-is@16.13.1:
|
/react-is@16.13.1:
|
||||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||||
dev: true
|
|
||||||
|
/react-is@18.2.0:
|
||||||
|
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-konva@18.2.10(konva@9.2.0)(react-dom@18.2.0)(react@18.2.0):
|
/react-konva@18.2.10(konva@9.2.0)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g==}
|
resolution: {integrity: sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g==}
|
||||||
@@ -2515,6 +2611,40 @@ packages:
|
|||||||
scheduler: 0.23.0
|
scheduler: 0.23.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-redux@8.1.3(@types/react-dom@18.2.7)(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1):
|
||||||
|
resolution: {integrity: sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8 || ^17.0 || ^18.0
|
||||||
|
'@types/react-dom': ^16.8 || ^17.0 || ^18.0
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-native: '>=0.59'
|
||||||
|
redux: ^4 || ^5.0.0-beta.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
react-dom:
|
||||||
|
optional: true
|
||||||
|
react-native:
|
||||||
|
optional: true
|
||||||
|
redux:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.22.15
|
||||||
|
'@types/hoist-non-react-statics': 3.3.2
|
||||||
|
'@types/react': 18.2.21
|
||||||
|
'@types/react-dom': 18.2.7
|
||||||
|
'@types/use-sync-external-store': 0.0.3
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
react-is: 18.2.0
|
||||||
|
redux: 4.2.1
|
||||||
|
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-ssr-prepass@1.5.0(react@18.2.0):
|
/react-ssr-prepass@1.5.0(react@18.2.0):
|
||||||
resolution: {integrity: sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==}
|
resolution: {integrity: sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2541,6 +2671,20 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
/redux-thunk@2.4.2(redux@4.2.1):
|
||||||
|
resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==}
|
||||||
|
peerDependencies:
|
||||||
|
redux: ^4
|
||||||
|
dependencies:
|
||||||
|
redux: 4.2.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/redux@4.2.1:
|
||||||
|
resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.22.15
|
||||||
|
dev: false
|
||||||
|
|
||||||
/reflect.getprototypeof@1.0.4:
|
/reflect.getprototypeof@1.0.4:
|
||||||
resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==}
|
resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -2565,6 +2709,10 @@ packages:
|
|||||||
functions-have-names: 1.2.3
|
functions-have-names: 1.2.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/reselect@4.1.8:
|
||||||
|
resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/resolve-from@4.0.0:
|
/resolve-from@4.0.0:
|
||||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|||||||
@@ -4,17 +4,31 @@ import {
|
|||||||
} from "@/components/transformable-image";
|
} from "@/components/transformable-image";
|
||||||
|
|
||||||
import type { KonvaEventObject } from "konva/lib/Node";
|
import type { KonvaEventObject } from "konva/lib/Node";
|
||||||
import { ChangeEvent, useState } from "react";
|
import { ChangeEvent, FormEventHandler, useState } from "react";
|
||||||
import { Layer, Stage } from "react-konva";
|
import { Layer, Stage } from "react-konva";
|
||||||
|
|
||||||
import { v1 } from "uuid";
|
import { v1 } from "uuid";
|
||||||
import TransformableText, {
|
import TransformableText, {
|
||||||
TransformableTextProps,
|
TransformableTextProps,
|
||||||
} from "./transformable-text";
|
} from "./transformable-text";
|
||||||
|
import { Button } from "./ui/button";
|
||||||
|
import { Input } from "./ui/input";
|
||||||
|
import { useAppDispatch, useAppSelector } from "@/hooks";
|
||||||
|
import { appSlice } from "@/store/app.slice";
|
||||||
|
|
||||||
|
// Provider *
|
||||||
|
|
||||||
const Canvas = () => {
|
const Canvas = () => {
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
|
const selectedItemId = useAppSelector((state) => state.app.selectedItemId)
|
||||||
|
|
||||||
|
const selectItem = (id: string) => dispatch(appSlice.actions.selectItem(id))
|
||||||
|
|
||||||
const [selectedImageId, selectImage] = useState<string | null>(null);
|
const [selectedImageId, selectImage] = useState<string | null>(null);
|
||||||
const [selectedTextId, selectText] = useState<string | null>(null);
|
const [selectedTextId, selectText] = useState<string | null>(null);
|
||||||
|
const [inputText, setInputText] = useState("");
|
||||||
|
|
||||||
const [images, setImages] = useState<TransformableImageProps["imageProps"][]>(
|
const [images, setImages] = useState<TransformableImageProps["imageProps"][]>(
|
||||||
[],
|
[],
|
||||||
@@ -22,47 +36,25 @@ const Canvas = () => {
|
|||||||
|
|
||||||
const [texts, setTexts] = useState<TransformableTextProps["textProps"][]>([]);
|
const [texts, setTexts] = useState<TransformableTextProps["textProps"][]>([]);
|
||||||
|
|
||||||
const checkDeselect = (e: KonvaEventObject<MouseEvent>) => {
|
|
||||||
// deselect when clicked on empty area
|
|
||||||
const clickedOnEmpty = e.target === e.target.getStage();
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
if (clickedOnEmpty) {
|
setInputText(e.target.value);
|
||||||
selectImage(null);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageUploaded = (e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const file = e.target.files?.[0];
|
|
||||||
if (!file) return;
|
|
||||||
|
|
||||||
const imageId = v1();
|
|
||||||
const imageUrl = URL.createObjectURL(file);
|
|
||||||
setImages((prev) => [...prev, { imageUrl, imageId }]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTextAdd = (e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const text = e.target.value;
|
|
||||||
const textId = v1();
|
|
||||||
|
|
||||||
setTexts((prev) => [...prev, { text, textId }]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*console.log(texts, " ++++ ", images);*/
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main className="flex">
|
||||||
<input type="file" onChange={handleImageUploaded} />
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
onChange={handleTextAdd}
|
|
||||||
placeholder="tape your text"
|
|
||||||
/>
|
|
||||||
<Stage width={window.innerWidth} height={window.innerHeight}>
|
<Stage width={window.innerWidth} height={window.innerHeight}>
|
||||||
<Layer>
|
<Layer>
|
||||||
{images.map((image) => {
|
{images.map((image) => {
|
||||||
return (
|
return (
|
||||||
<TransformableImage
|
<TransformableImage
|
||||||
onSelect={() => selectImage(image.imageId)}
|
onSelect={() => selectItem(image.imageId)}
|
||||||
isSelected={image.imageId === selectedImageId}
|
isSelected={image.imageId === selectedItemId}
|
||||||
onChange={(newAttrs) => {
|
onChange={(newAttrs) => {
|
||||||
setImages(
|
setImages(
|
||||||
images.map((i) =>
|
images.map((i) =>
|
||||||
@@ -78,8 +70,8 @@ const Canvas = () => {
|
|||||||
{texts.map((text) => {
|
{texts.map((text) => {
|
||||||
return (
|
return (
|
||||||
<TransformableText
|
<TransformableText
|
||||||
onSelect={() => selectText(text.textId)}
|
onSelect={() => selectItem(text.textId)}
|
||||||
isSelected={text.textId === selectedTextId}
|
isSelected={text.textId === selectedItemId}
|
||||||
onChange={(newAttrs) => {
|
onChange={(newAttrs) => {
|
||||||
setTexts(
|
setTexts(
|
||||||
texts.map((t) => (t.textId === text.textId ? newAttrs : t)),
|
texts.map((t) => (t.textId === text.textId ? newAttrs : t)),
|
||||||
|
|||||||
15
src/components/layout/layout.tsx
Normal file
15
src/components/layout/layout.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { ReactNode } from "react";
|
||||||
|
import { Sidebar } from "./sidebar";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Layout = ({ children }: Props) => {
|
||||||
|
return (
|
||||||
|
<div className="flex h-full ">
|
||||||
|
<Sidebar {} />
|
||||||
|
<main>{children}</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
37
src/components/layout/sidebar.tsx
Normal file
37
src/components/layout/sidebar.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { Button } from "../ui/button";
|
||||||
|
import { Input } from "../ui/input";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
handleImageUploaded: any;
|
||||||
|
handleInputChange: any;
|
||||||
|
inputText: any;
|
||||||
|
handleTextAdd: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Sidebar({
|
||||||
|
handleImageUploaded,
|
||||||
|
handleInputChange,
|
||||||
|
handleTextAdd,
|
||||||
|
inputText,
|
||||||
|
}: Props) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col ">
|
||||||
|
<Input
|
||||||
|
type="file"
|
||||||
|
className="m-[2rem] w-auto "
|
||||||
|
onChange={handleImageUploaded}
|
||||||
|
/>
|
||||||
|
<div className="m-[2rem] flex max-w-md justify-between">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
placeholder="enter the text"
|
||||||
|
value={inputText}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<Button className="mx-[2rem] text-xs" onClick={handleTextAdd}>
|
||||||
|
Add new Text
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
56
src/components/ui/button.tsx
Normal file
56
src/components/ui/button.tsx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { Slot } from '@radix-ui/react-icons'
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||||
|
destructive:
|
||||||
|
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||||
|
outline:
|
||||||
|
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||||
|
secondary:
|
||||||
|
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: "h-10 px-4 py-2",
|
||||||
|
sm: "h-9 rounded-md px-3",
|
||||||
|
lg: "h-11 rounded-md px-8",
|
||||||
|
icon: "h-10 w-10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export interface ButtonProps
|
||||||
|
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
|
VariantProps<typeof buttonVariants> {
|
||||||
|
asChild?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||||
|
const Comp = asChild ? Slot : "button"
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Button.displayName = "Button"
|
||||||
|
|
||||||
|
export { Button, buttonVariants }
|
||||||
25
src/components/ui/input.tsx
Normal file
25
src/components/ui/input.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
export interface InputProps
|
||||||
|
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
|
|
||||||
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
|
({ className, type, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type={type}
|
||||||
|
className={cn(
|
||||||
|
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Input.displayName = "Input"
|
||||||
|
|
||||||
|
export { Input }
|
||||||
2
src/hooks/index.ts
Normal file
2
src/hooks/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./use-app-dispatch"
|
||||||
|
export * from "./use-app-selector"
|
||||||
4
src/hooks/use-app-dispatch.ts
Normal file
4
src/hooks/use-app-dispatch.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import type { AppDispatch } from "@/store/store";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
|
export const useAppDispatch: () => AppDispatch = useDispatch
|
||||||
4
src/hooks/use-app-selector.ts
Normal file
4
src/hooks/use-app-selector.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import type { RootState } from "@/store/store";
|
||||||
|
import { TypedUseSelectorHook, useSelector } from "react-redux";
|
||||||
|
|
||||||
|
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
|
||||||
@@ -5,6 +5,7 @@ import { type AppType } from "next/app";
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
|
||||||
import "@/styles/globals.css";
|
import "@/styles/globals.css";
|
||||||
|
import { Layout } from "@/components/layout/layout";
|
||||||
|
|
||||||
const MyApp: AppType<{ session: Session | null }> = ({
|
const MyApp: AppType<{ session: Session | null }> = ({
|
||||||
Component,
|
Component,
|
||||||
@@ -12,7 +13,9 @@ const MyApp: AppType<{ session: Session | null }> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<SessionProvider session={session}>
|
<SessionProvider session={session}>
|
||||||
|
<Layout>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
|
</Layout>
|
||||||
</SessionProvider>
|
</SessionProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
|
import Head from "next/head";
|
||||||
|
|
||||||
const Canvas = dynamic(() => import("../components/canvas"), { ssr: false });
|
const Canvas = dynamic(() => import("../components/canvas"), { ssr: false });
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return <Canvas />;
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>Labbel Application</title>
|
||||||
|
</Head>
|
||||||
|
<div className="flex">
|
||||||
|
<Canvas />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
47
src/store/app.slice.ts
Normal file
47
src/store/app.slice.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { TransformableImageProps } from "@/components/transformable-image";
|
||||||
|
import { TransformableTextProps } from "@/components/transformable-text";
|
||||||
|
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||||
|
import { KonvaEventObject } from "konva/lib/Node";
|
||||||
|
import { ChangeEvent } from "react";
|
||||||
|
import { v1 } from "uuid";
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
selectedItemId: null as string | null,
|
||||||
|
images: [] as TransformableImageProps["imageProps"][],
|
||||||
|
texts: [] as TransformableTextProps["textProps"][],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const appSlice = createSlice({
|
||||||
|
name: "app",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
addImage: (state, action: PayloadAction<ChangeEvent<HTMLInputElement>>) => {
|
||||||
|
const file = action.payload.target.files?.[0];
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
const imageId = v1();
|
||||||
|
const imageUrl = URL.createObjectURL(file);
|
||||||
|
state.images.push({ imageUrl, id: imageId });
|
||||||
|
},
|
||||||
|
addText: (state, action: PayloadAction<{ initialValue: string }>) => {
|
||||||
|
const textId = v1();
|
||||||
|
state.texts.push({ text: action.payload.initialValue, id: textId });
|
||||||
|
},
|
||||||
|
|
||||||
|
selectItem: (state, action: PayloadAction<string>) => {
|
||||||
|
state.selectedItemId = action.payload;
|
||||||
|
},
|
||||||
|
|
||||||
|
checkDeselect: (
|
||||||
|
state,
|
||||||
|
action: PayloadAction<KonvaEventObject<MouseEvent>>,
|
||||||
|
) => {
|
||||||
|
// deselect when clicked on empty area
|
||||||
|
const clickedOnEmpty =
|
||||||
|
action.payload.target === action.payload.target.getStage();
|
||||||
|
if (clickedOnEmpty) {
|
||||||
|
state.selectedItemId = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
11
src/store/store.ts
Normal file
11
src/store/store.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { configureStore } from "@reduxjs/toolkit";
|
||||||
|
import { appSlice } from "./app.slice";
|
||||||
|
|
||||||
|
export const store = configureStore({
|
||||||
|
reducer: {
|
||||||
|
[appSlice.name]: appSlice.reducer,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export type AppDispatch = typeof store.dispatch;
|
||||||
|
export type RootState = ReturnType<typeof store.getState>;
|
||||||
Reference in New Issue
Block a user