diff --git a/package-lock.json b/package-lock.json index 0ab63e1b..375826c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3604,6 +3604,16 @@ "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", "dev": true }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3619,6 +3629,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -4027,6 +4047,12 @@ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==", + "dev": true + }, "css-declaration-sorter": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", @@ -4141,6 +4167,12 @@ } } }, + "css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==", + "dev": true + }, "css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -7026,6 +7058,12 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, "hey-listen": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", @@ -7060,6 +7098,18 @@ "wbuf": "^1.1.0" } }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A==", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA==", + "dev": true + }, "html-encoding-sniffer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", @@ -7104,6 +7154,12 @@ } } }, + "html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", + "dev": true + }, "html-webpack-plugin": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", @@ -7457,6 +7513,20 @@ "ci-info": "^3.2.0" } }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==", + "dev": true, + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, "is-core-module": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", @@ -8842,6 +8912,12 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.topath": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz", + "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==", + "dev": true + }, "lodash.union": { "version": "4.6.0", "resolved": "https://npm.zone51.tf/lodash.union/-/lodash.union-4.6.0.tgz", @@ -9282,6 +9358,12 @@ "minimist": "^1.2.6" } }, + "modern-normalize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz", + "integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==", + "dev": true + }, "mrmime": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", @@ -9361,6 +9443,15 @@ "semver": "^7.3.5" } }, + "node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, "node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -10449,6 +10540,12 @@ } } }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -10538,6 +10635,100 @@ } } }, + "ps-scrollbar-tailwind": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ps-scrollbar-tailwind/-/ps-scrollbar-tailwind-0.0.1.tgz", + "integrity": "sha512-IPAAIXn0gNx4AzwHA9YY2+jZm18WTOzR+Xk+M3HfyEWWqRrGhBzQFUkgpQNe6mI2Bch1P4Bl62wh8rlR2W75jw==", + "dev": true, + "requires": { + "tailwindcss": "^2.0.2" + }, + "dependencies": { + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "dev": true + }, + "postcss-js": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz", + "integrity": "sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==", + "dev": true, + "requires": { + "camelcase-css": "^2.0.1", + "postcss": "^8.1.6" + } + }, + "tailwindcss": { + "version": "2.2.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.2.19.tgz", + "integrity": "sha512-6Ui7JSVtXadtTUo2NtkBBacobzWiQYVjYW0ZnKaP9S1ZCKQ0w7KVNz+YSDI/j7O7KCMHbOkz94ZMQhbT9pOqjw==", + "dev": true, + "requires": { + "arg": "^5.0.1", + "bytes": "^3.0.0", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "color": "^4.0.1", + "cosmiconfig": "^7.0.1", + "detective": "^5.2.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.7", + "fs-extra": "^10.0.0", + "glob-parent": "^6.0.1", + "html-tags": "^3.1.0", + "is-color-stop": "^1.1.0", + "is-glob": "^4.0.1", + "lodash": "^4.17.21", + "lodash.topath": "^4.5.2", + "modern-normalize": "^1.1.0", + "node-emoji": "^1.11.0", + "normalize-path": "^3.0.0", + "object-hash": "^2.2.0", + "postcss-js": "^3.0.3", + "postcss-load-config": "^3.1.0", + "postcss-nested": "5.0.6", + "postcss-selector-parser": "^6.0.6", + "postcss-value-parser": "^4.1.0", + "pretty-hrtime": "^1.0.3", + "purgecss": "^4.0.3", + "quick-lru": "^5.1.1", + "reduce-css-calc": "^2.1.8", + "resolve": "^1.20.0", + "tmp": "^0.2.1" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -10577,6 +10768,26 @@ "escape-goat": "^2.0.0" } }, + "purgecss": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.1.3.tgz", + "integrity": "sha512-99cKy4s+VZoXnPxaoM23e5ABcP851nC2y2GROkkjS8eJaJtlciGavd7iYAw2V84WeBqggZ12l8ef44G99HmTaw==", + "dev": true, + "requires": { + "commander": "^8.0.0", + "glob": "^7.1.7", + "postcss": "^8.3.5", + "postcss-selector-parser": "^6.0.6" + }, + "dependencies": { + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + } + } + }, "qs": { "version": "6.10.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", @@ -10896,6 +11107,24 @@ "strip-indent": "^3.0.0" } }, + "reduce-css-calc": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", + "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", + "dev": true, + "requires": { + "css-unit-converter": "^1.1.1", + "postcss-value-parser": "^3.3.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, "reflect.ownkeys": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz", @@ -11074,6 +11303,18 @@ "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", "dev": true }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w==", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -11466,6 +11707,23 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + } + } + }, "sirv": { "version": "1.0.19", "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", diff --git a/package.json b/package.json index 63037887..a9fc4c5b 100644 --- a/package.json +++ b/package.json @@ -200,6 +200,7 @@ "postcss": "^8.4.16", "postcss-loader": "^6.2.1", "prettier": "^2.7.1", + "ps-scrollbar-tailwind": "0.0.1", "react-refresh": "^0.12.0", "react-refresh-typescript": "^2.0.7", "react-test-renderer": "^18.2.0", diff --git a/src/main/services/maps/local-maps-manager.service.ts b/src/main/services/maps/local-maps-manager.service.ts index f50531cc..5aa5dd6e 100644 --- a/src/main/services/maps/local-maps-manager.service.ts +++ b/src/main/services/maps/local-maps-manager.service.ts @@ -18,7 +18,6 @@ export class LocalMapsManagerService { private readonly LEVELS_ROOT_FOLDER = "Beat Saber_Data"; private readonly CUSTOM_LEVELS_FOLDER = "CustomLevels"; - private readonly WIP_LEVELS_FOLDER = "CustomWIPLevels"; private readonly localVersion: BSLocalVersionService; private readonly installLocation: InstallationLocationService; diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 452f248b..4e3bb3f5 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -19,14 +19,17 @@ export default function App() { const location = useLocation(); - pageState.setLocation(location); - useEffect(() => { themeService.theme$.subscribe(() => { if(themeService.isDark || (themeService.isOS && window.matchMedia('(prefers-color-scheme: dark)').matches)){ return document.documentElement.classList.add('dark'); } document.documentElement.classList.remove('dark'); }); }, []); + + + useEffect(() => { + pageState.setLocation(location); + }, [location]) return ( diff --git a/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx b/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx new file mode 100644 index 00000000..e48061df --- /dev/null +++ b/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx @@ -0,0 +1,68 @@ +import { MapsManagerService } from "renderer/services/maps-manager.service" +import { BSVersion } from "shared/bs-version.interface" +import VisibilitySensor from "react-visibility-sensor" +import { useEffect, useState } from "react" +import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface" +import { Subscription } from "rxjs" +import { MapItem, MapItemProps } from "./map-item.component" +import { BsvMapCharacteristic, BsvMapDifficultyType } from "shared/models/maps/beat-saver.model" + +type Props = { + version: BSVersion, + className?: string +} + +export function LocalMapsListPanel({version, className} : Props) { + + const mapsManager = MapsManagerService.getInstance(); + + const [isVisible, setIsVisible] = useState(false); + const [maps, setMaps] = useState([] as BsmLocalMap[]); + + useEffect(() => { + + const subs: Subscription[] = []; + + if(isVisible && !maps?.length){ + subs.push(mapsManager.getMaps(version).subscribe(localMaps => setMaps(() => localMaps))); + } + + return () => { subs.forEach(s => s.unsubscribe()); } + }, [isVisible]) + + const extractMapDiffs = (map: BsmLocalMap): Map => { + const res = new Map(); + map.rawInfo._difficultyBeatmapSets.forEach(set => { + set._difficultyBeatmaps.forEach(diff => { + const arr = res.get(set._beatmapCharacteristicName) || []; + arr.push(diff._difficulty); + res.set(set._beatmapCharacteristicName, arr); + }) + }) + return res; + } + + const renderMapItem = (map: BsmLocalMap) => { + + return ; + + } + + return ( + +
    + {maps.map(map => renderMapItem(map))} +
+
+ ) +} diff --git a/src/renderer/components/maps-mangement-components/map-item.component.tsx b/src/renderer/components/maps-mangement-components/map-item.component.tsx new file mode 100644 index 00000000..3c10ee7d --- /dev/null +++ b/src/renderer/components/maps-mangement-components/map-item.component.tsx @@ -0,0 +1,84 @@ +import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface" +import { BsmImage } from "../shared/bsm-image.component"; +import { BsvMapCharacteristic, BsvMapDifficultyType } from "shared/models/maps/beat-saver.model" +import { useThemeColor } from "renderer/hooks/use-theme-color.hook"; +import { LinkOpenerService } from "renderer/services/link-opener.service"; +import { BsmLink } from "../shared/bsm-link.component"; +import { BsmIcon } from "../svgs/bsm-icon.component"; +import { BsmButton } from "../shared/bsm-button.component"; + +export type MapItemProps = { + hash: string, + title: string, + autor: string, + coverUrl: string, + songUrl: string, + autorLink: string, + mapId: string, + diffs: Map, + qualified: boolean, + ranked: boolean, + bpm: number, + duration: number, + onDelete?: (hash: string) => void, + onDownload?: (id: string) => void, +} + +export function MapItem({hash, title, autor, coverUrl, songUrl, autorLink, mapId, diffs, qualified, ranked, onDelete, onDownload}: MapItemProps) { + + const color = useThemeColor("first-color"); + + const zipUrl = `https://r2cdn.beatsaver.com/${hash}.zip` + const previewUrl = `https://skystudioapps.com/bs-viewer/?url=${zipUrl}` + + console.log(diffs) + + const renderAutor = () => { + if(!autor){ null; } + if(autorLink){ + return {autor} + } + return {autor} + } + + const renderDiff = (charac: BsvMapCharacteristic, diff: BsvMapDifficultyType) => { + + const colorPill = diffColors[diff] ?? ""; + + return ( +
  • + + {diff === "ExpertPlus" ? "Expert+" : diff} +
  • + ) + } + + return ( +
  • + +
    +

    {title}

    + {renderAutor()} +
      + {Array.from(diffs.entries()).map(([charac, diffs]) => diffs.map(diff => renderDiff(charac, diff)))} +
    +
    +
    + + + + + + +
    +
  • + ) +} + +const diffColors: Record = { + Easy: "#008055", + Normal: "#1268a1", + Hard: "#bd5500", + Expert: "#b52a1c", + ExpertPlus: "#7646af" +} diff --git a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx index 4b0e3047..7d099a69 100644 --- a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx +++ b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx @@ -1,8 +1,7 @@ import { useState } from "react" -import { useObservable } from "renderer/hooks/use-observable.hook" -import { MapsManagerService } from "renderer/services/maps-manager.service" import { BSVersion } from "shared/bs-version.interface" import { TabNavBar } from "../shared/tab-nav-bar.component" +import { LocalMapsListPanel } from "./local-maps-list-panel.component" type Props = { oneBlock?: boolean, @@ -10,24 +9,17 @@ type Props = { } export function MapsPlaylistsPanel({version, oneBlock = false}: Props) { - - const mapsManager = MapsManagerService.getInstance(); const [tabIndex, setTabIndex] = useState(0); - const maps = useObservable(mapsManager.getMaps(version)); - - console.log(maps); return ( <> {!oneBlock && } -
    +
    {oneBlock && }
    -
    - a -
    -
    b
    + +
    b
    diff --git a/src/renderer/components/modal/modal-types/iframe-modal.component.tsx b/src/renderer/components/modal/modal-types/iframe-modal.component.tsx new file mode 100644 index 00000000..a6cc6c24 --- /dev/null +++ b/src/renderer/components/modal/modal-types/iframe-modal.component.tsx @@ -0,0 +1,9 @@ +import { ModalComponent } from "renderer/services/modale.service" + +export const IframeModal: ModalComponent = ({resolver, data}) => { + return ( +
    + +
    + ) +} diff --git a/src/renderer/components/shared/bsm-button.component.tsx b/src/renderer/components/shared/bsm-button.component.tsx index 82eb20cb..29de51a4 100644 --- a/src/renderer/components/shared/bsm-button.component.tsx +++ b/src/renderer/components/shared/bsm-button.component.tsx @@ -25,9 +25,10 @@ type propsType = { typeColor?:BsmButtonType, color?: string, title?: string, + iconColor?: string, } -export function BsmButton({className, style, imgClassName, iconClassName, icon, image, text, type, active, withBar = true, disabled, onClickOutside, onClick, typeColor, color, title}: propsType) { +export function BsmButton({className, style, imgClassName, iconClassName, icon, image, text, type, active, withBar = true, disabled, onClickOutside, onClick, typeColor, color, title, iconColor}: propsType) { const t = useTranslation(); const secondColor = useThemeColor("second-color"); @@ -52,7 +53,7 @@ export function BsmButton({className, style, imgClassName, iconClassName, icon, onClickOutside && onClickOutside(e)}>
    { image && } - { icon && } + { icon && } {text && (type === "submit" ? : {t(text)})} { withBar && (
    diff --git a/src/renderer/components/shared/bsm-link.component.tsx b/src/renderer/components/shared/bsm-link.component.tsx new file mode 100644 index 00000000..f91617ef --- /dev/null +++ b/src/renderer/components/shared/bsm-link.component.tsx @@ -0,0 +1,24 @@ +import { LinkOpenerService } from "renderer/services/link-opener.service" +import { ModalService } from "renderer/services/modale.service"; +import { IframeModal } from "../modal/modal-types/iframe-modal.component"; + +type Props = { + className?: string, + href?: string, + internal?: boolean + children?: React.ReactNode, + style?: React.CSSProperties +} + +export function BsmLink({className, href, children, style, internal}: Props) { + + const linkOpener = LinkOpenerService.getInstance(); + + const openLink = () => { + linkOpener.open(href, internal); + } + + return ( + {children} + ) +} diff --git a/src/renderer/components/svgs/bsm-icon.component.tsx b/src/renderer/components/svgs/bsm-icon.component.tsx index d8fce540..1a20e048 100644 --- a/src/renderer/components/svgs/bsm-icon.component.tsx +++ b/src/renderer/components/svgs/bsm-icon.component.tsx @@ -25,9 +25,12 @@ import { ThreeDotsIcon } from "./icons/three-dots-icon.component"; import { GitHubIcon } from "./icons/github-icon.component"; import { CloseIcon } from "./icons/close-icon.component"; import { BsMapDifficultyIcon } from "./icons/bs-map-difficulty-icon.component"; +import { TwitchIcon } from "./icons/twitch-icon.component"; +import EyeIcon from "./icons/eye-icon.component"; +import { PlayIcon } from "./icons/play-icon.component"; export type BsmIconType = ( - "settings"|"trash"|"favorite"|"folder"|"bsNote"|"check"|"three-dots"| + "settings"|"trash"|"favorite"|"folder"|"bsNote"|"check"|"three-dots"|"twitch"|"eye"|"play"| "terminal"|"desktop"|"oculus"|"add"|"cross"|"task"|"github"|"close"| "copy"|"steam"|"edit"|"export"|"patreon"|"search"|"bsMapDifficulty"| "fr-FR-flag"|"es-ES-flag"|"en-US-flag"|"en-EN-flag" @@ -62,6 +65,9 @@ export const BsmIcon = memo(({className, icon, style}: {className?: string, icon if(icon === "github"){ return } if(icon === "close"){ return } if(icon === "bsMapDifficulty"){ return } + if(icon === "twitch"){ return } + if(icon === "eye"){ return } + if(icon === "play"){ return } return } diff --git a/src/renderer/components/svgs/icons/eye-icon.component.tsx b/src/renderer/components/svgs/icons/eye-icon.component.tsx new file mode 100644 index 00000000..2490f82c --- /dev/null +++ b/src/renderer/components/svgs/icons/eye-icon.component.tsx @@ -0,0 +1,9 @@ +import { CSSProperties } from "react"; + +export default function EyeIcon(props: {className?: string, style?: CSSProperties}) { + return ( + + + + ) +} diff --git a/src/renderer/components/svgs/icons/play-icon.component.tsx b/src/renderer/components/svgs/icons/play-icon.component.tsx new file mode 100644 index 00000000..e82a6403 --- /dev/null +++ b/src/renderer/components/svgs/icons/play-icon.component.tsx @@ -0,0 +1,9 @@ +import { CSSProperties } from "react"; + +export function PlayIcon(props: {className?: string, style?: CSSProperties}) { + return ( + + + + ) +} diff --git a/src/renderer/components/svgs/icons/twitch-icon.component.tsx b/src/renderer/components/svgs/icons/twitch-icon.component.tsx new file mode 100644 index 00000000..862e346d --- /dev/null +++ b/src/renderer/components/svgs/icons/twitch-icon.component.tsx @@ -0,0 +1,9 @@ +import { CSSProperties } from "react"; + +export function TwitchIcon(props: {className?: string, style?: CSSProperties}) { + return ( + + + + ) +} diff --git a/src/renderer/services/link-opener.service.ts b/src/renderer/services/link-opener.service.ts index 5df418c1..98addf0f 100644 --- a/src/renderer/services/link-opener.service.ts +++ b/src/renderer/services/link-opener.service.ts @@ -1,10 +1,13 @@ +import { IframeModal } from "renderer/components/modal/modal-types/iframe-modal.component"; import { IpcService } from "./ipc.service"; +import { ModalService } from "./modale.service"; export class LinkOpenerService{ private static instance: LinkOpenerService; - private readonly ipcService: IpcService + private readonly ipcService: IpcService; + private readonly modals: ModalService; public static getInstance(): LinkOpenerService{ if(!LinkOpenerService.instance){ LinkOpenerService.instance = new LinkOpenerService(); } @@ -13,9 +16,14 @@ export class LinkOpenerService{ private constructor(){ this.ipcService = IpcService.getInstance(); + this.modals = ModalService.getInsance(); } - public open(url: string): void{ + public open(url: string, internal?: boolean): void{ + if(internal){ + this.modals.openModal(IframeModal, url); + return; + } this.ipcService.sendLazy("new-window", {args: url}); } diff --git a/src/renderer/services/maps-manager.service.ts b/src/renderer/services/maps-manager.service.ts index 0dcbe73f..f263ef95 100644 --- a/src/renderer/services/maps-manager.service.ts +++ b/src/renderer/services/maps-manager.service.ts @@ -19,6 +19,7 @@ export class MapsManagerService { } public getMaps(version?: BSVersion): Observable{ + console.log("get maps") return new Observable(obs => { this.ipcService.send("get-version-maps", {args: version}).then(res => { if(!res.success){ return obs.next(null);} diff --git a/src/renderer/services/page-state.service.ts b/src/renderer/services/page-state.service.ts index 1e26b15e..e9893256 100644 --- a/src/renderer/services/page-state.service.ts +++ b/src/renderer/services/page-state.service.ts @@ -24,7 +24,7 @@ export class PageStateService { } public getRoute(): string{ - return this.location$.value.pathname; + return this.location$.value?.pathname; } public get state$(): Observable{ @@ -32,7 +32,7 @@ export class PageStateService { } public get route$(): Observable{ - return this.location$.pipe(map(location => location.pathname)); + return this.location$.pipe(map(location => location?.pathname)); } } \ No newline at end of file diff --git a/src/shared/models/maps/beat-saver.model.ts b/src/shared/models/maps/beat-saver.model.ts index f6f2f665..dd9bb4fe 100644 --- a/src/shared/models/maps/beat-saver.model.ts +++ b/src/shared/models/maps/beat-saver.model.ts @@ -115,10 +115,10 @@ export interface BsvMapTestplay { export interface BsvMapDifficulty { bombs: number, - characteristic: string, + characteristic: BsvMapCharacteristic, chroma: boolean, cinema: boolean, - difficulty: string, + difficulty: BsvMapDifficultyType, events: number, length: number, maxScore: number, @@ -138,4 +138,7 @@ export interface BsvMapParitySummary { errors: number, resets: number, warns: number, -} \ No newline at end of file +} + +export type BsvMapCharacteristic = ("Standard" | "OneSaber" | "NoArrows" | "90Degree" | "360Degree" | "Lightshow" | "Lawless") +export type BsvMapDifficultyType = ("Easy" | "Normal" | "Hard" | "Expert" | "ExpertPlus") \ No newline at end of file diff --git a/src/shared/models/maps/raw-map.model.ts b/src/shared/models/maps/raw-map.model.ts index f54cf17e..2d48b7eb 100644 --- a/src/shared/models/maps/raw-map.model.ts +++ b/src/shared/models/maps/raw-map.model.ts @@ -1,3 +1,5 @@ +import { BsvMapCharacteristic, BsvMapDifficultyType } from "./beat-saver.model" + export interface RawMapInfoData { _version: string, _songName: string, @@ -19,12 +21,12 @@ export interface RawMapInfoData { } export interface RawDifficultySet { - _beatmapCharacteristicName: string, + _beatmapCharacteristicName: BsvMapCharacteristic, _difficultyBeatmaps: RawMapDifficulty[] } export interface RawMapDifficulty { - _difficulty: string, + _difficulty: BsvMapDifficultyType, _difficultyRank: string, _beatmapFilename: string, _noteJumpMovementSpeed: number, diff --git a/tailwind.config.js b/tailwind.config.js index 34588d5d..c430d77d 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -6,7 +6,7 @@ module.exports = { darkMode: 'class', content: ['./src/renderer/**/*.tsx'], mode: 'jit', - plugins: [require('tailwind-scrollbar-hide'), require('tailwind-scrollbar')({ nocompatible: true }), require("tailwindcss-scoped-groups")({groups: ["one"]})], + plugins: [require('tailwind-scrollbar-hide'), require('tailwind-scrollbar')({ nocompatible: true }), require("tailwindcss-scoped-groups")({groups: ["one"]}), require('ps-scrollbar-tailwind')], theme:{ colors:{ ...colors, @@ -26,7 +26,7 @@ module.exports = { }, boxShadow: { 'center': '0px 0px 8px 0px', - } + }, } } };