add context menu to server and player
All checks were successful
Deploy App / docker (ubuntu-latest) (push) Successful in 2m2s
All checks were successful
Deploy App / docker (ubuntu-latest) (push) Successful in 2m2s
This commit is contained in:
parent
6f0b3ec252
commit
3ebc3c0612
@ -9,12 +9,14 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@radix-ui/react-context-menu": "^2.1.5",
|
||||||
"@radix-ui/react-separator": "^1.0.3",
|
"@radix-ui/react-separator": "^1.0.3",
|
||||||
"@radix-ui/react-slot": "^1.0.2",
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
"@radix-ui/react-toast": "^1.1.5",
|
"@radix-ui/react-toast": "^1.1.5",
|
||||||
"@radix-ui/react-tooltip": "^1.0.7",
|
"@radix-ui/react-tooltip": "^1.0.7",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
|
"clipboard-copy": "^4.0.1",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"lucide-react": "^0.368.0",
|
"lucide-react": "^0.368.0",
|
||||||
"mcutils-library": "^1.2.1",
|
"mcutils-library": "^1.2.1",
|
||||||
|
259
pnpm-lock.yaml
generated
259
pnpm-lock.yaml
generated
@ -5,6 +5,9 @@ settings:
|
|||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@radix-ui/react-context-menu':
|
||||||
|
specifier: ^2.1.5
|
||||||
|
version: 2.1.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-separator':
|
'@radix-ui/react-separator':
|
||||||
specifier: ^1.0.3
|
specifier: ^1.0.3
|
||||||
version: 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
@ -23,6 +26,9 @@ dependencies:
|
|||||||
class-variance-authority:
|
class-variance-authority:
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.0
|
||||||
version: 0.7.0
|
version: 0.7.0
|
||||||
|
clipboard-copy:
|
||||||
|
specifier: ^4.0.1
|
||||||
|
version: 4.0.1
|
||||||
clsx:
|
clsx:
|
||||||
specifier: ^2.1.0
|
specifier: ^2.1.0
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
@ -986,6 +992,32 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-context-menu@2.1.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-R5XaDj06Xul1KGb+WP8qiOh7tKJNz2durpLBXAGZjSVtctcRFCuEvy2gtMwRJGePwQQE5nV77gs4FwRi8T+r2g==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.4
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-menu': 2.0.6(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
'@types/react-dom': 18.2.25
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-context@1.0.1(@types/react@18.2.78)(react@18.2.0):
|
/@radix-ui/react-context@1.0.1(@types/react@18.2.78)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==}
|
resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1000,6 +1032,20 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-direction@1.0.1(@types/react@18.2.78)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.4
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
|
resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1025,6 +1071,43 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.78)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.4
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.4
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
'@types/react-dom': 18.2.25
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-id@1.0.1(@types/react@18.2.78)(react@18.2.0):
|
/@radix-ui/react-id@1.0.1(@types/react@18.2.78)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
|
resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1040,6 +1123,44 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-menu@2.0.6(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.4
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
'@types/react-dom': 18.2.25
|
||||||
|
aria-hidden: 1.2.4
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
react-remove-scroll: 2.5.5(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
|
resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1134,6 +1255,35 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.4
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
'@types/react-dom': 18.2.25
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==}
|
resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1643,6 +1793,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/aria-hidden@1.2.4:
|
||||||
|
resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.6.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/aria-query@5.3.0:
|
/aria-query@5.3.0:
|
||||||
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
|
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2005,6 +2162,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
|
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/clipboard-copy@4.0.1:
|
||||||
|
resolution: {integrity: sha512-wOlqdqziE/NNTUJsfSgXmBMIrYmfd5V0HCGsR8uAKHcg+h9NENWINcfRjtWGU77wDHC8B8ijV4hMTGYbrKovng==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/cliui@8.0.1:
|
/cliui@8.0.1:
|
||||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -2217,6 +2378,10 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/detect-node-es@1.1.0:
|
||||||
|
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/didyoumean@1.2.2:
|
/didyoumean@1.2.2:
|
||||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||||
|
|
||||||
@ -2889,6 +3054,11 @@ packages:
|
|||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/get-nonce@1.0.1:
|
||||||
|
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/get-package-type@0.1.0:
|
/get-package-type@0.1.0:
|
||||||
resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
|
resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
|
||||||
engines: {node: '>=8.0.0'}
|
engines: {node: '>=8.0.0'}
|
||||||
@ -3098,6 +3268,12 @@ packages:
|
|||||||
side-channel: 1.0.6
|
side-channel: 1.0.6
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/invariant@2.2.4:
|
||||||
|
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-array-buffer@3.0.4:
|
/is-array-buffer@3.0.4:
|
||||||
resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
|
resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -4483,6 +4659,58 @@ packages:
|
|||||||
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-remove-scroll-bar@2.3.6(@types/react@18.2.78)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
react: 18.2.0
|
||||||
|
react-style-singleton: 2.2.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
tslib: 2.6.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/react-remove-scroll@2.5.5(@types/react@18.2.78)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
react: 18.2.0
|
||||||
|
react-remove-scroll-bar: 2.3.6(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
react-style-singleton: 2.2.1(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
tslib: 2.6.2
|
||||||
|
use-callback-ref: 1.3.2(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
use-sidecar: 1.1.2(@types/react@18.2.78)(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/react-style-singleton@2.2.1(@types/react@18.2.78)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
get-nonce: 1.0.1
|
||||||
|
invariant: 2.2.4
|
||||||
|
react: 18.2.0
|
||||||
|
tslib: 2.6.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-use-websocket@3.0.0(react-dom@18.2.0)(react@18.2.0):
|
/react-use-websocket@3.0.0(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-BInlbhXYrODBPKIplDAmI0J1VPM+1KhCLN09o+dzgQ8qMyrYs4t5kEYmCrTqyRuMTmpahylHFZWQXpfYyDkqOw==}
|
resolution: {integrity: sha512-BInlbhXYrODBPKIplDAmI0J1VPM+1KhCLN09o+dzgQ8qMyrYs4t5kEYmCrTqyRuMTmpahylHFZWQXpfYyDkqOw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -5160,6 +5388,37 @@ packages:
|
|||||||
punycode: 2.3.1
|
punycode: 2.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/use-callback-ref@1.3.2(@types/react@18.2.78)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
react: 18.2.0
|
||||||
|
tslib: 2.6.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/use-sidecar@1.1.2(@types/react@18.2.78)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.78
|
||||||
|
detect-node-es: 1.1.0
|
||||||
|
react: 18.2.0
|
||||||
|
tslib: 2.6.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/util-deprecate@1.0.2:
|
/util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { Card } from "@/app/components/card";
|
import { Card } from "@/app/components/card";
|
||||||
|
import { CopyButton } from "@/app/components/copy-button";
|
||||||
import { ErrorCard } from "@/app/components/error-card";
|
import { ErrorCard } from "@/app/components/error-card";
|
||||||
import { LookupPlayer } from "@/app/components/player/lookup-player";
|
import { LookupPlayer } from "@/app/components/player/lookup-player";
|
||||||
|
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from "@/app/components/ui/context-menu";
|
||||||
import { Separator } from "@/app/components/ui/separator";
|
import { Separator } from "@/app/components/ui/separator";
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/app/components/ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/app/components/ui/tooltip";
|
||||||
import { generateEmbed } from "@/common/embed";
|
import { generateEmbed } from "@/common/embed";
|
||||||
@ -10,6 +12,7 @@ import { Metadata } from "next";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ReactElement } from "react";
|
import { ReactElement } from "react";
|
||||||
|
import config from "../../../../../config.json";
|
||||||
|
|
||||||
type Params = {
|
type Params = {
|
||||||
params: {
|
params: {
|
||||||
@ -69,53 +72,70 @@ export default async function Page({ params: { id } }: Params): Promise<ReactEle
|
|||||||
|
|
||||||
{error && <ErrorCard message={error} />}
|
{error && <ErrorCard message={error} />}
|
||||||
{player != undefined && (
|
{player != undefined && (
|
||||||
<Card className="w-max xs:w-fit">
|
<ContextMenu>
|
||||||
<div className="flex gap-4 flex-col xs:flex-row">
|
<ContextMenuTrigger>
|
||||||
<div className="flex justify-center xs:justify-start">
|
<Card className="w-max xs:w-fit">
|
||||||
<Image
|
<div className="flex gap-4 flex-col xs:flex-row">
|
||||||
className="w-[96px] h-[96px]"
|
<div className="flex justify-center xs:justify-start">
|
||||||
src={player.skin.parts.head}
|
<Image
|
||||||
width={96}
|
className="w-[96px] h-[96px]"
|
||||||
height={96}
|
src={player.skin.parts.head}
|
||||||
quality={100}
|
width={96}
|
||||||
alt="The player's skin"
|
height={96}
|
||||||
/>
|
quality={100}
|
||||||
</div>
|
alt="The player's skin"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl text-primary font-semibold">{player.username}</h2>
|
<h2 className="text-xl text-primary font-semibold">{player.username}</h2>
|
||||||
<p>{player.uniqueId}</p>
|
<p>{player.uniqueId}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<p className="text-lg">Skin Parts</p>
|
<p className="text-lg">Skin Parts</p>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{Object.entries(player.skin.parts)
|
{Object.entries(player.skin.parts)
|
||||||
.filter(([part]) => part !== SkinPart.HEAD) // Don't show the head part again
|
.filter(([part]) => part !== SkinPart.HEAD) // Don't show the head part again
|
||||||
.map(([part, url]) => {
|
.map(([part, url]) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip key={part}>
|
<Tooltip key={part}>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Link href={url} target="_blank">
|
<Link href={url} target="_blank">
|
||||||
<img className="h-[64px]" src={url} alt={`The player's ${part}`} loading="lazy" />
|
<img className="h-[64px]" src={url} alt={`The player's ${part}`} loading="lazy" />
|
||||||
</Link>
|
</Link>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>
|
<p>
|
||||||
Click to view {player.username}'s {part}
|
Click to view {player.username}'s {part}
|
||||||
</p>
|
</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Card>
|
||||||
</div>
|
</ContextMenuTrigger>
|
||||||
</Card>
|
<ContextMenuContent className="flex flex-col">
|
||||||
|
<CopyButton content={player.username}>
|
||||||
|
<ContextMenuItem>Copy Player Username</ContextMenuItem>
|
||||||
|
</CopyButton>
|
||||||
|
|
||||||
|
<CopyButton content={player.uniqueId}>
|
||||||
|
<ContextMenuItem>Copy Player UUID</ContextMenuItem>
|
||||||
|
</CopyButton>
|
||||||
|
|
||||||
|
<CopyButton content={`${config.siteUrl}/player/${id}`}>
|
||||||
|
<ContextMenuItem>Copy Share URL</ContextMenuItem>
|
||||||
|
</CopyButton>
|
||||||
|
</ContextMenuContent>
|
||||||
|
</ContextMenu>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { Card } from "@/app/components/card";
|
import { Card } from "@/app/components/card";
|
||||||
|
import { CopyButton } from "@/app/components/copy-button";
|
||||||
import { ErrorCard } from "@/app/components/error-card";
|
import { ErrorCard } from "@/app/components/error-card";
|
||||||
import { LookupServer } from "@/app/components/server/lookup-server";
|
import { LookupServer } from "@/app/components/server/lookup-server";
|
||||||
|
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from "@/app/components/ui/context-menu";
|
||||||
import { generateEmbed } from "@/common/embed";
|
import { generateEmbed } from "@/common/embed";
|
||||||
import { formatNumber } from "@/common/number-utils";
|
import { formatNumber } from "@/common/number-utils";
|
||||||
import { capitalizeFirstLetter } from "@/common/string-utils";
|
import { capitalizeFirstLetter } from "@/common/string-utils";
|
||||||
@ -118,39 +120,53 @@ export default async function Page({ params: { platform, hostname } }: Params):
|
|||||||
|
|
||||||
{error && <ErrorCard message={error} />}
|
{error && <ErrorCard message={error} />}
|
||||||
{server != null && (
|
{server != null && (
|
||||||
<Card className="w-max xs:w-fit">
|
<ContextMenu>
|
||||||
<div className="flex gap-2 flex-col">
|
<ContextMenuTrigger>
|
||||||
<div className="flex gap-4 flex-col xs:flex-row">
|
<Card className="w-max xs:w-fit">
|
||||||
{favicon && (
|
<div className="flex gap-2 flex-col">
|
||||||
<div className="flex justify-center xs:justify-start">
|
<div className="flex gap-4 flex-col xs:flex-row">
|
||||||
<Image
|
{favicon && (
|
||||||
className="w-[64px] h-[64px]"
|
<div className="flex justify-center xs:justify-start">
|
||||||
src={favicon}
|
<Image
|
||||||
width={64}
|
className="w-[64px] h-[64px]"
|
||||||
height={64}
|
src={favicon}
|
||||||
quality={100}
|
width={64}
|
||||||
alt="The server's favicon"
|
height={64}
|
||||||
/>
|
quality={100}
|
||||||
</div>
|
alt="The server's favicon"
|
||||||
)}
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<h2 className="text-xl text-primary font-semibold">{server.hostname}</h2>
|
<h2 className="text-xl text-primary font-semibold">{server.hostname}</h2>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
Players online: {formatNumber(server.players.online)}/{formatNumber(server.players.max)}
|
Players online: {formatNumber(server.players.online)}/{formatNumber(server.players.max)}
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-background rounded-lg p-2 text-sm xs:text-lg">
|
||||||
|
{server.motd.html.map((line, index) => {
|
||||||
|
return <p key={index} dangerouslySetInnerHTML={{ __html: line }}></p>;
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Card>
|
||||||
|
</ContextMenuTrigger>
|
||||||
<div className="bg-background rounded-lg p-2 text-sm xs:text-lg">
|
<ContextMenuContent className="flex flex-col">
|
||||||
{server.motd.html.map((line, index) => {
|
<CopyButton content={server.hostname}>
|
||||||
return <p key={index} dangerouslySetInnerHTML={{ __html: line }}></p>;
|
<ContextMenuItem>Copy Server Hostname</ContextMenuItem>
|
||||||
})}
|
</CopyButton>
|
||||||
</div>
|
{favicon && (
|
||||||
</div>
|
<CopyButton content={favicon}>
|
||||||
</Card>
|
<ContextMenuItem>Copy Server Favicon URL</ContextMenuItem>
|
||||||
|
</CopyButton>
|
||||||
|
)}
|
||||||
|
</ContextMenuContent>
|
||||||
|
</ContextMenu>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
35
src/app/components/copy-button.tsx
Normal file
35
src/app/components/copy-button.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useToast } from "@/common/use-toast";
|
||||||
|
import copy from "clipboard-copy";
|
||||||
|
import { ReactElement } from "react";
|
||||||
|
|
||||||
|
type CopyButtonProps = {
|
||||||
|
content: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A button that copies the content to the clipboard
|
||||||
|
*
|
||||||
|
* @param props the properties for the button
|
||||||
|
* @returns the copy button
|
||||||
|
*/
|
||||||
|
export function CopyButton({ content, children }: CopyButtonProps): ReactElement {
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={async () => {
|
||||||
|
await copy(content);
|
||||||
|
toast({
|
||||||
|
title: "Copied!",
|
||||||
|
description: `Copied "${content}" to the clipboard.`,
|
||||||
|
duration: 5000,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
200
src/app/components/ui/context-menu.tsx
Normal file
200
src/app/components/ui/context-menu.tsx
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
|
||||||
|
import { Check, ChevronRight, Circle } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/common/utils"
|
||||||
|
|
||||||
|
const ContextMenu = ContextMenuPrimitive.Root
|
||||||
|
|
||||||
|
const ContextMenuTrigger = ContextMenuPrimitive.Trigger
|
||||||
|
|
||||||
|
const ContextMenuGroup = ContextMenuPrimitive.Group
|
||||||
|
|
||||||
|
const ContextMenuPortal = ContextMenuPrimitive.Portal
|
||||||
|
|
||||||
|
const ContextMenuSub = ContextMenuPrimitive.Sub
|
||||||
|
|
||||||
|
const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup
|
||||||
|
|
||||||
|
const ContextMenuSubTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
|
||||||
|
inset?: boolean
|
||||||
|
}
|
||||||
|
>(({ className, inset, children, ...props }, ref) => (
|
||||||
|
<ContextMenuPrimitive.SubTrigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||||
|
inset && "pl-8",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<ChevronRight className="ml-auto h-4 w-4" />
|
||||||
|
</ContextMenuPrimitive.SubTrigger>
|
||||||
|
))
|
||||||
|
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName
|
||||||
|
|
||||||
|
const ContextMenuSubContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<ContextMenuPrimitive.SubContent
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName
|
||||||
|
|
||||||
|
const ContextMenuContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ContextMenuPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<ContextMenuPrimitive.Portal>
|
||||||
|
<ContextMenuPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</ContextMenuPrimitive.Portal>
|
||||||
|
))
|
||||||
|
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const ContextMenuItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ContextMenuPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
|
||||||
|
inset?: boolean
|
||||||
|
}
|
||||||
|
>(({ className, inset, ...props }, ref) => (
|
||||||
|
<ContextMenuPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
inset && "pl-8",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName
|
||||||
|
|
||||||
|
const ContextMenuCheckboxItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
|
||||||
|
>(({ className, children, checked, ...props }, ref) => (
|
||||||
|
<ContextMenuPrimitive.CheckboxItem
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
checked={checked}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<ContextMenuPrimitive.ItemIndicator>
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</ContextMenuPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
{children}
|
||||||
|
</ContextMenuPrimitive.CheckboxItem>
|
||||||
|
))
|
||||||
|
ContextMenuCheckboxItem.displayName =
|
||||||
|
ContextMenuPrimitive.CheckboxItem.displayName
|
||||||
|
|
||||||
|
const ContextMenuRadioItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<ContextMenuPrimitive.RadioItem
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<ContextMenuPrimitive.ItemIndicator>
|
||||||
|
<Circle className="h-2 w-2 fill-current" />
|
||||||
|
</ContextMenuPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
{children}
|
||||||
|
</ContextMenuPrimitive.RadioItem>
|
||||||
|
))
|
||||||
|
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName
|
||||||
|
|
||||||
|
const ContextMenuLabel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ContextMenuPrimitive.Label>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
|
||||||
|
inset?: boolean
|
||||||
|
}
|
||||||
|
>(({ className, inset, ...props }, ref) => (
|
||||||
|
<ContextMenuPrimitive.Label
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"px-2 py-1.5 text-sm font-semibold text-foreground",
|
||||||
|
inset && "pl-8",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName
|
||||||
|
|
||||||
|
const ContextMenuSeparator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ContextMenuPrimitive.Separator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<ContextMenuPrimitive.Separator
|
||||||
|
ref={ref}
|
||||||
|
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName
|
||||||
|
|
||||||
|
const ContextMenuShortcut = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ContextMenuShortcut.displayName = "ContextMenuShortcut"
|
||||||
|
|
||||||
|
export {
|
||||||
|
ContextMenu,
|
||||||
|
ContextMenuTrigger,
|
||||||
|
ContextMenuContent,
|
||||||
|
ContextMenuItem,
|
||||||
|
ContextMenuCheckboxItem,
|
||||||
|
ContextMenuRadioItem,
|
||||||
|
ContextMenuLabel,
|
||||||
|
ContextMenuSeparator,
|
||||||
|
ContextMenuShortcut,
|
||||||
|
ContextMenuGroup,
|
||||||
|
ContextMenuPortal,
|
||||||
|
ContextMenuSub,
|
||||||
|
ContextMenuSubContent,
|
||||||
|
ContextMenuSubTrigger,
|
||||||
|
ContextMenuRadioGroup,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user