From 91f4b7d812c37b5010b43e0bc576d865c8cfd641 Mon Sep 17 00:00:00 2001 From: Zibbp Date: Fri, 5 Jul 2024 13:38:25 +0000 Subject: [PATCH 01/34] Initial commit --- .devcontainer/devcontainer.json | 6 +- .vscode/settings.json | 9 + package-lock.json | 1623 +++++++++++++++-- package.json | 5 +- src/components/Landing/ContinueWatching.tsx | 2 +- src/components/Landing/Recent.tsx | 2 +- .../{Vod => Video}/ChatMessage.module.css | 0 src/components/{Vod => Video}/ChatMessage.tsx | 0 .../{Vod => Video}/ChatPlayer.module.css | 0 src/components/{Vod => Video}/ChatPlayer.tsx | 0 .../Core/VideoCard.module.css} | 0 .../Card.tsx => Video/Core/VideoCard.tsx} | 62 +- src/components/{Vod => Video}/EventBus.ts | 0 .../ExperimentalChatPlayer.module.css | 0 .../{Vod => Video}/ExperimentalChatPlayer.tsx | 0 .../{Vod => Video}/InfoModalContent.tsx | 0 .../{Vod => Video}/LoginRequired.module.css | 0 .../{Vod => Video}/LoginRequred.tsx | 0 src/components/{Vod => Video}/Menu.module.css | 0 src/components/{Vod => Video}/Menu.tsx | 0 .../{Vod => Video}/MissingThumbnailImage.tsx | 0 .../PlaylistModalContent.module.css | 0 .../{Vod => Video}/PlaylistModalContent.tsx | 0 .../{Vod => Video}/TheaterModeIcon.module.css | 0 .../{Vod => Video}/TheaterModeIcon.tsx | 0 .../{Vod => Video}/TitleBar.module.css | 0 src/components/{Vod => Video}/TitleBar.tsx | 0 .../{Vod => Video}/VideoPlayer.module.css | 0 src/components/{Vod => Video}/VideoPlayer.tsx | 0 src/components/Video/test.ts | 57 + src/hooks/getAuthentication.tsx | 117 +- src/pages/_app.tsx | 10 - src/pages/archive/index.tsx | 80 +- src/pages/channels/[channelName].tsx | 2 +- src/pages/playlists/[playlistId].tsx | 2 +- src/pages/search/index.tsx | 2 +- src/pages/vods/[vodId].tsx | 10 +- src/types/authentication.d.ts | 7 + src/types/user.d.ts | 17 + src/types/video.d.ts | 44 + 40 files changed, 1683 insertions(+), 374 deletions(-) rename src/components/{Vod => Video}/ChatMessage.module.css (100%) rename src/components/{Vod => Video}/ChatMessage.tsx (100%) rename src/components/{Vod => Video}/ChatPlayer.module.css (100%) rename src/components/{Vod => Video}/ChatPlayer.tsx (100%) rename src/components/{Vod/Card.module.css => Video/Core/VideoCard.module.css} (100%) rename src/components/{Vod/Card.tsx => Video/Core/VideoCard.tsx} (74%) rename src/components/{Vod => Video}/EventBus.ts (100%) rename src/components/{Vod => Video}/ExperimentalChatPlayer.module.css (100%) rename src/components/{Vod => Video}/ExperimentalChatPlayer.tsx (100%) rename src/components/{Vod => Video}/InfoModalContent.tsx (100%) rename src/components/{Vod => Video}/LoginRequired.module.css (100%) rename src/components/{Vod => Video}/LoginRequred.tsx (100%) rename src/components/{Vod => Video}/Menu.module.css (100%) rename src/components/{Vod => Video}/Menu.tsx (100%) rename src/components/{Vod => Video}/MissingThumbnailImage.tsx (100%) rename src/components/{Vod => Video}/PlaylistModalContent.module.css (100%) rename src/components/{Vod => Video}/PlaylistModalContent.tsx (100%) rename src/components/{Vod => Video}/TheaterModeIcon.module.css (100%) rename src/components/{Vod => Video}/TheaterModeIcon.tsx (100%) rename src/components/{Vod => Video}/TitleBar.module.css (100%) rename src/components/{Vod => Video}/TitleBar.tsx (100%) rename src/components/{Vod => Video}/VideoPlayer.module.css (100%) rename src/components/{Vod => Video}/VideoPlayer.tsx (100%) create mode 100644 src/components/Video/test.ts create mode 100644 src/types/authentication.d.ts create mode 100644 src/types/user.d.ts create mode 100644 src/types/video.d.ts diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b45a645..38298bd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,7 +3,7 @@ { "name": "Ganymede Frontend", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/javascript-node:0-20", + "image": "mcr.microsoft.com/devcontainers/typescript-node:20", // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, @@ -16,7 +16,9 @@ "customizations": { "vscode": { "extensions": [ - "eamodio.gitlens" + "eamodio.gitlens", + "vunguyentuan.vscode-postcss", + "vunguyentuan.vscode-css-variables" ] } } diff --git a/.vscode/settings.json b/.vscode/settings.json index e69de29..076b96e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "cssVariables.lookupFiles": [ + "**/*.css", + "**/*.scss", + "**/*.sass", + "**/*.less", + "node_modules/@mantine/core/styles.css" + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index af05671..35070d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,11 +26,9 @@ "cookies-next": "^2.1.1", "dayjs": "^1.11.10", "embla-carousel-react": "^8.0.2", - "events": "^3.3.0", "lodash": "^4.17.21", "mantine-datatable": "^7.8.1", - "media-icons": "^0.10.0", - "next": "^14.1.4", + "next": "^14.2.4", "plyr-react": "^5.3.0", "react": "18.2.0", "react-dom": "18.2.0", @@ -39,6 +37,7 @@ "zustand": "^4.5.2" }, "devDependencies": { + "@tanstack/eslint-plugin-query": "^5.43.1", "postcss": "^8.4.38", "postcss-preset-mantine": "^1.14.4", "postcss-simple-vars": "^7.0.1" @@ -55,29 +54,161 @@ "node": ">=6.9.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.15.1.tgz", + "integrity": "sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint/object-schema": "^2.1.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.4.0.tgz", + "integrity": "sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==", + "dev": true, + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.3.tgz", + "integrity": "sha512-HAbhAYKfsAC2EkTqve00ibWIZlaU74Z1EHwAjYr4PXF0YU2VEA1zSIKSSpKszRLRWwHzzRZXvK632u+uXzvsvw==", + "dev": true, + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@floating-ui/core": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", - "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz", + "integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==", "dependencies": { - "@floating-ui/utils": "^0.2.1" + "@floating-ui/utils": "^0.2.0" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", - "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz", + "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==", "dependencies": { "@floating-ui/core": "^1.0.0", "@floating-ui/utils": "^0.2.0" } }, "node_modules/@floating-ui/react": { - "version": "0.26.12", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.12.tgz", - "integrity": "sha512-D09o62HrWdIkstF2kGekIKAC0/N/Dl6wo3CQsnLcOmO3LkW6Ik8uIb3kw8JYkwxNCcg+uJ2bpWUiIijTBep05w==", + "version": "0.26.16", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.16.tgz", + "integrity": "sha512-HEf43zxZNAI/E781QIVpYSF3K2VH4TTYZpqecjdsFkjsaU1EbaWcM++kw0HXFffj7gDUcBFevX8s0rQGQpxkow==", "dependencies": { - "@floating-ui/react-dom": "^2.0.0", + "@floating-ui/react-dom": "^2.1.0", "@floating-ui/utils": "^0.2.0", "tabbable": "^6.0.0" }, @@ -87,11 +218,11 @@ } }, "node_modules/@floating-ui/react-dom": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", - "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.0.tgz", + "integrity": "sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==", "dependencies": { - "@floating-ui/dom": "^1.6.1" + "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "react": ">=16.8.0", @@ -99,59 +230,87 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", - "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz", + "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==" + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@mantine/carousel": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@mantine/carousel/-/carousel-7.8.0.tgz", - "integrity": "sha512-nxuLtZ4N4KJaayab5KuaffYhiVi4UaIjywkgQiNfTxABlgFdERNfo5if9sSMyisL0r3RUPJBfLkyi8A4fEC8GQ==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@mantine/carousel/-/carousel-7.10.1.tgz", + "integrity": "sha512-dUDc8d4V/goCP9GvlV66K11pVGa3y2Jq391/lrIJBOG3fcIpBFrzdMAjCVxDLCOemOubXQkW4fP0TBXq8cBhlQ==", "peerDependencies": { - "@mantine/core": "7.8.0", - "@mantine/hooks": "7.8.0", + "@mantine/core": "7.10.1", + "@mantine/hooks": "7.10.1", "embla-carousel-react": ">=7.0.0", "react": "^18.2.0", "react-dom": "^18.2.0" } }, "node_modules/@mantine/core": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@mantine/core/-/core-7.8.0.tgz", - "integrity": "sha512-19RKuNdJ/s8pZjy2w2rvTsl4ybi/XM6vf+Kc0WY7kpLFCvdG+/UxNi1MuJF8t2Zs0QSFeb/H5yZQNe0XPbegHw==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@mantine/core/-/core-7.10.1.tgz", + "integrity": "sha512-l9ypojKN3PjwO1CSLIsqxi7mA25+7w+xc71Q+JuCCREI0tuGwkZsKbIOpuTATIJOjPh8ycLiW7QxX1LYsRTq6w==", "dependencies": { "@floating-ui/react": "^0.26.9", - "clsx": "2.1.0", + "clsx": "^2.1.1", "react-number-format": "^5.3.1", "react-remove-scroll": "^2.5.7", "react-textarea-autosize": "8.5.3", "type-fest": "^4.12.0" }, "peerDependencies": { - "@mantine/hooks": "7.8.0", + "@mantine/hooks": "7.10.1", "react": "^18.2.0", "react-dom": "^18.2.0" } }, "node_modules/@mantine/dates": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-7.8.0.tgz", - "integrity": "sha512-9jjiYMwP3jQOpOLKkjhp9uf2BGhtEbOnOzyAlpLOS0CJJlYtB0tO6dJ3JaogrOZ/Yfee7ZUBgouCG5EkR4/qtQ==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-7.10.1.tgz", + "integrity": "sha512-XkzYaHgzJPrquG78/exJd0dLeghJvRgypfSRwFH7IcR34Eo2MD3nsuorZp09i9sYnROcXqIFhZWgwk5cqg/8nw==", "dependencies": { - "clsx": "2.1.0" + "clsx": "^2.1.1" }, "peerDependencies": { - "@mantine/core": "7.8.0", - "@mantine/hooks": "7.8.0", + "@mantine/core": "7.10.1", + "@mantine/hooks": "7.10.1", "dayjs": ">=1.0.0", "react": "^18.2.0", "react-dom": "^18.2.0" } }, "node_modules/@mantine/form": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@mantine/form/-/form-7.8.0.tgz", - "integrity": "sha512-Qn3/69zGt/p3wyMwGz2V0+FbmvqC2/PvXaeyO0a4CnwhROeE7ObyCKXDcBmgapOSBHr/7wFvMeTDMaTMfe3DXw==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@mantine/form/-/form-7.10.1.tgz", + "integrity": "sha512-mZwzg4GEWKEDKEIZu9FmSpGFzYYhFD2YArVOXUM0MMciUqX7yxSCon1PaPJxrV8ldc6FE+JLVI2+G2KVxJ3ZXA==", "dependencies": { "fast-deep-equal": "^3.1.3", "klona": "^2.0.6" @@ -161,45 +320,45 @@ } }, "node_modules/@mantine/hooks": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-7.8.0.tgz", - "integrity": "sha512-+70fkgjhVJeJ+nJqnburIM3UAsfvxat1Low9HMPobLbv64FIdB4Nzu5ct3qojNQ58r5sK01tg5UoFIJYslaVrg==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-7.10.1.tgz", + "integrity": "sha512-0EH9WBWUdtQLGU3Ak+csQ77EtUxI6pPNfwZdRJQWcaA3f8SFOLo9h9CGxiikFExerhvuCeUlaTf3s+TB9Op/rw==", "peerDependencies": { "react": "^18.2.0" } }, "node_modules/@mantine/notifications": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-7.8.0.tgz", - "integrity": "sha512-O7BnaCcwVg38fh+gSZ6GEsTFPPgJAiOTrRkOMXG+7pNqJT9YNa9KDZhiPZzn3WV4wexncjyK32a8gGSVtf+kdg==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-7.10.1.tgz", + "integrity": "sha512-cx3JR3BJzEzH6t2EF1ysrWVY/rdJk0WbSBQo/qFamJd2sbU+8XAHriI8Cx6hNo7uRGCwd8VGAj7Cf3aWK2VC5A==", "dependencies": { - "@mantine/store": "7.8.0", + "@mantine/store": "7.10.1", "react-transition-group": "4.4.5" }, "peerDependencies": { - "@mantine/core": "7.8.0", - "@mantine/hooks": "7.8.0", + "@mantine/core": "7.10.1", + "@mantine/hooks": "7.10.1", "react": "^18.2.0", "react-dom": "^18.2.0" } }, "node_modules/@mantine/store": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@mantine/store/-/store-7.8.0.tgz", - "integrity": "sha512-oN/BXGYdUywRi0zj9ppaShv2sw5QON2DaRisB4ewJ5tDDz8qyeckgdE0NMaaU2TwpoScs8ibSnOVWV5y+vYkMA==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@mantine/store/-/store-7.10.1.tgz", + "integrity": "sha512-KrGBsSoMsfrYeLxPwf5rFv0s2Nl/4wf+AaF/U1SpQrMgPI8vYokPXx52Wp3jCmlo12NCZnCIG+/6YHAdTWH1qQ==", "peerDependencies": { "react": "^18.2.0" } }, "node_modules/@next/env": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.4.tgz", - "integrity": "sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==" + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.4.tgz", + "integrity": "sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==" }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.4.tgz", - "integrity": "sha512-ubmUkbmW65nIAOmoxT1IROZdmmJMmdYvXIe8211send9ZYJu+SqxSnJM4TrPj9wmL6g9Atvj0S/2cFmMSS99jg==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.4.tgz", + "integrity": "sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==", "cpu": [ "arm64" ], @@ -212,9 +371,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.4.tgz", - "integrity": "sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.4.tgz", + "integrity": "sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==", "cpu": [ "x64" ], @@ -227,9 +386,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.4.tgz", - "integrity": "sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.4.tgz", + "integrity": "sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==", "cpu": [ "arm64" ], @@ -242,9 +401,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.4.tgz", - "integrity": "sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.4.tgz", + "integrity": "sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==", "cpu": [ "arm64" ], @@ -257,9 +416,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.4.tgz", - "integrity": "sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.4.tgz", + "integrity": "sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==", "cpu": [ "x64" ], @@ -272,9 +431,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.4.tgz", - "integrity": "sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.4.tgz", + "integrity": "sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==", "cpu": [ "x64" ], @@ -287,9 +446,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.4.tgz", - "integrity": "sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.4.tgz", + "integrity": "sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==", "cpu": [ "arm64" ], @@ -302,9 +461,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.4.tgz", - "integrity": "sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.4.tgz", + "integrity": "sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==", "cpu": [ "ia32" ], @@ -317,9 +476,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.4.tgz", - "integrity": "sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.4.tgz", + "integrity": "sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==", "cpu": [ "x64" ], @@ -366,11 +525,17 @@ "node": ">= 8" } }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" + }, "node_modules/@swc/helpers": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", - "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", "dependencies": { + "@swc/counter": "^0.1.3", "tslib": "^2.4.0" } }, @@ -399,30 +564,46 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@tanstack/eslint-plugin-query": { + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.43.1.tgz", + "integrity": "sha512-5WZmkny6u/lSjzUpgnvn+vnA1KtIa7umNZYLqCg9TZK0lmz9SRP6Hnui1PI279eisDy/O+1yD0MfEHTJWlQGVw==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "8.0.0-alpha.28" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "eslint": "^8 || ^9" + } + }, "node_modules/@tanstack/query-core": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.29.0.tgz", - "integrity": "sha512-WgPTRs58hm9CMzEr5jpISe8HXa3qKQ8CxewdYZeVnA54JrPY9B1CZiwsCoLpLkf0dGRZq+LcX5OiJb0bEsOFww==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.40.0.tgz", + "integrity": "sha512-eD8K8jsOIq0Z5u/QbvOmfvKKE/XC39jA7yv4hgpl/1SRiU+J8QCIwgM/mEHuunQsL87dcvnHqSVLmf9pD4CiaA==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/query-devtools": { - "version": "5.28.10", - "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.28.10.tgz", - "integrity": "sha512-5UN629fKa5/1K/2Pd26gaU7epxRrYiT1gy+V+pW5K6hnf1DeUKK3pANSb2eHKlecjIKIhTwyF7k9XdyE2gREvQ==", + "version": "5.37.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.37.1.tgz", + "integrity": "sha512-XcG4IIHIv0YQKrexTqo2zogQWR1Sz672tX2KsfE9kzB+9zhx44vRKH5si4WDILE1PIWQpStFs/NnrDQrBAUQpg==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/react-query": { - "version": "5.29.2", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.29.2.tgz", - "integrity": "sha512-nyuWILR4u7H5moLGSiifLh8kIqQDLNOHGuSz0rcp+J75fNc8aQLyr5+I2JCHU3n+nJrTTW1ssgAD8HiKD7IFBQ==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.40.1.tgz", + "integrity": "sha512-gOcmu+gpFd2taHrrgMM9RemLYYEDYfsCqszxCC0xtx+csDa4R8t7Hr7SfWXQP13S2sF+mOxySo/+FNXJFYBqcA==", "dependencies": { - "@tanstack/query-core": "5.29.0" + "@tanstack/query-core": "5.40.0" }, "funding": { "type": "github", @@ -433,19 +614,19 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.29.2", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.29.2.tgz", - "integrity": "sha512-EmsaLNa8iFtReAW+5ftom0/TW78fIosVor517ak/+JFaoTBw8Yub3ao937JFE6AM3K/HXhteqvObetgt1ndLcw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.40.1.tgz", + "integrity": "sha512-/AN2UsbuL+28/KSlBkVHq/4chHTEp4l2UWTKWixXbn4pprLQrZGmQTAKN4tYxZDuNwNZY5+Zp67pDfXj+F/UBA==", "dependencies": { - "@tanstack/query-devtools": "5.28.10" + "@tanstack/query-devtools": "5.37.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.29.2", - "react": "^18.0.0" + "@tanstack/react-query": "^5.40.1", + "react": "^18 || ^19" } }, "node_modules/@types/cookie": { @@ -483,6 +664,103 @@ "@types/react": "*" } }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.28.tgz", + "integrity": "sha512-Iq8QFmJ2DH2tx7jfOraMZM1Y1axRfWh4t29JXRgbzvgiDQ2uHRHcaXqTulqsZXzJ0+vERNvNkOIPcQYGsNeGVQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.28", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.28" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.28.tgz", + "integrity": "sha512-HYg+e0EWVShx0FEX0MAjDinYLmd+wD6nGMpbaddB1iACYwqaJFbf7vw0l+hdLTJvQC6UY8ndRkaEsL68QEoIZQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.28.tgz", + "integrity": "sha512-I/5ODd4XJ+TO0XrKwDaB4tVGVi6kz2LAlN3WPd7mZVVtW21HHByCILRhOF9RbC69gJQ/TGHFpWCmAcsq2RZisg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.28", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.28", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0-alpha.28.tgz", + "integrity": "sha512-PnIz94+nbyjJisMI+KZqXMfw0wfIHvbyh0MGEx2M314wqm6SUWcxB5I8zduGQgJbRB0YFnboPS+MeSlBYPWrBQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.0.0-alpha.28", + "@typescript-eslint/types": "8.0.0-alpha.28", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.28" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.28.tgz", + "integrity": "sha512-+ewAOeKDycydKMlnfmW8zAURTA8PR5Csyvxy6PJt4XRYjoquode9/eWaMt9Sp4Rz1FGMSVU9KxDRR83ASH/xkQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.28", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@vidstack/react": { "version": "1.11.21", "resolved": "https://registry.npmjs.org/@vidstack/react/-/react-1.11.21.tgz", @@ -498,28 +776,125 @@ "react": "^18.0.0" } }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -536,6 +911,16 @@ "node": ">=10.16.0" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -564,19 +949,56 @@ } ] }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, "node_modules/clsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "engines": { "node": ">=6" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -588,6 +1010,13 @@ "node": ">= 0.8" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "peer": true + }, "node_modules/cookie": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", @@ -607,9 +1036,9 @@ } }, "node_modules/cookies-next/node_modules/@types/node": { - "version": "16.18.65", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.65.tgz", - "integrity": "sha512-5E9WgTy95B7i90oISjui9U5Zu7iExUPfU4ygtv4yXEy6zJFE3oQYHCnh5H1jZRPkjphJt2Ml3oQW6M0qtK534A==" + "version": "16.18.98", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz", + "integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==" }, "node_modules/core-js": { "version": "3.33.3", @@ -621,6 +1050,21 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -644,9 +1088,33 @@ "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==" }, "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "peer": true }, "node_modules/delayed-stream": { "version": "1.0.0", @@ -661,6 +1129,18 @@ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -671,36 +1151,249 @@ } }, "node_modules/embla-carousel": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.0.2.tgz", - "integrity": "sha512-bogsDO8xosuh/l3PxIvA5AMl3+BnRVAse9sDW/60amzj4MbGS5re4WH5eVEXiuH8G1/3G7QUAX2QNr3Yx8z5rA==" + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.1.3.tgz", + "integrity": "sha512-GiRpKtzidV3v50oVMly8S+D7iE1r96ttt7fSlvtyKHoSkzrAnVcu8fX3c4j8Ol2hZSQlVfDqDIqdrFPs0u5TWQ==" }, "node_modules/embla-carousel-react": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/embla-carousel-react/-/embla-carousel-react-8.0.2.tgz", - "integrity": "sha512-RHe1GKLulOW8EDN+cJgbFbVVfRXcaLT2/89dyVw3ONGgVpZjD19wB87I1LUZ1aCzOSrTccx0PFSQanK4OOfGPA==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/embla-carousel-react/-/embla-carousel-react-8.1.3.tgz", + "integrity": "sha512-YrezDPgxPDKa+OKMhSrwuPEU2OgF5147vFW473EWT3bx9DETV3W/RyWTxq0/2pf3M4VXkjqFNbS/W1xM8lTaVg==", "dependencies": { - "embla-carousel": "8.0.2", - "embla-carousel-reactive-utils": "8.0.2" + "embla-carousel": "8.1.3", + "embla-carousel-reactive-utils": "8.1.3" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.1 || ^18.0.0" } }, "node_modules/embla-carousel-reactive-utils": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/embla-carousel-reactive-utils/-/embla-carousel-reactive-utils-8.0.2.tgz", - "integrity": "sha512-nLZqDkQdO0hvOP49/dUwjkkepMnUXgIzhyRuDjwGqswpB4Ibnc5M+w7rSQQAM+uMj0cPaXnYOTlv8XD7I/zVNw==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/embla-carousel-reactive-utils/-/embla-carousel-reactive-utils-8.1.3.tgz", + "integrity": "sha512-D8tAK6NRQVEubMWb+b/BJ3VvGPsbEeEFOBM6cCCwfiyfLzNlacOAt0q2dtUEA9DbGxeWkB8ExgXzFRxhGV2Hig==", "peerDependencies": { - "embla-carousel": "8.0.2" + "embla-carousel": "8.1.3" } }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.4.0.tgz", + "integrity": "sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/config-array": "^0.15.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.4.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", + "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "dev": true, + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "peer": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, "engines": { - "node": ">=0.8.x" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/fast-deep-equal": { @@ -724,6 +1417,20 @@ "node": ">=8.6.0" } }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "peer": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -733,10 +1440,23 @@ "reusify": "^1.0.4" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "peer": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -745,6 +1465,44 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "peer": true + }, "node_modules/follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", @@ -777,30 +1535,109 @@ "node": ">= 6" } }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, "engines": { - "node": ">=6" + "node": ">= 4" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "peer": true, "dependencies": { - "is-glob": "^4.0.1" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.19" + } }, "node_modules/invariant": { "version": "2.2.4", @@ -840,11 +1677,72 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "peer": true + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "peer": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/klona": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", @@ -853,16 +1751,53 @@ "node": ">= 8" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/loadjs": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loadjs/-/loadjs-4.2.0.tgz", "integrity": "sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==" }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "peer": true + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -875,9 +1810,9 @@ } }, "node_modules/mantine-datatable": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/mantine-datatable/-/mantine-datatable-7.8.1.tgz", - "integrity": "sha512-lsU6tiM1m0N6A/b/nxjMYq+xEtFYbyFoYAyFL32rf7CKmcyygy9gSIm955RA0Hb41D99riI4Vz45fVzHbG/Y/Q==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/mantine-datatable/-/mantine-datatable-7.10.1.tgz", + "integrity": "sha512-RYMJCL5HKdelorEy9e9Og+7beVVE2+NLb+jpcibZ1m1ted4Q/kKbP0v2ytbgBADd4iXjmiqyzX3DOHesORe3Bg==", "funding": { "type": "github", "url": "https://github.com/sponsors/icflorescu" @@ -897,14 +1832,6 @@ "node": ">=16" } }, - "node_modules/media-icons": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/media-icons/-/media-icons-0.10.0.tgz", - "integrity": "sha512-M9loX7KUWsID3T8pRSN6/+MNKPEm9dNteqJk7yfo9ZaAIEYzEd07jWTVRlRmgVMKoAh1kY7funD6Qe1prrTJMQ==", - "engines": { - "node": ">=16" - } - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -946,6 +1873,27 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -963,13 +1911,20 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "peer": true + }, "node_modules/next": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/next/-/next-14.1.4.tgz", - "integrity": "sha512-1WTaXeSrUwlz/XcnhGTY7+8eiaFvdet5z9u3V2jb+Ek1vFo0VhHKSAIJvDWfQpttWjnyw14kBeq28TPq7bTeEQ==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.4.tgz", + "integrity": "sha512-R8/V7vugY+822rsQGQCjoLhMuC9oFj9SOi4Cl4b2wjDrseD0LRZ10W7R6Czo4w9ZznVSshKjuIomsRjvm9EKJQ==", "dependencies": { - "@next/env": "14.1.4", - "@swc/helpers": "0.5.2", + "@next/env": "14.2.4", + "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "graceful-fs": "^4.2.11", @@ -983,18 +1938,19 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.1.4", - "@next/swc-darwin-x64": "14.1.4", - "@next/swc-linux-arm64-gnu": "14.1.4", - "@next/swc-linux-arm64-musl": "14.1.4", - "@next/swc-linux-x64-gnu": "14.1.4", - "@next/swc-linux-x64-musl": "14.1.4", - "@next/swc-win32-arm64-msvc": "14.1.4", - "@next/swc-win32-ia32-msvc": "14.1.4", - "@next/swc-win32-x64-msvc": "14.1.4" + "@next/swc-darwin-arm64": "14.2.4", + "@next/swc-darwin-x64": "14.2.4", + "@next/swc-linux-arm64-gnu": "14.2.4", + "@next/swc-linux-arm64-musl": "14.2.4", + "@next/swc-linux-x64-gnu": "14.2.4", + "@next/swc-linux-x64-musl": "14.2.4", + "@next/swc-win32-arm64-msvc": "14.2.4", + "@next/swc-win32-ia32-msvc": "14.2.4", + "@next/swc-win32-x64-msvc": "14.2.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -1003,6 +1959,9 @@ "@opentelemetry/api": { "optional": true }, + "@playwright/test": { + "optional": true + }, "sass": { "optional": true } @@ -1043,6 +2002,98 @@ "node": ">=0.10.0" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "peer": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "peer": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -1185,9 +2236,9 @@ } }, "node_modules/postcss-preset-mantine": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/postcss-preset-mantine/-/postcss-preset-mantine-1.14.4.tgz", - "integrity": "sha512-T1K3MVhU1hA9mJWfqoGvMcK5WKcHpVi4JUX6AYTbESvp78WneB/KFONUi+eXDG9Lpw62W/KNxEYl1ic3Dpm88w==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/postcss-preset-mantine/-/postcss-preset-mantine-1.15.0.tgz", + "integrity": "sha512-OKPs6uoORSXlU/GFH1ZtFaslecHBPwuoSikdL5W3WKJm4ZPAQM0mw9x9m3toa/Mo1JhoBmYMM28i+zEdav5Edg==", "dev": true, "dependencies": { "postcss-mixins": "^9.0.4", @@ -1226,6 +2277,16 @@ "postcss": "^8.2.1" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -1241,6 +2302,16 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -1306,9 +2377,9 @@ } }, "node_modules/react-hook-form": { - "version": "7.51.3", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.3.tgz", - "integrity": "sha512-cvJ/wbHdhYx8aviSWh28w9ImjmVsb5Y05n1+FW786vEZQJV5STNM0pW6ujS+oiBecb0ARBxJFyAnXj9+GHXACQ==", + "version": "7.51.5", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.5.tgz", + "integrity": "sha512-J2ILT5gWx1XUIJRETiA7M19iXHlG74+6O3KApzvqB/w8S5NQR7AbU8HVZrMALdmDgWpRPYiZJl0zx8Z4L2mP6Q==", "engines": { "node": ">=12.22.0" }, @@ -1326,9 +2397,9 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-number-format": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.3.1.tgz", - "integrity": "sha512-qpYcQLauIeEhCZUZY9jXZnnroOtdy3jYaS1zQ3M1Sr6r/KMOBEIGNIb7eKT19g2N1wbYgFgvDzs19hw5TrB8XQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.4.0.tgz", + "integrity": "sha512-NWdICrqLhI7rAS8yUeLVd6Wr4cN7UjJ9IBTS0f/a9i7UB4x4Ti70kGnksBtZ7o4Z7YRbvCMMR/jQmkoOBa/4fg==", "dependencies": { "prop-types": "^15.7.2" }, @@ -1440,6 +2511,16 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -1474,13 +2555,57 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { "loose-envify": "^1.1.0" } }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "peer": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/source-map-js": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", @@ -1497,6 +2622,32 @@ "node": ">=10.0.0" } }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/styled-jsx": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", @@ -1535,11 +2686,31 @@ "postcss": "^8.3.3" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "peer": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1552,11 +2723,36 @@ "node": ">=8.0" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-fest": { "version": "4.15.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.15.0.tgz", @@ -1585,6 +2781,16 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/url-polyfill": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.12.tgz", @@ -1682,6 +2888,45 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zustand": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz", diff --git a/package.json b/package.json index 0cf7ad1..2a4d7ab 100644 --- a/package.json +++ b/package.json @@ -27,11 +27,9 @@ "cookies-next": "^2.1.1", "dayjs": "^1.11.10", "embla-carousel-react": "^8.0.2", - "events": "^3.3.0", "lodash": "^4.17.21", "mantine-datatable": "^7.8.1", - "media-icons": "^0.10.0", - "next": "^14.1.4", + "next": "^14.2.4", "plyr-react": "^5.3.0", "react": "18.2.0", "react-dom": "18.2.0", @@ -40,6 +38,7 @@ "zustand": "^4.5.2" }, "devDependencies": { + "@tanstack/eslint-plugin-query": "^5.43.1", "postcss": "^8.4.38", "postcss-preset-mantine": "^1.14.4", "postcss-simple-vars": "^7.0.1" diff --git a/src/components/Landing/ContinueWatching.tsx b/src/components/Landing/ContinueWatching.tsx index d99ab1c..d0b3a23 100644 --- a/src/components/Landing/ContinueWatching.tsx +++ b/src/components/Landing/ContinueWatching.tsx @@ -3,7 +3,7 @@ import { useQuery } from "@tanstack/react-query"; import React from "react"; import { useApi } from "../../hooks/useApi"; import GanymedeLoader from "../Utils/GanymedeLoader"; -import VideoCard from "../Vod/Card"; +import VideoCard from "../Video/Core/VideoCard"; import { useMediaQuery } from "@mantine/hooks"; import { Carousel } from "@mantine/carousel"; diff --git a/src/components/Landing/Recent.tsx b/src/components/Landing/Recent.tsx index e3f680a..5227a87 100644 --- a/src/components/Landing/Recent.tsx +++ b/src/components/Landing/Recent.tsx @@ -3,7 +3,7 @@ import { useQuery } from "@tanstack/react-query"; import React from "react"; import { useApi } from "../../hooks/useApi"; import GanymedeLoader from "../Utils/GanymedeLoader"; -import VideoCard from "../Vod/Card"; +import VideoCard from "../Video/Core/VideoCard"; import { useMediaQuery } from "@mantine/hooks"; import { Carousel } from "@mantine/carousel"; diff --git a/src/components/Vod/ChatMessage.module.css b/src/components/Video/ChatMessage.module.css similarity index 100% rename from src/components/Vod/ChatMessage.module.css rename to src/components/Video/ChatMessage.module.css diff --git a/src/components/Vod/ChatMessage.tsx b/src/components/Video/ChatMessage.tsx similarity index 100% rename from src/components/Vod/ChatMessage.tsx rename to src/components/Video/ChatMessage.tsx diff --git a/src/components/Vod/ChatPlayer.module.css b/src/components/Video/ChatPlayer.module.css similarity index 100% rename from src/components/Vod/ChatPlayer.module.css rename to src/components/Video/ChatPlayer.module.css diff --git a/src/components/Vod/ChatPlayer.tsx b/src/components/Video/ChatPlayer.tsx similarity index 100% rename from src/components/Vod/ChatPlayer.tsx rename to src/components/Video/ChatPlayer.tsx diff --git a/src/components/Vod/Card.module.css b/src/components/Video/Core/VideoCard.module.css similarity index 100% rename from src/components/Vod/Card.module.css rename to src/components/Video/Core/VideoCard.module.css diff --git a/src/components/Vod/Card.tsx b/src/components/Video/Core/VideoCard.tsx similarity index 74% rename from src/components/Vod/Card.tsx rename to src/components/Video/Core/VideoCard.tsx index f4a0f18..e8316e5 100644 --- a/src/components/Vod/Card.tsx +++ b/src/components/Video/Core/VideoCard.tsx @@ -1,63 +1,44 @@ import React, { useEffect, useState } from "react"; -import { IconBookmark, IconHeart, IconShare } from "@tabler/icons-react"; import { Card, Image, Text, - ActionIcon, Badge, Group, Center, Avatar, - rem, Tooltip, ThemeIcon, Progress, - Overlay, Loader, Flex, LoadingOverlay, } from "@mantine/core"; -import { PlaybackData, Video } from "../../ganymede-defs"; import getConfig from "next/config"; import dayjs from "dayjs"; import duration from "dayjs/plugin/duration"; import localizedFormat from "dayjs/plugin/localizedFormat"; -import useUserStore, { UserState } from "../../store/user"; +import useUserStore, { UserState } from "../../../store/user"; import { IconCircleCheck, IconMenu2 } from "@tabler/icons-react"; -import { ROLES } from "../../hooks/useJsxAuth"; -import { VodMenu } from "./Menu"; +import { ROLES } from "../../../hooks/useJsxAuth"; +import { VodMenu } from "../Menu"; import Link from "next/link"; -import { escapeURL } from "../../util/util"; +import { escapeURL } from "../../../util/util"; dayjs.extend(duration); dayjs.extend(localizedFormat); -import classes from "./Card.module.css"; +import classes from "./VideoCard.module.css"; +import { Video } from "../../../types/video"; +type Props = { + video: Video + progress: number + showMenu: boolean + showChannel: boolean +} -const formatDuration = (duration: number) => { - const hours = Math.floor(duration / 3600); - const minutes = Math.floor((duration % 3600) / 60); - const seconds = Math.floor(duration % 60); - - const formattedHours = hours.toString().padStart(2, "0"); - const formattedMinutes = minutes.toString().padStart(2, "0"); - const formattedSeconds = seconds.toString().padStart(2, "0"); - - return `${formattedHours}:${formattedMinutes}:${formattedSeconds}`; -}; - -const VideoCard = ({ - video, - playback, - showChannel = false, -}: { - video: Video; - playback?: PlaybackData[]; - showChannel?: boolean; -}) => { +const VideoCard = ({ video, progress = 5, showMenu = true, showChannel = true }: Props) => { const { publicRuntimeConfig } = getConfig(); const user: UserState = useUserStore(); - const [progress, setProgress] = useState(0); const [watched, setWatched] = useState(false); const [imageError, setImageError] = useState(false); @@ -65,21 +46,6 @@ const VideoCard = ({ setImageError(true); }; - useEffect(() => { - if (playback) { - const videoInPlayback = playback.find((p: any) => p.vod_id === video.id); - if (videoInPlayback) { - if (videoInPlayback.status == "finished") { - setWatched(true); - } - if (videoInPlayback.time) { - const progress = (videoInPlayback.time / video.duration) * 100; - setProgress(progress); - } - } - } - }, [playback]); - const menuPermissions = () => { if (!user.isLoggedIn) { return false; @@ -194,7 +160,7 @@ const VideoCard = ({ {video.type.toUpperCase()} - {menuPermissions() && ( + {(showMenu && menuPermissions()) && ( )} diff --git a/src/components/Vod/EventBus.ts b/src/components/Video/EventBus.ts similarity index 100% rename from src/components/Vod/EventBus.ts rename to src/components/Video/EventBus.ts diff --git a/src/components/Vod/ExperimentalChatPlayer.module.css b/src/components/Video/ExperimentalChatPlayer.module.css similarity index 100% rename from src/components/Vod/ExperimentalChatPlayer.module.css rename to src/components/Video/ExperimentalChatPlayer.module.css diff --git a/src/components/Vod/ExperimentalChatPlayer.tsx b/src/components/Video/ExperimentalChatPlayer.tsx similarity index 100% rename from src/components/Vod/ExperimentalChatPlayer.tsx rename to src/components/Video/ExperimentalChatPlayer.tsx diff --git a/src/components/Vod/InfoModalContent.tsx b/src/components/Video/InfoModalContent.tsx similarity index 100% rename from src/components/Vod/InfoModalContent.tsx rename to src/components/Video/InfoModalContent.tsx diff --git a/src/components/Vod/LoginRequired.module.css b/src/components/Video/LoginRequired.module.css similarity index 100% rename from src/components/Vod/LoginRequired.module.css rename to src/components/Video/LoginRequired.module.css diff --git a/src/components/Vod/LoginRequred.tsx b/src/components/Video/LoginRequred.tsx similarity index 100% rename from src/components/Vod/LoginRequred.tsx rename to src/components/Video/LoginRequred.tsx diff --git a/src/components/Vod/Menu.module.css b/src/components/Video/Menu.module.css similarity index 100% rename from src/components/Vod/Menu.module.css rename to src/components/Video/Menu.module.css diff --git a/src/components/Vod/Menu.tsx b/src/components/Video/Menu.tsx similarity index 100% rename from src/components/Vod/Menu.tsx rename to src/components/Video/Menu.tsx diff --git a/src/components/Vod/MissingThumbnailImage.tsx b/src/components/Video/MissingThumbnailImage.tsx similarity index 100% rename from src/components/Vod/MissingThumbnailImage.tsx rename to src/components/Video/MissingThumbnailImage.tsx diff --git a/src/components/Vod/PlaylistModalContent.module.css b/src/components/Video/PlaylistModalContent.module.css similarity index 100% rename from src/components/Vod/PlaylistModalContent.module.css rename to src/components/Video/PlaylistModalContent.module.css diff --git a/src/components/Vod/PlaylistModalContent.tsx b/src/components/Video/PlaylistModalContent.tsx similarity index 100% rename from src/components/Vod/PlaylistModalContent.tsx rename to src/components/Video/PlaylistModalContent.tsx diff --git a/src/components/Vod/TheaterModeIcon.module.css b/src/components/Video/TheaterModeIcon.module.css similarity index 100% rename from src/components/Vod/TheaterModeIcon.module.css rename to src/components/Video/TheaterModeIcon.module.css diff --git a/src/components/Vod/TheaterModeIcon.tsx b/src/components/Video/TheaterModeIcon.tsx similarity index 100% rename from src/components/Vod/TheaterModeIcon.tsx rename to src/components/Video/TheaterModeIcon.tsx diff --git a/src/components/Vod/TitleBar.module.css b/src/components/Video/TitleBar.module.css similarity index 100% rename from src/components/Vod/TitleBar.module.css rename to src/components/Video/TitleBar.module.css diff --git a/src/components/Vod/TitleBar.tsx b/src/components/Video/TitleBar.tsx similarity index 100% rename from src/components/Vod/TitleBar.tsx rename to src/components/Video/TitleBar.tsx diff --git a/src/components/Vod/VideoPlayer.module.css b/src/components/Video/VideoPlayer.module.css similarity index 100% rename from src/components/Vod/VideoPlayer.module.css rename to src/components/Video/VideoPlayer.module.css diff --git a/src/components/Vod/VideoPlayer.tsx b/src/components/Video/VideoPlayer.tsx similarity index 100% rename from src/components/Vod/VideoPlayer.tsx rename to src/components/Video/VideoPlayer.tsx diff --git a/src/components/Video/test.ts b/src/components/Video/test.ts new file mode 100644 index 0000000..3cbd608 --- /dev/null +++ b/src/components/Video/test.ts @@ -0,0 +1,57 @@ + // setup chapters if there are any + if (vod.edges && vod.edges.chapters && vod.edges.chapters.length > 0) { + const tmpChapters: string = convertToChapters(vod.edges.chapters) + setChapters(tmpChapters) + + const foo = `[ + { + "startTime" 0, "endTime": 5, "text": foo" } + } + ]` + + const track = new TextTrack({ + content: JSON.stringify(foo), + kind: "chapters", + type: "json", + default: true, + }) + + player.current?.textTracks.add(track) + console.log(tmpChapters) + } + + + const convertToChapters = (json: any): string => { + const chapters: any[] = []; + + json.forEach((chapter: any) => { + const startTime = formatTime(chapter.start || 0); + const endTime = formatTime(chapter.end || 0); + const text = chapter.title || ""; + + chapters.push({ startTime, endTime, text }); + }); + + return JSON.stringify(chapters); + }; + + const formatTime = (seconds: number): string => { + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + return `${pad(hours)}:${pad(minutes)}`; + }; + + const pad = (num: number): string => { + return num.toString().padStart(2, '0'); + }; + + const padZero = (num: number): string => num.toString().padStart(2, '0'); + + + const content: VTTContent = { + regions: [], + cues: [ + { startTime: 0, endTime: 5, text: '...' }, + { startTime: 5, endTime: 10, text: '...' }, + ], + }; \ No newline at end of file diff --git a/src/hooks/getAuthentication.tsx b/src/hooks/getAuthentication.tsx index 7ef36d1..fad5db1 100644 --- a/src/hooks/getAuthentication.tsx +++ b/src/hooks/getAuthentication.tsx @@ -2,9 +2,43 @@ import axios from "axios"; import { getCookie } from "cookies-next"; import getConfig from "next/config"; import useUserStore from "../store/user"; +import { AuthMeResponse } from "../types/authentication"; + +const getUserData = async () => { + const { publicRuntimeConfig } = getConfig(); + + const axiosInstance = axios.create({ + baseURL: publicRuntimeConfig.API_URL, + timeout: 5000, + withCredentials: true + }) + + return await axiosInstance.get( + `/api/v1/auth/me`, + ); +} + +const setUserState = (data: AuthMeResponse, oauth: boolean = false) => { + useUserStore.setState({ + isLoggedIn: true, + id: data.id, + username: data.username, + role: data.role, // @ts-ignore + updatedAt: data.updated_at, + createdAt: data.created_at, + oauth: oauth, + }); +} export const getAuthentication = async () => { const { publicRuntimeConfig } = getConfig(); + + const axiosInstance = axios.create({ + baseURL: publicRuntimeConfig.API_URL, + timeout: 5000, + withCredentials: true + }) + console.debug("getAuthentication hook called"); // Check for user settings stored in localstorage @@ -24,26 +58,15 @@ export const getAuthentication = async () => { if (refreshTokenCookie) { // If refresh token exists, attempt to refresh and get access token try { - await axios.post( - `${publicRuntimeConfig.API_URL}/api/v1/auth/refresh`, - {}, - { withCredentials: true } - ); - const response = await axios.get( - `${publicRuntimeConfig.API_URL}/api/v1/auth/me`, - { - withCredentials: true, - } + await axiosInstance.post( + `/api/v1/auth/refresh`, ); + const response = await getUserData() + + console.log(response) + + setUserState(response.data) - useUserStore.setState({ - isLoggedIn: true, - id: response.data.id, - username: response.data.username, - role: response.data.role, - updatedAt: response.data.updatedAt, - createdAt: response.data.created_at, - }); console.debug("getAuthentication hook: user logged in"); } catch (error) { console.error("Error refreshing token"); @@ -53,59 +76,37 @@ export const getAuthentication = async () => { if (oauthRefreshCookie) { try { - const response = await axios.get( - `${publicRuntimeConfig.API_URL}/api/v1/auth/me`, - { - withCredentials: true, - } - ); - useUserStore.setState({ - isLoggedIn: true, - id: response.data.id, - username: response.data.username, - role: response.data.role, - updatedAt: response.data.updatedAt, - createdAt: response.data.created_at, - oauth: true, - }); - console.debug("[getAuthentication]: user logged in via oauth"); + const response = await getUserData() + + setUserState(response.data) + + console.debug("getAuthentication: user logged in via oauth"); } catch (error) { - if (error.response.status === 401) { - // Attempt a refresh + if (axios.isAxiosError(error) && error.response?.status == 401) { + // attempt refresh try { - await axios.get( - `${publicRuntimeConfig.API_URL}/api/v1/auth/oauth/refresh`, - { - withCredentials: true, - } + await axiosInstance.get( + `/api/v1/auth/oauth/refresh`, ); - const response = await axios.get( - `${publicRuntimeConfig.API_URL}/api/v1/auth/me`, - { - withCredentials: true, - } - ); + const response = await getUserData() - useUserStore.setState({ - isLoggedIn: true, - id: response.data.id, - username: response.data.username, - role: response.data.role, - updatedAt: response.data.updatedAt, - createdAt: response.data.created_at, - oauth: true, - }); + setUserState(response.data, true + + ) console.debug( - "[getAuthentication]: tokens refreshed and user logged in via oauth" + "getAuthentication hook: tokens refreshed and user logged in via oauth" ); } catch (error) { console.debug( - "[getAuthentication]: error refreshing oauth tokens - user not logged in" + "getAuthentication hook: error refreshing oauth tokens - user not logged in" ); return; } + } else { + console.error(`Unexpected error: ${error}`) } + } } diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 8f2a5d3..f739b68 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -48,16 +48,6 @@ export default function MyApp({ Component, pageProps }: AppProps) { "7xl": rem(1400), }; - const BREAK_POINTS: Record = { - xs: em(36), - sm: em(48), - md: em(62), - lg: em(75), - xl: em(88), - xxl: em(100), - } - - const theme = createTheme({ fontFamily: inter.style.fontFamily, breakpoints: { diff --git a/src/pages/archive/index.tsx b/src/pages/archive/index.tsx index 04366a6..ca52950 100644 --- a/src/pages/archive/index.tsx +++ b/src/pages/archive/index.tsx @@ -81,62 +81,34 @@ const ArchivePage = () => { return; } setArchiveSubmitLoading(true); - if (archiveInput != "") { - return useApi( - { - method: "POST", - url: `/api/v1/archive/vod`, - data: { - vod_id: archiveInput, - quality: archiveQuality, - chat: archiveChat, - render_chat: renderChat, - }, - withCredentials: true, - }, - false - ) - .then((res) => { - setArchiveSubmitLoading(false); - setTwitchVodInfo(null); - setArchiveInput(""); - showNotification({ - title: "VOD Archived", - message: "VOD has been added to the archive queue", - }); - }) - .catch((err) => { - setArchiveSubmitLoading(false); - }); - } - if (channelId != "") { - return useApi( - { - method: "POST", - url: `/api/v1/live/archive`, - data: { - channel_id: channelId, - resolution: archiveQuality, - archive_chat: archiveChat, - render_chat: renderChat, - }, - withCredentials: true, + + return useApi( + { + method: "POST", + url: `/api/v1/archive/video`, + data: { + video_id: archiveInput, + channel_id: channelId, + quality: archiveQuality, + archive_chat: archiveChat, + render_chat: renderChat, }, - false - ) - .then((res) => { - setArchiveSubmitLoading(false); - setTwitchVodInfo(null); - setArchiveInput(""); - showNotification({ - title: "Livestream Archived", - message: "Livestream has been added to the archive queue", - }); - }) - .catch((err) => { - setArchiveSubmitLoading(false); + withCredentials: true, + }, + false + ) + .then((res) => { + setArchiveSubmitLoading(false); + setTwitchVodInfo(null); + setArchiveInput(""); + showNotification({ + title: "VOD Archived", + message: "VOD has been added to the archive queue", }); - } + }) + .catch((err) => { + setArchiveSubmitLoading(false); + }); }, }); diff --git a/src/pages/channels/[channelName].tsx b/src/pages/channels/[channelName].tsx index 494a4c1..9f8ceba 100644 --- a/src/pages/channels/[channelName].tsx +++ b/src/pages/channels/[channelName].tsx @@ -21,7 +21,7 @@ import { ChannelHeader } from "../../components/Channel/Header"; import ChannelNoVideosFound from "../../components/Channel/NoVideosFound"; import GanymedeLoader from "../../components/Utils/GanymedeLoader"; import { useApi } from "../../hooks/useApi"; -import VideoCard from "../../components/Vod/Card"; +import VideoCard from "../../components/Video/Core/VideoCard"; import { Video } from "../../ganymede-defs"; import classes from "./channelName.module.css" diff --git a/src/pages/playlists/[playlistId].tsx b/src/pages/playlists/[playlistId].tsx index b60f1f4..e50dfb7 100644 --- a/src/pages/playlists/[playlistId].tsx +++ b/src/pages/playlists/[playlistId].tsx @@ -8,7 +8,7 @@ import DeletePlaylistModal from "../../components/Playlist/DeletePlaylistModal"; import EditPlaylistModal from "../../components/Playlist/EditPlaylistModal"; import PlaylistHeader from "../../components/Playlist/Header"; import GanymedeLoader from "../../components/Utils/GanymedeLoader"; -import VideoCard from "../../components/Vod/Card"; +import VideoCard from "../../components/Video/Core/VideoCard"; import { useApi } from "../../hooks/useApi"; const PlaylistPage = (props: any) => { diff --git a/src/pages/search/index.tsx b/src/pages/search/index.tsx index 45e114f..5a9bff8 100644 --- a/src/pages/search/index.tsx +++ b/src/pages/search/index.tsx @@ -17,7 +17,7 @@ import React, { useEffect, useRef, useState } from "react"; import ChannelNoVideosFound from "../../components/Channel/NoVideosFound"; import GanymedeLoader from "../../components/Utils/GanymedeLoader"; import { useApi } from "../../hooks/useApi"; -import VideoCard from "../../components/Vod/Card"; +import VideoCard from "../../components/Video/Core/VideoCard"; interface SearchPageProps { q: string; diff --git a/src/pages/vods/[vodId].tsx b/src/pages/vods/[vodId].tsx index b21f3fa..b1f3571 100644 --- a/src/pages/vods/[vodId].tsx +++ b/src/pages/vods/[vodId].tsx @@ -1,15 +1,15 @@ import { Box, Grid, em } from "@mantine/core"; import { useDocumentTitle, useFullscreen, useInterval, useMediaQuery } from "@mantine/hooks"; import { dehydrate, QueryClient, useQuery } from "@tanstack/react-query"; -import { VodChatPlayer } from "../../components/Vod/ChatPlayer"; -import ExperimentalChatPlayer from "../../components/Vod/ExperimentalChatPlayer"; -import { VodTitleBar } from "../../components/Vod/TitleBar"; +import { VodChatPlayer } from "../../components/Video/ChatPlayer"; +import ExperimentalChatPlayer from "../../components/Video/ExperimentalChatPlayer"; +import { VodTitleBar } from "../../components/Video/TitleBar"; import { useApi } from "../../hooks/useApi"; import useUserStore from "../../store/user"; import Error from "next/error"; -import NewVideoPlayer from "../../components/Vod/VideoPlayer"; +import NewVideoPlayer from "../../components/Video/VideoPlayer"; import getConfig from "next/config"; -import VodLoginRequired from "../../components/Vod/LoginRequred"; +import VodLoginRequired from "../../components/Video/LoginRequred"; import Head from "next/head"; import { useEffect, useRef, useState } from "react"; import eventBus from "../../util/eventBus"; diff --git a/src/types/authentication.d.ts b/src/types/authentication.d.ts new file mode 100644 index 0000000..27110d7 --- /dev/null +++ b/src/types/authentication.d.ts @@ -0,0 +1,7 @@ +export interface AuthMeResponse { + id: string; + username: string; + role: keyof typeof Role; + updated_at: string + created_at: string +} \ No newline at end of file diff --git a/src/types/user.d.ts b/src/types/user.d.ts new file mode 100644 index 0000000..24b40dd --- /dev/null +++ b/src/types/user.d.ts @@ -0,0 +1,17 @@ +export enum Role { + User = "user", + Archiver = "archiver", + Editor = "editor", + Admin = "admin", +} + +type Roles = keyof typeof Role; + +export interface User { + id: string; + role: Role; + username: string; + created_at: string; + updated_at: string; +} + diff --git a/src/types/video.d.ts b/src/types/video.d.ts new file mode 100644 index 0000000..e83e905 --- /dev/null +++ b/src/types/video.d.ts @@ -0,0 +1,44 @@ +export interface GetVideosRequest { + limit: number; + offset: number; + types: keyof typeof VideoType; +} + +export interface VideoResponse { + offset: number; + limit: number; + total_count: number; + pages: number; + data: Video[]; +} + +type VideoTypeList = `${VideoTypes},${VideoTypeList}` | VideoTypes; + +export interface Video { + id: string; + ext_id: string; + platform: string; + type: VideoTypeList; + title: string; + duration: number; + views: number; + resolution: string; + processing: boolean; + thumbnail_path: string; + web_thumbnail_path: string; + video_path: string; + chat_path: string; + chat_video_path: string; + info_path: string; + caption_path: string; + streamed_at: string; + created_at: string; + updated_at: string; + folder_name: string; + file_name: string; + edges: Edge; +} + +interface Edge { + channel: Channel; +} From a579901d016085009efe98161f303e2490b277f8 Mon Sep 17 00:00:00 2001 From: Zibbp Date: Mon, 8 Jul 2024 01:58:58 +0000 Subject: [PATCH 02/34] update admin info page --- src/pages/admin/info.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/pages/admin/info.tsx b/src/pages/admin/info.tsx index 7d0f920..7c3a10e 100644 --- a/src/pages/admin/info.tsx +++ b/src/pages/admin/info.tsx @@ -59,17 +59,13 @@ const AdminInfoPage = () => {
- Version: - {data.version} + Commit: + {data.commit_hash}
Build Date: {data.build_time}
-
- Git Commit Hash: - {data.git_hash} -
Uptime: {data.uptime} From a8f360400a06ba6f7d77291dd61a905ded56b120 Mon Sep 17 00:00:00 2001 From: Zibbp Date: Thu, 11 Jul 2024 01:55:31 +0000 Subject: [PATCH 03/34] feat(queue): restart tasks support --- src/components/Queue/ChatTimeline.tsx | 55 +++++++++++++++++++++++ src/components/Queue/RestartTaskModal.tsx | 15 ++++--- src/components/Queue/VideoTimeline.tsx | 46 ++++++++++++++++++- src/components/Queue/VodTimeline.tsx | 52 ++++++++++++++++++--- 4 files changed, 154 insertions(+), 14 deletions(-) diff --git a/src/components/Queue/ChatTimeline.tsx b/src/components/Queue/ChatTimeline.tsx index f5a05ad..9cd8ac9 100644 --- a/src/components/Queue/ChatTimeline.tsx +++ b/src/components/Queue/ChatTimeline.tsx @@ -14,6 +14,10 @@ import classes from "./Timeline.module.css" const QueueChatTimeline = ({ queue }: Object) => { const [logName, setLogName] = useState(""); + // modal + const [opened, setOpened] = useState(false); + const [restartTaskName, setRestartTaskName] = useState(""); + const openLog = (log: string) => { setLogName(log); window.open( @@ -23,6 +27,12 @@ const QueueChatTimeline = ({ queue }: Object) => { ); }; + const restartTask = (task: string) => { + console.log(task); + setRestartTaskName(task); + setOpened(true); + }; + return (
{ title="Chat Download" > + {!queue.live_archive && ( + + restartTask("task_chat_download")} + > + restart + + - + + )} openLog("chat")} @@ -52,6 +73,15 @@ const QueueChatTimeline = ({ queue }: Object) => { title="Chat Convert" > + + restartTask("task_chat_convert")} + > + restart + + - + openLog("chat-convert")} @@ -67,6 +97,15 @@ const QueueChatTimeline = ({ queue }: Object) => { title="Chat Render" > + + restartTask("task_chat_render")} + > + restart + + - + openLog("chat-render")} @@ -80,8 +119,24 @@ const QueueChatTimeline = ({ queue }: Object) => { bullet={} title="Chat Move" > + + restartTask("task_chat_move")} + > + restart + + + + setOpened(false)} + title="Restart Queue Task" + > + +
); }; diff --git a/src/components/Queue/RestartTaskModal.tsx b/src/components/Queue/RestartTaskModal.tsx index 84544d0..39a8003 100644 --- a/src/components/Queue/RestartTaskModal.tsx +++ b/src/components/Queue/RestartTaskModal.tsx @@ -5,7 +5,7 @@ import { useState } from "react"; import { useApi } from "../../hooks/useApi"; const QueueRestartTaskModalContent = ({ queue, task }: any) => { - const [checked, setChecked] = useState(false); + const [checked, setChecked] = useState(true); const [isLoading, setIsLoading] = useState(false); const restartTaskMutation = useMutation({ @@ -15,11 +15,11 @@ const QueueRestartTaskModalContent = ({ queue, task }: any) => { return useApi( { method: "POST", - url: `/api/v1/archive/restart`, + url: `/api/v1/queue/task/start`, data: { queue_id: queue.id, - task: task, - cont: checked, + task_name: task, + continue: checked, }, withCredentials: true, }, @@ -38,11 +38,12 @@ const QueueRestartTaskModalContent = ({ queue, task }: any) => { return (
- Restart task {task} for queue item {queue.id}? + Restart queue task {task}?
setChecked(event.currentTarget.checked)} /> @@ -52,7 +53,7 @@ const QueueRestartTaskModalContent = ({ queue, task }: any) => { onClick={() => restartTaskMutation.mutate()} fullWidth radius="md" - mt="xl" + mt="sm" size="md" color="green" loading={isLoading} diff --git a/src/components/Queue/VideoTimeline.tsx b/src/components/Queue/VideoTimeline.tsx index 8fbf0cc..5aebed7 100644 --- a/src/components/Queue/VideoTimeline.tsx +++ b/src/components/Queue/VideoTimeline.tsx @@ -14,6 +14,10 @@ import classes from "./Timeline.module.css" const QueueVideoTimeline = ({ queue }: Object) => { const [logName, setLogName] = useState(""); + // modal + const [opened, setOpened] = useState(false); + const [restartTaskName, setRestartTaskName] = useState(""); + const openLog = (log: string) => { console.log(log); setLogName(log); @@ -24,6 +28,14 @@ const QueueVideoTimeline = ({ queue }: Object) => { ); }; + const restartTask = (task: string) => { + console.log(task); + setRestartTaskName(task); + setOpened(true); + }; + + + return (
@@ -32,6 +44,17 @@ const QueueVideoTimeline = ({ queue }: Object) => { title="Video Download" > + {!queue.live_archive && ( + + restartTask("task_video_download")} + > + restart + + - + + )} openLog("video")} @@ -46,6 +69,13 @@ const QueueVideoTimeline = ({ queue }: Object) => { title="Video Convert" > + restartTask("task_video_convert")} + > + restart + + - openLog("video-convert")} @@ -59,9 +89,23 @@ const QueueVideoTimeline = ({ queue }: Object) => { bullet={} title="Video Move" > - + + restartTask("task_video_move")} + > + restart + + + setOpened(false)} + title="Restart Queue Task" + > + +
); }; diff --git a/src/components/Queue/VodTimeline.tsx b/src/components/Queue/VodTimeline.tsx index 9dd4d86..40a2513 100644 --- a/src/components/Queue/VodTimeline.tsx +++ b/src/components/Queue/VodTimeline.tsx @@ -11,6 +11,15 @@ import QueueTimelineBullet from "./TimelineBullet"; import classes from "./Timeline.module.css"; const QueueVodTimeline = ({ queue }: Object) => { + // modal + const [opened, setOpened] = useState(false); + const [restartTaskName, setRestartTaskName] = useState(""); + + const restartTask = (task: string) => { + console.log(task); + setRestartTaskName(task); + setOpened(true); + }; return (
@@ -19,22 +28,53 @@ const QueueVodTimeline = ({ queue }: Object) => { bullet={} title="Create Folder" > + + restartTask("task_vod_create_folder")} + > + restart + + - } - title="Download Thumbnail" + bullet={} + title="Save Info" > + + restartTask("task_vod_save_info")} + > + restart + + } - title="Save Info" + bullet={ + + } + title="Download Thumbnail" > + + restartTask("task_vod_download_thumbnail")} + > + restart + + + setOpened(false)} + title="Restart Queue Task" + > + +
); }; From 37bcd5afb0fd095944c0f78972cfd98e1366ddc3 Mon Sep 17 00:00:00 2001 From: Zibbp Date: Tue, 16 Jul 2024 02:43:30 +0000 Subject: [PATCH 04/34] use new twitch route --- src/components/Archive/VodPreview.tsx | 27 +++++++++++++++------ src/ganymede-defs.d.ts | 34 +++++++++++++++++++++++++++ src/pages/archive/index.tsx | 27 ++++----------------- 3 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/components/Archive/VodPreview.tsx b/src/components/Archive/VodPreview.tsx index 7da74d8..2ace9eb 100644 --- a/src/components/Archive/VodPreview.tsx +++ b/src/components/Archive/VodPreview.tsx @@ -1,8 +1,9 @@ -import { TwitchVODResponse } from "../../pages/archive"; +import { PlatformVideoInfo } from "../../ganymede-defs"; import { Image, Title } from "@mantine/core"; -export const VodPreview = ({ vod }: TwitchVODResponse) => { - const thumbnailUrl = vod.thumbnail_url +export const VodPreview = ({ video }: { video: PlatformVideoInfo }) => { + console.log(video) + const thumbnailUrl = video.thumbnail_url .replace("%{width}", "640") .replace("%{height}", "360"); return ( @@ -10,21 +11,33 @@ export const VodPreview = ({ vod }: TwitchVODResponse) => {
- {vod.title} + {video.title}
Created At: - {vod.created_at} + {video.created_at}
Duration: - {vod.duration} + {video.duration}
Views: - {vod.view_count} + {video.view_count}
+ {video.chapters && ( +
+ Chapters: + {video.chapters.length} +
+ )} + {video.muted_segments && ( +
+ Muted Segments: + {video.muted_segments.length} +
+ )}
diff --git a/src/ganymede-defs.d.ts b/src/ganymede-defs.d.ts index 5201486..86bc033 100644 --- a/src/ganymede-defs.d.ts +++ b/src/ganymede-defs.d.ts @@ -187,4 +187,38 @@ export interface LiveTitleRegex { regex: string; negative: boolean; apply_to_videos: boolean; +} + +type PlatformVideoInfo = { + id: string; + stream_id: string; + user_id: string; + user_login: string; + user_name: string; + title: string; + description: string; + created_at: string; + published_at: string; + url: string; + thumbnail_url: string; + viewable: string; + view_count: number; + language: string; + type: string; + duration: string; + chapters: Chapter[]; + muted_segments: MutedSegment[]; +} + +type MutedSegment = { + duration: number; + offset: number; +} + +type Chapter = { + id: string; + type: string; + title: string; + start: number; + end: number; } \ No newline at end of file diff --git a/src/pages/archive/index.tsx b/src/pages/archive/index.tsx index ca52950..28a61a2 100644 --- a/src/pages/archive/index.tsx +++ b/src/pages/archive/index.tsx @@ -22,31 +22,14 @@ import { VodPreview } from "../../components/Archive/VodPreview"; import { Authorization, ROLES } from "../../components/ProtectedRoute"; import { useApi } from "../../hooks/useApi"; import classes from "./archive.module.css" +import { PlatformVideoInfo } from "../../ganymede-defs"; + -export interface TwitchVODResponse { - id: string; - stream_id: string; - user_id: string; - user_login: string; - user_name: string; - title: string; - description: string; - created_at: Date; - published_at: Date; - url: string; - thumbnail_url: string; - viewable: string; - view_count: number; - language: string; - type: string; - duration: string; - muted_segments: null; -} const ArchivePage = () => { const [archiveInput, setArchiveInput] = useInputState(""); const [archiveSubmitLoading, setArchiveSubmitLoading] = useState(false); - const [twitchVodInfo, setTwitchVodInfo] = useState( + const [twitchVodInfo, setTwitchVodInfo] = useState( null ); const [archiveChat, setArchiveChat] = useInputState(true); @@ -156,7 +139,7 @@ const ArchivePage = () => { if (id.length < 4) return; return useApi( - { method: "GET", url: `/api/v1/twitch/vod?id=${id}` }, + { method: "GET", url: `/api/v1/twitch/video?id=${id}` }, false ) .then((res) => { @@ -240,7 +223,7 @@ const ArchivePage = () => { Archive - {twitchVodInfo?.id && } + {twitchVodInfo?.id && }
From b22ba78c594cd2e3d5be8e95380b8a37a4871bea Mon Sep 17 00:00:00 2001 From: Zibbp Date: Sat, 20 Jul 2024 03:07:35 +0000 Subject: [PATCH 05/34] update category route --- src/components/Admin/Watched/Drawer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Admin/Watched/Drawer.tsx b/src/components/Admin/Watched/Drawer.tsx index 26e099b..2fc4236 100644 --- a/src/components/Admin/Watched/Drawer.tsx +++ b/src/components/Admin/Watched/Drawer.tsx @@ -239,7 +239,7 @@ const AdminWatchedDrawer = ({ handleClose, watched, mode }) => { return useApi( { method: "GET", - url: `/api/v1/twitch/categories`, + url: `/api/v1/category`, withCredentials: true, }, false From 452ca834229bf951c074b7dfcbd97c6fe3c72b30 Mon Sep 17 00:00:00 2001 From: Zibbp Date: Thu, 25 Jul 2024 02:24:19 +0000 Subject: [PATCH 06/34] blocked video support --- src/components/layouts/Navbar.tsx | 8 + src/pages/admin/blocked-vods.module.css | 18 ++ src/pages/admin/blocked-vods.tsx | 230 ++++++++++++++++++++++++ src/pages/admin/tasks.tsx | 63 ++----- 4 files changed, 275 insertions(+), 44 deletions(-) create mode 100644 src/pages/admin/blocked-vods.module.css create mode 100644 src/pages/admin/blocked-vods.tsx diff --git a/src/components/layouts/Navbar.tsx b/src/components/layouts/Navbar.tsx index f35579a..2a533c4 100644 --- a/src/components/layouts/Navbar.tsx +++ b/src/components/layouts/Navbar.tsx @@ -41,6 +41,7 @@ import { IconSearch, IconSun, IconMoon, + IconBarrierBlock, } from '@tabler/icons-react'; import classes from './Navbar.module.css'; import Image from 'next/image'; @@ -67,6 +68,13 @@ const adminLinks = [ description: "Manage and create VODs", link: "/admin/vods", }, + { + id: "blocked_vods", + icon: IconBarrierBlock, + title: "Blocked VODs", + description: "Manage blocked VODs", + link: "/admin/blocked-vods", + }, { id: "user", icon: IconUser, diff --git a/src/pages/admin/blocked-vods.module.css b/src/pages/admin/blocked-vods.module.css new file mode 100644 index 0000000..e2cb4f8 --- /dev/null +++ b/src/pages/admin/blocked-vods.module.css @@ -0,0 +1,18 @@ +.header { + display: flex; + margin-top: 0.5rem; + margin-bottom: 0.5rem; +} +.right { + margin-left: auto; + order: 2 +} +.vodDrawer { + overflow-y: scroll; +} +.actionButton { + cursor: pointer; +} +.actionButtons { + display: flex; +} \ No newline at end of file diff --git a/src/pages/admin/blocked-vods.tsx b/src/pages/admin/blocked-vods.tsx new file mode 100644 index 0000000..e0c87d8 --- /dev/null +++ b/src/pages/admin/blocked-vods.tsx @@ -0,0 +1,230 @@ +import React, { useState, useEffect } from 'react' +import classes from "./blocked-vods.module.css" +import { Authorization, ROLES } from '../../components/ProtectedRoute' +import { Button, Code, Container, Title } from '@mantine/core' +import { useDocumentTitle } from '@mantine/hooks' +import { useDisclosure } from '@mantine/hooks'; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import dayjs from "dayjs"; +import { DataTable, DataTableSortStatus } from "mantine-datatable"; +import sortBy from "lodash/sortBy"; +import { + ActionIcon, + Group, + Modal, + TextInput, +} from "@mantine/core"; +import { IconPencil, IconSearch, IconTrash } from "@tabler/icons-react"; +import { useDebouncedValue } from "@mantine/hooks"; +import GanymedeLoader from "../../components/Utils/GanymedeLoader"; +import { useApi } from '../../hooks/useApi' +import { showNotification } from '@mantine/notifications' + + +type Props = {} + +const BlockedVideos = (props: Props) => { + const queryClient = useQueryClient(); + const [page, setPage] = useState(1); + const [perPage, setPerPage] = useState(20); + const [records, setRecords] = useState(null); + const [initialRecords, setInitialRecords] = useState(false); + const [sortStatus, setSortStatus] = useState({ + columnAccessor: "name", + direction: "asc", + }); + const [query, setQuery] = useState(""); + const [debouncedQuery] = useDebouncedValue(query, 200); + + useDocumentTitle("Ganymede - Admin - Blocked VODs"); + + const [activeBlockedVideo, setActiveBlockedVideo] = useState(null); + const [createModal, { open: openCreateModal, close: closeCreateModal }] = useDisclosure(false); + const [deleteModal, { open: openDeleteModal, close: closeDeleteModal }] = useDisclosure(false); + + const [blockedVideoId, setBlockedVideoId] = useState(""); + + const openDeleteModalHandler = (blockedVideo) => { + setActiveBlockedVideo(blockedVideo); + openDeleteModal() + }; + + const { isLoading, error, data } = useQuery({ + queryKey: ["admin-blocked-vods"], + queryFn: async () => + useApi( + { method: "GET", url: "/api/v1/blocked-video", withCredentials: true }, + false + ).then((res) => res?.data), + }); + + useEffect(() => { + if (data && !initialRecords) { + setRecords(data.slice(0, perPage)); + setInitialRecords(true); + } + if (data) { + const from = (page - 1) * perPage; + const to = from + perPage; + setRecords(data.slice(from, to)); + } + if (data) { + const tmpData = sortBy(data, sortStatus.columnAccessor); + setRecords(sortStatus.direction === "desc" ? tmpData.reverse() : tmpData); + } + if (data && debouncedQuery != "") { + // Search by ID, name, or display_name + setRecords( + data.filter((blockedVideos) => { + return ( + blockedVideos.id.includes(debouncedQuery) + ); + }) + ); + } + }, [data, page, perPage, sortStatus, debouncedQuery]); + + const createBlockedVideo = useMutation({ + mutationKey: ["create-blocked-vod"], + mutationFn: (id: string) => { + return useApi( + { + method: "POST", + url: `/api/v1/blocked-video/${id}`, + withCredentials: true, + }, + false + ) + .then(() => { + queryClient.invalidateQueries(["admin-blocked-videos"]); + closeCreateModal(); + setBlockedVideoId(""); + }) + }, + }); + + const deleteBlockedVideo = useMutation({ + mutationKey: ["create-blocked-video"], + mutationFn: () => { + return useApi( + { + method: "DELETE", + url: `/api/v1/blocked-video/${activeBlockedVideo.id}`, + withCredentials: true, + }, + false + ) + .then(() => { + queryClient.invalidateQueries(["admin-blocked-videos"]); + closeDeleteModal(); + }) + }, + }); + + if (error) return
failed to load
; + if (isLoading) return ; + + return ( + +
+ +
+
+ Blocked VODs +
+
+ +
+
+ + {/* table */} +
+
+ } + value={query} + onChange={(e) => setQuery(e.currentTarget.value)} + mb={10} + /> +
+ ( +
{dayjs(created_at).format("YYYY/MM/DD")}
+ ), + }, + { + accessor: "actions", + title: "Actions", + width: 50, + render: (blockedVideo) => ( + + openDeleteModalHandler(blockedVideo)} + className={classes.actionButton} + variant="light" color="red" + > + + + + ), + }, + ]} + // pagination + totalRecords={data.length} + page={page} + recordsPerPage={perPage} + onPageChange={(p) => setPage(p)} + recordsPerPageOptions={[20, 40, 100]} + onRecordsPerPageChange={setPerPage} + // sorting + sortStatus={sortStatus} + onSortStatusChange={setSortStatus} + /> +
+
+ +
+ +
+ setBlockedVideoId(event.currentTarget.value)} + /> + +
+
+ +
+ {activeBlockedVideo && ({activeBlockedVideo.id})} + +
+
+
+ ) +} + +export default BlockedVideos \ No newline at end of file diff --git a/src/pages/admin/tasks.tsx b/src/pages/admin/tasks.tsx index 79ad0c4..b753d95 100644 --- a/src/pages/admin/tasks.tsx +++ b/src/pages/admin/tasks.tsx @@ -14,7 +14,7 @@ import { } from "@mantine/core"; import { useDocumentTitle } from "@mantine/hooks"; import { showNotification } from "@mantine/notifications"; -import { IconPlayerPlay, IconRefresh } from "@tabler/icons-react"; +import { IconPlayerPlay } from "@tabler/icons-react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import React, { useState } from "react"; import { Authorization, ROLES } from "../../components/ProtectedRoute"; @@ -98,8 +98,8 @@ const AdminTasksPage = () => {
- Check watched channels for live streams - + Check watched channels for live streams to archive + Occurs at interval set in config. @@ -114,7 +114,7 @@ const AdminTasksPage = () => { variant="filled" size="lg" > - + @@ -126,7 +126,7 @@ const AdminTasksPage = () => { Check watched channels for new videos to archive - + Occurs at interval set in config. @@ -141,7 +141,7 @@ const AdminTasksPage = () => { variant="filled" size="lg" > - + @@ -152,38 +152,13 @@ const AdminTasksPage = () => {
Ganymede
- - -
- - Authenticate with Twitch - - Occurs every 7 days. - - -
-
- - - startTask.mutate("twitch_auth")} - loading={loading} - color="green" - variant="filled" - size="lg" - > - - - - -
Get JWKS - - Occurs every day. + + Occurs daily at 00:00.
@@ -197,7 +172,7 @@ const AdminTasksPage = () => { variant="filled" size="lg" > - +
@@ -213,8 +188,8 @@ const AdminTasksPage = () => { - - startWorkflow.mutate("SaveTwitchVideoChapters")}> + + startTask.mutate("save_chapters")}> @@ -317,7 +292,7 @@ const AdminTasksPage = () => { - startWorkflow.mutate("UpdateTwitchLiveStreamArchivesWithVodIds")}> + startTask.mutate("update_stream_vod_ids")}> From 14d147ba30afec97dd3cb36e55448d8896f17d0f Mon Sep 17 00:00:00 2001 From: Zibbp Date: Fri, 26 Jul 2024 01:46:25 +0000 Subject: [PATCH 07/34] support categories with live streams --- src/components/Admin/Watched/Drawer.tsx | 25 +++++++++++++++++++++---- src/components/Admin/Watched/Table.tsx | 8 ++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/components/Admin/Watched/Drawer.tsx b/src/components/Admin/Watched/Drawer.tsx index 2fc4236..b44202b 100644 --- a/src/components/Admin/Watched/Drawer.tsx +++ b/src/components/Admin/Watched/Drawer.tsx @@ -50,6 +50,7 @@ const AdminWatchedDrawer = ({ handleClose, watched, mode }) => { ); const [selectedTwitchCategories, setSelectedTwitchCategories] = useState([]); const [liveTitleRegexes, setLiveTitleRegexes] = useState([]); + const [applyCategoriesToLive, setApplyCategoriesToLive] = useState(false); const qualityOptions = [ { label: "Best", value: "best" }, @@ -76,6 +77,7 @@ const AdminWatchedDrawer = ({ handleClose, watched, mode }) => { setDownloadSubOnly(watched?.download_sub_only); setMaxVideoAge(watched?.video_age); setLiveTitleRegexes(watched?.edges.title_regex) + setApplyCategoriesToLive(watched?.apply_categories_to_live); if (watched?.edges?.categories) { const tmpArr = []; @@ -110,7 +112,8 @@ const AdminWatchedDrawer = ({ handleClose, watched, mode }) => { download_sub_only: downloadSubOnly, categories: selectedTwitchCategories, max_age: maxVideoAge, - regex: liveTitleRegexes + regex: liveTitleRegexes, + apply_categories_to_live: applyCategoriesToLive }, withCredentials: true, }, @@ -151,7 +154,8 @@ const AdminWatchedDrawer = ({ handleClose, watched, mode }) => { download_sub_only: downloadSubOnly, categories: selectedTwitchCategories, max_age: maxVideoAge, - regex: liveTitleRegexes + regex: liveTitleRegexes, + apply_categories_to_live: applyCategoriesToLive }, withCredentials: true, }, @@ -175,7 +179,8 @@ const AdminWatchedDrawer = ({ handleClose, watched, mode }) => { download_sub_only: downloadSubOnly, categories: selectedTwitchCategories, max_age: maxVideoAge, - regex: liveTitleRegexes + regex: liveTitleRegexes, + apply_categories_to_live: applyCategoriesToLive }, withCredentials: true, }, @@ -474,9 +479,21 @@ const AdminWatchedDrawer = ({ handleClose, watched, mode }) => { Categories
- Archive videos from these categories. Leave blank to archive all categories. Does not apply to live streams. + Archive videos from select categories. Leave blank to archive all categories.
+ + + Apply categories to livestream check. Stream will only be archived if the category is matched. + setApplyCategoriesToLive(e.currentTarget.checked)} + /> + + +
{formattedTwitchCategories.length == 0 ? ( +
+
); }; From ba087b7eb592cc636914d0e532bc62439a52e2bd Mon Sep 17 00:00:00 2001 From: Zibbp Date: Sun, 28 Jul 2024 03:29:13 +0000 Subject: [PATCH 10/34] all-in-one settings page --- .../Admin/Settings/NotificationsDrawer.tsx | 472 ----------- .../Admin/Settings/Settings.module.css | 13 - .../Admin/Settings/StorageSettingsDrawer.tsx | 169 ---- src/ganymede-defs.d.ts | 56 +- src/pages/admin/settings.tsx | 751 +++++++++++++++--- 5 files changed, 708 insertions(+), 753 deletions(-) delete mode 100644 src/components/Admin/Settings/NotificationsDrawer.tsx delete mode 100644 src/components/Admin/Settings/Settings.module.css delete mode 100644 src/components/Admin/Settings/StorageSettingsDrawer.tsx diff --git a/src/components/Admin/Settings/NotificationsDrawer.tsx b/src/components/Admin/Settings/NotificationsDrawer.tsx deleted file mode 100644 index 200085b..0000000 --- a/src/components/Admin/Settings/NotificationsDrawer.tsx +++ /dev/null @@ -1,472 +0,0 @@ -import { - ActionIcon, - Button, - Code, - Collapse, - Switch, - Text, - Textarea, - TextInput, - ThemeIcon, - Title, -} from "@mantine/core"; -import { IconChevronDown, IconChevronUp } from "@tabler/icons-react"; -import { useMutation, useQuery } from "@tanstack/react-query"; -import { useState } from "react"; -import { useForm } from "react-hook-form"; -import { useApi } from "../../../hooks/useApi"; -import GanymedeLoader from "../../Utils/GanymedeLoader"; -import classes from "./Settings.module.css" - -const AdminNotificationsDrawer = ({ handleClose }) => { - - const { handleSubmit } = useForm(); - - const [videoSuccessWebhookUrl, setVideoSuccessWebhookUrl] = useState(""); - const [videoSuccessTemplate, setVideoSuccessTemplate] = useState(""); - const [videoSuccessEnabled, setVideoSuccessEnabled] = useState(true); - const [videoSuccessCollapse, setVideoSuccessCollapse] = useState(false); - const [liveSuccessWebhookUrl, setLiveSuccessWebhookUrl] = useState(""); - const [liveSuccessTemplate, setLiveSuccessTemplate] = useState(""); - const [liveSuccessEnabled, setLiveSuccessEnabled] = useState(true); - const [liveSuccessCollapse, setLiveSuccessCollapse] = useState(false); - const [errorWebhookUrl, setErrorWebhookUrl] = useState(""); - const [errorTemplate, setErrorTemplate] = useState(""); - const [errorEnabled, setErrorEnabled] = useState(true); - const [errorCollapse, setErrorCollapse] = useState(false); - const [isLiveWebhookUrl, setIsLiveWebhookUrl] = useState(""); - const [isLiveTemplate, setIsLiveTemplate] = useState(""); - const [isLiveEnabled, setIsLiveEnabled] = useState(true); - const [isLiveCollapse, setIsLiveCollapse] = useState(false); - - const [loading, setLoading] = useState(false); - const [testNotificationLoading, setTestNotificationLoading] = useState(false); - - const { data, error, isLoading } = useQuery({ - refetchOnWindowFocus: false, - queryKey: ["admin-notifications"], - queryFn: () => { - return useApi( - { - method: "GET", - url: "/api/v1/config/notification", - withCredentials: true, - }, - false - ).then((res) => { - setVideoSuccessWebhookUrl(res?.data.video_success_webhook_url); - setVideoSuccessTemplate(res?.data.video_success_template); - setVideoSuccessEnabled(res?.data.video_success_enabled); - setLiveSuccessWebhookUrl(res?.data.live_success_webhook_url); - setLiveSuccessTemplate(res?.data.live_success_template); - setLiveSuccessEnabled(res?.data.live_success_enabled); - setErrorWebhookUrl(res?.data.error_webhook_url); - setErrorTemplate(res?.data.error_template); - setErrorEnabled(res?.data.error_enabled); - setIsLiveWebhookUrl(res?.data.is_live_webhook_url); - setIsLiveTemplate(res?.data.is_live_template); - setIsLiveEnabled(res?.data.is_live_enabled); - return res?.data; - }); - }, - }); - - const { mutate, error: mutateError } = useMutation({ - mutationKey: ["save-notification-settings"], - mutationFn: () => { - setLoading(true); - return useApi( - { - method: "PUT", - url: "/api/v1/config/notification", - data: { - video_success_webhook_url: videoSuccessWebhookUrl, - video_success_template: videoSuccessTemplate, - video_success_enabled: videoSuccessEnabled, - live_success_webhook_url: liveSuccessWebhookUrl, - live_success_template: liveSuccessTemplate, - live_success_enabled: liveSuccessEnabled, - error_webhook_url: errorWebhookUrl, - error_template: errorTemplate, - error_enabled: errorEnabled, - is_live_webhook_url: isLiveWebhookUrl, - is_live_template: isLiveTemplate, - is_live_enabled: isLiveEnabled, - }, - withCredentials: true, - }, - false - ) - .then((res) => { - setLoading(false); - return res?.data; - }) - .catch((err) => { - setLoading(false); - return err; - }); - }, - }); - - const { mutate: testNotification } = useMutation({ - mutationKey: ["test-notification"], - mutationFn: (type: string) => { - setTestNotificationLoading(true); - return useApi( - { - method: "POST", - url: `/api/v1/notification/test?type=${type}`, - withCredentials: true, - }, - false - ) - .then((res) => { - setTestNotificationLoading(false); - return res?.data; - }) - .catch((err) => { - setTestNotificationLoading(false); - return err; - }); - }, - }); - - if (error) return
failed to load
; - if (isLoading) return ; - - return ( -
- - Must be a webhook url or an - - {" "} - Apprise{" "} - - url, visit the{" "} - - {" "} - wiki{" "} - - for more information. - -
-
- - Video Archive Success Notification - -
- - setVideoSuccessEnabled(event.currentTarget.checked) - } - label="Enabled" - /> -
- -
-
- setVideoSuccessWebhookUrl(e.currentTarget.value)} - placeholder="https://webhook.curl" - label="Webhook URL" - mb="xs" - /> -