💄 feat: Added mobile file details display.
This commit is contained in:
parent
0b01b5345d
commit
8aea462790
10 changed files with 884 additions and 113 deletions
508
web/package-lock.json
generated
508
web/package-lock.json
generated
|
|
@ -14,12 +14,13 @@
|
||||||
"@hookform/resolvers": "^3.9.1",
|
"@hookform/resolvers": "^3.9.1",
|
||||||
"@radix-ui/react-avatar": "^1.1.1",
|
"@radix-ui/react-avatar": "^1.1.1",
|
||||||
"@radix-ui/react-checkbox": "^1.1.2",
|
"@radix-ui/react-checkbox": "^1.1.2",
|
||||||
"@radix-ui/react-dialog": "^1.1.2",
|
"@radix-ui/react-dialog": "^1.1.4",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-popover": "^1.1.2",
|
"@radix-ui/react-popover": "^1.1.2",
|
||||||
"@radix-ui/react-progress": "^1.1.0",
|
"@radix-ui/react-progress": "^1.1.0",
|
||||||
"@radix-ui/react-select": "^2.1.2",
|
"@radix-ui/react-select": "^2.1.2",
|
||||||
|
"@radix-ui/react-separator": "^1.1.1",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
"@radix-ui/react-tabs": "^1.1.1",
|
"@radix-ui/react-tabs": "^1.1.1",
|
||||||
"@radix-ui/react-toast": "^1.2.2",
|
"@radix-ui/react-toast": "^1.2.2",
|
||||||
|
|
@ -45,6 +46,7 @@
|
||||||
"tailwind-merge": "^2.5.5",
|
"tailwind-merge": "^2.5.5",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"use-debounce": "^10.0.4",
|
"use-debounce": "^10.0.4",
|
||||||
|
"vaul": "^1.1.2",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -1110,24 +1112,24 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-dialog": {
|
"node_modules/@radix-ui/react-dialog": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz",
|
||||||
"integrity": "sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==",
|
"integrity": "sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/primitive": "1.1.0",
|
"@radix-ui/primitive": "1.1.1",
|
||||||
"@radix-ui/react-compose-refs": "1.1.0",
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
"@radix-ui/react-context": "1.1.1",
|
"@radix-ui/react-context": "1.1.1",
|
||||||
"@radix-ui/react-dismissable-layer": "1.1.1",
|
"@radix-ui/react-dismissable-layer": "1.1.3",
|
||||||
"@radix-ui/react-focus-guards": "1.1.1",
|
"@radix-ui/react-focus-guards": "1.1.1",
|
||||||
"@radix-ui/react-focus-scope": "1.1.0",
|
"@radix-ui/react-focus-scope": "1.1.1",
|
||||||
"@radix-ui/react-id": "1.1.0",
|
"@radix-ui/react-id": "1.1.0",
|
||||||
"@radix-ui/react-portal": "1.1.2",
|
"@radix-ui/react-portal": "1.1.3",
|
||||||
"@radix-ui/react-presence": "1.1.1",
|
"@radix-ui/react-presence": "1.1.2",
|
||||||
"@radix-ui/react-primitive": "2.0.0",
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
"@radix-ui/react-slot": "1.1.0",
|
"@radix-ui/react-slot": "1.1.1",
|
||||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||||
"aria-hidden": "^1.1.1",
|
"aria-hidden": "^1.1.1",
|
||||||
"react-remove-scroll": "2.6.0"
|
"react-remove-scroll": "^2.6.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
|
|
@ -1144,6 +1146,184 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/primitive": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.1",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||||
|
"@radix-ui/react-use-escape-keydown": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==",
|
||||||
|
"dependencies": {
|
||||||
|
"react-remove-scroll-bar": "^2.3.7",
|
||||||
|
"react-style-singleton": "^2.2.1",
|
||||||
|
"tslib": "^2.1.0",
|
||||||
|
"use-callback-ref": "^1.3.3",
|
||||||
|
"use-sidecar": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-direction": {
|
"node_modules/@radix-ui/react-direction": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
|
||||||
|
|
@ -1600,6 +1780,81 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-separator": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-RRiNRSrD8iUiXriq/Y5n4/3iE8HzqgLHsusUSg5jVpU2+3tqcUFPJXHDymwEypunc2sWxDUS3UC+rkZRlHedsw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-primitive": "2.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-slot": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-slot": {
|
"node_modules/@radix-ui/react-slot": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
|
||||||
|
|
@ -4497,14 +4752,6 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/invariant": {
|
|
||||||
"version": "2.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
|
||||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
|
||||||
"dependencies": {
|
|
||||||
"loose-envify": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-array-buffer": {
|
"node_modules/is-array-buffer": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
||||||
|
|
@ -5902,19 +6149,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-remove-scroll-bar": {
|
"node_modules/react-remove-scroll-bar": {
|
||||||
"version": "2.3.6",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
|
||||||
"integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==",
|
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-style-singleton": "^2.2.1",
|
"react-style-singleton": "^2.2.2",
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
"@types/react": "*",
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
|
|
@ -5923,20 +6170,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-style-singleton": {
|
"node_modules/react-style-singleton": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||||
"integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
|
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"get-nonce": "^1.0.0",
|
"get-nonce": "^1.0.0",
|
||||||
"invariant": "^2.2.4",
|
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
"@types/react": "*",
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
|
|
@ -6923,9 +7169,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/use-callback-ref": {
|
"node_modules/use-callback-ref": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
|
||||||
"integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==",
|
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
},
|
},
|
||||||
|
|
@ -6933,8 +7179,8 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
"@types/react": "*",
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
|
|
@ -6987,6 +7233,18 @@
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/vaul": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-dialog": "^1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
@ -7812,24 +8070,105 @@
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@radix-ui/react-dialog": {
|
"@radix-ui/react-dialog": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz",
|
||||||
"integrity": "sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==",
|
"integrity": "sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@radix-ui/primitive": "1.1.0",
|
"@radix-ui/primitive": "1.1.1",
|
||||||
"@radix-ui/react-compose-refs": "1.1.0",
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
"@radix-ui/react-context": "1.1.1",
|
"@radix-ui/react-context": "1.1.1",
|
||||||
"@radix-ui/react-dismissable-layer": "1.1.1",
|
"@radix-ui/react-dismissable-layer": "1.1.3",
|
||||||
"@radix-ui/react-focus-guards": "1.1.1",
|
"@radix-ui/react-focus-guards": "1.1.1",
|
||||||
"@radix-ui/react-focus-scope": "1.1.0",
|
"@radix-ui/react-focus-scope": "1.1.1",
|
||||||
"@radix-ui/react-id": "1.1.0",
|
"@radix-ui/react-id": "1.1.0",
|
||||||
"@radix-ui/react-portal": "1.1.2",
|
"@radix-ui/react-portal": "1.1.3",
|
||||||
"@radix-ui/react-presence": "1.1.1",
|
"@radix-ui/react-presence": "1.1.2",
|
||||||
"@radix-ui/react-primitive": "2.0.0",
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
"@radix-ui/react-slot": "1.1.0",
|
"@radix-ui/react-slot": "1.1.1",
|
||||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||||
"aria-hidden": "^1.1.1",
|
"aria-hidden": "^1.1.1",
|
||||||
"react-remove-scroll": "2.6.0"
|
"react-remove-scroll": "^2.6.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
|
||||||
|
},
|
||||||
|
"@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-dismissable-layer": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/primitive": "1.1.1",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||||
|
"@radix-ui/react-use-escape-keydown": "1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-focus-scope": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-portal": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-presence": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-primitive": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/react-slot": "1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-slot": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-remove-scroll": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==",
|
||||||
|
"requires": {
|
||||||
|
"react-remove-scroll-bar": "^2.3.7",
|
||||||
|
"react-style-singleton": "^2.2.1",
|
||||||
|
"tslib": "^2.1.0",
|
||||||
|
"use-callback-ref": "^1.3.3",
|
||||||
|
"use-sidecar": "^1.1.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@radix-ui/react-direction": {
|
"@radix-ui/react-direction": {
|
||||||
|
|
@ -8063,6 +8402,38 @@
|
||||||
"react-remove-scroll": "2.6.0"
|
"react-remove-scroll": "2.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@radix-ui/react-separator": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-RRiNRSrD8iUiXriq/Y5n4/3iE8HzqgLHsusUSg5jVpU2+3tqcUFPJXHDymwEypunc2sWxDUS3UC+rkZRlHedsw==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/react-primitive": "2.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-primitive": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/react-slot": "1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-slot": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@radix-ui/react-slot": {
|
"@radix-ui/react-slot": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
|
||||||
|
|
@ -10005,14 +10376,6 @@
|
||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"invariant": {
|
|
||||||
"version": "2.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
|
||||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
|
||||||
"requires": {
|
|
||||||
"loose-envify": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"is-array-buffer": {
|
"is-array-buffer": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
||||||
|
|
@ -10872,21 +11235,20 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-remove-scroll-bar": {
|
"react-remove-scroll-bar": {
|
||||||
"version": "2.3.6",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
|
||||||
"integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==",
|
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"react-style-singleton": "^2.2.1",
|
"react-style-singleton": "^2.2.2",
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-style-singleton": {
|
"react-style-singleton": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||||
"integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
|
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"get-nonce": "^1.0.0",
|
"get-nonce": "^1.0.0",
|
||||||
"invariant": "^2.2.4",
|
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -11567,9 +11929,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"use-callback-ref": {
|
"use-callback-ref": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
|
||||||
"integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==",
|
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
|
@ -11600,6 +11962,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
|
"vaul": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==",
|
||||||
|
"requires": {
|
||||||
|
"@radix-ui/react-dialog": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"which": {
|
"which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,13 @@
|
||||||
"@hookform/resolvers": "^3.9.1",
|
"@hookform/resolvers": "^3.9.1",
|
||||||
"@radix-ui/react-avatar": "^1.1.1",
|
"@radix-ui/react-avatar": "^1.1.1",
|
||||||
"@radix-ui/react-checkbox": "^1.1.2",
|
"@radix-ui/react-checkbox": "^1.1.2",
|
||||||
"@radix-ui/react-dialog": "^1.1.2",
|
"@radix-ui/react-dialog": "^1.1.4",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-popover": "^1.1.2",
|
"@radix-ui/react-popover": "^1.1.2",
|
||||||
"@radix-ui/react-progress": "^1.1.0",
|
"@radix-ui/react-progress": "^1.1.0",
|
||||||
"@radix-ui/react-select": "^2.1.2",
|
"@radix-ui/react-select": "^2.1.2",
|
||||||
|
"@radix-ui/react-separator": "^1.1.1",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
"@radix-ui/react-tabs": "^1.1.1",
|
"@radix-ui/react-tabs": "^1.1.1",
|
||||||
"@radix-ui/react-toast": "^1.2.2",
|
"@radix-ui/react-toast": "^1.2.2",
|
||||||
|
|
@ -53,6 +54,7 @@
|
||||||
"tailwind-merge": "^2.5.5",
|
"tailwind-merge": "^2.5.5",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"use-debounce": "^10.0.4",
|
"use-debounce": "^10.0.4",
|
||||||
|
"vaul": "^1.1.2",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,77 @@
|
||||||
|
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { type TelegramFile } from "@/lib/types";
|
import { type TelegramFile } from "@/lib/types";
|
||||||
import { FileAudio2Icon, FileIcon, ImageIcon, VideoIcon } from "lucide-react";
|
import {
|
||||||
|
Calendar,
|
||||||
|
Download,
|
||||||
|
FileAudio2Icon,
|
||||||
|
FileIcon,
|
||||||
|
HardDrive,
|
||||||
|
ImageIcon,
|
||||||
|
Type,
|
||||||
|
VideoIcon,
|
||||||
|
} from "lucide-react";
|
||||||
import SpoiledWrapper from "@/components/spoiled-wrapper";
|
import SpoiledWrapper from "@/components/spoiled-wrapper";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import prettyBytes from "pretty-bytes";
|
import prettyBytes from "pretty-bytes";
|
||||||
import FileProgress from "@/components/file-progress";
|
import FileProgress from "@/components/file-progress";
|
||||||
import FileControl from "@/components/file-control";
|
import FileControl, { MobileFileControl } from "@/components/file-control";
|
||||||
|
import {
|
||||||
|
Drawer,
|
||||||
|
DrawerContent,
|
||||||
|
DrawerDescription,
|
||||||
|
DrawerFooter,
|
||||||
|
DrawerHeader,
|
||||||
|
DrawerTitle,
|
||||||
|
DrawerTrigger,
|
||||||
|
} from "./ui/drawer";
|
||||||
|
import PhotoPreview from "@/components/photo-preview";
|
||||||
|
import React from "react";
|
||||||
|
import { Separator } from "./ui/separator";
|
||||||
|
import { Badge } from "./ui/badge";
|
||||||
|
import { formatDistanceToNow } from "date-fns";
|
||||||
|
import FileStatus from "@/components/file-status";
|
||||||
|
|
||||||
interface FileCardProps {
|
interface FileCardProps {
|
||||||
file: TelegramFile;
|
file: TelegramFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FileCard({ file }: FileCardProps) {
|
export function FileCard({ file }: FileCardProps) {
|
||||||
|
return (
|
||||||
|
<FileDrawer file={file}>
|
||||||
|
<Card>
|
||||||
|
<CardContent className="p-4">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<FileAvatar file={file} />
|
||||||
|
<div className="flex-1">
|
||||||
|
<h3 className="mb-1 font-medium">{file.name}</h3>
|
||||||
|
<div className="mb-2 flex items-center justify-between text-sm text-muted-foreground">
|
||||||
|
<span>
|
||||||
|
{prettyBytes(file.size)} • {file.type}
|
||||||
|
</span>
|
||||||
|
<FileStatus status={file.downloadStatus} />
|
||||||
|
</div>
|
||||||
|
<div className="mb-2 w-full overflow-hidden">
|
||||||
|
<FileProgress file={file} showSize={false} />
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-end">
|
||||||
|
<FileControl file={file} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</FileDrawer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function FileAvatar({
|
||||||
|
file,
|
||||||
|
loadPreview,
|
||||||
|
}: {
|
||||||
|
file: TelegramFile;
|
||||||
|
loadPreview?: boolean;
|
||||||
|
}) {
|
||||||
const getIcon = () => {
|
const getIcon = () => {
|
||||||
switch (file.type) {
|
switch (file.type) {
|
||||||
case "photo":
|
case "photo":
|
||||||
|
|
@ -28,46 +87,127 @@ export function FileCard({ file }: FileCardProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<>
|
||||||
<CardContent className="p-4">
|
{file.type === "photo" || file.type === "video" ? (
|
||||||
<div className="flex items-center gap-4">
|
file.thumbnail ? (
|
||||||
{file.type === "photo" || file.type === "video" ? (
|
<SpoiledWrapper hasSensitiveContent={file.hasSensitiveContent}>
|
||||||
file.thumbnail ? (
|
{loadPreview ? (
|
||||||
<SpoiledWrapper hasSensitiveContent={file.hasSensitiveContent}>
|
<PhotoPreview
|
||||||
<Image
|
thumbnail={file.thumbnail}
|
||||||
src={`data:image/jpeg;base64,${file.thumbnail}`}
|
name={file.name}
|
||||||
alt={file.name ?? "File thumbnail"}
|
chatId={file.chatId}
|
||||||
width={32}
|
messageId={file.messageId}
|
||||||
height={32}
|
/>
|
||||||
className="h-16 w-16 rounded object-cover inline-block"
|
|
||||||
/>
|
|
||||||
</SpoiledWrapper>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-16 w-16 items-center justify-center rounded bg-muted">
|
<Image
|
||||||
{getIcon()}
|
src={`data:image/jpeg;base64,${file.thumbnail}`}
|
||||||
</div>
|
alt={file.name ?? "File thumbnail"}
|
||||||
)
|
width={32}
|
||||||
) : (
|
height={32}
|
||||||
<div className="flex h-16 w-16 items-center justify-center rounded bg-muted">
|
className="inline-block h-16 w-16 rounded object-cover"
|
||||||
{getIcon()}
|
/>
|
||||||
</div>
|
)}
|
||||||
)}
|
</SpoiledWrapper>
|
||||||
|
) : (
|
||||||
|
<div className="flex h-16 w-16 items-center justify-center rounded bg-muted">
|
||||||
|
{getIcon()}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<div className="flex h-16 w-16 items-center justify-center rounded bg-muted">
|
||||||
|
{getIcon()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
<div className="flex-1">
|
function FileDrawer({
|
||||||
<h3 className="mb-1 font-medium">{file.name}</h3>
|
file,
|
||||||
<div className="mb-2 flex justify-between items-center text-sm text-muted-foreground">
|
children,
|
||||||
<span>{prettyBytes(file.size)} • {file.type}</span>
|
}: {
|
||||||
<span>{file.downloadStatus}</span>
|
file: TelegramFile;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Drawer>
|
||||||
|
<DrawerTrigger asChild>{children}</DrawerTrigger>
|
||||||
|
<DrawerContent
|
||||||
|
className="max-h-[96vh] focus:outline-none"
|
||||||
|
aria-describedby={undefined}
|
||||||
|
>
|
||||||
|
<DrawerHeader className="text-center">
|
||||||
|
<DrawerTitle className="flex items-center justify-center gap-2 text-xl">
|
||||||
|
<FileAvatar file={file} loadPreview={true} />
|
||||||
|
<span className="max-w-md truncate">{file.name}</span>
|
||||||
|
</DrawerTitle>
|
||||||
|
<div className="py-1">
|
||||||
|
<FileStatus status={file.downloadStatus} />
|
||||||
|
</div>
|
||||||
|
{file.caption && (
|
||||||
|
<SpoiledWrapper hasSensitiveContent={file.hasSensitiveContent}>
|
||||||
|
<DrawerDescription className="mx-auto mt-2 max-w-md">
|
||||||
|
{file.caption}
|
||||||
|
</DrawerDescription>
|
||||||
|
</SpoiledWrapper>
|
||||||
|
)}
|
||||||
|
<FileProgress file={file} showSize={false} />
|
||||||
|
</DrawerHeader>
|
||||||
|
|
||||||
|
<div className="px-2">
|
||||||
|
<Separator className="my-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-6 p-4">
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
|
<Type className="h-4 w-4" />
|
||||||
|
<span>Type</span>
|
||||||
|
</div>
|
||||||
|
<Badge variant="secondary" className="text-xs">
|
||||||
|
{file.type}
|
||||||
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-2 w-full overflow-hidden">
|
|
||||||
<FileProgress file={file} />
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
|
<HardDrive className="h-4 w-4" />
|
||||||
|
<span>Size</span>
|
||||||
|
</div>
|
||||||
|
<Badge variant="secondary" className="text-xs">
|
||||||
|
{prettyBytes(file.size)}
|
||||||
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end">
|
|
||||||
<FileControl file={file} />
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
|
<Calendar className="h-4 w-4" />
|
||||||
|
<span>Date</span>
|
||||||
|
</div>
|
||||||
|
<Badge variant="secondary" className="text-xs">
|
||||||
|
{formatDistanceToNow(new Date(file.date * 1000), {
|
||||||
|
addSuffix: true,
|
||||||
|
})}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
|
<Download className="h-4 w-4" />
|
||||||
|
<span>Downloaded Size</span>
|
||||||
|
</div>
|
||||||
|
<Badge variant="secondary" className="text-xs">
|
||||||
|
{prettyBytes(file.downloadedSize)}
|
||||||
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
|
||||||
</Card>
|
<DrawerFooter>
|
||||||
|
<MobileFileControl file={file} />
|
||||||
|
</DrawerFooter>
|
||||||
|
</DrawerContent>
|
||||||
|
</Drawer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,3 +102,51 @@ export default function FileControl({ file }: { file: TelegramFile }) {
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function MobileFileControl({ file }: { file: TelegramFile }) {
|
||||||
|
const { start, starting, togglePause, togglingPause, cancel, cancelling } =
|
||||||
|
useFileControl(file);
|
||||||
|
|
||||||
|
if (file.downloadStatus === "completed") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex w-full items-center justify-between space-x-2">
|
||||||
|
{(file.downloadStatus === "idle" || file.downloadStatus === "error") && (
|
||||||
|
<Button className="w-full" onClick={() => start(file.id)}>
|
||||||
|
{starting ? (
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<ArrowDown className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{(file.downloadStatus === "downloading" ||
|
||||||
|
file.downloadStatus === "paused") && (
|
||||||
|
<>
|
||||||
|
<Button className="w-full" onClick={() => togglePause(file.id)}>
|
||||||
|
{togglingPause ? (
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
) : file.downloadStatus === "downloading" ? (
|
||||||
|
<Pause className="h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<StepForward className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
className="w-full"
|
||||||
|
onClick={() => cancel(file.id)}
|
||||||
|
>
|
||||||
|
{cancelling ? (
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<SquareX className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ import FileProgress from "@/components/file-progress";
|
||||||
import FileNotFount from "@/components/file-not-found";
|
import FileNotFount from "@/components/file-not-found";
|
||||||
import FileExtra from "@/components/file-extra";
|
import FileExtra from "@/components/file-extra";
|
||||||
import useIsMobile from "@/hooks/use-is-mobile";
|
import useIsMobile from "@/hooks/use-is-mobile";
|
||||||
|
import FileStatus from "@/components/file-status";
|
||||||
|
|
||||||
interface FileListProps {
|
interface FileListProps {
|
||||||
accountId: string;
|
accountId: string;
|
||||||
|
|
@ -265,9 +266,7 @@ export function FileList({ accountId, chatId }: FileListProps) {
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
size: (file: TelegramFile) => <span>{prettyBytes(file.size)}</span>,
|
size: (file: TelegramFile) => <span>{prettyBytes(file.size)}</span>,
|
||||||
status: (file: TelegramFile) => (
|
status: (file: TelegramFile) => <FileStatus status={file.downloadStatus} />,
|
||||||
<span className="capitalize">{file.downloadStatus}</span>
|
|
||||||
),
|
|
||||||
extra: (file: TelegramFile) => (
|
extra: (file: TelegramFile) => (
|
||||||
<FileExtra file={file} rowHeight={rowHeight} />
|
<FileExtra file={file} rowHeight={rowHeight} />
|
||||||
),
|
),
|
||||||
|
|
@ -371,7 +370,7 @@ export function FileList({ accountId, chatId }: FileListProps) {
|
||||||
colSpan={columns.length + 1}
|
colSpan={columns.length + 1}
|
||||||
className="h-px p-0"
|
className="h-px p-0"
|
||||||
>
|
>
|
||||||
<FileProgress file={file} />
|
<FileProgress file={file} showSize={true} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,13 @@ import { useFileSpeed } from "@/hooks/use-file-speed";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { ClockArrowDown, Zap } from "lucide-react";
|
import { ClockArrowDown, Zap } from "lucide-react";
|
||||||
|
|
||||||
export default function FileProgress({ file }: { file: TelegramFile }) {
|
export default function FileProgress({
|
||||||
|
file,
|
||||||
|
showSize,
|
||||||
|
}: {
|
||||||
|
file: TelegramFile;
|
||||||
|
showSize: boolean;
|
||||||
|
}) {
|
||||||
const { downloadProgress, downloadSpeed } = useFileSpeed(file.id);
|
const { downloadProgress, downloadSpeed } = useFileSpeed(file.id);
|
||||||
const progress = useMemo(() => {
|
const progress = useMemo(() => {
|
||||||
const fileDownloadProgress =
|
const fileDownloadProgress =
|
||||||
|
|
@ -31,7 +37,7 @@ export default function FileProgress({ file }: { file: TelegramFile }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-end justify-between gap-2">
|
<div className="flex items-end justify-between gap-2">
|
||||||
{file.downloadedSize > 0 && (
|
{showSize && file.downloadedSize > 0 && (
|
||||||
<div className="flex min-w-32 items-center gap-1 bg-gray-100 px-1">
|
<div className="flex min-w-32 items-center gap-1 bg-gray-100 px-1">
|
||||||
<ClockArrowDown className="h-3 w-3" />
|
<ClockArrowDown className="h-3 w-3" />
|
||||||
<span className="text-nowrap text-xs">
|
<span className="text-nowrap text-xs">
|
||||||
|
|
|
||||||
33
web/src/components/file-status.tsx
Normal file
33
web/src/components/file-status.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { type DownloadStatus } from "@/lib/types";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import React from "react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
export default function FileStatus({ status }: { status: DownloadStatus }) {
|
||||||
|
const STATUS = {
|
||||||
|
idle: {
|
||||||
|
className: "bg-gray-100 text-gray-600",
|
||||||
|
text: "Idle",
|
||||||
|
},
|
||||||
|
downloading: {
|
||||||
|
className: "bg-blue-100 text-blue-600",
|
||||||
|
text: "Downloading",
|
||||||
|
},
|
||||||
|
paused: {
|
||||||
|
className: "bg-yellow-100 text-yellow-600",
|
||||||
|
text: "Paused",
|
||||||
|
},
|
||||||
|
completed: {
|
||||||
|
className: "bg-green-100 text-green-600",
|
||||||
|
text: "Completed",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
className: "bg-red-100 text-red-600",
|
||||||
|
text: "Error",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return <Badge className={cn("text-xs", STATUS[status].className)}>
|
||||||
|
{STATUS[status].text}
|
||||||
|
</Badge>;
|
||||||
|
}
|
||||||
|
|
@ -3,12 +3,13 @@ import Image from "next/image";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { CloudAlert, Loader } from "lucide-react";
|
import { CloudAlert, Loader } from "lucide-react";
|
||||||
import { useWebsocket } from "@/hooks/use-websocket";
|
import { useWebsocket } from "@/hooks/use-websocket";
|
||||||
import { useEffect, useState } from "react";
|
import {useEffect, useRef, useState} from "react";
|
||||||
import { WebSocketMessageType } from "@/lib/websocket-types";
|
import { WebSocketMessageType } from "@/lib/websocket-types";
|
||||||
import { toast } from "@/hooks/use-toast";
|
import { toast } from "@/hooks/use-toast";
|
||||||
import { useSettings } from "@/hooks/use-settings";
|
import { useSettings } from "@/hooks/use-settings";
|
||||||
import { type TDFile } from "@/lib/types";
|
import { type TDFile } from "@/lib/types";
|
||||||
import { getApiUrl } from "@/lib/api";
|
import { getApiUrl } from "@/lib/api";
|
||||||
|
import useIsMobile from "@/hooks/use-is-mobile";
|
||||||
|
|
||||||
interface PhotoPreviewProps {
|
interface PhotoPreviewProps {
|
||||||
thumbnail: string;
|
thumbnail: string;
|
||||||
|
|
@ -25,7 +26,9 @@ export default function PhotoPreview({
|
||||||
}: PhotoPreviewProps) {
|
}: PhotoPreviewProps) {
|
||||||
const url = `${getApiUrl()}/file/preview?chatId=${chatId}&messageId=${messageId}`;
|
const url = `${getApiUrl()}/file/preview?chatId=${chatId}&messageId=${messageId}`;
|
||||||
const { settings } = useSettings();
|
const { settings } = useSettings();
|
||||||
|
const isMobile = useIsMobile();
|
||||||
const [isReady, setIsReady] = useState(false);
|
const [isReady, setIsReady] = useState(false);
|
||||||
|
const imageRef = useRef<HTMLImageElement>(null);
|
||||||
const [fileStatus, setFileStatus] = useState<{
|
const [fileStatus, setFileStatus] = useState<{
|
||||||
fileId: number | null;
|
fileId: number | null;
|
||||||
readyFileIds: number[];
|
readyFileIds: number[];
|
||||||
|
|
@ -130,9 +133,29 @@ export default function PhotoPreview({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleFullScreen = () => {
|
||||||
|
if (!isMobile) return;
|
||||||
|
if (!document.fullscreenEnabled) {
|
||||||
|
console.error("Full-screen mode is not supported.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const image = imageRef.current;
|
||||||
|
if (!image) return;
|
||||||
|
if (!document.fullscreenElement) {
|
||||||
|
image.requestFullscreen().catch((err: Error) => {
|
||||||
|
console.error(`Error attempting to enable full-screen mode: ${err.message}`)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (document.exitFullscreen) {
|
||||||
|
void document.exitFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border border-gray-300 bg-white p-2 shadow-lg">
|
<div className="rounded-lg border border-gray-300 bg-white p-2 shadow-lg">
|
||||||
<Image
|
<Image
|
||||||
|
ref={imageRef}
|
||||||
src={url}
|
src={url}
|
||||||
unoptimized={true}
|
unoptimized={true}
|
||||||
blurDataURL={`data:image/jpeg;base64,${thumbnail}`}
|
blurDataURL={`data:image/jpeg;base64,${thumbnail}`}
|
||||||
|
|
@ -140,6 +163,7 @@ export default function PhotoPreview({
|
||||||
width={32}
|
width={32}
|
||||||
height={32}
|
height={32}
|
||||||
className="h-[200px] w-full"
|
className="h-[200px] w-full"
|
||||||
|
onClick={toggleFullScreen}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
118
web/src/components/ui/drawer.tsx
Normal file
118
web/src/components/ui/drawer.tsx
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import { Drawer as DrawerPrimitive } from "vaul";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
const Drawer = ({
|
||||||
|
shouldScaleBackground = true,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
|
||||||
|
<DrawerPrimitive.Root
|
||||||
|
shouldScaleBackground={shouldScaleBackground}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
Drawer.displayName = "Drawer";
|
||||||
|
|
||||||
|
const DrawerTrigger = DrawerPrimitive.Trigger;
|
||||||
|
|
||||||
|
const DrawerPortal = DrawerPrimitive.Portal;
|
||||||
|
|
||||||
|
const DrawerClose = DrawerPrimitive.Close;
|
||||||
|
|
||||||
|
const DrawerOverlay = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DrawerPrimitive.Overlay>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DrawerPrimitive.Overlay
|
||||||
|
ref={ref}
|
||||||
|
className={cn("fixed inset-0 z-50 bg-black/80", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
|
const DrawerContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DrawerPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<DrawerPortal>
|
||||||
|
<DrawerOverlay />
|
||||||
|
<DrawerPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
|
||||||
|
{children}
|
||||||
|
</DrawerPrimitive.Content>
|
||||||
|
</DrawerPortal>
|
||||||
|
));
|
||||||
|
DrawerContent.displayName = "DrawerContent";
|
||||||
|
|
||||||
|
const DrawerHeader = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
DrawerHeader.displayName = "DrawerHeader";
|
||||||
|
|
||||||
|
const DrawerFooter = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
DrawerFooter.displayName = "DrawerFooter";
|
||||||
|
|
||||||
|
const DrawerTitle = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DrawerPrimitive.Title>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DrawerPrimitive.Title
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"text-lg font-semibold leading-none tracking-tight",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
|
||||||
|
|
||||||
|
const DrawerDescription = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DrawerPrimitive.Description>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DrawerPrimitive.Description
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Drawer,
|
||||||
|
DrawerPortal,
|
||||||
|
DrawerOverlay,
|
||||||
|
DrawerTrigger,
|
||||||
|
DrawerClose,
|
||||||
|
DrawerContent,
|
||||||
|
DrawerHeader,
|
||||||
|
DrawerFooter,
|
||||||
|
DrawerTitle,
|
||||||
|
DrawerDescription,
|
||||||
|
};
|
||||||
31
web/src/components/ui/separator.tsx
Normal file
31
web/src/components/ui/separator.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Separator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
|
||||||
|
>(
|
||||||
|
(
|
||||||
|
{ className, orientation = "horizontal", decorative = true, ...props },
|
||||||
|
ref
|
||||||
|
) => (
|
||||||
|
<SeparatorPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
decorative={decorative}
|
||||||
|
orientation={orientation}
|
||||||
|
className={cn(
|
||||||
|
"shrink-0 bg-border",
|
||||||
|
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Separator.displayName = SeparatorPrimitive.Root.displayName
|
||||||
|
|
||||||
|
export { Separator }
|
||||||
Loading…
Reference in a new issue