Added search params to Home

This commit is contained in:
2025-03-19 14:26:44 -06:00
parent b5cb3e705c
commit c90ce83fd4
10 changed files with 479 additions and 183 deletions

233
package-lock.json generated
View File

@@ -19,6 +19,7 @@
"dompurify": "^3.2.3", "dompurify": "^3.2.3",
"localforage": "^1.10.0", "localforage": "^1.10.0",
"moment": "^2.30.1", "moment": "^2.30.1",
"qapp-core": "^1.0.8",
"quill": "^2.0.2", "quill": "^2.0.2",
"quill-image-resize-module-react": "^3.0.0", "quill-image-resize-module-react": "^3.0.0",
"react": "^19.0.0", "react": "^19.0.0",
@@ -1207,18 +1208,20 @@
} }
}, },
"node_modules/@mui/core-downloads-tracker": { "node_modules/@mui/core-downloads-tracker": {
"version": "6.3.0", "version": "6.4.7",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.3.0.tgz", "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.7.tgz",
"integrity": "sha512-/d8NwSuC3rMwCjswmGB3oXC4sdDuhIUJ8inVQAxGrADJhf0eq/kmy+foFKvpYhHl2siOZR+MLdFttw6/Bzqtqg==", "integrity": "sha512-XjJrKFNt9zAKvcnoIIBquXyFyhfrHYuttqMsoDS7lM7VwufYG4fAPw4kINjBFg++fqXM2BNAuWR9J7XVIuKIKg==",
"license": "MIT",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/mui-org" "url": "https://opencollective.com/mui-org"
} }
}, },
"node_modules/@mui/icons-material": { "node_modules/@mui/icons-material": {
"version": "6.3.0", "version": "6.4.7",
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.3.0.tgz", "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.4.7.tgz",
"integrity": "sha512-3uWws6DveDn5KxCS34p+sUNMxehuclQY6OmoJeJJ+Sfg9L7LGBpksY/nX5ywKAqickTZnn+sQyVcp963ep9jvw==", "integrity": "sha512-Rk8cs9ufQoLBw582Rdqq7fnSXXZTqhYRbpe1Y5SAz9lJKZP3CIdrj0PfG8HJLGw1hrsHFN/rkkm70IDzhJsG1g==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0" "@babel/runtime": "^7.26.0"
}, },
@@ -1230,7 +1233,7 @@
"url": "https://opencollective.com/mui-org" "url": "https://opencollective.com/mui-org"
}, },
"peerDependencies": { "peerDependencies": {
"@mui/material": "^6.3.0", "@mui/material": "^6.4.7",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0" "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
}, },
@@ -1285,15 +1288,16 @@
} }
}, },
"node_modules/@mui/material": { "node_modules/@mui/material": {
"version": "6.3.0", "version": "6.4.7",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-6.3.0.tgz", "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.7.tgz",
"integrity": "sha512-qhlTFyRMxfoVPxUtA5e8IvqxP0dWo2Ij7cvot7Orag+etUlZH+3UwD8gZGt+3irOoy7Ms3UNBflYjwEikUXtAQ==", "integrity": "sha512-K65StXUeGAtFJ4ikvHKtmDCO5Ab7g0FZUu2J5VpoKD+O6Y3CjLYzRi+TMlI3kaL4CL158+FccMoOd/eaddmeRQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@mui/core-downloads-tracker": "^6.3.0", "@mui/core-downloads-tracker": "^6.4.7",
"@mui/system": "^6.3.0", "@mui/system": "^6.4.7",
"@mui/types": "^7.2.20", "@mui/types": "^7.2.21",
"@mui/utils": "^6.3.0", "@mui/utils": "^6.4.6",
"@popperjs/core": "^2.11.8", "@popperjs/core": "^2.11.8",
"@types/react-transition-group": "^4.4.12", "@types/react-transition-group": "^4.4.12",
"clsx": "^2.1.1", "clsx": "^2.1.1",
@@ -1312,7 +1316,7 @@
"peerDependencies": { "peerDependencies": {
"@emotion/react": "^11.5.0", "@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0", "@emotion/styled": "^11.3.0",
"@mui/material-pigment-css": "^6.3.0", "@mui/material-pigment-css": "^6.4.7",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -1333,12 +1337,13 @@
} }
}, },
"node_modules/@mui/private-theming": { "node_modules/@mui/private-theming": {
"version": "6.3.0", "version": "6.4.6",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.3.0.tgz", "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.6.tgz",
"integrity": "sha512-tdS8jvqMokltNTXg6ioRCCbVdDmZUJZa/T9VtTnX2Lwww3FTgCakst9tWLZSxm1fEE9Xp0m7onZJmgeUmWQYVw==", "integrity": "sha512-T5FxdPzCELuOrhpA2g4Pi6241HAxRwZudzAuL9vBvniuB5YU82HCmrARw32AuCiyTfWzbrYGGpZ4zyeqqp9RvQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@mui/utils": "^6.3.0", "@mui/utils": "^6.4.6",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
}, },
"engines": { "engines": {
@@ -1359,9 +1364,10 @@
} }
}, },
"node_modules/@mui/styled-engine": { "node_modules/@mui/styled-engine": {
"version": "6.3.0", "version": "6.4.6",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.3.0.tgz", "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.6.tgz",
"integrity": "sha512-iWA6eyiPkO07AlHxRUvI7dwVRSc+84zV54kLmjUms67GJeOWVuXlu8ZO+UhCnwJxHacghxnabsMEqet5PYQmHg==", "integrity": "sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@emotion/cache": "^11.13.5", "@emotion/cache": "^11.13.5",
@@ -1392,15 +1398,16 @@
} }
}, },
"node_modules/@mui/system": { "node_modules/@mui/system": {
"version": "6.3.0", "version": "6.4.7",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-6.3.0.tgz", "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.7.tgz",
"integrity": "sha512-L+8hUHMNlfReKSqcnVslFrVhoNfz/jw7Fe9NfDE85R3KarvZ4O3MU9daF/lZeqEAvnYxEilkkTfDwQ7qCgJdFg==", "integrity": "sha512-7wwc4++Ak6tGIooEVA9AY7FhH2p9fvBMORT4vNLMAysH3Yus/9B9RYMbrn3ANgsOyvT3Z7nE+SP8/+3FimQmcg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@mui/private-theming": "^6.3.0", "@mui/private-theming": "^6.4.6",
"@mui/styled-engine": "^6.3.0", "@mui/styled-engine": "^6.4.6",
"@mui/types": "^7.2.20", "@mui/types": "^7.2.21",
"@mui/utils": "^6.3.0", "@mui/utils": "^6.4.6",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"csstype": "^3.1.3", "csstype": "^3.1.3",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
@@ -1431,9 +1438,10 @@
} }
}, },
"node_modules/@mui/types": { "node_modules/@mui/types": {
"version": "7.2.20", "version": "7.2.21",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.20.tgz", "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.21.tgz",
"integrity": "sha512-straFHD7L8v05l/N5vcWk+y7eL9JF0C2mtph/y4BPm3gn2Eh61dDwDB65pa8DLss3WJfDXYC7Kx5yjP0EmXpgw==", "integrity": "sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==",
"license": "MIT",
"peerDependencies": { "peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
}, },
@@ -1444,12 +1452,13 @@
} }
}, },
"node_modules/@mui/utils": { "node_modules/@mui/utils": {
"version": "6.3.0", "version": "6.4.6",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.3.0.tgz", "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.6.tgz",
"integrity": "sha512-MkDBF08OPVwXhAjedyMykRojgvmf0y/jxkBWjystpfI/pasyTYrfdv4jic6s7j3y2+a+SJzS9qrD6X8ZYj/8AQ==", "integrity": "sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@mui/types": "^7.2.20", "@mui/types": "^7.2.21",
"@types/prop-types": "^15.7.14", "@types/prop-types": "^15.7.14",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
@@ -1811,6 +1820,33 @@
"win32" "win32"
] ]
}, },
"node_modules/@tanstack/react-virtual": {
"version": "3.13.3",
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.3.tgz",
"integrity": "sha512-khJmiDJCkklsDTvXxTZHfEa7H161e94eDKxKyXqg9/3LstIbRg4JWBxPD2/e3LKtklC5dxkoYzNllCMVR904FA==",
"license": "MIT",
"dependencies": {
"@tanstack/virtual-core": "3.13.3"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@tanstack/virtual-core": {
"version": "3.13.3",
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.3.tgz",
"integrity": "sha512-9kfCeSG6zUx1I1iF4RKZrquNog3Eho1T6+LyJEDYpHjNNdDlRhXyqzTod5u6LCEBSeG0f2txkNjAq0tFbCJ4bA==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@types/babel__core": { "node_modules/@types/babel__core": {
"version": "7.20.5", "version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1880,9 +1916,10 @@
"integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==" "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "19.0.2", "version": "19.0.11",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.11.tgz",
"integrity": "sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg==", "integrity": "sha512-vrdxRZfo9ALXth6yPfV16PYTLZwsUWhVjjC+DkfE5t1suNSbBrWC9YqSuuxJZ8Ps6z1o2ycRpIqzZJIgklq4Tw==",
"license": "MIT",
"dependencies": { "dependencies": {
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
@@ -2204,6 +2241,26 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true "dev": true
}, },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/blueimp-canvas-to-blob": { "node_modules/blueimp-canvas-to-blob": {
"version": "3.29.0", "version": "3.29.0",
"resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz", "resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz",
@@ -2262,6 +2319,30 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
} }
}, },
"node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/call-bind": { "node_modules/call-bind": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
@@ -3184,6 +3265,26 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
}, },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -3834,6 +3935,25 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/qapp-core": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/qapp-core/-/qapp-core-1.0.8.tgz",
"integrity": "sha512-b9DlZ7bg+aTpFPVaTopViIS6YgEr8P8w8psXYlSsYojrU/rShfOo+QlrUwrY2dIWmEhNIsjGl8q4GHzUltRZ6w==",
"license": "MIT",
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/icons-material": "^6.4.7",
"@mui/material": "^6.4.7",
"@tanstack/react-virtual": "^3.13.2",
"@types/react": "^19.0.10",
"buffer": "^6.0.3",
"react": "^19.0.0",
"react-intersection-observer": "^9.16.0",
"short-unique-id": "^5.2.0",
"zustand": "^4.3.2"
}
},
"node_modules/queue-microtask": { "node_modules/queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -4013,9 +4133,10 @@
} }
}, },
"node_modules/react-intersection-observer": { "node_modules/react-intersection-observer": {
"version": "9.14.0", "version": "9.16.0",
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.14.0.tgz", "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz",
"integrity": "sha512-AYqlmDZn85VUmlODwYym9y5OlqY2cFyIu41dkN0GJWvhdbd19Mh16mz5IH6fO1gp5V4FfQOO4m0zGc04Tj13rQ==", "integrity": "sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==",
"license": "MIT",
"peerDependencies": { "peerDependencies": {
"react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -4683,6 +4804,34 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
},
"node_modules/zustand": {
"version": "4.5.6",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.6.tgz",
"integrity": "sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ==",
"license": "MIT",
"dependencies": {
"use-sync-external-store": "^1.2.2"
},
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"@types/react": ">=16.8",
"immer": ">=9.0.6",
"react": ">=16.8"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"immer": {
"optional": true
},
"react": {
"optional": true
}
}
} }
} }
} }

View File

@@ -21,6 +21,7 @@
"dompurify": "^3.2.3", "dompurify": "^3.2.3",
"localforage": "^1.10.0", "localforage": "^1.10.0",
"moment": "^2.30.1", "moment": "^2.30.1",
"qapp-core": "^1.0.8",
"quill": "^2.0.2", "quill": "^2.0.2",
"quill-image-resize-module-react": "^3.0.0", "quill-image-resize-module-react": "^3.0.0",
"react": "^19.0.0", "react": "^19.0.0",

View File

@@ -7,6 +7,7 @@ import { persistStore } from "redux-persist";
import { PersistGate } from "redux-persist/integration/react"; import { PersistGate } from "redux-persist/integration/react";
import { subscriptionListFilter } from "./App-Functions.ts"; import { subscriptionListFilter } from "./App-Functions.ts";
import Notification from "./components/common/Notification/Notification"; import Notification from "./components/common/Notification/Notification";
import { appName } from "./constants/Misc.ts";
import { useIframe } from "./hooks/useIframe.tsx"; import { useIframe } from "./hooks/useIframe.tsx";
import { IndividualProfile } from "./pages/ContentPages/IndividualProfile/IndividualProfile"; import { IndividualProfile } from "./pages/ContentPages/IndividualProfile/IndividualProfile";
import { PlaylistContent } from "./pages/ContentPages/PlaylistContent/PlaylistContent"; import { PlaylistContent } from "./pages/ContentPages/PlaylistContent/PlaylistContent";
@@ -35,7 +36,12 @@ function App() {
return ( return (
<Provider store={store}> <Provider store={store}>
<PersistGate loading={null} persistor={persistor}> <PersistGate loading={null} persistor={persistor}>
<GlobalProvider> <GlobalProvider
config={{
appName,
publicSalt: "usVbeM9YpjGCbLrTcc78YJS0ap1AxDkHAOMZrp3+wDY=",
}}
>
<ThemeProvider theme={theme === "light" ? lightTheme : darkTheme}> <ThemeProvider theme={theme === "light" ? lightTheme : darkTheme}>
<Notification /> <Notification />
<DownloadWrapper> <DownloadWrapper>

View File

@@ -53,6 +53,7 @@ import {
NewCrowdfundTitle, NewCrowdfundTitle,
TimesIcon, TimesIcon,
} from "./EditVideo-styles.tsx"; } from "./EditVideo-styles.tsx";
import { useGlobal } from "qapp-core";
const uid = new ShortUniqueId(); const uid = new ShortUniqueId();
const shortuid = new ShortUniqueId({ length: 5 }); const shortuid = new ShortUniqueId({ length: 5 });
@@ -60,6 +61,7 @@ const shortuid = new ShortUniqueId({ length: 5 });
export const EditVideo = () => { export const EditVideo = () => {
const theme = useTheme(); const theme = useTheme();
const dispatch = useDispatch(); const dispatch = useDispatch();
const resource = useGlobal();
const username = useSelector((state: RootState) => state.auth?.user?.name); const username = useSelector((state: RootState) => state.auth?.user?.name);
const userAddress = useSelector( const userAddress = useSelector(
(state: RootState) => state.auth?.user?.address (state: RootState) => state.auth?.user?.address

View File

@@ -1,5 +1,6 @@
import { useTestIdentifiers } from "./Identifiers.ts"; import { useTestIdentifiers } from "./Identifiers.ts";
export const appName = "Q-Tube";
export const minPriceSuperLike = 1; export const minPriceSuperLike = 1;
export const minPriceSuperDislike = 1; export const minPriceSuperDislike = 1;

View File

@@ -34,9 +34,8 @@ export const VideoCardContainer = styled("div")(({ theme }) => ({
export const VideoCardCol = styled("div")({ export const VideoCardCol = styled("div")({
position: "relative", position: "relative",
minWidth: "200px", // Minimum width of each item width: "100%", // Minimum width of each item
maxWidth: "300px", // Maximum width, allowing the item to fill the column maxWidth: "300px", // Maximum width, allowing the item to fill the column
// ... other styles
}); });
export const VideoCard = styled(Grid)(({ theme }) => ({ export const VideoCard = styled(Grid)(({ theme }) => ({

View File

@@ -1,7 +1,15 @@
import BlockIcon from "@mui/icons-material/Block"; import BlockIcon from "@mui/icons-material/Block";
import EditIcon from "@mui/icons-material/Edit"; import EditIcon from "@mui/icons-material/Edit";
import { Avatar, Box, Tooltip, Typography, useTheme } from "@mui/material"; import DeleteIcon from "@mui/icons-material/Delete";
import React, { useState } from "react"; import {
Avatar,
Box,
Skeleton,
Tooltip,
Typography,
useTheme,
} from "@mui/material";
import React, { useCallback, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { PlaylistSVG } from "../../../assets/svgs/PlaylistSVG.tsx"; import { PlaylistSVG } from "../../../assets/svgs/PlaylistSVG.tsx";
@@ -29,20 +37,18 @@ import {
VideoCardTitle, VideoCardTitle,
VideoUploadDate, VideoUploadDate,
} from "./VideoList-styles.tsx"; } from "./VideoList-styles.tsx";
import { ResourceListDisplay } from "qapp-core"; import { ResourceListDisplay, useGlobal } from "qapp-core";
interface VideoListProps { interface VideoListProps {
listName: string; listName: string;
searchParameters: any;
} }
export const VideoList = ({ listName }: VideoListProps) => { export const VideoList = ({ listName, searchParameters }: VideoListProps) => {
const [showIcons, setShowIcons] = useState(null); const [showIcons, setShowIcons] = useState(null);
const hashMapVideos = useSelector(
(state: RootState) => state.video.hashMapVideos
);
const username = useSelector((state: RootState) => state.auth?.user?.name); const username = useSelector((state: RootState) => state.auth?.user?.name);
const { resources } = useGlobal();
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useDispatch(); const dispatch = useDispatch();
const theme = useTheme(); const theme = useTheme();
@@ -65,135 +71,197 @@ export const VideoList = ({ listName }: VideoListProps) => {
} }
}; };
const listItem = useCallback(
(item, index) => {
const { qortalMetadata, data: video } = item;
return (
<VideoCardCol
key={qortalMetadata?.identifier}
onMouseEnter={() => setShowIcons(qortalMetadata?.identifier)}
onMouseLeave={() => setShowIcons(null)}
>
<IconsBox
sx={{
opacity: showIcons === qortalMetadata.identifier ? 1 : 0,
zIndex: 2,
}}
>
{qortalMetadata?.name === username && (
<Tooltip title="Edit video properties" placement="top">
<BlockIconContainer>
<EditIcon
onClick={() => {
dispatch(setEditVideo(item));
}}
/>
</BlockIconContainer>
</Tooltip>
)}
{qortalMetadata?.name !== username && (
<Tooltip title="Block user content" placement="top">
<BlockIconContainer>
<BlockIcon
onClick={() => {
blockUserFunc(qortalMetadata?.name);
}}
/>
</BlockIconContainer>
</Tooltip>
)}
{qortalMetadata?.name === username && (
<Tooltip title="Delete video" placement="top">
<BlockIconContainer>
<DeleteIcon
onClick={() => {
resources.deleteProduct([
qortalMetadata,
video.videoReference,
]);
}}
/>
</BlockIconContainer>
</Tooltip>
)}
</IconsBox>
<VideoCard
onClick={() => {
navigate(
`/video/${qortalMetadata?.name}/${qortalMetadata?.identifier}`
);
}}
>
{video?.duration > minDuration && (
<Box
position="absolute"
right={0}
bottom={0}
bgcolor="#202020"
zIndex={999}
>
<Typography color="white">
{formatTime(video.duration)}
</Typography>
</Box>
)}
<VideoCardImageContainer
width={266}
height={150}
videoImage={video.videoImage}
frameImages={video?.extracts || []}
/>
<Tooltip
title={video.title}
placement="top"
slotProps={{ tooltip: { sx: { fontSize: fontSizeSmall } } }}
>
<VideoCardTitle>{video.title}</VideoCardTitle>
</Tooltip>
<BottomParent>
<NameContainer
onClick={e => {
e.stopPropagation();
navigate(`/channel/${qortalMetadata?.name}`);
}}
>
<Avatar
sx={{ height: 24, width: 24 }}
src={`/arbitrary/THUMBNAIL/${qortalMetadata?.name}/qortal_avatar`}
alt={`${qortalMetadata?.name}'s avatar`}
/>
<VideoCardName
sx={{
":hover": {
textDecoration: "underline",
},
}}
>
{qortalMetadata?.name}
</VideoCardName>
</NameContainer>
{qortalMetadata?.created && (
<Box sx={{ flexDirection: "row", width: "100%" }}>
<VideoUploadDate sx={{ display: "inline" }}>
{formatDate(qortalMetadata.created)}
</VideoUploadDate>
</Box>
)}
</BottomParent>
</VideoCard>
</VideoCardCol>
);
},
[username, showIcons]
);
const skeletonVideoCard = (
<VideoCard>
<Skeleton
variant="rectangular"
style={{
width: 187,
height: 130,
borderRadius: "8px",
marginTop: 10,
alignSelf: "center",
}}
/>
<BottomParent>
<NameContainer>
<Skeleton
variant="rectangular"
style={{
width: 200,
height: 50,
marginTop: 12,
alignSelf: "center",
}}
/>
</NameContainer>
<Skeleton
variant="rectangular"
style={{
width: 200,
height: 24,
marginTop: 15,
alignSelf: "center",
}}
/>
<Skeleton
variant="rectangular"
style={{
width: 200,
height: 24,
marginTop: 15,
alignSelf: "center",
}}
/>
</BottomParent>
</VideoCard>
);
return ( return (
<VideoCardContainer> <VideoCardContainer>
<ResourceListDisplay <ResourceListDisplay
styles={{ styles={{
gap: 20, gap: 20,
horizontalStyles: {
minItemWidth: 200,
},
}} }}
retryAttempts={3}
listName={listName} listName={listName}
direction="HORIZONTAL" direction="HORIZONTAL"
disableVirtualization disableVirtualization
params={{ disablePagination
identifier: "qtube_vid_", search={searchParameters}
service: "DOCUMENT",
offset: 0,
reverse: true,
limit: 20,
}}
loaderItem={status => { loaderItem={status => {
return <div>{status === "LOADING" ? "is Loading" : "has error"}</div>;
}}
listItem={(item, index) => {
const { qortalMetadata, data: video } = item;
const fullId = video
? `${qortalMetadata.identifier}-${qortalMetadata.name}`
: undefined;
return ( return (
<VideoCardCol //<div>{status === "LOADING" ? skeletonVideoCard : "has error"}</div>
key={qortalMetadata?.identifier} skeletonVideoCard
onMouseEnter={() => setShowIcons(qortalMetadata?.identifier)}
onMouseLeave={() => setShowIcons(null)}
>
<IconsBox
sx={{
opacity: showIcons === qortalMetadata.identifier ? 1 : 0,
zIndex: 2,
}}
>
{qortalMetadata?.name === username && (
<Tooltip title="Edit video properties" placement="top">
<BlockIconContainer>
<EditIcon
onClick={() => {
dispatch(setEditVideo(item));
}}
/>
</BlockIconContainer>
</Tooltip>
)}
{qortalMetadata?.name !== username && (
<Tooltip title="Block user content" placement="top">
<BlockIconContainer>
<BlockIcon
onClick={() => {
blockUserFunc(qortalMetadata?.name);
}}
/>
</BlockIconContainer>
</Tooltip>
)}
</IconsBox>
<VideoCard
onClick={() => {
navigate(
`/video/${qortalMetadata?.name}/${qortalMetadata?.identifier}`
);
}}
>
{video?.duration > minDuration && (
<Box
position="absolute"
right={0}
bottom={0}
bgcolor="#202020"
zIndex={999}
>
<Typography color="white">
{formatTime(video.duration)}
</Typography>
</Box>
)}
<VideoCardImageContainer
width={266}
height={150}
videoImage={video.videoImage}
frameImages={video?.extracts || []}
/>
<Tooltip
title={video.title}
placement="top"
slotProps={{ tooltip: { sx: { fontSize: fontSizeSmall } } }}
>
<VideoCardTitle>{video.title}</VideoCardTitle>
</Tooltip>
<BottomParent>
<NameContainer
onClick={e => {
e.stopPropagation();
navigate(`/channel/${qortalMetadata?.name}`);
}}
>
<Avatar
sx={{ height: 24, width: 24 }}
src={`/arbitrary/THUMBNAIL/${qortalMetadata?.name}/qortal_avatar`}
alt={`${qortalMetadata?.name}'s avatar`}
/>
<VideoCardName
sx={{
":hover": {
textDecoration: "underline",
},
}}
>
{qortalMetadata?.name}
</VideoCardName>
</NameContainer>
{qortalMetadata?.created && (
<Box sx={{ flexDirection: "row", width: "100%" }}>
<VideoUploadDate sx={{ display: "inline" }}>
{formatDate(qortalMetadata.created)}
</VideoUploadDate>
</Box>
)}
</BottomParent>
</VideoCard>
</VideoCardCol>
); );
}} }}
listItem={listItem}
/> />
</VideoCardContainer> </VideoCardContainer>
); );

View File

@@ -106,7 +106,17 @@ export const VideoListComponentLevel = ({ mode }: VideoListProps) => {
alignItems: "center", alignItems: "center",
}} }}
> >
<VideoList videos={videos} /> <VideoList
listName={"ChannelVideos"}
searchParameters={{
identifier: QTUBE_VIDEO_BASE,
name: paramName,
service: "DOCUMENT",
offset: 0,
reverse: true,
limit: 20,
}}
/>
<LazyLoad onLoadMore={getVideos} isLoading={isLoading.value}></LazyLoad> <LazyLoad onLoadMore={getVideos} isLoading={isLoading.value}></LazyLoad>
</Box> </Box>
</VideoManagerRow> </VideoManagerRow>

View File

@@ -135,7 +135,13 @@ export const useHomeState = (mode: string) => {
changeTab, changeTab,
videos, videos,
isLoading, isLoading,
filteredSubscriptionList,
getVideosHandler, getVideosHandler,
filterName,
filterSearch,
filterValue,
filterType,
selectedCategoryVideos,
selectedSubCategoryVideos,
filteredSubscriptionList,
}; };
}; };

View File

@@ -1,13 +1,20 @@
import { TabContext, TabList, TabPanel } from "@mui/lab"; import { TabContext, TabList, TabPanel } from "@mui/lab";
import { Box, Tab, useMediaQuery } from "@mui/material"; import { Box, Tab, useMediaQuery } from "@mui/material";
import React from "react"; import React, { useState } from "react";
import LazyLoad from "../../components/common/LazyLoad"; import LazyLoad from "../../components/common/LazyLoad";
import { ListSuperLikeContainer } from "../../components/common/ListSuperLikes/ListSuperLikeContainer.tsx"; import { ListSuperLikeContainer } from "../../components/common/ListSuperLikes/ListSuperLikeContainer.tsx";
import {
QTUBE_PLAYLIST_BASE,
QTUBE_VIDEO_BASE,
useTestIdentifiers,
} from "../../constants/Identifiers.ts";
import { fontSizeLarge, fontSizeSmall } from "../../constants/Misc.ts"; import { fontSizeLarge, fontSizeSmall } from "../../constants/Misc.ts";
import { RootState } from "../../state/store.ts";
import { SearchSidebar } from "./Components/SearchSidebar.tsx"; import { SearchSidebar } from "./Components/SearchSidebar.tsx";
import VideoList from "./Components/VideoList.tsx"; import VideoList from "./Components/VideoList.tsx";
import { useHomeState } from "./Home-State.ts"; import { useHomeState } from "./Home-State.ts";
import { useSelector } from "react-redux";
interface HomeProps { interface HomeProps {
mode?: string; mode?: string;
@@ -18,6 +25,12 @@ export const Home = ({ mode }: HomeProps) => {
changeTab, changeTab,
videos, videos,
isLoading, isLoading,
filterName,
filterSearch,
filterValue,
filterType,
selectedCategoryVideos,
selectedSubCategoryVideos,
filteredSubscriptionList, filteredSubscriptionList,
getVideosHandler, getVideosHandler,
} = useHomeState(mode); } = useHomeState(mode);
@@ -46,10 +59,45 @@ export const Home = ({ mode }: HomeProps) => {
else if (!isScreenSmall) homeColumns = mediumGridSX; else if (!isScreenSmall) homeColumns = mediumGridSX;
else homeColumns = smallGridSX; else homeColumns = smallGridSX;
let description: string = undefined;
if (selectedCategoryVideos) {
description = `category:${selectedCategoryVideos}`;
if (selectedSubCategoryVideos)
description += `;subcategory:${selectedSubCategoryVideos}`;
}
const initialSearchParams = {
identifier:
filterType === "playlists" ? QTUBE_PLAYLIST_BASE : QTUBE_VIDEO_BASE,
service: filterType === "playlists" ? "PLAYLIST" : "DOCUMENT",
offset: 0,
reverse: true,
limit: 20,
excludeBlocked: true,
};
const [searchParametersBase, setSearchParametersBase] =
useState<any>(initialSearchParams);
return ( return (
<> <>
<Box sx={{ ...homeBaseSX, ...homeColumns }}> <Box sx={{ ...homeBaseSX, ...homeColumns }}>
<SearchSidebar onSearch={getVideosHandler} /> <SearchSidebar
onSearch={() =>
setSearchParametersBase({
...initialSearchParams,
identifier:
filterType === "playlists"
? QTUBE_PLAYLIST_BASE
: QTUBE_VIDEO_BASE,
service: filterType === "playlists" ? "PLAYLIST" : "DOCUMENT",
description,
query: filterSearch,
offset: 0,
reverse: true,
limit: 20,
})
}
/>
<Box <Box
sx={{ sx={{
width: "100%", width: "100%",
@@ -69,20 +117,26 @@ export const Home = ({ mode }: HomeProps) => {
<Tab label="Subscriptions" value={"subscriptions"} sx={tabSX} /> <Tab label="Subscriptions" value={"subscriptions"} sx={tabSX} />
</TabList> </TabList>
<TabPanel value={"all"} sx={tabPaneSX}> <TabPanel value={"all"} sx={tabPaneSX}>
<VideoList listName={"AllVideos"} /> <VideoList
{/*<LazyLoad*/} listName={"AllVideos"}
{/* onLoadMore={getVideosHandler}*/} searchParameters={{
{/* isLoading={isLoading}*/} ...searchParametersBase,
{/*></LazyLoad>*/} name: filterName,
}}
/>
</TabPanel> </TabPanel>
<TabPanel value={"subscriptions"} sx={tabPaneSX}> <TabPanel value={"subscriptions"} sx={tabPaneSX}>
{filteredSubscriptionList.length > 0 ? ( {filteredSubscriptionList.length > 0 ? (
<> <>
<VideoList listName={"SubscribedVideos"} /> <VideoList
{/*<LazyLoad*/} listName={"SubscribedVideos"}
{/* onLoadMore={getVideosHandler}*/} searchParameters={{
{/* isLoading={isLoading}*/} ...searchParametersBase,
{/*></LazyLoad>*/} names:
filterName ||
filteredSubscriptionList.map(s => s.subscriberName),
}}
/>
</> </>
) : ( ) : (
!isLoading && ( !isLoading && (