A photo manager for VRChat.

change styles, fix filters

+3 -1
changelog
··· 99 99 - Fixed some icons not fading out when moving to the settings menu 100 100 - Removed the auto updater 101 101 - Removed account login stuff 102 - - Fixed app name on windows 102 + - Fixed app name on windows 103 + - Update styles 104 + - Fixed filters removing photos without metadata
+1 -1
package.json
··· 18 18 "@tauri-apps/plugin-process": "2.0.0-rc.0", 19 19 "@tauri-apps/plugin-shell": "2.0.0-rc.0", 20 20 "@types/animejs": "^3.1.13", 21 - "animejs": "^3.2.2", 21 + "animejs": "^4.1.3", 22 22 "solid-js": "^1.9.9" 23 23 }, 24 24 "devDependencies": {
+105 -105
pnpm-lock.yaml
··· 27 27 specifier: ^3.1.13 28 28 version: 3.1.13 29 29 animejs: 30 - specifier: ^3.2.2 31 - version: 3.2.2 30 + specifier: ^4.1.3 31 + version: 4.1.3 32 32 solid-js: 33 33 specifier: ^1.9.9 34 34 version: 1.9.9 ··· 284 284 '@jridgewell/trace-mapping@0.3.30': 285 285 resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} 286 286 287 - '@rollup/rollup-android-arm-eabi@4.46.2': 288 - resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} 287 + '@rollup/rollup-android-arm-eabi@4.46.3': 288 + resolution: {integrity: sha512-UmTdvXnLlqQNOCJnyksjPs1G4GqXNGW1LrzCe8+8QoaLhhDeTXYBgJ3k6x61WIhlHX2U+VzEJ55TtIjR/HTySA==} 289 289 cpu: [arm] 290 290 os: [android] 291 291 292 - '@rollup/rollup-android-arm64@4.46.2': 293 - resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} 292 + '@rollup/rollup-android-arm64@4.46.3': 293 + resolution: {integrity: sha512-8NoxqLpXm7VyeI0ocidh335D6OKT0UJ6fHdnIxf3+6oOerZZc+O7r+UhvROji6OspyPm+rrIdb1gTXtVIqn+Sg==} 294 294 cpu: [arm64] 295 295 os: [android] 296 296 297 - '@rollup/rollup-darwin-arm64@4.46.2': 298 - resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} 297 + '@rollup/rollup-darwin-arm64@4.46.3': 298 + resolution: {integrity: sha512-csnNavqZVs1+7/hUKtgjMECsNG2cdB8F7XBHP6FfQjqhjF8rzMzb3SLyy/1BG7YSfQ+bG75Ph7DyedbUqwq1rA==} 299 299 cpu: [arm64] 300 300 os: [darwin] 301 301 302 - '@rollup/rollup-darwin-x64@4.46.2': 303 - resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} 302 + '@rollup/rollup-darwin-x64@4.46.3': 303 + resolution: {integrity: sha512-r2MXNjbuYabSIX5yQqnT8SGSQ26XQc8fmp6UhlYJd95PZJkQD1u82fWP7HqvGUf33IsOC6qsiV+vcuD4SDP6iw==} 304 304 cpu: [x64] 305 305 os: [darwin] 306 306 307 - '@rollup/rollup-freebsd-arm64@4.46.2': 308 - resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} 307 + '@rollup/rollup-freebsd-arm64@4.46.3': 308 + resolution: {integrity: sha512-uluObTmgPJDuJh9xqxyr7MV61Imq+0IvVsAlWyvxAaBSNzCcmZlhfYcRhCdMaCsy46ccZa7vtDDripgs9Jkqsw==} 309 309 cpu: [arm64] 310 310 os: [freebsd] 311 311 312 - '@rollup/rollup-freebsd-x64@4.46.2': 313 - resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} 312 + '@rollup/rollup-freebsd-x64@4.46.3': 313 + resolution: {integrity: sha512-AVJXEq9RVHQnejdbFvh1eWEoobohUYN3nqJIPI4mNTMpsyYN01VvcAClxflyk2HIxvLpRcRggpX1m9hkXkpC/A==} 314 314 cpu: [x64] 315 315 os: [freebsd] 316 316 317 - '@rollup/rollup-linux-arm-gnueabihf@4.46.2': 318 - resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} 317 + '@rollup/rollup-linux-arm-gnueabihf@4.46.3': 318 + resolution: {integrity: sha512-byyflM+huiwHlKi7VHLAYTKr67X199+V+mt1iRgJenAI594vcmGGddWlu6eHujmcdl6TqSNnvqaXJqZdnEWRGA==} 319 319 cpu: [arm] 320 320 os: [linux] 321 321 322 - '@rollup/rollup-linux-arm-musleabihf@4.46.2': 323 - resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} 322 + '@rollup/rollup-linux-arm-musleabihf@4.46.3': 323 + resolution: {integrity: sha512-aLm3NMIjr4Y9LklrH5cu7yybBqoVCdr4Nvnm8WB7PKCn34fMCGypVNpGK0JQWdPAzR/FnoEoFtlRqZbBBLhVoQ==} 324 324 cpu: [arm] 325 325 os: [linux] 326 326 327 - '@rollup/rollup-linux-arm64-gnu@4.46.2': 328 - resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} 327 + '@rollup/rollup-linux-arm64-gnu@4.46.3': 328 + resolution: {integrity: sha512-VtilE6eznJRDIoFOzaagQodUksTEfLIsvXymS+UdJiSXrPW7Ai+WG4uapAc3F7Hgs791TwdGh4xyOzbuzIZrnw==} 329 329 cpu: [arm64] 330 330 os: [linux] 331 331 332 - '@rollup/rollup-linux-arm64-musl@4.46.2': 333 - resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} 332 + '@rollup/rollup-linux-arm64-musl@4.46.3': 333 + resolution: {integrity: sha512-dG3JuS6+cRAL0GQ925Vppafi0qwZnkHdPeuZIxIPXqkCLP02l7ka+OCyBoDEv8S+nKHxfjvjW4OZ7hTdHkx8/w==} 334 334 cpu: [arm64] 335 335 os: [linux] 336 336 337 - '@rollup/rollup-linux-loongarch64-gnu@4.46.2': 338 - resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} 337 + '@rollup/rollup-linux-loongarch64-gnu@4.46.3': 338 + resolution: {integrity: sha512-iU8DxnxEKJptf8Vcx4XvAUdpkZfaz0KWfRrnIRrOndL0SvzEte+MTM7nDH4A2Now4FvTZ01yFAgj6TX/mZl8hQ==} 339 339 cpu: [loong64] 340 340 os: [linux] 341 341 342 - '@rollup/rollup-linux-ppc64-gnu@4.46.2': 343 - resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} 342 + '@rollup/rollup-linux-ppc64-gnu@4.46.3': 343 + resolution: {integrity: sha512-VrQZp9tkk0yozJoQvQcqlWiqaPnLM6uY1qPYXvukKePb0fqaiQtOdMJSxNFUZFsGw5oA5vvVokjHrx8a9Qsz2A==} 344 344 cpu: [ppc64] 345 345 os: [linux] 346 346 347 - '@rollup/rollup-linux-riscv64-gnu@4.46.2': 348 - resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} 347 + '@rollup/rollup-linux-riscv64-gnu@4.46.3': 348 + resolution: {integrity: sha512-uf2eucWSUb+M7b0poZ/08LsbcRgaDYL8NCGjUeFMwCWFwOuFcZ8D9ayPl25P3pl+D2FH45EbHdfyUesQ2Lt9wA==} 349 349 cpu: [riscv64] 350 350 os: [linux] 351 351 352 - '@rollup/rollup-linux-riscv64-musl@4.46.2': 353 - resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} 352 + '@rollup/rollup-linux-riscv64-musl@4.46.3': 353 + resolution: {integrity: sha512-7tnUcDvN8DHm/9ra+/nF7lLzYHDeODKKKrh6JmZejbh1FnCNZS8zMkZY5J4sEipy2OW1d1Ncc4gNHUd0DLqkSg==} 354 354 cpu: [riscv64] 355 355 os: [linux] 356 356 357 - '@rollup/rollup-linux-s390x-gnu@4.46.2': 358 - resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} 357 + '@rollup/rollup-linux-s390x-gnu@4.46.3': 358 + resolution: {integrity: sha512-MUpAOallJim8CsJK+4Lc9tQzlfPbHxWDrGXZm2z6biaadNpvh3a5ewcdat478W+tXDoUiHwErX/dOql7ETcLqg==} 359 359 cpu: [s390x] 360 360 os: [linux] 361 361 362 - '@rollup/rollup-linux-x64-gnu@4.46.2': 363 - resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} 362 + '@rollup/rollup-linux-x64-gnu@4.46.3': 363 + resolution: {integrity: sha512-F42IgZI4JicE2vM2PWCe0N5mR5vR0gIdORPqhGQ32/u1S1v3kLtbZ0C/mi9FFk7C5T0PgdeyWEPajPjaUpyoKg==} 364 364 cpu: [x64] 365 365 os: [linux] 366 366 367 - '@rollup/rollup-linux-x64-musl@4.46.2': 368 - resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} 367 + '@rollup/rollup-linux-x64-musl@4.46.3': 368 + resolution: {integrity: sha512-oLc+JrwwvbimJUInzx56Q3ujL3Kkhxehg7O1gWAYzm8hImCd5ld1F2Gry5YDjR21MNb5WCKhC9hXgU7rRlyegQ==} 369 369 cpu: [x64] 370 370 os: [linux] 371 371 372 - '@rollup/rollup-win32-arm64-msvc@4.46.2': 373 - resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} 372 + '@rollup/rollup-win32-arm64-msvc@4.46.3': 373 + resolution: {integrity: sha512-lOrQ+BVRstruD1fkWg9yjmumhowR0oLAAzavB7yFSaGltY8klttmZtCLvOXCmGE9mLIn8IBV/IFrQOWz5xbFPg==} 374 374 cpu: [arm64] 375 375 os: [win32] 376 376 377 - '@rollup/rollup-win32-ia32-msvc@4.46.2': 378 - resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} 377 + '@rollup/rollup-win32-ia32-msvc@4.46.3': 378 + resolution: {integrity: sha512-vvrVKPRS4GduGR7VMH8EylCBqsDcw6U+/0nPDuIjXQRbHJc6xOBj+frx8ksfZAh6+Fptw5wHrN7etlMmQnPQVg==} 379 379 cpu: [ia32] 380 380 os: [win32] 381 381 382 - '@rollup/rollup-win32-x64-msvc@4.46.2': 383 - resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} 382 + '@rollup/rollup-win32-x64-msvc@4.46.3': 383 + resolution: {integrity: sha512-fi3cPxCnu3ZeM3EwKZPgXbWoGzm2XHgB/WShKI81uj8wG0+laobmqy5wbgEwzstlbLu4MyO8C19FyhhWseYKNQ==} 384 384 cpu: [x64] 385 385 os: [win32] 386 386 ··· 388 388 resolution: {integrity: sha512-v454Qs3REHc3Za59U+/eSmBsdmF+3NE5+76+lFDaitVqN4ZglDHENDaMARYKGJVZuxiSkzyqG0SeG7lLQjVkPA==} 389 389 engines: {node: '>= 18.18', npm: '>= 6.6.0', yarn: '>= 1.19.1'} 390 390 391 - '@tauri-apps/api@2.7.0': 392 - resolution: {integrity: sha512-v7fVE8jqBl8xJFOcBafDzXFc8FnicoH3j8o8DNNs0tHuEBmXUDqrCOAzMRX0UkfpwqZLqvrvK0GNQ45DfnoVDg==} 391 + '@tauri-apps/api@2.8.0': 392 + resolution: {integrity: sha512-ga7zdhbS2GXOMTIZRT0mYjKJtR9fivsXzsyq5U3vjDL0s6DTMwYRm0UHNjzTY5dh4+LSC68Sm/7WEiimbQNYlw==} 393 393 394 394 '@tauri-apps/cli-darwin-arm64@2.0.0-rc.5': 395 395 resolution: {integrity: sha512-EoduJ5SeMfBKCe7I291JBH+lkrf2E0+mQF1rP+Jq4CjWPer11OeEcUSFtHURB3Z3ItzObQ7ALPulMGhMe6E9rg==} ··· 486 486 '@types/estree@1.0.8': 487 487 resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 488 488 489 - animejs@3.2.2: 490 - resolution: {integrity: sha512-Ao95qWLpDPXXM+WrmwcKbl6uNlC5tjnowlaRYtuVDHHoygjtIPfDUoK9NthrlZsQSKjZXlmji2TrBUAVbiH0LQ==} 489 + animejs@4.1.3: 490 + resolution: {integrity: sha512-4XzlIsQsku1ycSPzchxxT0N+ohEMZObG71nOSBBkZoV4sgQvtXa/qAANkFpTE6pegdV8JnIBZiB0LfdxNoRNMw==} 491 491 492 492 babel-plugin-jsx-dom-expressions@0.40.1: 493 493 resolution: {integrity: sha512-b4iHuirqK7RgaMzB2Lsl7MqrlDgQtVRSSazyrmx7wB3T759ggGjod5Rkok5MfHjQXhR7tRPmdwoeGPqBnW2KfA==} ··· 503 503 solid-js: 504 504 optional: true 505 505 506 - browserslist@4.25.2: 507 - resolution: {integrity: sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==} 506 + browserslist@4.25.3: 507 + resolution: {integrity: sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==} 508 508 engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 509 509 hasBin: true 510 510 ··· 526 526 supports-color: 527 527 optional: true 528 528 529 - electron-to-chromium@1.5.202: 530 - resolution: {integrity: sha512-NxbYjRmiHcHXV1Ws3fWUW+SLb62isauajk45LUJ/HgIOkUA7jLZu/X2Iif+X9FBNK8QkF9Zb4Q2mcwXCcY30mg==} 529 + electron-to-chromium@1.5.207: 530 + resolution: {integrity: sha512-mryFrrL/GXDTmAtIVMVf+eIXM09BBPlO5IQ7lUyKmK8d+A4VpRGG+M3ofoVef6qyF8s60rJei8ymlJxjUA8Faw==} 531 531 532 532 entities@6.0.1: 533 533 resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} ··· 599 599 resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 600 600 engines: {node: ^10 || ^12 || >=14} 601 601 602 - rollup@4.46.2: 603 - resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==} 602 + rollup@4.46.3: 603 + resolution: {integrity: sha512-RZn2XTjXb8t5g13f5YclGoilU/kwT696DIkY3sywjdZidNSi3+vseaQov7D7BZXVJCPv3pDWUN69C78GGbXsKw==} 604 604 engines: {node: '>=18.0.0', npm: '>=8.0.0'} 605 605 hasBin: true 606 606 ··· 743 743 dependencies: 744 744 '@babel/compat-data': 7.28.0 745 745 '@babel/helper-validator-option': 7.27.1 746 - browserslist: 4.25.2 746 + browserslist: 4.25.3 747 747 lru-cache: 5.1.1 748 748 semver: 6.3.1 749 749 ··· 897 897 '@jridgewell/resolve-uri': 3.1.2 898 898 '@jridgewell/sourcemap-codec': 1.5.5 899 899 900 - '@rollup/rollup-android-arm-eabi@4.46.2': 900 + '@rollup/rollup-android-arm-eabi@4.46.3': 901 901 optional: true 902 902 903 - '@rollup/rollup-android-arm64@4.46.2': 903 + '@rollup/rollup-android-arm64@4.46.3': 904 904 optional: true 905 905 906 - '@rollup/rollup-darwin-arm64@4.46.2': 906 + '@rollup/rollup-darwin-arm64@4.46.3': 907 907 optional: true 908 908 909 - '@rollup/rollup-darwin-x64@4.46.2': 909 + '@rollup/rollup-darwin-x64@4.46.3': 910 910 optional: true 911 911 912 - '@rollup/rollup-freebsd-arm64@4.46.2': 912 + '@rollup/rollup-freebsd-arm64@4.46.3': 913 913 optional: true 914 914 915 - '@rollup/rollup-freebsd-x64@4.46.2': 915 + '@rollup/rollup-freebsd-x64@4.46.3': 916 916 optional: true 917 917 918 - '@rollup/rollup-linux-arm-gnueabihf@4.46.2': 918 + '@rollup/rollup-linux-arm-gnueabihf@4.46.3': 919 919 optional: true 920 920 921 - '@rollup/rollup-linux-arm-musleabihf@4.46.2': 921 + '@rollup/rollup-linux-arm-musleabihf@4.46.3': 922 922 optional: true 923 923 924 - '@rollup/rollup-linux-arm64-gnu@4.46.2': 924 + '@rollup/rollup-linux-arm64-gnu@4.46.3': 925 925 optional: true 926 926 927 - '@rollup/rollup-linux-arm64-musl@4.46.2': 927 + '@rollup/rollup-linux-arm64-musl@4.46.3': 928 928 optional: true 929 929 930 - '@rollup/rollup-linux-loongarch64-gnu@4.46.2': 930 + '@rollup/rollup-linux-loongarch64-gnu@4.46.3': 931 931 optional: true 932 932 933 - '@rollup/rollup-linux-ppc64-gnu@4.46.2': 933 + '@rollup/rollup-linux-ppc64-gnu@4.46.3': 934 934 optional: true 935 935 936 - '@rollup/rollup-linux-riscv64-gnu@4.46.2': 936 + '@rollup/rollup-linux-riscv64-gnu@4.46.3': 937 937 optional: true 938 938 939 - '@rollup/rollup-linux-riscv64-musl@4.46.2': 939 + '@rollup/rollup-linux-riscv64-musl@4.46.3': 940 940 optional: true 941 941 942 - '@rollup/rollup-linux-s390x-gnu@4.46.2': 942 + '@rollup/rollup-linux-s390x-gnu@4.46.3': 943 943 optional: true 944 944 945 - '@rollup/rollup-linux-x64-gnu@4.46.2': 945 + '@rollup/rollup-linux-x64-gnu@4.46.3': 946 946 optional: true 947 947 948 - '@rollup/rollup-linux-x64-musl@4.46.2': 948 + '@rollup/rollup-linux-x64-musl@4.46.3': 949 949 optional: true 950 950 951 - '@rollup/rollup-win32-arm64-msvc@4.46.2': 951 + '@rollup/rollup-win32-arm64-msvc@4.46.3': 952 952 optional: true 953 953 954 - '@rollup/rollup-win32-ia32-msvc@4.46.2': 954 + '@rollup/rollup-win32-ia32-msvc@4.46.3': 955 955 optional: true 956 956 957 - '@rollup/rollup-win32-x64-msvc@4.46.2': 957 + '@rollup/rollup-win32-x64-msvc@4.46.3': 958 958 optional: true 959 959 960 960 '@tauri-apps/api@2.0.0-rc.0': {} 961 961 962 - '@tauri-apps/api@2.7.0': {} 962 + '@tauri-apps/api@2.8.0': {} 963 963 964 964 '@tauri-apps/cli-darwin-arm64@2.0.0-rc.5': 965 965 optional: true ··· 1006 1006 1007 1007 '@tauri-apps/plugin-deep-link@2.4.1': 1008 1008 dependencies: 1009 - '@tauri-apps/api': 2.7.0 1009 + '@tauri-apps/api': 2.8.0 1010 1010 1011 1011 '@tauri-apps/plugin-http@2.0.0-rc.1': 1012 1012 dependencies: 1013 - '@tauri-apps/api': 2.7.0 1013 + '@tauri-apps/api': 2.8.0 1014 1014 1015 1015 '@tauri-apps/plugin-process@2.0.0-rc.0': 1016 1016 dependencies: ··· 1045 1045 1046 1046 '@types/estree@1.0.8': {} 1047 1047 1048 - animejs@3.2.2: {} 1048 + animejs@4.1.3: {} 1049 1049 1050 1050 babel-plugin-jsx-dom-expressions@0.40.1(@babel/core@7.28.3): 1051 1051 dependencies: ··· 1064 1064 optionalDependencies: 1065 1065 solid-js: 1.9.9 1066 1066 1067 - browserslist@4.25.2: 1067 + browserslist@4.25.3: 1068 1068 dependencies: 1069 1069 caniuse-lite: 1.0.30001735 1070 - electron-to-chromium: 1.5.202 1070 + electron-to-chromium: 1.5.207 1071 1071 node-releases: 2.0.19 1072 - update-browserslist-db: 1.1.3(browserslist@4.25.2) 1072 + update-browserslist-db: 1.1.3(browserslist@4.25.3) 1073 1073 1074 1074 caniuse-lite@1.0.30001735: {} 1075 1075 ··· 1081 1081 dependencies: 1082 1082 ms: 2.1.3 1083 1083 1084 - electron-to-chromium@1.5.202: {} 1084 + electron-to-chromium@1.5.207: {} 1085 1085 1086 1086 entities@6.0.1: {} 1087 1087 ··· 1154 1154 picocolors: 1.1.1 1155 1155 source-map-js: 1.2.1 1156 1156 1157 - rollup@4.46.2: 1157 + rollup@4.46.3: 1158 1158 dependencies: 1159 1159 '@types/estree': 1.0.8 1160 1160 optionalDependencies: 1161 - '@rollup/rollup-android-arm-eabi': 4.46.2 1162 - '@rollup/rollup-android-arm64': 4.46.2 1163 - '@rollup/rollup-darwin-arm64': 4.46.2 1164 - '@rollup/rollup-darwin-x64': 4.46.2 1165 - '@rollup/rollup-freebsd-arm64': 4.46.2 1166 - '@rollup/rollup-freebsd-x64': 4.46.2 1167 - '@rollup/rollup-linux-arm-gnueabihf': 4.46.2 1168 - '@rollup/rollup-linux-arm-musleabihf': 4.46.2 1169 - '@rollup/rollup-linux-arm64-gnu': 4.46.2 1170 - '@rollup/rollup-linux-arm64-musl': 4.46.2 1171 - '@rollup/rollup-linux-loongarch64-gnu': 4.46.2 1172 - '@rollup/rollup-linux-ppc64-gnu': 4.46.2 1173 - '@rollup/rollup-linux-riscv64-gnu': 4.46.2 1174 - '@rollup/rollup-linux-riscv64-musl': 4.46.2 1175 - '@rollup/rollup-linux-s390x-gnu': 4.46.2 1176 - '@rollup/rollup-linux-x64-gnu': 4.46.2 1177 - '@rollup/rollup-linux-x64-musl': 4.46.2 1178 - '@rollup/rollup-win32-arm64-msvc': 4.46.2 1179 - '@rollup/rollup-win32-ia32-msvc': 4.46.2 1180 - '@rollup/rollup-win32-x64-msvc': 4.46.2 1161 + '@rollup/rollup-android-arm-eabi': 4.46.3 1162 + '@rollup/rollup-android-arm64': 4.46.3 1163 + '@rollup/rollup-darwin-arm64': 4.46.3 1164 + '@rollup/rollup-darwin-x64': 4.46.3 1165 + '@rollup/rollup-freebsd-arm64': 4.46.3 1166 + '@rollup/rollup-freebsd-x64': 4.46.3 1167 + '@rollup/rollup-linux-arm-gnueabihf': 4.46.3 1168 + '@rollup/rollup-linux-arm-musleabihf': 4.46.3 1169 + '@rollup/rollup-linux-arm64-gnu': 4.46.3 1170 + '@rollup/rollup-linux-arm64-musl': 4.46.3 1171 + '@rollup/rollup-linux-loongarch64-gnu': 4.46.3 1172 + '@rollup/rollup-linux-ppc64-gnu': 4.46.3 1173 + '@rollup/rollup-linux-riscv64-gnu': 4.46.3 1174 + '@rollup/rollup-linux-riscv64-musl': 4.46.3 1175 + '@rollup/rollup-linux-s390x-gnu': 4.46.3 1176 + '@rollup/rollup-linux-x64-gnu': 4.46.3 1177 + '@rollup/rollup-linux-x64-musl': 4.46.3 1178 + '@rollup/rollup-win32-arm64-msvc': 4.46.3 1179 + '@rollup/rollup-win32-ia32-msvc': 4.46.3 1180 + '@rollup/rollup-win32-x64-msvc': 4.46.3 1181 1181 fsevents: 2.3.3 1182 1182 1183 1183 semver@6.3.1: {} ··· 1207 1207 1208 1208 typescript@5.9.2: {} 1209 1209 1210 - update-browserslist-db@1.1.3(browserslist@4.25.2): 1210 + update-browserslist-db@1.1.3(browserslist@4.25.3): 1211 1211 dependencies: 1212 - browserslist: 4.25.2 1212 + browserslist: 4.25.3 1213 1213 escalade: 3.2.0 1214 1214 picocolors: 1.1.1 1215 1215 ··· 1232 1232 dependencies: 1233 1233 esbuild: 0.21.5 1234 1234 postcss: 8.5.6 1235 - rollup: 4.46.2 1235 + rollup: 4.46.3 1236 1236 optionalDependencies: 1237 1237 fsevents: 2.3.3 1238 1238
+1
public/icon/gear-solid-full.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M259.1 73.5C262.1 58.7 275.2 48 290.4 48L350.2 48C365.4 48 378.5 58.7 381.5 73.5L396 143.5C410.1 149.5 423.3 157.2 435.3 166.3L503.1 143.8C517.5 139 533.3 145 540.9 158.2L570.8 210C578.4 223.2 575.7 239.8 564.3 249.9L511 297.3C511.9 304.7 512.3 312.3 512.3 320C512.3 327.7 511.8 335.3 511 342.7L564.4 390.2C575.8 400.3 578.4 417 570.9 430.1L541 481.9C533.4 495 517.6 501.1 503.2 496.3L435.4 473.8C423.3 482.9 410.1 490.5 396.1 496.6L381.7 566.5C378.6 581.4 365.5 592 350.4 592L290.6 592C275.4 592 262.3 581.3 259.3 566.5L244.9 496.6C230.8 490.6 217.7 482.9 205.6 473.8L137.5 496.3C123.1 501.1 107.3 495.1 99.7 481.9L69.8 430.1C62.2 416.9 64.9 400.3 76.3 390.2L129.7 342.7C128.8 335.3 128.4 327.7 128.4 320C128.4 312.3 128.9 304.7 129.7 297.3L76.3 249.8C64.9 239.7 62.3 223 69.8 209.9L99.7 158.1C107.3 144.9 123.1 138.9 137.5 143.7L205.3 166.2C217.4 157.1 230.6 149.5 244.6 143.4L259.1 73.5zM320.3 400C364.5 399.8 400.2 363.9 400 319.7C399.8 275.5 363.9 239.8 319.7 240C275.5 240.2 239.8 276.1 240 320.3C240.2 364.5 276.1 400.2 320.3 400z"/></svg>
+1 -1
src-tauri/tauri.conf.json
··· 35 35 "minWidth": 600, 36 36 "minHeight": 400, 37 37 "visible": false, 38 - "decorations": false, 38 + "decorations": true, 39 39 "transparent": true 40 40 } 41 41 ]
+2 -5
src/Components/App.tsx
··· 1 1 import { onMount } from "solid-js"; 2 - import anime from "animejs"; 3 2 4 - import NavBar from "./NavBar"; 5 3 import PhotoList from "./PhotoList"; 6 4 import PhotoViewer from "./PhotoViewer"; 7 5 import SettingsMenu from "./SettingsMenu"; 6 + import { utils } from "animejs"; 8 7 9 8 let App = () => { 10 9 onMount(() => { 11 - anime.set('.settings', 10 + utils.set('.settings', 12 11 { 13 12 display: 'none', 14 13 opacity: 0, ··· 18 17 19 18 return ( 20 19 <div class="container"> 21 - <NavBar /> 22 - 23 20 <PhotoList /> 24 21 <PhotoViewer /> 25 22
+1 -1
src/Components/Managers/PhotoListRenderingManager.tsx
··· 22 22 23 23 let lastDateString = null; 24 24 let row = new PhotoListRow(); 25 - row.Height = 100; 25 + row.Height = 0; 26 26 27 27 for (let i = 0; i < window.PhotoManager.FilteredPhotos.length; i++) { 28 28 let photo = window.PhotoManager.FilteredPhotos[i];
+12 -3
src/Components/Managers/PhotoManager.tsx
··· 170 170 171 171 switch(this._filterType){ 172 172 case FilterType.USER: 173 + if(this._filter === '')return this.FilteredPhotos = this.Photos; 174 + 173 175 this.Photos.map(p => { 174 176 if(p.metadata){ 175 177 try{ 176 178 let meta = JSON.parse(p.metadata); 177 - let photo = meta.players.find(( y: any ) => y.displayName.toLowerCase().includes(this._filter) || y.id === this._filter); 179 + let photo = meta.players.find(( y: any ) => 180 + y.displayName.toLowerCase().includes(this._filter) || 181 + y.id === this._filter 182 + ); 178 183 179 184 if(photo)this.FilteredPhotos.push(p); 180 185 } catch(e){} ··· 182 187 }) 183 188 break; 184 189 case FilterType.WORLD: 190 + if(this._filter === '')return this.FilteredPhotos = this.Photos; 191 + 185 192 this.Photos.map(p => { 186 193 if(p.metadata){ 187 194 try{ 188 195 let meta = JSON.parse(p.metadata); 189 - let photo = meta.world.name.toLowerCase().includes(this._filter) || meta.world.id === this._filter; 190 - 196 + let photo = 197 + meta.world.name.toLowerCase().includes(this._filter) || 198 + meta.world.id === this._filter; 199 + 191 200 if(photo)this.FilteredPhotos.push(p); 192 201 } catch(e){} 193 202 }
-125
src/Components/NavBar.tsx
··· 1 - import { emit } from '@tauri-apps/api/event'; 2 - import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; 3 - import anime from 'animejs'; 4 - import { Show, onMount } from 'solid-js'; 5 - import { ViewState } from './Managers/ViewManager'; 6 - 7 - const appWindow = getCurrentWebviewWindow(); 8 - 9 - let NavBar = () => { 10 - let dropdownVisible = false; 11 - let inAnimation = false; 12 - let dropdown: HTMLElement; 13 - 14 - onMount(() => { 15 - anime.set(dropdown, { opacity: 0, translateX: -10 }); 16 - dropdown.style.display = 'none'; 17 - }) 18 - 19 - let setDropdownVisibility = ( visible: boolean ) => { 20 - if(inAnimation)return; 21 - 22 - if(dropdownVisible !== visible){ 23 - dropdownVisible = visible; 24 - inAnimation = true; 25 - 26 - if(visible){ 27 - dropdown.style.display = 'block'; 28 - 29 - anime({ 30 - targets: dropdown, 31 - opacity: 1, 32 - translateX: 0, 33 - easing: 'easeInOutQuad', 34 - duration: 250, 35 - complete: () => { 36 - inAnimation = false; 37 - } 38 - }) 39 - } else{ 40 - anime({ 41 - targets: dropdown, 42 - opacity: 0, 43 - translateX: -10, 44 - easing: 'easeInOutQuad', 45 - duration: 250, 46 - complete: () => { 47 - inAnimation = false; 48 - dropdown.style.display = 'none'; 49 - } 50 - }) 51 - } 52 - } 53 - } 54 - 55 - window.CloseAllPopups.push(() => setDropdownVisibility(false)); 56 - 57 - return ( 58 - <> 59 - <div class="navbar" data-tauri-drag-region> 60 - <div class="tabs" data-tauri-drag-region> 61 - <div class="nav-tab" onClick={() => { 62 - window.ViewManager.ChangeState(ViewState.PHOTO_LIST); 63 - anime( 64 - { 65 - targets: '.settings', 66 - opacity: 0, 67 - translateX: '500px', 68 - easing: 'easeInOutQuad', 69 - duration: 250, 70 - complete: () => { 71 - anime.set('.settings', { display: 'none' }); 72 - } 73 - }) 74 - }}>Photos</div> 75 - </div> 76 - <div class="nav-tab" style={{ width: '200px', "text-align": 'center', background: 'transparent' }} data-tauri-drag-region> 77 - <Show when={window.SyncManager.IsSyncing()}> 78 - <Show when={ window.SyncManager.SyncError() == "" } fallback={ "Error: " + window.SyncManager.SyncError() }> 79 - <div style={{ width: '100%', "text-align": 'center', 'font-size': '14px' }}> 80 - { window.SyncManager.SyncType() }ing: { window.SyncManager.SyncPhotoTransfers () } / { window.SyncManager.SyncPhotoTotal() }<br /> 81 - <div style={{ width: '80%', height: '2px', margin: 'auto', "margin-top": '5px', background: '#111' }}> 82 - <div style={{ height: '2px', width: (window.SyncManager.SyncPhotoTransfers() / window.SyncManager.SyncPhotoTotal()) * 100 + '%', background: '#00ccff' }}></div> 83 - </div> 84 - </div> 85 - </Show> 86 - </Show> 87 - </div> 88 - <div class="account" onClick={() => setDropdownVisibility(!dropdownVisible)}> 89 - <div class="icon"> 90 - <img draggable="false" width="24" height="24" src="/icon/caret-down-solid.svg"></img> 91 - </div> 92 - </div> 93 - <div class="control-lights"> 94 - <div class="light" onClick={() => appWindow.minimize()}> 95 - <img draggable="false" width="24" height="24" src="/icon/minus-solid.svg"></img> 96 - </div> 97 - <div class="light" onClick={() => appWindow.toggleMaximize()}> 98 - <img draggable="false" width="24" height="24" src="/icon/square-regular.svg"></img> 99 - </div> 100 - <div class="light" onClick={() => { appWindow.hide(); emit('hide-window'); } }> 101 - <img draggable="false" width="24" height="24" src="/icon/x-solid.svg"></img> 102 - </div> 103 - </div> 104 - </div> 105 - 106 - <div class="dropdown" ref={( el ) => dropdown = el}> 107 - <div class="dropdown-button" onClick={async () => { 108 - anime.set('.settings', { display: 'block' }); 109 - anime({ 110 - targets: '.settings', 111 - opacity: 1, 112 - translateX: '0px', 113 - easing: 'easeInOutQuad', 114 - duration: 250 115 - }) 116 - 117 - window.ViewManager.ChangeState(ViewState.SETTINGS); 118 - setDropdownVisibility(false); 119 - }}>Settings</div> 120 - </div> 121 - </> 122 - ) 123 - } 124 - 125 - export default NavBar;
+51 -72
src/Components/PhotoList.tsx
··· 2 2 import { listen } from '@tauri-apps/api/event'; 3 3 import { Window } from "@tauri-apps/api/window"; 4 4 5 - import anime from "animejs"; 6 5 import FilterMenu from "./FilterMenu"; 7 6 import { ViewState } from "./Managers/ViewManager"; 8 7 import { invoke } from "@tauri-apps/api/core"; 8 + import { animate, utils } from "animejs"; 9 9 10 10 enum ListPopup{ 11 11 FILTERS, ··· 13 13 } 14 14 15 15 let PhotoList = () => { 16 - let photoTreeLoadingContainer: HTMLElement; 17 - 18 16 let scrollToTop: HTMLElement; 19 17 let scrollToTopActive = false; 20 18 21 19 let photoContainer: HTMLCanvasElement; 22 - let photoContainerBG: HTMLCanvasElement; 23 20 24 21 let filterContainer: HTMLDivElement; 25 22 26 23 let ctx: CanvasRenderingContext2D; 27 - let ctxBG: CanvasRenderingContext2D; 28 24 29 25 let scroll: number = 0; 30 26 let targetScroll: number = 0; ··· 39 35 40 36 41 37 window.ViewManager.OnStateTransition(ViewState.PHOTO_LIST, ViewState.SETTINGS, () => { 42 - anime({ targets: photoContainer, opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 43 - anime({ targets: '.filter-options', opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 44 - anime({ targets: '.reload-photos', opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 38 + animate(photoContainer, { opacity: 0.5, filter: 'blur(10px)', easing: 'easeInOutQuad', duration: 100 }); 39 + animate('.filter-options', { opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 40 + animate('.scroll-to-top', { opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 45 41 }); 46 42 47 43 window.ViewManager.OnStateTransition(ViewState.SETTINGS, ViewState.PHOTO_LIST, () => { 48 - anime({ targets: photoContainer, opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 49 - anime({ targets: '.filter-options', opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 50 - anime({ targets: '.reload-photos', opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 44 + animate(photoContainer, { opacity: 1, filter: 'blur(0px)', easing: 'easeInOutQuad', duration: 100, onComplete: () => photoContainer.style.filter = '' }); 45 + animate('.filter-options', { opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 46 + animate('.scroll-to-top', { opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 51 47 }); 52 48 53 49 54 50 window.ViewManager.OnStateTransition(ViewState.PHOTO_LIST, ViewState.PHOTO_VIEWER, () => { 55 - anime({ targets: photoContainer, opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 56 - anime({ targets: '.filter-options', opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 57 - anime({ targets: '.reload-photos', opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 51 + animate(photoContainer, { opacity: 0.5, filter: 'blur(10px)', easing: 'easeInOutQuad', duration: 100 }); 52 + animate('.filter-options', { opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 53 + animate('.scroll-to-top', { opacity: 0, easing: 'easeInOutQuad', duration: 100 }); 58 54 }); 59 55 60 56 window.ViewManager.OnStateTransition(ViewState.PHOTO_VIEWER, ViewState.PHOTO_LIST, () => { 61 - anime({ targets: photoContainer, opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 62 - anime({ targets: '.filter-options', opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 63 - anime({ targets: '.reload-photos', opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 57 + animate(photoContainer, { opacity: 1, filter: 'blur(0px)', easing: 'easeInOutQuad', duration: 100, onComplete: () => photoContainer.style.filter = '' }); 58 + animate('.filter-options', { opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 59 + animate('.scroll-to-top', { opacity: 1, easing: 'easeInOutQuad', duration: 100 }); 64 60 }); 65 61 66 62 ··· 74 70 photoContainer.width = window.innerWidth; 75 71 photoContainer.height = window.innerHeight; 76 72 77 - photoContainerBG.width = window.innerWidth; 78 - photoContainerBG.height = window.innerHeight; 79 - 80 73 window.PhotoListRenderingManager.ComputeLayout(); 81 74 } 82 75 83 76 let closeCurrentPopup = () => { 84 77 switch(currentPopup){ 85 78 case ListPopup.FILTERS: 86 - anime({ 87 - targets: filterContainer!, 79 + animate(filterContainer!, { 88 80 opacity: 0, 81 + translateY: '10px', 89 82 easing: 'easeInOutQuad', 90 83 duration: 100, 91 - complete: () => { 84 + onComplete: () => { 92 85 filterContainer!.style.display = 'none'; 93 86 currentPopup = ListPopup.NONE; 94 87 } ··· 98 91 } 99 92 } 100 93 101 - let fps = 0; 102 - setInterval(() => { 103 - console.log('FPS: ' + fps); 104 - fps = 0; 105 - }, 1000); 106 - 107 94 let render = () => { 108 95 if(!quitRender) 109 96 requestAnimationFrame(render); ··· 112 99 113 100 if(!scrollToTopActive && scroll > photoContainer.height){ 114 101 scrollToTop.style.display = 'flex'; 115 - anime({ targets: scrollToTop, opacity: 1, translateY: '0px', easing: 'easeInOutQuad', duration: 100 }); 102 + animate(scrollToTop, { opacity: 1, translateY: '0px', easing: 'easeInOutQuad', duration: 100 }); 116 103 117 104 scrollToTopActive = true; 118 105 } else if(scrollToTopActive && scroll < photoContainer.height){ 119 - anime({ targets: scrollToTop, opacity: 0, translateY: '-10px', complete: () => scrollToTop.style.display = 'none', easing: 'easeInOutQuad', duration: 100 }); 106 + animate(scrollToTop, { opacity: 0, translateY: '-10px', complete: () => scrollToTop.style.display = 'none', easing: 'easeInOutQuad', duration: 100 }); 120 107 scrollToTopActive = false; 121 108 } 122 109 123 - if(!ctx || !ctxBG)return; 110 + if(!ctx)return; 124 111 ctx.clearRect(0, 0, photoContainer.width, photoContainer.height); 125 - ctxBG.clearRect(0, 0, photoContainerBG.width, photoContainerBG.height); 126 112 127 113 scroll = scroll + (targetScroll - scroll) * 0.1; 128 114 ··· 137 123 138 124 ctx.fillText("It's looking empty in here! You have no photos :O", photoContainer.width / 2, photoContainer.height / 2); 139 125 } 140 - 141 - ctxBG.drawImage(photoContainer, 0, 0); 142 - fps += 1; 143 126 } 144 127 145 128 listen('hide-window', () => { ··· 154 137 photoContainer.width = window.innerWidth; 155 138 photoContainer.height = window.innerHeight; 156 139 157 - photoContainerBG.width = window.innerWidth; 158 - photoContainerBG.height = window.innerHeight; 159 - 160 140 if(window.PhotoManager.HasFirstLoaded){ 161 141 requestAnimationFrame(render); 162 142 window.PhotoManager.HasFirstLoaded = false; ··· 166 146 window.PhotoManager.OnLoadingFinished(() => { 167 147 invoke('close_splashscreen'); 168 148 169 - anime({ 170 - targets: photoTreeLoadingContainer, 171 - height: 0, 172 - easing: 'easeInOutQuad', 173 - duration: 500, 174 - opacity: 0, 175 - complete: () => { 176 - photoTreeLoadingContainer.style.display = 'none'; 177 - } 178 - }) 179 - 180 - anime({ 181 - targets: '.reload-photos', 149 + animate('.reload-photos', { 182 150 opacity: 1, 183 151 duration: 150, 184 152 easing: 'easeInOutQuad' ··· 192 160 193 161 onMount(() => { 194 162 ctx = photoContainer.getContext('2d')!; 195 - ctxBG = photoContainerBG.getContext('2d')!; 196 163 197 164 window.PhotoManager.Load(); 198 165 199 - anime.set(scrollToTop, { opacity: 0, translateY: '-10px', display: 'none' }); 166 + utils.set(scrollToTop, { opacity: 0, translateY: '-10px', display: 'none' }); 200 167 201 168 photoContainer.onwheel = ( e: WheelEvent ) => { 202 169 targetScroll += e.deltaY * 2; ··· 210 177 211 178 photoContainer.width = window.innerWidth; 212 179 photoContainer.height = window.innerHeight; 213 - 214 - photoContainerBG.width = window.innerWidth; 215 - photoContainerBG.height = window.innerHeight; 216 180 217 181 photoContainer.onclick = ( e: MouseEvent ) => { 218 182 let photo = window.PhotoManager.FilteredPhotos.find(x => ··· 240 204 241 205 return ( 242 206 <div class="photo-list"> 243 - <div ref={filterContainer!} class="filter-container" style={{ 244 - height: window.PhotoManager.HasBeenIndexed() ? '83px' : '110px', 245 - width: window.PhotoManager.HasBeenIndexed() ? '600px' : '650px' 246 - }}> 207 + <div ref={filterContainer!} class="filter-container"> 247 208 <FilterMenu /> 248 209 </div> 249 - 250 - <div class="photo-tree-loading" ref={( el ) => photoTreeLoadingContainer = el}>Scanning Photo Tree...</div> 251 210 252 211 <div class="scroll-to-top" ref={( el ) => scrollToTop = el} onClick={() => targetScroll = 0}> 253 212 <div class="icon"> 254 213 <img draggable="false" src="/icon/angle-up-solid.svg"></img> 255 214 </div> 256 215 </div> 257 - <div class="reload-photos" onClick={() => window.ConfirmationBoxManager.SetConfirmationBox("Are you sure you want to reload all photos? This can cause the application to slow down while it is loading...", () => window.location.reload())}> 258 - <div class="icon" style={{ width: '17px' }}> 259 - <img draggable="false" width="17" height="17" src="/icon/arrows-rotate-solid.svg"></img> 260 - </div> 261 - </div> 262 216 263 217 <div class="filter-options"> 264 218 <div> ··· 268 222 269 223 filterContainer!.style.display = 'block'; 270 224 271 - anime({ 272 - targets: filterContainer!, 225 + animate(filterContainer!, { 273 226 opacity: 1, 227 + translateY: 0, 274 228 easing: 'easeInOutQuad', 275 229 duration: 100 276 230 }); 277 - }} class="icon" style={{ width: '20px', height: '20px', padding: '20px' }}> 231 + }} class="icon"> 278 232 <img draggable="false" style={{ width: "20px", height: "20px" }} src="/icon/sliders-solid.svg"></img> 279 233 </div> 280 234 <div class="icon-label">Filters</div> 281 235 </div> 236 + 237 + <div> 238 + <div onClick={() => { 239 + window.location.reload(); 240 + }} class="icon"> 241 + <img draggable="false" style={{ width: "20px", height: "20px" }} src="/icon/arrows-rotate-solid.svg"></img> 242 + </div> 243 + <div class="icon-label">Reload Photos</div> 244 + </div> 245 + 246 + <div> 247 + <div onClick={() => { 248 + utils.set('.settings', { display: 'block' }); 249 + animate('.settings', { 250 + opacity: 1, 251 + translateX: '0px', 252 + easing: 'easeInOutQuad', 253 + duration: 250 254 + }) 255 + 256 + window.ViewManager.ChangeState(ViewState.SETTINGS); 257 + }} class="icon"> 258 + <img draggable="false" style={{ width: "20px", height: "20px" }} src="/icon/gear-solid-full.svg"></img> 259 + </div> 260 + <div class="icon-label">Settings</div> 261 + </div> 282 262 </div> 283 263 284 264 <canvas class="photo-container" ref={( el ) => photoContainer = el}></canvas> 285 - <canvas class="photo-container-bg" ref={( el ) => photoContainerBG = el}></canvas> 286 265 </div> 287 266 ) 288 267 }
+64 -81
src/Components/PhotoViewer.tsx
··· 1 1 import { For, Show, createEffect, onCleanup, onMount } from "solid-js"; 2 2 import { invoke } from '@tauri-apps/api/core'; 3 - import anime from 'animejs'; 4 3 import { WorldCache } from "./Structs/WorldCache"; 4 + import { animate, JSAnimation, utils } from "animejs"; 5 5 6 6 let PhotoViewer = () => { 7 7 let viewer: HTMLElement; ··· 21 21 let viewerContextMenuButtons: HTMLElement[] = []; 22 22 23 23 let allowedToOpenTray = false; 24 - let trayInAnimation = false; 25 24 26 25 let authorProfileButton: HTMLDivElement; 27 26 ··· 52 51 } 53 52 } 54 53 54 + let trayAnimation: JSAnimation[] = []; 55 + 55 56 let openTray = () => { 56 - if(trayOpen || trayInAnimation)return; 57 + if(trayOpen)return; 58 + trayOpen = true; 57 59 58 - trayOpen = true; 59 - trayInAnimation = true; 60 + trayAnimation.forEach(anim => anim.cancel()); 60 61 61 62 window.CloseAllPopups.forEach(p => p()); 62 - anime({ targets: photoTray, bottom: '0px', duration: 500 }); 63 + trayAnimation[0] = animate(photoTray, { bottom: '-150px', duration: 500, ease: 'outElastic' }); 63 64 64 - anime({ 65 - targets: photoControls, 65 + trayAnimation[1] = animate(photoControls, { 66 66 bottom: '160px', 67 + ease: 'outElastic', 67 68 scale: '0.75', 68 69 opacity: 0, 69 70 duration: 500, 70 - complete: () => { 71 + onComplete: () => { 71 72 photoControls.style.display = 'none'; 72 - trayInAnimation = false; 73 73 } 74 74 }); 75 75 76 76 photoTrayCloseBtn.style.display = 'flex'; 77 - anime({ 78 - targets: photoTrayCloseBtn, 77 + trayAnimation[2] = animate(photoTrayCloseBtn, { 79 78 bottom: '160px', 79 + ease: 'outElastic', 80 80 opacity: 1, 81 81 scale: 1, 82 82 duration: 500 ··· 86 86 let copyImage = () => { 87 87 invoke('copy_image', { path: window.PhotoViewerManager.CurrentPhoto()!.path }) 88 88 .then(() => { 89 - anime.set('.copy-notif', { translateX: '-50%', translateY: '-100px' }); 90 - anime({ 91 - targets: '.copy-notif', 89 + utils.set('.copy-notif', { translateX: '-50%', translateY: '-100px' }); 90 + animate('.copy-notif', { 91 + ease: 'outElastic', 92 92 opacity: 1, 93 93 translateY: '0px' 94 94 }); 95 95 96 96 setTimeout(() => { 97 - anime({ 98 - targets: '.copy-notif', 97 + animate('.copy-notif', { 98 + ease: 'outElastic', 99 99 opacity: 0, 100 100 translateY: '-100px' 101 101 }); ··· 104 104 } 105 105 106 106 let closeTray = () => { 107 - if(!trayOpen || trayInAnimation)return; 108 - trayInAnimation = true; 107 + if(!trayOpen)return; 108 + trayOpen = false; 109 + 110 + trayAnimation.forEach(anim => anim.cancel()); 109 111 110 112 window.CloseAllPopups.forEach(p => p()); 111 - anime({ targets: photoTray, bottom: '-150px', duration: 500 }); 113 + trayAnimation[0] = animate(photoTray, { bottom: '-300px', duration: 500, ease: 'outElastic' }); 112 114 113 - anime({ 114 - targets: photoTrayCloseBtn, 115 + trayAnimation[2] = animate(photoTrayCloseBtn, { 115 116 bottom: '10px', 116 117 scale: '0.75', 118 + ease: 'outElastic', 117 119 opacity: 0, 118 120 duration: 500, 119 - complete: () => { 121 + onComplete: () => { 120 122 photoTrayCloseBtn.style.display = 'none'; 121 - trayOpen = false; 122 - trayInAnimation = false; 123 123 } 124 124 }); 125 125 126 126 photoControls.style.display = 'flex'; 127 - anime({ 128 - targets: photoControls, 127 + trayAnimation[1] = animate(photoControls, { 129 128 bottom: '10px', 129 + ease: 'outElastic', 130 130 opacity: 1, 131 131 scale: 1, 132 132 duration: 500, ··· 134 134 } 135 135 136 136 onMount(() => { 137 - anime.set(photoControls, { translateX: '-50%' }); 138 - anime.set(photoTrayCloseBtn, { translateX: '-50%', opacity: 0, scale: '0.75', bottom: '10px' }); 137 + utils.set(photoControls, { translateX: '-50%' }); 138 + utils.set(photoTrayCloseBtn, { translateX: '-50%', opacity: 0, scale: '0.75', bottom: '10px' }); 139 139 140 140 window.addEventListener('keyup', switchPhotoWithKey); 141 141 142 142 let contextMenuOpen = false; 143 143 window.CloseAllPopups.push(() => { 144 144 contextMenuOpen = false; 145 - anime.set(viewerContextMenu, { opacity: 1, rotate: '0deg' }); 145 + utils.set(viewerContextMenu, { opacity: 1, rotate: '0deg' }); 146 146 147 - anime({ 148 - targets: viewerContextMenu, 147 + animate(viewerContextMenu, { 149 148 opacity: 0, 150 149 easing: 'easeInOutQuad', 151 150 rotate: '30deg', 152 151 duration: 100, 153 - complete: () => { 152 + onComplete: () => { 154 153 viewerContextMenu.style.display = 'none'; 155 154 } 156 155 }) ··· 174 173 if(contextMenuOpen){ 175 174 contextMenuOpen = false; 176 175 177 - anime.set(viewerContextMenu, { opacity: 1, rotate: '0deg' }); 176 + utils.set(viewerContextMenu, { opacity: 1, rotate: '0deg' }); 178 177 179 - anime({ 180 - targets: viewerContextMenu, 178 + animate(viewerContextMenu, { 181 179 opacity: 0, 182 180 rotate: '30deg', 183 181 easing: 'easeInOutQuad', 184 182 duration: 100, 185 - complete: () => { 183 + onComplete: () => { 186 184 viewerContextMenu.style.display = 'none'; 187 185 } 188 186 }) ··· 193 191 viewerContextMenu.style.left = e.clientX + 'px'; 194 192 viewerContextMenu.style.display = 'block'; 195 193 196 - anime.set(viewerContextMenu, { opacity: 0, rotate: '-30deg' }); 194 + utils.set(viewerContextMenu, { opacity: 0, rotate: '-30deg' }); 197 195 198 - anime({ 199 - targets: viewerContextMenu, 196 + animate(viewerContextMenu, { 200 197 opacity: 1, 201 198 rotate: '0deg', 202 199 easing: 'easeInOutQuad', ··· 215 212 imageViewer.src = (window.OS === "windows" ? "http://photo.localhost/" : 'photo://localhost/') + window.PhotoViewerManager.CurrentPhoto()?.path.split('\\').join('/') + "?full"; 216 213 imageViewer.crossOrigin = 'anonymous'; 217 214 218 - anime({ 219 - targets: imageViewer, 215 + animate(imageViewer, { 220 216 opacity: 1, 221 217 delay: 50, 222 218 duration: 150, ··· 300 296 if(photo && !isOpen){ 301 297 viewer.style.display = 'flex'; 302 298 303 - anime({ 304 - targets: viewer, 299 + animate(viewer, { 305 300 opacity: 1, 306 301 easing: 'easeInOutQuad', 307 302 duration: 150 308 303 }); 309 - 310 - anime({ 311 - targets: '.navbar', 312 - top: '-50px' 313 - }) 314 304 315 - anime.set('.prev-button', { left: '-50px', top: '50%' }); 316 - anime.set('.next-button', { right: '-50px', top: '50%' }); 305 + utils.set('.prev-button', { left: '-50px', top: '50%' }); 306 + utils.set('.next-button', { right: '-50px', top: '50%' }); 317 307 318 - anime({ targets: '.prev-button', left: '0', easing: 'easeInOutQuad', duration: 100 }); 319 - anime({ targets: '.next-button', right: '0', easing: 'easeInOutQuad', duration: 100 }); 308 + animate('.prev-button', { left: '0', easing: 'easeInOutQuad', duration: 100 }); 309 + animate('.next-button', { right: '0', easing: 'easeInOutQuad', duration: 100 }); 320 310 321 311 window.CloseAllPopups.forEach(p => p()); 322 312 } else if(!photo && isOpen){ 323 - anime({ 324 - targets: viewer, 313 + animate(viewer, { 325 314 opacity: 0, 326 315 easing: 'easeInOutQuad', 327 316 duration: 150, 328 - complete: () => { 317 + onComplete: () => { 329 318 viewer.style.display = 'none'; 330 319 } 331 320 }); 332 - 333 - anime({ 334 - targets: '.navbar', 335 - top: '0px' 336 - }) 337 321 338 322 window.CloseAllPopups.forEach(p => p()); 339 323 340 - anime({ targets: '.prev-button', top: '75%', easing: 'easeInOutQuad', duration: 100 }); 341 - anime({ targets: '.next-button', top: '75%', easing: 'easeInOutQuad', duration: 100 }); 324 + animate('.prev-button', { top: '75%', easing: 'easeInOutQuad', duration: 100 }); 325 + animate('.next-button', { top: '75%', easing: 'easeInOutQuad', duration: 100 }); 342 326 } 343 327 344 328 isOpen = photo != null; ··· 387 371 </div> 388 372 389 373 <div class="viewer-close viewer-button" onClick={() => window.PhotoViewerManager.Close()}> 390 - <div class="icon" style={{ width: '10px', margin: '0' }}> 374 + <div class="icon-small" style={{ width: '10px', margin: '0' }}> 391 375 <img draggable="false" src="/icon/x-solid.svg"></img> 392 376 </div> 393 377 </div> ··· 397 381 window.CloseAllPopups.forEach(p => p()); 398 382 window.PhotoViewerManager.PreviousPhoto(); 399 383 }}> 400 - <div class="icon" style={{ width: '15px', margin: '0' }}> 384 + <div class="icon-small" style={{ width: '15px', margin: '0' }}> 401 385 <img draggable="false" src="/icon/arrow-left-solid.svg"></img> 402 386 </div> 403 387 </div> ··· 406 390 window.CloseAllPopups.forEach(p => p()); 407 391 window.PhotoViewerManager.NextPhoto(); 408 392 }}> 409 - <div class="icon" style={{ width: '15px', margin: '0' }}> 393 + <div class="icon-small" style={{ width: '15px', margin: '0' }}> 410 394 <img draggable="false" src="/icon/arrow-right-solid.svg"></img> 411 395 </div> 412 396 </div> ··· 417 401 onClick={() => closeTray()} 418 402 ref={( el ) => photoTrayCloseBtn = el} 419 403 > 420 - <div class="icon" style={{ width: '12px', margin: '0' }}> 404 + <div class="icon-small" style={{ width: '12px', margin: '0' }}> 421 405 <img draggable="false" src="/icon/angle-down-solid.svg"></img> 422 406 </div> 423 407 </div> 424 408 425 409 <div class="control-buttons" ref={( el ) => photoControls = el}> 426 410 <div class="viewer-button" 427 - onMouseOver={( el ) => anime({ targets: el.currentTarget, width: '40px', height: '40px', 'margin-left': '15px', 'margin-right': '15px', 'margin-top': '-10px' })} 428 - onMouseLeave={( el ) => anime({ targets: el.currentTarget, width: '30px', height: '30px', 'margin-left': '20px', 'margin-right': '20px', 'margin-top': '0px' })} 411 + onMouseOver={( el ) => animate(el.currentTarget, { width: '40px', height: '40px', 'margin-left': '15px', 'margin-right': '15px', 'margin-top': '-10px' })} 412 + onMouseLeave={( el ) => animate(el.currentTarget, { width: '30px', height: '30px', 'margin-left': '20px', 'margin-right': '20px', 'margin-top': '0px' })} 429 413 onClick={() => { copyImage(); }}> 430 - <div class="icon" style={{ width: '12px', margin: '0' }}> 414 + <div class="icon-small" style={{ width: '12px', margin: '0' }}> 431 415 <img draggable="false" src="/icon/copy-solid.svg"></img> 432 416 </div> 433 417 </div> 434 418 <div class="viewer-button" style={{ width: '50px' }} 435 - onMouseOver={( el ) => anime({ targets: el.currentTarget, width: '70px', height: '30px', 'margin-left': '10px', 'margin-right': '10px' })} 436 - onMouseLeave={( el ) => anime({ targets: el.currentTarget, width: '50px', height: '30px', 'margin-left': '20px', 'margin-right': '20px' })} 419 + onMouseOver={( el ) => animate(el.currentTarget, { width: '70px', height: '30px', 'margin-left': '10px', 'margin-right': '10px' })} 420 + onMouseLeave={( el ) => animate(el.currentTarget, { width: '50px', height: '30px', 'margin-left': '20px', 'margin-right': '20px' })} 437 421 ref={( el ) => trayButton = el} 438 422 onClick={() => openTray()} 439 423 > 440 - <div class="icon" style={{ width: '12px', margin: '0' }}> 424 + <div class="icon-small" style={{ width: '12px', margin: '0' }}> 441 425 <img draggable="false" src="/icon/angle-up-solid.svg"></img> 442 426 </div> 443 427 </div> 444 428 445 429 <div class="viewer-button" 446 430 ref={authorProfileButton!} 447 - onMouseOver={( el ) => anime({ targets: el.currentTarget, width: '40px', height: '40px', 'margin-left': '15px', 'margin-right': '15px', 'margin-top': '-10px' })} 448 - onMouseLeave={( el ) => anime({ targets: el.currentTarget, width: '30px', height: '30px', 'margin-left': '20px', 'margin-right': '20px', 'margin-top': '0px' })} 431 + onMouseOver={( el ) => animate(el.currentTarget, { width: '40px', height: '40px', 'margin-left': '15px', 'margin-right': '15px', 'margin-top': '-10px' })} 432 + onMouseLeave={( el ) => animate(el.currentTarget, { width: '30px', height: '30px', 'margin-left': '20px', 'margin-right': '20px', 'margin-top': '0px' })} 449 433 > 450 - <div class="icon" style={{ width: '12px', margin: '0' }}> 434 + <div class="icon-small" style={{ width: '12px', margin: '0' }}> 451 435 <img draggable="false" src="/icon/user-solid.svg"></img> 452 436 </div> 453 437 </div> 454 438 455 439 <div class="viewer-button" 456 - onMouseOver={( el ) => anime({ targets: el.currentTarget, width: '40px', height: '40px', 'margin-left': '15px', 'margin-right': '15px', 'margin-top': '-10px' })} 457 - onMouseLeave={( el ) => anime({ targets: el.currentTarget, width: '30px', height: '30px', 'margin-left': '20px', 'margin-right': '20px', 'margin-top': '0px' })} 440 + onMouseOver={( el ) => animate(el.currentTarget, { width: '40px', height: '40px', 'margin-left': '15px', 'margin-right': '15px', 'margin-top': '-10px' })} 441 + onMouseLeave={( el ) => animate(el.currentTarget, { width: '30px', height: '30px', 'margin-left': '20px', 'margin-right': '20px', 'margin-top': '0px' })} 458 442 onClick={() => window.ConfirmationBoxManager.SetConfirmationBox("Are you sure you want to delete this photo?", async () => { invoke("delete_photo", { 459 - path: window.PhotoViewerManager.CurrentPhoto()?.path, 460 - token: (await invoke('get_config_value_string', { key: 'token' })) || "none", 443 + path: window.PhotoViewerManager.CurrentPhoto()?.path 461 444 }); 462 445 })}> 463 - <div class="icon" style={{ width: '12px', margin: '0' }}> 446 + <div class="icon-small" style={{ width: '12px', margin: '0' }}> 464 447 <img draggable="false" src="/icon/trash-solid.svg"></img> 465 448 </div> 466 449 </div>
+40 -27
src/Components/SettingsMenu.tsx
··· 1 1 import { onCleanup, onMount, Show } from "solid-js"; 2 2 import { bytesToFormatted } from "../utils"; 3 3 import { invoke } from '@tauri-apps/api/core'; 4 - import anime from "animejs"; 5 4 import { ViewState } from "./Managers/ViewManager"; 5 + import { animate, utils } from "animejs"; 6 6 7 7 let SettingsMenu = () => { 8 8 let sliderBar: HTMLElement; ··· 17 17 let closeWithKey = ( e: KeyboardEvent ) => { 18 18 if(e.key === 'Escape'){ 19 19 window.ViewManager.ChangeState(ViewState.PHOTO_LIST); 20 - anime({ 21 - targets: '.settings', 20 + animate('.settings', { 22 21 opacity: 0, 23 22 translateX: '500px', 24 23 easing: 'easeInOutQuad', 25 24 duration: 250, 26 - complete: () => { 27 - anime.set('.settings', { display: 'none' }); 25 + onComplete: () => { 26 + utils.set('.settings', { display: 'none' }); 28 27 } 29 28 }) 30 29 } ··· 34 33 if(await invoke('get_config_value_string', { key: 'transparent' }) === "true"){ 35 34 invoke('set_config_value_string', { key: 'transparent', value: 'true' }); 36 35 37 - anime({ targets: document.body, background: 'rgba(0, 0, 0, 0.5)', easing: 'linear', duration: 100 }); 38 - anime({ targets: '.settings', background: 'rgba(0, 0, 0, 0.5)', easing: 'linear', duration: 100 }); 36 + animate(document.body, { background: 'rgba(0, 0, 0, 0.5)', easing: 'linear', duration: 100 }); 37 + animate('.settings', { background: 'rgba(0, 0, 0, 0.5)', easing: 'linear', duration: 100 }); 39 38 } else{ 40 39 invoke('set_config_value_string', { key: 'transparent', value: 'false' }); 41 40 42 - anime({ targets: document.body, background: 'rgba(0, 0, 0, 1)', easing: 'linear', duration: 100 }); 43 - anime({ targets: '.settings', background: 'rgba(0, 0, 0, 0)', easing: 'linear', duration: 100 }); 41 + animate(document.body, { background: 'rgba(0, 0, 0, 1)', easing: 'linear', duration: 100 }); 42 + animate('.settings', { background: 'rgba(0, 0, 0, 0)', easing: 'linear', duration: 100 }); 44 43 } 45 44 46 45 let sliderMouseDown = false; ··· 57 56 58 57 if(!sliderMouseDown){ 59 58 sliderPos = sliderPos + (width / 2 - buttons[currentButton] - sliderPos) * 0.25; 60 - anime.set(sliderBar, { translateX: sliderPos }); 59 + utils.set(sliderBar, { translateX: sliderPos }); 61 60 62 61 settingsContainer.style.left = (sliderPos - (width / 2 - buttons[0])) * sliderScale + 'px'; 63 62 } 64 63 } 65 64 66 65 render(); 67 - anime.set(sliderBar, { translateX: sliderPos }); 66 + utils.set(sliderBar, { translateX: sliderPos }); 68 67 69 68 sliderBar.addEventListener('touchstart', ( e: TouchEvent ) => { 70 69 sliderMouseDown = true; ··· 73 72 74 73 window.addEventListener('touchmove', ( e: TouchEvent ) => { 75 74 if(sliderMouseDown){ 76 - anime.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) }); 75 + utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) }); 77 76 settingsContainer.style.left = (sliderPos - (mouseStartX - e.touches[0].clientX) - (width / 2 - buttons[0])) * sliderScale + 'px'; 78 77 } 79 78 }) ··· 84 83 if(sliderMouseDown){ 85 84 sliderPos = sliderPos - (mouseStartX - e.touches[0].clientX); 86 85 87 - anime.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) }); 86 + utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) }); 88 87 sliderMouseDown = false; 89 88 90 89 if(Math.abs(mouseStartX - e.touches[0].clientX) > 50){ ··· 118 117 119 118 window.addEventListener('mousemove', ( e: MouseEvent ) => { 120 119 if(sliderMouseDown){ 121 - anime.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) }); 120 + utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) }); 122 121 settingsContainer.style.left = sliderPos - (mouseStartX - e.clientX) + 'px'; 123 122 settingsContainer.style.left = (sliderPos - (mouseStartX - e.clientX) - (width / 2 - buttons[0])) * sliderScale + 'px'; 124 123 } ··· 128 127 if(sliderMouseDown){ 129 128 sliderPos = sliderPos - (mouseStartX - e.clientX); 130 129 131 - anime.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) }); 130 + utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) }); 132 131 sliderMouseDown = false; 133 132 134 133 if(Math.abs(mouseStartX - e.clientX) > 50){ ··· 160 159 sliderPos = width / 2 - buttons[currentButton]; 161 160 sliderScale = width / (buttons[1] - buttons[0]); 162 161 163 - anime.set(sliderBar, { translateX: sliderPos }); 162 + utils.set(sliderBar, { translateX: sliderPos }); 164 163 }) 165 164 166 165 sliderBar.addEventListener('wheel', ( e: WheelEvent ) => { ··· 180 179 181 180 return ( 182 181 <div class="settings"> 182 + <div class="settings-close" onClick={() => { 183 + window.ViewManager.ChangeState(ViewState.PHOTO_LIST); 184 + animate('.settings', 185 + { 186 + opacity: 0, 187 + translateX: '500px', 188 + easing: 'easeInOutQuad', 189 + duration: 250, 190 + onComplete: () => { 191 + utils.set('.settings', { display: 'none' }); 192 + } 193 + }) 194 + }}> 195 + <div class="icon"><img draggable="false" src="/icon/x-solid.svg"></img></div> 196 + </div> 183 197 <div class="settings-container" ref={( el ) => settingsContainer = el}> 184 198 <div class="settings-block"> 185 199 <h1>Storage Settings</h1> ··· 199 213 200 214 <label for="start-in-bg-check"> 201 215 <div class="selection-box"> 202 - <div class="icon" style={{ width: '10px', margin: '0', display: 'inline-flex' }}> 216 + <div class="icon-small" style={{ margin: '0', display: 'inline-flex' }}> 203 217 <img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img> 204 218 </div> 205 219 </div> ··· 223 237 224 238 <label for="start-with-win-check"> 225 239 <div class="selection-box"> 226 - <div class="icon" style={{ width: '10px', margin: '0', display: 'inline-flex' }}> 240 + <div class="icon-small" style={{ margin: '0', display: 'inline-flex' }}> 227 241 <img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img> 228 242 </div> 229 243 </div> ··· 238 252 if(el.target.checked){ 239 253 invoke('set_config_value_string', { key: 'transparent', value: 'true' }); 240 254 241 - anime({ targets: document.body, background: 'rgba(0, 0, 0, 0.5)', easing: 'linear', duration: 100 }); 242 - anime({ targets: '.settings', background: 'rgba(0, 0, 0, 0.5)', easing: 'linear', duration: 100 }); 255 + animate(document.body, { background: 'rgba(0, 0, 0, 0.5)', easing: 'linear', duration: 100 }); 256 + animate('.settings', { background: 'rgba(0, 0, 0, 0.5)', easing: 'linear', duration: 100 }); 243 257 } else{ 244 258 invoke('set_config_value_string', { key: 'transparent', value: 'false' }); 245 259 246 - anime({ targets: document.body, background: 'rgba(0, 0, 0, 1)', easing: 'linear', duration: 100 }); 247 - anime({ targets: '.settings', background: 'rgba(0, 0, 0, 0)', easing: 'linear', duration: 100 }); 260 + animate(document.body, { background: 'rgba(0, 0, 0, 1)', easing: 'linear', duration: 100 }); 261 + animate('.settings', { background: 'rgba(0, 0, 0, 0)', easing: 'linear', duration: 100 }); 248 262 } 249 263 }} /> 250 264 Window Transparency 251 265 252 266 <label for="transparent-check"> 253 267 <div class="selection-box"> 254 - <div class="icon" style={{ width: '10px', margin: '0', display: 'inline-flex' }}> 268 + <div class="icon-small" style={{ margin: '0', display: 'inline-flex' }}> 255 269 <img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img> 256 270 </div> 257 271 </div> ··· 282 296 await invoke('change_final_path', { newPath: finalPathData }); 283 297 window.location.reload(); 284 298 285 - anime({ 286 - targets: '.settings', 299 + animate('.settings', { 287 300 opacity: 0, 288 301 translateX: '500px', 289 302 easing: 'easeInOutQuad', 290 303 duration: 250, 291 - complete: () => { 292 - anime.set('.settings', { display: 'none' }); 304 + onComplete: () => { 305 + utils.set('.settings', { display: 'none' }); 293 306 } 294 307 }) 295 308
+71
src/css/filters.css
··· 1 + 2 + .filter-options{ 3 + position: fixed; 4 + top: 10px; 5 + left: 10px; 6 + } 7 + 8 + .filter-container{ 9 + display: none; 10 + position: fixed; 11 + bottom: 0; 12 + left: 0; 13 + width: 100vw; 14 + padding: 10px 200px; 15 + background: rgba(85, 85, 85, 0.904); 16 + transform: translateY(10px); 17 + color: #fff; 18 + text-align: center; 19 + box-shadow: #0005 0 0 10px; 20 + opacity: 0; 21 + } 22 + 23 + .filter-container > .filter-title{ 24 + font-size: 30px; 25 + } 26 + 27 + .filter-type-select{ 28 + display: flex; 29 + justify-content: center; 30 + align-items: center; 31 + width: 75%; 32 + margin: auto; 33 + } 34 + 35 + .filter-type-select > div{ 36 + width: 100%; 37 + border: #fff 4px solid; 38 + border-left: #fff 2px solid; 39 + border-right: #fff 2px solid; 40 + padding: 5px 0; 41 + cursor: pointer; 42 + user-select: none; 43 + -webkit-user-select: none; 44 + } 45 + 46 + .filter-type-select > div:first-child{ 47 + border-left: #fff 4px solid; 48 + border-radius: 10px 0 0 10px; 49 + } 50 + 51 + .filter-type-select > div:last-child{ 52 + border-right: #fff 4px solid; 53 + border-radius: 0 10px 10px 0; 54 + } 55 + 56 + .filter-type-select > .selected-filter{ 57 + background: #00ccff55; 58 + } 59 + 60 + .filter-search{ 61 + margin-top: 10px; 62 + padding: 5px; 63 + border: #fff 4px solid; 64 + border-radius: 10px; 65 + background: #0008; 66 + outline: none; 67 + color: white; 68 + font-size: 15px; 69 + font-family: 'Rubik'; 70 + width: calc(75% - 18px); 71 + }
+40
src/css/icons.css
··· 1 + .icon{ 2 + width: 40px; 3 + height: 40px; 4 + padding: 10px; 5 + filter: invert(100%); 6 + display: flex; 7 + align-items: center; 8 + justify-content: center; 9 + height: 100%; 10 + cursor: pointer; 11 + user-select: none; 12 + -webkit-user-select: none; 13 + } 14 + 15 + .icon-small{ 16 + filter: invert(100%); 17 + display: flex; 18 + align-items: center; 19 + justify-content: center; 20 + height: 100%; 21 + } 22 + 23 + .icon-label{ 24 + margin-top: -20px; 25 + margin-right: -200px; 26 + width: 200px; 27 + color: white; 28 + pointer-events: none; 29 + transform: translate(20px, -9px); 30 + opacity: 0; 31 + transition: 0.25s; 32 + user-select: none; 33 + -webkit-user-select: none; 34 + } 35 + 36 + .icon:hover ~ .icon-label{ 37 + opacity: 1; 38 + transform: translate(40px, -9px); 39 + } 40 +
+23
src/css/list.css
··· 1 + .photo-list{ 2 + width: 100%; 3 + height: 100%; 4 + position: fixed; 5 + top: 0; 6 + left: 0; 7 + overflow: hidden; 8 + } 9 + 10 + .scroll-to-top{ 11 + position: fixed; 12 + bottom: 10px; 13 + right: 10px; 14 + color: white; 15 + width: 40px; 16 + height: 40px; 17 + cursor: pointer; 18 + border-radius: 50%; 19 + border: 2px solid white; 20 + display: flex; 21 + justify-content: center; 22 + align-items: center; 23 + }
+84
src/css/settings.css
··· 1 + .settings{ 2 + position: fixed; 3 + top: 0; 4 + left: 0; 5 + width: 100%; 6 + height: 100%; 7 + background: rgba(0, 0, 0, 0.4); 8 + } 9 + 10 + .settings-container{ 11 + position: fixed; 12 + top: 50px; 13 + left: 0px; 14 + width: 200%; 15 + height: calc(100% - 100px); 16 + display: flex; 17 + } 18 + 19 + .settings-close{ 20 + position: absolute; 21 + top: 10px; 22 + left: 10px; 23 + z-index: 100; 24 + cursor: pointer; 25 + user-select: none; 26 + width: 40px; 27 + height: 40px; 28 + } 29 + 30 + .settings-block{ 31 + width: 50%; 32 + height: 100%; 33 + color: white; 34 + text-align: center; 35 + } 36 + 37 + .selector{ 38 + padding: 10px 20px; 39 + border-radius: 10px; 40 + background: #000a; 41 + display: inline-block; 42 + margin: 10px; 43 + } 44 + 45 + .selector .selection-box{ 46 + height: 20px; 47 + background: #777a; 48 + margin: 5px -10px 0 -10px; 49 + border-radius: 8px; 50 + user-select: none; 51 + -webkit-user-select: none; 52 + cursor: pointer; 53 + transition: 0.25s; 54 + color: #fff1; 55 + } 56 + 57 + .selector .selection-box:hover{ 58 + height: 20px; 59 + background: #777a; 60 + margin: 5px -10px 0 -10px; 61 + border-radius: 8px; 62 + user-select: none; 63 + -webkit-user-select: none; 64 + cursor: pointer; 65 + transition: 0.25s; 66 + color: #fff5; 67 + } 68 + 69 + .selector input{ 70 + display: none; 71 + } 72 + 73 + .selector input:checked ~ label .selection-box{ 74 + background: rgba(0, 146, 204, 0.705); 75 + color: #fff; 76 + } 77 + 78 + .path{ 79 + padding: 5px 10px; 80 + background: #000a; 81 + border-radius: 5px; 82 + margin-left: 5px; 83 + cursor: pointer; 84 + }
+55
src/css/slide-bar.css
··· 1 + .slide-bar{ 2 + position: fixed; 3 + bottom: 0; 4 + left: 0; 5 + width: 100%; 6 + height: 50px; 7 + border-top: #aaa 1px solid; 8 + overflow-x: hidden; 9 + mask-image: linear-gradient(to left, #0000 0%, #000 20%, #000 80%, #0000 100%); 10 + background: #aaa2; 11 + box-shadow: #000 0 0 10px; 12 + } 13 + 14 + .inner-slide-bar{ 15 + display: flex; 16 + height: 50px; 17 + width: 200%; 18 + color: white; 19 + align-items: center; 20 + cursor: pointer; 21 + user-select: none; 22 + -webkit-user-select: none; 23 + } 24 + 25 + .slider-dot{ 26 + width: 5px; 27 + height: 5px; 28 + border-radius: 5px; 29 + background: #aaa; 30 + margin: auto 25px; 31 + } 32 + 33 + .slider-text{ 34 + width: 200px; 35 + text-align: center; 36 + height: 50px; 37 + display: flex; 38 + justify-content: center; 39 + align-items: center; 40 + color: #aaa; 41 + transition: 0.25s; 42 + } 43 + 44 + .slider-text:hover{ 45 + color: #fff; 46 + } 47 + 48 + .slide-bar-tri{ 49 + position: fixed; 50 + bottom: 40px; 51 + left: 50%; 52 + transform: translateX(-50%); 53 + border: transparent solid 5px; 54 + border-top: #fff solid 5px; 55 + }
+82
src/css/tray.css
··· 1 + .photo-tray{ 2 + position: fixed; 3 + bottom: -300px; 4 + left: 0; 5 + width: 100%; 6 + height: 300px; 7 + background: rgba(43, 43, 43, 0.76); 8 + backdrop-filter: blur(10px); 9 + -webkit-backdrop-filter: blur(10px); 10 + box-shadow: #0008 0 0 10px; 11 + padding-bottom: 150px; 12 + } 13 + 14 + .photo-tray-close{ 15 + position: fixed; 16 + bottom: 160px; 17 + left: 50%; 18 + transform: translate(-50%); 19 + color: white; 20 + background: #8885; 21 + backdrop-filter: blur(10px); 22 + -webkit-backdrop-filter: blur(10px); 23 + box-shadow: #0008 0 0 10px; 24 + display: flex; 25 + justify-content: center; 26 + align-items: center; 27 + height: 30px; 28 + width: 50px; 29 + border-radius: 50px; 30 + cursor: pointer; 31 + font-size: 12px; 32 + user-select: none; 33 + -webkit-user-select: none; 34 + transition: 0.25s width; 35 + } 36 + 37 + .photo-tray-close:hover{ 38 + width: 70px; 39 + } 40 + 41 + .photo-tray-columns{ 42 + width: 100%; 43 + height: 100%; 44 + display: flex; 45 + color: white; 46 + text-align: center; 47 + } 48 + 49 + .photo-tray-column{ 50 + height: 100%; 51 + width: 100%; 52 + scrollbar-width: thin; 53 + overflow-y: auto; 54 + overflow-x: hidden; 55 + mask-image: linear-gradient(to bottom, #0000 0%, #000 10%, #000 90%, #0000 100%); 56 + } 57 + 58 + .tray-heading{ 59 + font-weight: bold; 60 + font-size: 20px; 61 + } 62 + 63 + .world-tags{ 64 + display: flex; 65 + width: 100%; 66 + justify-content: center; 67 + align-items: center; 68 + } 69 + 70 + .world-tags div{ 71 + padding: 0 10px; 72 + color: #bbb; 73 + transition: 0.25s; 74 + } 75 + 76 + .world-tags div:hover{ 77 + color: #ddd; 78 + } 79 + 80 + .world-name{ 81 + font-size: 17px; 82 + }
+169
src/css/viewer.css
··· 1 + 2 + .photo-container{ 3 + width: 100%; 4 + height: 100%; 5 + } 6 + 7 + .photo-container-bg{ 8 + width: 100%; 9 + height: 100%; 10 + position: fixed; 11 + top: 0; 12 + left: 0; 13 + z-index: -1; 14 + /* filter: blur(100px); */ 15 + } 16 + 17 + .single-photo-container{ 18 + margin: 10px; 19 + display: inline-block; 20 + } 21 + 22 + .photo-viewer{ 23 + justify-content: center; 24 + width: 100%; 25 + height: 100%; 26 + position: fixed; 27 + top: 0; 28 + left: 0; 29 + z-index: 5; 30 + background: #0009; 31 + opacity: 0; 32 + display: none; 33 + } 34 + 35 + .photo-context-menu{ 36 + position: fixed; 37 + top: 0; 38 + left: 0; 39 + padding: 10px; 40 + border-radius: 5px; 41 + background: #555a; 42 + color: #aaa; 43 + box-shadow: #0005 0 0 10px; 44 + opacity: 0; 45 + } 46 + 47 + .photo-context-menu > div{ 48 + padding: 2px 10px; 49 + width: 100; 50 + text-align: center; 51 + transition: 0.1s; 52 + } 53 + 54 + .photo-context-menu > div:hover{ 55 + color: #fff; 56 + cursor: pointer; 57 + user-select: none; 58 + -webkit-user-select: none; 59 + } 60 + 61 + .image-container{ 62 + height: 100%; 63 + background-size: contain !important; 64 + background-repeat: no-repeat !important; 65 + background-position: center !important; 66 + opacity: 0; 67 + } 68 + 69 + .viewer-button{ 70 + color: white; 71 + width: 30px; 72 + height: 30px; 73 + display: flex; 74 + justify-content: center; 75 + align-items: center; 76 + border-radius: 50px; 77 + font-size: 12px; 78 + background: #8885; 79 + user-select: none; 80 + -webkit-user-select: none; 81 + cursor: pointer; 82 + z-index: 7; 83 + box-shadow: #0008 0 0 10px; 84 + } 85 + 86 + .viewer-close{ 87 + position: fixed; 88 + top: 10px; 89 + right: 10px; 90 + width: 35px; 91 + height: 35px; 92 + } 93 + 94 + .prev-button{ 95 + transition: 0.25s; 96 + position: fixed; 97 + top: 50%; 98 + left: 0; 99 + color: white; 100 + width: 50px; 101 + height: 150px; 102 + display: flex; 103 + justify-content: center; 104 + align-items: center; 105 + transform: translateY(-50%); 106 + background: rgba(255, 255, 255, 0.144); 107 + border-radius: 0 15px 15px 0; 108 + cursor: pointer; 109 + user-select: none; 110 + -webkit-user-select: none; 111 + box-shadow: #000 0 0 10px; 112 + } 113 + 114 + .prev-button:hover{ 115 + background: rgba(255, 255, 255, 0.349); 116 + } 117 + 118 + .next-button{ 119 + transition: 0.25s; 120 + position: fixed; 121 + top: 50%; 122 + right: 0; 123 + color: white; 124 + width: 50px; 125 + height: 150px; 126 + display: flex; 127 + justify-content: center; 128 + align-items: center; 129 + transform: translateY(-50%); 130 + background: rgba(255, 255, 255, 0.144); 131 + border-radius: 15px 0 0 15px; 132 + cursor: pointer; 133 + user-select: none; 134 + -webkit-user-select: none; 135 + box-shadow: #000 0 0 10px; 136 + } 137 + 138 + .next-button:hover{ 139 + background: rgba(255, 255, 255, 0.349); 140 + } 141 + 142 + .control-buttons{ 143 + position: fixed; 144 + bottom: 10px; 145 + left: 50%; 146 + transform: translateX(-50%); 147 + display: flex; 148 + } 149 + 150 + .control-buttons div{ 151 + margin: 0 20px; 152 + } 153 + 154 + .copy-notif{ 155 + position: fixed; 156 + top: 40px; 157 + left: 50%; 158 + color: white; 159 + transform: translateX(-50%) translateY(-100px); 160 + background: #8885; 161 + padding: 10px 40px; 162 + backdrop-filter: blur(10px); 163 + -webkit-backdrop-filter: blur(10px); 164 + border-radius: 50px; 165 + box-shadow: #000 0 0 10px; 166 + z-index: 12; 167 + opacity: 0; 168 + pointer-events: none; 169 + }
+9
src/index.tsx
··· 22 22 23 23 window.oncontextmenu = ( e ) => e.preventDefault(); 24 24 25 + import './css/icons.css'; 26 + import './css/tray.css'; 27 + import './css/settings.css'; 28 + import './css/slide-bar.css'; 29 + import './css/viewer.css'; 30 + import './css/filters.css'; 31 + import './css/list.css'; 32 + 25 33 import "./styles.css"; 34 + 26 35 import App from "./Components/App"; 27 36 import { invoke } from "@tauri-apps/api/core"; 28 37
+6 -779
src/styles.css
··· 7 7 background: #000; 8 8 margin: 0; 9 9 font-family: Rubik, 'Courier New'; 10 + overflow: hidden; 11 + } 12 + 13 + * { 14 + box-sizing: border-box; 10 15 } 11 16 12 17 .loading{ ··· 24 29 align-items: center; 25 30 } 26 31 27 - .navbar{ 28 - background: #555a; 29 - position: fixed; 30 - top: 0; 31 - left: 0; 32 - width: 100%; 33 - margin-top: -50px; 34 - padding-top: 50px; 35 - height: 50px; 36 - display: flex; 37 - backdrop-filter: blur(10px); 38 - -webkit-backdrop-filter: blur(10px); 39 - z-index: 10; 40 - box-shadow: #000 0 0 10px; 41 - } 42 - 43 - .navbar .tabs{ 44 - width: calc(100% - 450px); 45 - height: 100%; 46 - display: flex; 47 - } 48 - 49 - .navbar .account{ 50 - width: 100px; 51 - height: 100%; 52 - display: flex; 53 - justify-content: center; 54 - align-items: center; 55 - transition: 0.1s; 56 - cursor: pointer; 57 - user-select: none; 58 - -webkit-user-select: none; 59 - } 60 - 61 - .navbar .account:hover{ 62 - background: #0005; 63 - } 64 - 65 - .navbar .control-lights{ 66 - width: 150px; 67 - height: 50px; 68 - display: flex; 69 - justify-content: center; 70 - align-items: center; 71 - } 72 - 73 - .control-lights .light{ 74 - user-select: none; 75 - -webkit-user-select: none; 76 - font-size: 20px; 77 - text-align: center; 78 - color: white; 79 - width: 100%; 80 - cursor: pointer; 81 - display: flex; 82 - justify-content: center; 83 - align-items: center; 84 - height: 50px; 85 - filter: invert(100%); 86 - } 87 - 88 - .control-lights .light:hover{ 89 - background: #fff5; 90 - } 91 - 92 - .control-lights .light img{ 93 - width: 25%; 94 - } 95 - 96 - .icon{ 97 - width: 15px; 98 - filter: invert(100%); 99 - display: flex; 100 - align-items: center; 101 - justify-content: center; 102 - height: 100%; 103 - } 104 - 105 - .icon-label{ 106 - margin-top: -20px; 107 - margin-right: -200px; 108 - width: 200px; 109 - color: white; 110 - pointer-events: none; 111 - transform: translate(40px, -19px); 112 - opacity: 0; 113 - transition: 0.25s; 114 - user-select: none; 115 - -webkit-user-select: none; 116 - } 117 - 118 - .icon:hover ~ .icon-label{ 119 - opacity: 1; 120 - transform: translate(60px, -19px); 121 - } 122 - 123 - .user-pfp{ 124 - width: 35px; 125 - height: 35px; 126 - background-size: cover !important; 127 - background-position: center !important; 128 - border-radius: 50%; 129 - margin-right: 10px; 130 - } 131 - 132 - .account-dropdown{ 133 - font-size: 20px; 134 - color: white; 135 - } 136 - 137 - .nav-tab{ 138 - color: white; 139 - width: 150px; 140 - height: 100%; 141 - transition: 0.1s; 142 - cursor: pointer; 143 - user-select: none; 144 - -webkit-user-select: none; 145 - justify-content: center; 146 - align-items: center; 147 - display: flex; 148 - } 149 - 150 - .nav-tab:hover{ 151 - background: #0005; 152 - } 153 - 154 - .dropdown{ 155 - position: fixed; 156 - right: 125px; 157 - top: 60px; 158 - background: #555a; 159 - height: 60px; 160 - width: 150px; 161 - border-radius: 5px; 162 - backdrop-filter: blur(5px); 163 - z-index: 10; 164 - } 165 - 166 - .dropdown-button{ 167 - width: 100%; 168 - text-align: center; 169 - padding: 5.5px 0; 170 - color: #aaa; 171 - cursor: pointer; 172 - user-select: none; 173 - -webkit-user-select: none; 174 - transition: 0.1s; 175 - } 176 - 177 - .dropdown-button:hover{ 178 - color: #fff; 179 - } 180 - 181 - .photo-list{ 182 - width: 100%; 183 - height: 100%; 184 - position: fixed; 185 - top: 0; 186 - left: 0; 187 - overflow: hidden; 188 - } 189 - 190 - .filter-options{ 191 - position: fixed; 192 - top: 55px; 193 - left: 5px; 194 - width: 40px; 195 - height: 50px; 196 - } 197 - 198 - .filter-options img{ 199 - cursor: pointer; 200 - user-select: none; 201 - -webkit-user-select: none; 202 - } 203 - 204 - .filter-container{ 205 - display: none; 206 - position: fixed; 207 - bottom: 0; 208 - left: 50%; 209 - width: 600px; 210 - height: 83px; 211 - transform: translate(-50%); 212 - padding: 10px; 213 - border-radius: 5px 5px 0 0; 214 - backdrop-filter: blur(5px); 215 - -webkit-backdrop-filter: blur(5px); 216 - background: #555a; 217 - color: #fff; 218 - text-align: center; 219 - box-shadow: #0005 0 0 10px; 220 - opacity: 0; 221 - } 222 - 223 - .filter-container > .filter-title{ 224 - font-size: 30px; 225 - } 226 - 227 - .filter-type-select{ 228 - display: flex; 229 - justify-content: center; 230 - align-items: center; 231 - width: 75%; 232 - margin: auto; 233 - } 234 - 235 - .filter-type-select > div{ 236 - width: 100%; 237 - border: #fff 4px solid; 238 - border-left: #fff 2px solid; 239 - border-right: #fff 2px solid; 240 - padding: 5px 0; 241 - cursor: pointer; 242 - user-select: none; 243 - -webkit-user-select: none; 244 - } 245 - 246 - .filter-type-select > div:first-child{ 247 - border-left: #fff 4px solid; 248 - border-radius: 10px 0 0 10px; 249 - } 250 - 251 - .filter-type-select > div:last-child{ 252 - border-right: #fff 4px solid; 253 - border-radius: 0 10px 10px 0; 254 - } 255 - 256 - .filter-type-select > .selected-filter{ 257 - background: #00ccff55; 258 - } 259 - 260 - .filter-search{ 261 - margin-top: 10px; 262 - padding: 5px; 263 - border: #fff 4px solid; 264 - border-radius: 10px; 265 - background: #0008; 266 - outline: none; 267 - color: white; 268 - font-size: 15px; 269 - font-family: 'Rubik'; 270 - width: calc(75% - 18px); 271 - } 272 - 273 - .date-list{ 274 - mask-image: linear-gradient(to bottom, #0000, #000, #0000); 275 - overflow: auto; 276 - scrollbar-width: thin; 277 - height: calc(100% - 100px); 278 - padding: 50px 0; 279 - } 280 - 281 - .date-list-date{ 282 - padding: 10px; 283 - user-select: none; 284 - -webkit-user-select: none; 285 - cursor: pointer; 286 - transition: 0.1s; 287 - border-radius: 10px; 288 - } 289 - 290 - .date-list-date:hover{ 291 - background: #0005; 292 - box-shadow: inset #0005 0 0 10px; 293 - } 294 - 295 - .photo-tree-loading{ 296 - position: fixed; 297 - top: 0; 298 - left: 0; 299 - width: 100%; 300 - height: 100%; 301 - display: flex; 302 - justify-content: center; 303 - align-items: center; 304 - color: white; 305 - font-size: 20px; 306 - } 307 - 308 - .loading-bar{ 309 - width: 500px; 310 - height: 8px; 311 - border-radius: 12px; 312 - background: #333; 313 - margin-top: 10px; 314 - padding: 2px; 315 - } 316 - 317 - .loading-bar-inner{ 318 - width: 0%; 319 - height: 8px; 320 - border-radius: 18px; 321 - background: #00ccff; 322 - } 323 - 324 - .photo-container{ 325 - width: 100%; 326 - height: 100%; 327 - } 328 - 329 - .photo-container-bg{ 330 - width: 100%; 331 - height: 100%; 332 - position: fixed; 333 - top: 0; 334 - left: 0; 335 - z-index: -1; 336 - /* filter: blur(100px); */ 337 - } 338 - 339 - .single-photo-container{ 340 - margin: 10px; 341 - display: inline-block; 342 - } 343 - 344 - .photo-viewer{ 345 - justify-content: center; 346 - width: 100%; 347 - height: 100%; 348 - position: fixed; 349 - top: 0; 350 - left: 0; 351 - z-index: 5; 352 - background: #0009; 353 - backdrop-filter: blur(75px); 354 - -webkit-backdrop-filter: blur(75px); 355 - opacity: 0; 356 - display: none; 357 - } 358 - 359 - .photo-context-menu{ 360 - position: fixed; 361 - top: 0; 362 - left: 0; 363 - padding: 10px; 364 - border-radius: 5px; 365 - backdrop-filter: blur(5px); 366 - -webkit-backdrop-filter: blur(5px); 367 - background: #555a; 368 - color: #aaa; 369 - box-shadow: #0005 0 0 10px; 370 - opacity: 0; 371 - } 372 - 373 - .photo-context-menu > div{ 374 - padding: 2px 10px; 375 - width: calc(100% - 10px); 376 - text-align: center; 377 - transition: 0.1s; 378 - } 379 - 380 - .photo-context-menu > div:hover{ 381 - color: #fff; 382 - cursor: pointer; 383 - user-select: none; 384 - -webkit-user-select: none; 385 - } 386 - 387 - .image-container{ 388 - height: 100%; 389 - background-size: contain !important; 390 - background-repeat: no-repeat !important; 391 - background-position: center !important; 392 - opacity: 0; 393 - } 394 - 395 - .viewer-button{ 396 - color: white; 397 - width: 30px; 398 - height: 30px; 399 - display: flex; 400 - justify-content: center; 401 - align-items: center; 402 - border-radius: 50px; 403 - font-size: 12px; 404 - background: #8885; 405 - backdrop-filter: blur(10px); 406 - -webkit-backdrop-filter: blur(10px); 407 - user-select: none; 408 - -webkit-user-select: none; 409 - cursor: pointer; 410 - z-index: 7; 411 - box-shadow: #0008 0 0 10px; 412 - } 413 - 414 - .viewer-close{ 415 - position: fixed; 416 - top: 10px; 417 - right: 10px; 418 - width: 35px; 419 - height: 35px; 420 - } 421 - 422 - .prev-button{ 423 - transition: 0.25s; 424 - position: fixed; 425 - top: 50%; 426 - left: 0; 427 - color: white; 428 - width: 50px; 429 - height: 150px; 430 - display: flex; 431 - justify-content: center; 432 - align-items: center; 433 - transform: translateY(-50%); 434 - background: rgba(255, 255, 255, 0.144); 435 - backdrop-filter: blur(50px); 436 - -webkit-backdrop-filter: blur(50px); 437 - border-radius: 0 15px 15px 0; 438 - cursor: pointer; 439 - user-select: none; 440 - -webkit-user-select: none; 441 - box-shadow: #000 0 0 10px; 442 - } 443 - 444 - .prev-button:hover{ 445 - background: rgba(255, 255, 255, 0.349); 446 - } 447 - 448 - .next-button{ 449 - transition: 0.25s; 450 - position: fixed; 451 - top: 50%; 452 - right: 0; 453 - color: white; 454 - width: 50px; 455 - height: 150px; 456 - display: flex; 457 - justify-content: center; 458 - align-items: center; 459 - transform: translateY(-50%); 460 - background: rgba(255, 255, 255, 0.144); 461 - backdrop-filter: blur(50px); 462 - -webkit-backdrop-filter: blur(50px); 463 - border-radius: 15px 0 0 15px; 464 - cursor: pointer; 465 - user-select: none; 466 - -webkit-user-select: none; 467 - box-shadow: #000 0 0 10px; 468 - } 469 - 470 - .next-button:hover{ 471 - background: rgba(255, 255, 255, 0.349); 472 - } 473 - 474 - .reload-photos{ 475 - position: fixed; 476 - top: 70px; 477 - right: 20px; 478 - color: white; 479 - user-select: none; 480 - -webkit-user-select: none; 481 - cursor: pointer; 482 - opacity: 0; 483 - } 484 - 485 32 .confirmation-box{ 486 33 position: fixed; 487 34 top: 0; ··· 489 36 width: 100%; 490 37 height: 100%; 491 38 z-index: 15; 492 - background: #0005; 39 + background: rgba(0, 0, 0, 0.76); 493 40 transition: 0.25s; 494 - backdrop-filter: blur(10px); 495 - -webkit-backdrop-filter: blur(10px); 496 41 } 497 42 498 43 .confirmation-box-container{ ··· 550 95 551 96 .button-danger:hover{ 552 97 box-shadow: #000a inset 0 0 10px; 553 - } 554 - 555 - .control-buttons{ 556 - position: fixed; 557 - bottom: 10px; 558 - left: 50%; 559 - transform: translateX(-50%); 560 - display: flex; 561 - } 562 - 563 - .control-buttons div{ 564 - margin: 0 20px; 565 - } 566 - 567 - .copy-notif{ 568 - position: fixed; 569 - top: 40px; 570 - left: 50%; 571 - color: white; 572 - transform: translateX(-50%) translateY(-100px); 573 - background: #8885; 574 - padding: 10px 40px; 575 - backdrop-filter: blur(10px); 576 - -webkit-backdrop-filter: blur(10px); 577 - border-radius: 50px; 578 - box-shadow: #000 0 0 10px; 579 - z-index: 12; 580 - opacity: 0; 581 - pointer-events: none; 582 - } 583 - 584 - .photo-tray{ 585 - position: fixed; 586 - bottom: -150px; 587 - left: 0; 588 - width: 100%; 589 - height: 150px; 590 - background: #7778; 591 - backdrop-filter: blur(10px); 592 - -webkit-backdrop-filter: blur(10px); 593 - box-shadow: #0008 0 0 10px; 594 - padding-bottom: 150px; 595 - margin-bottom: -150px; 596 - } 597 - 598 - .photo-tray-close{ 599 - position: fixed; 600 - bottom: 160px; 601 - left: 50%; 602 - transform: translate(-50%); 603 - color: white; 604 - background: #8885; 605 - backdrop-filter: blur(10px); 606 - -webkit-backdrop-filter: blur(10px); 607 - box-shadow: #0008 0 0 10px; 608 - display: flex; 609 - justify-content: center; 610 - align-items: center; 611 - height: 30px; 612 - width: 50px; 613 - border-radius: 50px; 614 - cursor: pointer; 615 - font-size: 12px; 616 - user-select: none; 617 - -webkit-user-select: none; 618 - transition: 0.25s width; 619 - } 620 - 621 - .photo-tray-close:hover{ 622 - width: 70px; 623 - } 624 - 625 - .photo-tray-columns{ 626 - width: 100%; 627 - height: 100%; 628 - display: flex; 629 - color: white; 630 - text-align: center; 631 - } 632 - 633 - .photo-tray-column{ 634 - height: 100%; 635 - width: 100%; 636 - scrollbar-width: thin; 637 - overflow-y: auto; 638 - overflow-x: hidden; 639 - mask-image: linear-gradient(to bottom, #0000 0%, #000 10%, #000 90%, #0000 100%); 640 - } 641 - 642 - .tray-heading{ 643 - font-weight: bold; 644 - font-size: 20px; 645 - } 646 - 647 - .world-tags{ 648 - display: flex; 649 - width: 100%; 650 - justify-content: center; 651 - align-items: center; 652 - } 653 - 654 - .world-tags div{ 655 - padding: 0 10px; 656 - color: #bbb; 657 - transition: 0.25s; 658 - } 659 - 660 - .world-tags div:hover{ 661 - color: #ddd; 662 - } 663 - 664 - .world-name{ 665 - font-size: 17px; 666 - } 667 - 668 - .settings{ 669 - position: fixed; 670 - top: 0; 671 - left: 0; 672 - width: 100%; 673 - height: 100%; 674 - background: rgba(0, 0, 0, 0.4); 675 - backdrop-filter: blur(100px); 676 - -webkit-backdrop-filter: blur(100px); 677 - } 678 - 679 - .slide-bar{ 680 - position: fixed; 681 - bottom: 0; 682 - left: 0; 683 - width: 100%; 684 - height: 50px; 685 - border-top: #aaa 1px solid; 686 - overflow-x: hidden; 687 - mask-image: linear-gradient(to left, #0000 0%, #000 20%, #000 80%, #0000 100%); 688 - background: #aaa2; 689 - box-shadow: #000 0 0 10px; 690 - } 691 - 692 - .inner-slide-bar{ 693 - display: flex; 694 - height: 50px; 695 - width: 200%; 696 - color: white; 697 - align-items: center; 698 - cursor: pointer; 699 - user-select: none; 700 - -webkit-user-select: none; 701 - } 702 - 703 - .slider-dot{ 704 - width: 5px; 705 - height: 5px; 706 - border-radius: 5px; 707 - background: #aaa; 708 - margin: auto 25px; 709 - } 710 - 711 - .slider-text{ 712 - width: 200px; 713 - text-align: center; 714 - height: 50px; 715 - display: flex; 716 - justify-content: center; 717 - align-items: center; 718 - color: #aaa; 719 - transition: 0.25s; 720 - } 721 - 722 - .slider-text:hover{ 723 - color: #fff; 724 - } 725 - 726 - .slide-bar-tri{ 727 - position: fixed; 728 - bottom: 40px; 729 - left: 50%; 730 - transform: translateX(-50%); 731 - border: transparent solid 5px; 732 - border-top: #fff solid 5px; 733 - } 734 - 735 - .settings-container{ 736 - position: fixed; 737 - top: 50px; 738 - left: 0px; 739 - width: 200%; 740 - height: calc(100% - 100px); 741 - display: flex; 742 - } 743 - 744 - .settings-block{ 745 - width: 50%; 746 - height: 100%; 747 - color: white; 748 - text-align: center; 749 - } 750 - 751 - .selector{ 752 - padding: 10px 20px; 753 - border-radius: 10px; 754 - background: #000a; 755 - display: inline-block; 756 - margin: 10px; 757 - } 758 - 759 - .selector .selection-box{ 760 - height: 20px; 761 - background: #777a; 762 - margin: 5px -10px 0 -10px; 763 - border-radius: 8px; 764 - user-select: none; 765 - -webkit-user-select: none; 766 - cursor: pointer; 767 - transition: 0.25s; 768 - color: #fff1; 769 - } 770 - 771 - .selector .selection-box:hover{ 772 - height: 20px; 773 - background: #777a; 774 - margin: 5px -10px 0 -10px; 775 - border-radius: 8px; 776 - user-select: none; 777 - -webkit-user-select: none; 778 - cursor: pointer; 779 - transition: 0.25s; 780 - color: #fff5; 781 - } 782 - 783 - .selector input{ 784 - display: none; 785 - } 786 - 787 - .selector input:checked ~ label .selection-box{ 788 - background: rgba(0, 146, 204, 0.705); 789 - color: #fff; 790 - } 791 - 792 - .path{ 793 - padding: 5px 10px; 794 - background: #000a; 795 - border-radius: 5px; 796 - margin-left: 5px; 797 - cursor: pointer; 798 - } 799 - 800 - .scroll-to-top{ 801 - position: fixed; 802 - bottom: 10px; 803 - right: 10px; 804 - color: white; 805 - width: 40px; 806 - height: 40px; 807 - cursor: pointer; 808 - border-radius: 50%; 809 - border: 2px solid white; 810 - display: flex; 811 - justify-content: center; 812 - align-items: center; 813 - } 814 - 815 - .account-profile{ 816 - margin: auto; 817 - width: 50%; 818 - height: 200px; 819 - display: flex; 820 - } 821 - 822 - .account-pfp{ 823 - width: 200px; 824 - height: 200px; 825 - background-position: center !important; 826 - background-size: cover !important; 827 - border-radius: 50%; 828 - box-shadow: #0005 0 0 10px; 829 - position: relative; 830 - z-index: 10; 831 - } 832 - 833 - .account-desc{ 834 - width: calc(100% - 200px); 835 - padding-left: 100px; 836 - height: 150px; 837 - margin: 25px 0; 838 - margin-left: -100px; 839 - background: #0009; 840 - border-radius: 10px; 841 - box-shadow: #0005 0 0 10px; 842 - } 843 - 844 - .storage-bar{ 845 - width: calc(100% - 20px); 846 - height: 10px; 847 - margin-left: 10px; 848 - background: #555; 849 - border-radius: 10px; 850 - display: flex; 851 - justify-content: left; 852 - align-items: center; 853 - margin-bottom: 2px; 854 - } 855 - 856 - .storage-bar-inner{ 857 - margin: 2px; 858 - height: 6px; 859 - background: #00ccff; 860 - border-radius: 10px; 861 - } 862 - 863 - .account-notice{ 864 - background: #0007; 865 - border-radius: 5px; 866 - box-shadow: #0005 0 0 10px; 867 - padding: 10px; 868 - margin: auto; 869 - width: calc(50% - 20px); 870 - margin-top: 25px; 871 98 } 872 99 873 100 img{