+3
-1
changelog
+3
-1
changelog
+1
-1
package.json
+1
-1
package.json
+105
-105
pnpm-lock.yaml
+105
-105
pnpm-lock.yaml
···
27
specifier: ^3.1.13
28
version: 3.1.13
29
animejs:
30
-
specifier: ^3.2.2
31
-
version: 3.2.2
32
solid-js:
33
specifier: ^1.9.9
34
version: 1.9.9
···
284
'@jridgewell/trace-mapping@0.3.30':
285
resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==}
286
287
-
'@rollup/rollup-android-arm-eabi@4.46.2':
288
-
resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==}
289
cpu: [arm]
290
os: [android]
291
292
-
'@rollup/rollup-android-arm64@4.46.2':
293
-
resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==}
294
cpu: [arm64]
295
os: [android]
296
297
-
'@rollup/rollup-darwin-arm64@4.46.2':
298
-
resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==}
299
cpu: [arm64]
300
os: [darwin]
301
302
-
'@rollup/rollup-darwin-x64@4.46.2':
303
-
resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==}
304
cpu: [x64]
305
os: [darwin]
306
307
-
'@rollup/rollup-freebsd-arm64@4.46.2':
308
-
resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==}
309
cpu: [arm64]
310
os: [freebsd]
311
312
-
'@rollup/rollup-freebsd-x64@4.46.2':
313
-
resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==}
314
cpu: [x64]
315
os: [freebsd]
316
317
-
'@rollup/rollup-linux-arm-gnueabihf@4.46.2':
318
-
resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==}
319
cpu: [arm]
320
os: [linux]
321
322
-
'@rollup/rollup-linux-arm-musleabihf@4.46.2':
323
-
resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==}
324
cpu: [arm]
325
os: [linux]
326
327
-
'@rollup/rollup-linux-arm64-gnu@4.46.2':
328
-
resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==}
329
cpu: [arm64]
330
os: [linux]
331
332
-
'@rollup/rollup-linux-arm64-musl@4.46.2':
333
-
resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==}
334
cpu: [arm64]
335
os: [linux]
336
337
-
'@rollup/rollup-linux-loongarch64-gnu@4.46.2':
338
-
resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==}
339
cpu: [loong64]
340
os: [linux]
341
342
-
'@rollup/rollup-linux-ppc64-gnu@4.46.2':
343
-
resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==}
344
cpu: [ppc64]
345
os: [linux]
346
347
-
'@rollup/rollup-linux-riscv64-gnu@4.46.2':
348
-
resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==}
349
cpu: [riscv64]
350
os: [linux]
351
352
-
'@rollup/rollup-linux-riscv64-musl@4.46.2':
353
-
resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==}
354
cpu: [riscv64]
355
os: [linux]
356
357
-
'@rollup/rollup-linux-s390x-gnu@4.46.2':
358
-
resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==}
359
cpu: [s390x]
360
os: [linux]
361
362
-
'@rollup/rollup-linux-x64-gnu@4.46.2':
363
-
resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==}
364
cpu: [x64]
365
os: [linux]
366
367
-
'@rollup/rollup-linux-x64-musl@4.46.2':
368
-
resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==}
369
cpu: [x64]
370
os: [linux]
371
372
-
'@rollup/rollup-win32-arm64-msvc@4.46.2':
373
-
resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==}
374
cpu: [arm64]
375
os: [win32]
376
377
-
'@rollup/rollup-win32-ia32-msvc@4.46.2':
378
-
resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==}
379
cpu: [ia32]
380
os: [win32]
381
382
-
'@rollup/rollup-win32-x64-msvc@4.46.2':
383
-
resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==}
384
cpu: [x64]
385
os: [win32]
386
···
388
resolution: {integrity: sha512-v454Qs3REHc3Za59U+/eSmBsdmF+3NE5+76+lFDaitVqN4ZglDHENDaMARYKGJVZuxiSkzyqG0SeG7lLQjVkPA==}
389
engines: {node: '>= 18.18', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
390
391
-
'@tauri-apps/api@2.7.0':
392
-
resolution: {integrity: sha512-v7fVE8jqBl8xJFOcBafDzXFc8FnicoH3j8o8DNNs0tHuEBmXUDqrCOAzMRX0UkfpwqZLqvrvK0GNQ45DfnoVDg==}
393
394
'@tauri-apps/cli-darwin-arm64@2.0.0-rc.5':
395
resolution: {integrity: sha512-EoduJ5SeMfBKCe7I291JBH+lkrf2E0+mQF1rP+Jq4CjWPer11OeEcUSFtHURB3Z3ItzObQ7ALPulMGhMe6E9rg==}
···
486
'@types/estree@1.0.8':
487
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
488
489
-
animejs@3.2.2:
490
-
resolution: {integrity: sha512-Ao95qWLpDPXXM+WrmwcKbl6uNlC5tjnowlaRYtuVDHHoygjtIPfDUoK9NthrlZsQSKjZXlmji2TrBUAVbiH0LQ==}
491
492
babel-plugin-jsx-dom-expressions@0.40.1:
493
resolution: {integrity: sha512-b4iHuirqK7RgaMzB2Lsl7MqrlDgQtVRSSazyrmx7wB3T759ggGjod5Rkok5MfHjQXhR7tRPmdwoeGPqBnW2KfA==}
···
503
solid-js:
504
optional: true
505
506
-
browserslist@4.25.2:
507
-
resolution: {integrity: sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==}
508
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
509
hasBin: true
510
···
526
supports-color:
527
optional: true
528
529
-
electron-to-chromium@1.5.202:
530
-
resolution: {integrity: sha512-NxbYjRmiHcHXV1Ws3fWUW+SLb62isauajk45LUJ/HgIOkUA7jLZu/X2Iif+X9FBNK8QkF9Zb4Q2mcwXCcY30mg==}
531
532
entities@6.0.1:
533
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
···
599
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
600
engines: {node: ^10 || ^12 || >=14}
601
602
-
rollup@4.46.2:
603
-
resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==}
604
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
605
hasBin: true
606
···
743
dependencies:
744
'@babel/compat-data': 7.28.0
745
'@babel/helper-validator-option': 7.27.1
746
-
browserslist: 4.25.2
747
lru-cache: 5.1.1
748
semver: 6.3.1
749
···
897
'@jridgewell/resolve-uri': 3.1.2
898
'@jridgewell/sourcemap-codec': 1.5.5
899
900
-
'@rollup/rollup-android-arm-eabi@4.46.2':
901
optional: true
902
903
-
'@rollup/rollup-android-arm64@4.46.2':
904
optional: true
905
906
-
'@rollup/rollup-darwin-arm64@4.46.2':
907
optional: true
908
909
-
'@rollup/rollup-darwin-x64@4.46.2':
910
optional: true
911
912
-
'@rollup/rollup-freebsd-arm64@4.46.2':
913
optional: true
914
915
-
'@rollup/rollup-freebsd-x64@4.46.2':
916
optional: true
917
918
-
'@rollup/rollup-linux-arm-gnueabihf@4.46.2':
919
optional: true
920
921
-
'@rollup/rollup-linux-arm-musleabihf@4.46.2':
922
optional: true
923
924
-
'@rollup/rollup-linux-arm64-gnu@4.46.2':
925
optional: true
926
927
-
'@rollup/rollup-linux-arm64-musl@4.46.2':
928
optional: true
929
930
-
'@rollup/rollup-linux-loongarch64-gnu@4.46.2':
931
optional: true
932
933
-
'@rollup/rollup-linux-ppc64-gnu@4.46.2':
934
optional: true
935
936
-
'@rollup/rollup-linux-riscv64-gnu@4.46.2':
937
optional: true
938
939
-
'@rollup/rollup-linux-riscv64-musl@4.46.2':
940
optional: true
941
942
-
'@rollup/rollup-linux-s390x-gnu@4.46.2':
943
optional: true
944
945
-
'@rollup/rollup-linux-x64-gnu@4.46.2':
946
optional: true
947
948
-
'@rollup/rollup-linux-x64-musl@4.46.2':
949
optional: true
950
951
-
'@rollup/rollup-win32-arm64-msvc@4.46.2':
952
optional: true
953
954
-
'@rollup/rollup-win32-ia32-msvc@4.46.2':
955
optional: true
956
957
-
'@rollup/rollup-win32-x64-msvc@4.46.2':
958
optional: true
959
960
'@tauri-apps/api@2.0.0-rc.0': {}
961
962
-
'@tauri-apps/api@2.7.0': {}
963
964
'@tauri-apps/cli-darwin-arm64@2.0.0-rc.5':
965
optional: true
···
1006
1007
'@tauri-apps/plugin-deep-link@2.4.1':
1008
dependencies:
1009
-
'@tauri-apps/api': 2.7.0
1010
1011
'@tauri-apps/plugin-http@2.0.0-rc.1':
1012
dependencies:
1013
-
'@tauri-apps/api': 2.7.0
1014
1015
'@tauri-apps/plugin-process@2.0.0-rc.0':
1016
dependencies:
···
1045
1046
'@types/estree@1.0.8': {}
1047
1048
-
animejs@3.2.2: {}
1049
1050
babel-plugin-jsx-dom-expressions@0.40.1(@babel/core@7.28.3):
1051
dependencies:
···
1064
optionalDependencies:
1065
solid-js: 1.9.9
1066
1067
-
browserslist@4.25.2:
1068
dependencies:
1069
caniuse-lite: 1.0.30001735
1070
-
electron-to-chromium: 1.5.202
1071
node-releases: 2.0.19
1072
-
update-browserslist-db: 1.1.3(browserslist@4.25.2)
1073
1074
caniuse-lite@1.0.30001735: {}
1075
···
1081
dependencies:
1082
ms: 2.1.3
1083
1084
-
electron-to-chromium@1.5.202: {}
1085
1086
entities@6.0.1: {}
1087
···
1154
picocolors: 1.1.1
1155
source-map-js: 1.2.1
1156
1157
-
rollup@4.46.2:
1158
dependencies:
1159
'@types/estree': 1.0.8
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
1181
fsevents: 2.3.3
1182
1183
semver@6.3.1: {}
···
1207
1208
typescript@5.9.2: {}
1209
1210
-
update-browserslist-db@1.1.3(browserslist@4.25.2):
1211
dependencies:
1212
-
browserslist: 4.25.2
1213
escalade: 3.2.0
1214
picocolors: 1.1.1
1215
···
1232
dependencies:
1233
esbuild: 0.21.5
1234
postcss: 8.5.6
1235
-
rollup: 4.46.2
1236
optionalDependencies:
1237
fsevents: 2.3.3
1238
···
27
specifier: ^3.1.13
28
version: 3.1.13
29
animejs:
30
+
specifier: ^4.1.3
31
+
version: 4.1.3
32
solid-js:
33
specifier: ^1.9.9
34
version: 1.9.9
···
284
'@jridgewell/trace-mapping@0.3.30':
285
resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==}
286
287
+
'@rollup/rollup-android-arm-eabi@4.46.3':
288
+
resolution: {integrity: sha512-UmTdvXnLlqQNOCJnyksjPs1G4GqXNGW1LrzCe8+8QoaLhhDeTXYBgJ3k6x61WIhlHX2U+VzEJ55TtIjR/HTySA==}
289
cpu: [arm]
290
os: [android]
291
292
+
'@rollup/rollup-android-arm64@4.46.3':
293
+
resolution: {integrity: sha512-8NoxqLpXm7VyeI0ocidh335D6OKT0UJ6fHdnIxf3+6oOerZZc+O7r+UhvROji6OspyPm+rrIdb1gTXtVIqn+Sg==}
294
cpu: [arm64]
295
os: [android]
296
297
+
'@rollup/rollup-darwin-arm64@4.46.3':
298
+
resolution: {integrity: sha512-csnNavqZVs1+7/hUKtgjMECsNG2cdB8F7XBHP6FfQjqhjF8rzMzb3SLyy/1BG7YSfQ+bG75Ph7DyedbUqwq1rA==}
299
cpu: [arm64]
300
os: [darwin]
301
302
+
'@rollup/rollup-darwin-x64@4.46.3':
303
+
resolution: {integrity: sha512-r2MXNjbuYabSIX5yQqnT8SGSQ26XQc8fmp6UhlYJd95PZJkQD1u82fWP7HqvGUf33IsOC6qsiV+vcuD4SDP6iw==}
304
cpu: [x64]
305
os: [darwin]
306
307
+
'@rollup/rollup-freebsd-arm64@4.46.3':
308
+
resolution: {integrity: sha512-uluObTmgPJDuJh9xqxyr7MV61Imq+0IvVsAlWyvxAaBSNzCcmZlhfYcRhCdMaCsy46ccZa7vtDDripgs9Jkqsw==}
309
cpu: [arm64]
310
os: [freebsd]
311
312
+
'@rollup/rollup-freebsd-x64@4.46.3':
313
+
resolution: {integrity: sha512-AVJXEq9RVHQnejdbFvh1eWEoobohUYN3nqJIPI4mNTMpsyYN01VvcAClxflyk2HIxvLpRcRggpX1m9hkXkpC/A==}
314
cpu: [x64]
315
os: [freebsd]
316
317
+
'@rollup/rollup-linux-arm-gnueabihf@4.46.3':
318
+
resolution: {integrity: sha512-byyflM+huiwHlKi7VHLAYTKr67X199+V+mt1iRgJenAI594vcmGGddWlu6eHujmcdl6TqSNnvqaXJqZdnEWRGA==}
319
cpu: [arm]
320
os: [linux]
321
322
+
'@rollup/rollup-linux-arm-musleabihf@4.46.3':
323
+
resolution: {integrity: sha512-aLm3NMIjr4Y9LklrH5cu7yybBqoVCdr4Nvnm8WB7PKCn34fMCGypVNpGK0JQWdPAzR/FnoEoFtlRqZbBBLhVoQ==}
324
cpu: [arm]
325
os: [linux]
326
327
+
'@rollup/rollup-linux-arm64-gnu@4.46.3':
328
+
resolution: {integrity: sha512-VtilE6eznJRDIoFOzaagQodUksTEfLIsvXymS+UdJiSXrPW7Ai+WG4uapAc3F7Hgs791TwdGh4xyOzbuzIZrnw==}
329
cpu: [arm64]
330
os: [linux]
331
332
+
'@rollup/rollup-linux-arm64-musl@4.46.3':
333
+
resolution: {integrity: sha512-dG3JuS6+cRAL0GQ925Vppafi0qwZnkHdPeuZIxIPXqkCLP02l7ka+OCyBoDEv8S+nKHxfjvjW4OZ7hTdHkx8/w==}
334
cpu: [arm64]
335
os: [linux]
336
337
+
'@rollup/rollup-linux-loongarch64-gnu@4.46.3':
338
+
resolution: {integrity: sha512-iU8DxnxEKJptf8Vcx4XvAUdpkZfaz0KWfRrnIRrOndL0SvzEte+MTM7nDH4A2Now4FvTZ01yFAgj6TX/mZl8hQ==}
339
cpu: [loong64]
340
os: [linux]
341
342
+
'@rollup/rollup-linux-ppc64-gnu@4.46.3':
343
+
resolution: {integrity: sha512-VrQZp9tkk0yozJoQvQcqlWiqaPnLM6uY1qPYXvukKePb0fqaiQtOdMJSxNFUZFsGw5oA5vvVokjHrx8a9Qsz2A==}
344
cpu: [ppc64]
345
os: [linux]
346
347
+
'@rollup/rollup-linux-riscv64-gnu@4.46.3':
348
+
resolution: {integrity: sha512-uf2eucWSUb+M7b0poZ/08LsbcRgaDYL8NCGjUeFMwCWFwOuFcZ8D9ayPl25P3pl+D2FH45EbHdfyUesQ2Lt9wA==}
349
cpu: [riscv64]
350
os: [linux]
351
352
+
'@rollup/rollup-linux-riscv64-musl@4.46.3':
353
+
resolution: {integrity: sha512-7tnUcDvN8DHm/9ra+/nF7lLzYHDeODKKKrh6JmZejbh1FnCNZS8zMkZY5J4sEipy2OW1d1Ncc4gNHUd0DLqkSg==}
354
cpu: [riscv64]
355
os: [linux]
356
357
+
'@rollup/rollup-linux-s390x-gnu@4.46.3':
358
+
resolution: {integrity: sha512-MUpAOallJim8CsJK+4Lc9tQzlfPbHxWDrGXZm2z6biaadNpvh3a5ewcdat478W+tXDoUiHwErX/dOql7ETcLqg==}
359
cpu: [s390x]
360
os: [linux]
361
362
+
'@rollup/rollup-linux-x64-gnu@4.46.3':
363
+
resolution: {integrity: sha512-F42IgZI4JicE2vM2PWCe0N5mR5vR0gIdORPqhGQ32/u1S1v3kLtbZ0C/mi9FFk7C5T0PgdeyWEPajPjaUpyoKg==}
364
cpu: [x64]
365
os: [linux]
366
367
+
'@rollup/rollup-linux-x64-musl@4.46.3':
368
+
resolution: {integrity: sha512-oLc+JrwwvbimJUInzx56Q3ujL3Kkhxehg7O1gWAYzm8hImCd5ld1F2Gry5YDjR21MNb5WCKhC9hXgU7rRlyegQ==}
369
cpu: [x64]
370
os: [linux]
371
372
+
'@rollup/rollup-win32-arm64-msvc@4.46.3':
373
+
resolution: {integrity: sha512-lOrQ+BVRstruD1fkWg9yjmumhowR0oLAAzavB7yFSaGltY8klttmZtCLvOXCmGE9mLIn8IBV/IFrQOWz5xbFPg==}
374
cpu: [arm64]
375
os: [win32]
376
377
+
'@rollup/rollup-win32-ia32-msvc@4.46.3':
378
+
resolution: {integrity: sha512-vvrVKPRS4GduGR7VMH8EylCBqsDcw6U+/0nPDuIjXQRbHJc6xOBj+frx8ksfZAh6+Fptw5wHrN7etlMmQnPQVg==}
379
cpu: [ia32]
380
os: [win32]
381
382
+
'@rollup/rollup-win32-x64-msvc@4.46.3':
383
+
resolution: {integrity: sha512-fi3cPxCnu3ZeM3EwKZPgXbWoGzm2XHgB/WShKI81uj8wG0+laobmqy5wbgEwzstlbLu4MyO8C19FyhhWseYKNQ==}
384
cpu: [x64]
385
os: [win32]
386
···
388
resolution: {integrity: sha512-v454Qs3REHc3Za59U+/eSmBsdmF+3NE5+76+lFDaitVqN4ZglDHENDaMARYKGJVZuxiSkzyqG0SeG7lLQjVkPA==}
389
engines: {node: '>= 18.18', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
390
391
+
'@tauri-apps/api@2.8.0':
392
+
resolution: {integrity: sha512-ga7zdhbS2GXOMTIZRT0mYjKJtR9fivsXzsyq5U3vjDL0s6DTMwYRm0UHNjzTY5dh4+LSC68Sm/7WEiimbQNYlw==}
393
394
'@tauri-apps/cli-darwin-arm64@2.0.0-rc.5':
395
resolution: {integrity: sha512-EoduJ5SeMfBKCe7I291JBH+lkrf2E0+mQF1rP+Jq4CjWPer11OeEcUSFtHURB3Z3ItzObQ7ALPulMGhMe6E9rg==}
···
486
'@types/estree@1.0.8':
487
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
488
489
+
animejs@4.1.3:
490
+
resolution: {integrity: sha512-4XzlIsQsku1ycSPzchxxT0N+ohEMZObG71nOSBBkZoV4sgQvtXa/qAANkFpTE6pegdV8JnIBZiB0LfdxNoRNMw==}
491
492
babel-plugin-jsx-dom-expressions@0.40.1:
493
resolution: {integrity: sha512-b4iHuirqK7RgaMzB2Lsl7MqrlDgQtVRSSazyrmx7wB3T759ggGjod5Rkok5MfHjQXhR7tRPmdwoeGPqBnW2KfA==}
···
503
solid-js:
504
optional: true
505
506
+
browserslist@4.25.3:
507
+
resolution: {integrity: sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==}
508
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
509
hasBin: true
510
···
526
supports-color:
527
optional: true
528
529
+
electron-to-chromium@1.5.207:
530
+
resolution: {integrity: sha512-mryFrrL/GXDTmAtIVMVf+eIXM09BBPlO5IQ7lUyKmK8d+A4VpRGG+M3ofoVef6qyF8s60rJei8ymlJxjUA8Faw==}
531
532
entities@6.0.1:
533
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
···
599
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
600
engines: {node: ^10 || ^12 || >=14}
601
602
+
rollup@4.46.3:
603
+
resolution: {integrity: sha512-RZn2XTjXb8t5g13f5YclGoilU/kwT696DIkY3sywjdZidNSi3+vseaQov7D7BZXVJCPv3pDWUN69C78GGbXsKw==}
604
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
605
hasBin: true
606
···
743
dependencies:
744
'@babel/compat-data': 7.28.0
745
'@babel/helper-validator-option': 7.27.1
746
+
browserslist: 4.25.3
747
lru-cache: 5.1.1
748
semver: 6.3.1
749
···
897
'@jridgewell/resolve-uri': 3.1.2
898
'@jridgewell/sourcemap-codec': 1.5.5
899
900
+
'@rollup/rollup-android-arm-eabi@4.46.3':
901
optional: true
902
903
+
'@rollup/rollup-android-arm64@4.46.3':
904
optional: true
905
906
+
'@rollup/rollup-darwin-arm64@4.46.3':
907
optional: true
908
909
+
'@rollup/rollup-darwin-x64@4.46.3':
910
optional: true
911
912
+
'@rollup/rollup-freebsd-arm64@4.46.3':
913
optional: true
914
915
+
'@rollup/rollup-freebsd-x64@4.46.3':
916
optional: true
917
918
+
'@rollup/rollup-linux-arm-gnueabihf@4.46.3':
919
optional: true
920
921
+
'@rollup/rollup-linux-arm-musleabihf@4.46.3':
922
optional: true
923
924
+
'@rollup/rollup-linux-arm64-gnu@4.46.3':
925
optional: true
926
927
+
'@rollup/rollup-linux-arm64-musl@4.46.3':
928
optional: true
929
930
+
'@rollup/rollup-linux-loongarch64-gnu@4.46.3':
931
optional: true
932
933
+
'@rollup/rollup-linux-ppc64-gnu@4.46.3':
934
optional: true
935
936
+
'@rollup/rollup-linux-riscv64-gnu@4.46.3':
937
optional: true
938
939
+
'@rollup/rollup-linux-riscv64-musl@4.46.3':
940
optional: true
941
942
+
'@rollup/rollup-linux-s390x-gnu@4.46.3':
943
optional: true
944
945
+
'@rollup/rollup-linux-x64-gnu@4.46.3':
946
optional: true
947
948
+
'@rollup/rollup-linux-x64-musl@4.46.3':
949
optional: true
950
951
+
'@rollup/rollup-win32-arm64-msvc@4.46.3':
952
optional: true
953
954
+
'@rollup/rollup-win32-ia32-msvc@4.46.3':
955
optional: true
956
957
+
'@rollup/rollup-win32-x64-msvc@4.46.3':
958
optional: true
959
960
'@tauri-apps/api@2.0.0-rc.0': {}
961
962
+
'@tauri-apps/api@2.8.0': {}
963
964
'@tauri-apps/cli-darwin-arm64@2.0.0-rc.5':
965
optional: true
···
1006
1007
'@tauri-apps/plugin-deep-link@2.4.1':
1008
dependencies:
1009
+
'@tauri-apps/api': 2.8.0
1010
1011
'@tauri-apps/plugin-http@2.0.0-rc.1':
1012
dependencies:
1013
+
'@tauri-apps/api': 2.8.0
1014
1015
'@tauri-apps/plugin-process@2.0.0-rc.0':
1016
dependencies:
···
1045
1046
'@types/estree@1.0.8': {}
1047
1048
+
animejs@4.1.3: {}
1049
1050
babel-plugin-jsx-dom-expressions@0.40.1(@babel/core@7.28.3):
1051
dependencies:
···
1064
optionalDependencies:
1065
solid-js: 1.9.9
1066
1067
+
browserslist@4.25.3:
1068
dependencies:
1069
caniuse-lite: 1.0.30001735
1070
+
electron-to-chromium: 1.5.207
1071
node-releases: 2.0.19
1072
+
update-browserslist-db: 1.1.3(browserslist@4.25.3)
1073
1074
caniuse-lite@1.0.30001735: {}
1075
···
1081
dependencies:
1082
ms: 2.1.3
1083
1084
+
electron-to-chromium@1.5.207: {}
1085
1086
entities@6.0.1: {}
1087
···
1154
picocolors: 1.1.1
1155
source-map-js: 1.2.1
1156
1157
+
rollup@4.46.3:
1158
dependencies:
1159
'@types/estree': 1.0.8
1160
optionalDependencies:
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
fsevents: 2.3.3
1182
1183
semver@6.3.1: {}
···
1207
1208
typescript@5.9.2: {}
1209
1210
+
update-browserslist-db@1.1.3(browserslist@4.25.3):
1211
dependencies:
1212
+
browserslist: 4.25.3
1213
escalade: 3.2.0
1214
picocolors: 1.1.1
1215
···
1232
dependencies:
1233
esbuild: 0.21.5
1234
postcss: 8.5.6
1235
+
rollup: 4.46.3
1236
optionalDependencies:
1237
fsevents: 2.3.3
1238
+1
public/icon/gear-solid-full.svg
+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
+1
-1
src-tauri/tauri.conf.json
+2
-5
src/Components/App.tsx
+2
-5
src/Components/App.tsx
···
1
import { onMount } from "solid-js";
2
-
import anime from "animejs";
3
4
-
import NavBar from "./NavBar";
5
import PhotoList from "./PhotoList";
6
import PhotoViewer from "./PhotoViewer";
7
import SettingsMenu from "./SettingsMenu";
8
9
let App = () => {
10
onMount(() => {
11
-
anime.set('.settings',
12
{
13
display: 'none',
14
opacity: 0,
···
18
19
return (
20
<div class="container">
21
-
<NavBar />
22
-
23
<PhotoList />
24
<PhotoViewer />
25
···
1
import { onMount } from "solid-js";
2
3
import PhotoList from "./PhotoList";
4
import PhotoViewer from "./PhotoViewer";
5
import SettingsMenu from "./SettingsMenu";
6
+
import { utils } from "animejs";
7
8
let App = () => {
9
onMount(() => {
10
+
utils.set('.settings',
11
{
12
display: 'none',
13
opacity: 0,
···
17
18
return (
19
<div class="container">
20
<PhotoList />
21
<PhotoViewer />
22
+1
-1
src/Components/Managers/PhotoListRenderingManager.tsx
+1
-1
src/Components/Managers/PhotoListRenderingManager.tsx
+12
-3
src/Components/Managers/PhotoManager.tsx
+12
-3
src/Components/Managers/PhotoManager.tsx
···
170
171
switch(this._filterType){
172
case FilterType.USER:
173
this.Photos.map(p => {
174
if(p.metadata){
175
try{
176
let meta = JSON.parse(p.metadata);
177
-
let photo = meta.players.find(( y: any ) => y.displayName.toLowerCase().includes(this._filter) || y.id === this._filter);
178
179
if(photo)this.FilteredPhotos.push(p);
180
} catch(e){}
···
182
})
183
break;
184
case FilterType.WORLD:
185
this.Photos.map(p => {
186
if(p.metadata){
187
try{
188
let meta = JSON.parse(p.metadata);
189
-
let photo = meta.world.name.toLowerCase().includes(this._filter) || meta.world.id === this._filter;
190
-
191
if(photo)this.FilteredPhotos.push(p);
192
} catch(e){}
193
}
···
170
171
switch(this._filterType){
172
case FilterType.USER:
173
+
if(this._filter === '')return this.FilteredPhotos = this.Photos;
174
+
175
this.Photos.map(p => {
176
if(p.metadata){
177
try{
178
let meta = JSON.parse(p.metadata);
179
+
let photo = meta.players.find(( y: any ) =>
180
+
y.displayName.toLowerCase().includes(this._filter) ||
181
+
y.id === this._filter
182
+
);
183
184
if(photo)this.FilteredPhotos.push(p);
185
} catch(e){}
···
187
})
188
break;
189
case FilterType.WORLD:
190
+
if(this._filter === '')return this.FilteredPhotos = this.Photos;
191
+
192
this.Photos.map(p => {
193
if(p.metadata){
194
try{
195
let meta = JSON.parse(p.metadata);
196
+
let photo =
197
+
meta.world.name.toLowerCase().includes(this._filter) ||
198
+
meta.world.id === this._filter;
199
+
200
if(photo)this.FilteredPhotos.push(p);
201
} catch(e){}
202
}
+51
-72
src/Components/PhotoList.tsx
+51
-72
src/Components/PhotoList.tsx
···
2
import { listen } from '@tauri-apps/api/event';
3
import { Window } from "@tauri-apps/api/window";
4
5
-
import anime from "animejs";
6
import FilterMenu from "./FilterMenu";
7
import { ViewState } from "./Managers/ViewManager";
8
import { invoke } from "@tauri-apps/api/core";
9
10
enum ListPopup{
11
FILTERS,
···
13
}
14
15
let PhotoList = () => {
16
-
let photoTreeLoadingContainer: HTMLElement;
17
-
18
let scrollToTop: HTMLElement;
19
let scrollToTopActive = false;
20
21
let photoContainer: HTMLCanvasElement;
22
-
let photoContainerBG: HTMLCanvasElement;
23
24
let filterContainer: HTMLDivElement;
25
26
let ctx: CanvasRenderingContext2D;
27
-
let ctxBG: CanvasRenderingContext2D;
28
29
let scroll: number = 0;
30
let targetScroll: number = 0;
···
39
40
41
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 });
45
});
46
47
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 });
51
});
52
53
54
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 });
58
});
59
60
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 });
64
});
65
66
···
74
photoContainer.width = window.innerWidth;
75
photoContainer.height = window.innerHeight;
76
77
-
photoContainerBG.width = window.innerWidth;
78
-
photoContainerBG.height = window.innerHeight;
79
-
80
window.PhotoListRenderingManager.ComputeLayout();
81
}
82
83
let closeCurrentPopup = () => {
84
switch(currentPopup){
85
case ListPopup.FILTERS:
86
-
anime({
87
-
targets: filterContainer!,
88
opacity: 0,
89
easing: 'easeInOutQuad',
90
duration: 100,
91
-
complete: () => {
92
filterContainer!.style.display = 'none';
93
currentPopup = ListPopup.NONE;
94
}
···
98
}
99
}
100
101
-
let fps = 0;
102
-
setInterval(() => {
103
-
console.log('FPS: ' + fps);
104
-
fps = 0;
105
-
}, 1000);
106
-
107
let render = () => {
108
if(!quitRender)
109
requestAnimationFrame(render);
···
112
113
if(!scrollToTopActive && scroll > photoContainer.height){
114
scrollToTop.style.display = 'flex';
115
-
anime({ targets: scrollToTop, opacity: 1, translateY: '0px', easing: 'easeInOutQuad', duration: 100 });
116
117
scrollToTopActive = true;
118
} else if(scrollToTopActive && scroll < photoContainer.height){
119
-
anime({ targets: scrollToTop, opacity: 0, translateY: '-10px', complete: () => scrollToTop.style.display = 'none', easing: 'easeInOutQuad', duration: 100 });
120
scrollToTopActive = false;
121
}
122
123
-
if(!ctx || !ctxBG)return;
124
ctx.clearRect(0, 0, photoContainer.width, photoContainer.height);
125
-
ctxBG.clearRect(0, 0, photoContainerBG.width, photoContainerBG.height);
126
127
scroll = scroll + (targetScroll - scroll) * 0.1;
128
···
137
138
ctx.fillText("It's looking empty in here! You have no photos :O", photoContainer.width / 2, photoContainer.height / 2);
139
}
140
-
141
-
ctxBG.drawImage(photoContainer, 0, 0);
142
-
fps += 1;
143
}
144
145
listen('hide-window', () => {
···
154
photoContainer.width = window.innerWidth;
155
photoContainer.height = window.innerHeight;
156
157
-
photoContainerBG.width = window.innerWidth;
158
-
photoContainerBG.height = window.innerHeight;
159
-
160
if(window.PhotoManager.HasFirstLoaded){
161
requestAnimationFrame(render);
162
window.PhotoManager.HasFirstLoaded = false;
···
166
window.PhotoManager.OnLoadingFinished(() => {
167
invoke('close_splashscreen');
168
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',
182
opacity: 1,
183
duration: 150,
184
easing: 'easeInOutQuad'
···
192
193
onMount(() => {
194
ctx = photoContainer.getContext('2d')!;
195
-
ctxBG = photoContainerBG.getContext('2d')!;
196
197
window.PhotoManager.Load();
198
199
-
anime.set(scrollToTop, { opacity: 0, translateY: '-10px', display: 'none' });
200
201
photoContainer.onwheel = ( e: WheelEvent ) => {
202
targetScroll += e.deltaY * 2;
···
210
211
photoContainer.width = window.innerWidth;
212
photoContainer.height = window.innerHeight;
213
-
214
-
photoContainerBG.width = window.innerWidth;
215
-
photoContainerBG.height = window.innerHeight;
216
217
photoContainer.onclick = ( e: MouseEvent ) => {
218
let photo = window.PhotoManager.FilteredPhotos.find(x =>
···
240
241
return (
242
<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
-
}}>
247
<FilterMenu />
248
</div>
249
-
250
-
<div class="photo-tree-loading" ref={( el ) => photoTreeLoadingContainer = el}>Scanning Photo Tree...</div>
251
252
<div class="scroll-to-top" ref={( el ) => scrollToTop = el} onClick={() => targetScroll = 0}>
253
<div class="icon">
254
<img draggable="false" src="/icon/angle-up-solid.svg"></img>
255
</div>
256
</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
263
<div class="filter-options">
264
<div>
···
268
269
filterContainer!.style.display = 'block';
270
271
-
anime({
272
-
targets: filterContainer!,
273
opacity: 1,
274
easing: 'easeInOutQuad',
275
duration: 100
276
});
277
-
}} class="icon" style={{ width: '20px', height: '20px', padding: '20px' }}>
278
<img draggable="false" style={{ width: "20px", height: "20px" }} src="/icon/sliders-solid.svg"></img>
279
</div>
280
<div class="icon-label">Filters</div>
281
</div>
282
</div>
283
284
<canvas class="photo-container" ref={( el ) => photoContainer = el}></canvas>
285
-
<canvas class="photo-container-bg" ref={( el ) => photoContainerBG = el}></canvas>
286
</div>
287
)
288
}
···
2
import { listen } from '@tauri-apps/api/event';
3
import { Window } from "@tauri-apps/api/window";
4
5
import FilterMenu from "./FilterMenu";
6
import { ViewState } from "./Managers/ViewManager";
7
import { invoke } from "@tauri-apps/api/core";
8
+
import { animate, utils } from "animejs";
9
10
enum ListPopup{
11
FILTERS,
···
13
}
14
15
let PhotoList = () => {
16
let scrollToTop: HTMLElement;
17
let scrollToTopActive = false;
18
19
let photoContainer: HTMLCanvasElement;
20
21
let filterContainer: HTMLDivElement;
22
23
let ctx: CanvasRenderingContext2D;
24
25
let scroll: number = 0;
26
let targetScroll: number = 0;
···
35
36
37
window.ViewManager.OnStateTransition(ViewState.PHOTO_LIST, ViewState.SETTINGS, () => {
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 });
41
});
42
43
window.ViewManager.OnStateTransition(ViewState.SETTINGS, ViewState.PHOTO_LIST, () => {
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 });
47
});
48
49
50
window.ViewManager.OnStateTransition(ViewState.PHOTO_LIST, ViewState.PHOTO_VIEWER, () => {
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 });
54
});
55
56
window.ViewManager.OnStateTransition(ViewState.PHOTO_VIEWER, ViewState.PHOTO_LIST, () => {
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 });
60
});
61
62
···
70
photoContainer.width = window.innerWidth;
71
photoContainer.height = window.innerHeight;
72
73
window.PhotoListRenderingManager.ComputeLayout();
74
}
75
76
let closeCurrentPopup = () => {
77
switch(currentPopup){
78
case ListPopup.FILTERS:
79
+
animate(filterContainer!, {
80
opacity: 0,
81
+
translateY: '10px',
82
easing: 'easeInOutQuad',
83
duration: 100,
84
+
onComplete: () => {
85
filterContainer!.style.display = 'none';
86
currentPopup = ListPopup.NONE;
87
}
···
91
}
92
}
93
94
let render = () => {
95
if(!quitRender)
96
requestAnimationFrame(render);
···
99
100
if(!scrollToTopActive && scroll > photoContainer.height){
101
scrollToTop.style.display = 'flex';
102
+
animate(scrollToTop, { opacity: 1, translateY: '0px', easing: 'easeInOutQuad', duration: 100 });
103
104
scrollToTopActive = true;
105
} else if(scrollToTopActive && scroll < photoContainer.height){
106
+
animate(scrollToTop, { opacity: 0, translateY: '-10px', complete: () => scrollToTop.style.display = 'none', easing: 'easeInOutQuad', duration: 100 });
107
scrollToTopActive = false;
108
}
109
110
+
if(!ctx)return;
111
ctx.clearRect(0, 0, photoContainer.width, photoContainer.height);
112
113
scroll = scroll + (targetScroll - scroll) * 0.1;
114
···
123
124
ctx.fillText("It's looking empty in here! You have no photos :O", photoContainer.width / 2, photoContainer.height / 2);
125
}
126
}
127
128
listen('hide-window', () => {
···
137
photoContainer.width = window.innerWidth;
138
photoContainer.height = window.innerHeight;
139
140
if(window.PhotoManager.HasFirstLoaded){
141
requestAnimationFrame(render);
142
window.PhotoManager.HasFirstLoaded = false;
···
146
window.PhotoManager.OnLoadingFinished(() => {
147
invoke('close_splashscreen');
148
149
+
animate('.reload-photos', {
150
opacity: 1,
151
duration: 150,
152
easing: 'easeInOutQuad'
···
160
161
onMount(() => {
162
ctx = photoContainer.getContext('2d')!;
163
164
window.PhotoManager.Load();
165
166
+
utils.set(scrollToTop, { opacity: 0, translateY: '-10px', display: 'none' });
167
168
photoContainer.onwheel = ( e: WheelEvent ) => {
169
targetScroll += e.deltaY * 2;
···
177
178
photoContainer.width = window.innerWidth;
179
photoContainer.height = window.innerHeight;
180
181
photoContainer.onclick = ( e: MouseEvent ) => {
182
let photo = window.PhotoManager.FilteredPhotos.find(x =>
···
204
205
return (
206
<div class="photo-list">
207
+
<div ref={filterContainer!} class="filter-container">
208
<FilterMenu />
209
</div>
210
211
<div class="scroll-to-top" ref={( el ) => scrollToTop = el} onClick={() => targetScroll = 0}>
212
<div class="icon">
213
<img draggable="false" src="/icon/angle-up-solid.svg"></img>
214
</div>
215
</div>
216
217
<div class="filter-options">
218
<div>
···
222
223
filterContainer!.style.display = 'block';
224
225
+
animate(filterContainer!, {
226
opacity: 1,
227
+
translateY: 0,
228
easing: 'easeInOutQuad',
229
duration: 100
230
});
231
+
}} class="icon">
232
<img draggable="false" style={{ width: "20px", height: "20px" }} src="/icon/sliders-solid.svg"></img>
233
</div>
234
<div class="icon-label">Filters</div>
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>
262
</div>
263
264
<canvas class="photo-container" ref={( el ) => photoContainer = el}></canvas>
265
</div>
266
)
267
}
+64
-81
src/Components/PhotoViewer.tsx
+64
-81
src/Components/PhotoViewer.tsx
···
1
import { For, Show, createEffect, onCleanup, onMount } from "solid-js";
2
import { invoke } from '@tauri-apps/api/core';
3
-
import anime from 'animejs';
4
import { WorldCache } from "./Structs/WorldCache";
5
6
let PhotoViewer = () => {
7
let viewer: HTMLElement;
···
21
let viewerContextMenuButtons: HTMLElement[] = [];
22
23
let allowedToOpenTray = false;
24
-
let trayInAnimation = false;
25
26
let authorProfileButton: HTMLDivElement;
27
···
52
}
53
}
54
55
let openTray = () => {
56
-
if(trayOpen || trayInAnimation)return;
57
58
-
trayOpen = true;
59
-
trayInAnimation = true;
60
61
window.CloseAllPopups.forEach(p => p());
62
-
anime({ targets: photoTray, bottom: '0px', duration: 500 });
63
64
-
anime({
65
-
targets: photoControls,
66
bottom: '160px',
67
scale: '0.75',
68
opacity: 0,
69
duration: 500,
70
-
complete: () => {
71
photoControls.style.display = 'none';
72
-
trayInAnimation = false;
73
}
74
});
75
76
photoTrayCloseBtn.style.display = 'flex';
77
-
anime({
78
-
targets: photoTrayCloseBtn,
79
bottom: '160px',
80
opacity: 1,
81
scale: 1,
82
duration: 500
···
86
let copyImage = () => {
87
invoke('copy_image', { path: window.PhotoViewerManager.CurrentPhoto()!.path })
88
.then(() => {
89
-
anime.set('.copy-notif', { translateX: '-50%', translateY: '-100px' });
90
-
anime({
91
-
targets: '.copy-notif',
92
opacity: 1,
93
translateY: '0px'
94
});
95
96
setTimeout(() => {
97
-
anime({
98
-
targets: '.copy-notif',
99
opacity: 0,
100
translateY: '-100px'
101
});
···
104
}
105
106
let closeTray = () => {
107
-
if(!trayOpen || trayInAnimation)return;
108
-
trayInAnimation = true;
109
110
window.CloseAllPopups.forEach(p => p());
111
-
anime({ targets: photoTray, bottom: '-150px', duration: 500 });
112
113
-
anime({
114
-
targets: photoTrayCloseBtn,
115
bottom: '10px',
116
scale: '0.75',
117
opacity: 0,
118
duration: 500,
119
-
complete: () => {
120
photoTrayCloseBtn.style.display = 'none';
121
-
trayOpen = false;
122
-
trayInAnimation = false;
123
}
124
});
125
126
photoControls.style.display = 'flex';
127
-
anime({
128
-
targets: photoControls,
129
bottom: '10px',
130
opacity: 1,
131
scale: 1,
132
duration: 500,
···
134
}
135
136
onMount(() => {
137
-
anime.set(photoControls, { translateX: '-50%' });
138
-
anime.set(photoTrayCloseBtn, { translateX: '-50%', opacity: 0, scale: '0.75', bottom: '10px' });
139
140
window.addEventListener('keyup', switchPhotoWithKey);
141
142
let contextMenuOpen = false;
143
window.CloseAllPopups.push(() => {
144
contextMenuOpen = false;
145
-
anime.set(viewerContextMenu, { opacity: 1, rotate: '0deg' });
146
147
-
anime({
148
-
targets: viewerContextMenu,
149
opacity: 0,
150
easing: 'easeInOutQuad',
151
rotate: '30deg',
152
duration: 100,
153
-
complete: () => {
154
viewerContextMenu.style.display = 'none';
155
}
156
})
···
174
if(contextMenuOpen){
175
contextMenuOpen = false;
176
177
-
anime.set(viewerContextMenu, { opacity: 1, rotate: '0deg' });
178
179
-
anime({
180
-
targets: viewerContextMenu,
181
opacity: 0,
182
rotate: '30deg',
183
easing: 'easeInOutQuad',
184
duration: 100,
185
-
complete: () => {
186
viewerContextMenu.style.display = 'none';
187
}
188
})
···
193
viewerContextMenu.style.left = e.clientX + 'px';
194
viewerContextMenu.style.display = 'block';
195
196
-
anime.set(viewerContextMenu, { opacity: 0, rotate: '-30deg' });
197
198
-
anime({
199
-
targets: viewerContextMenu,
200
opacity: 1,
201
rotate: '0deg',
202
easing: 'easeInOutQuad',
···
215
imageViewer.src = (window.OS === "windows" ? "http://photo.localhost/" : 'photo://localhost/') + window.PhotoViewerManager.CurrentPhoto()?.path.split('\\').join('/') + "?full";
216
imageViewer.crossOrigin = 'anonymous';
217
218
-
anime({
219
-
targets: imageViewer,
220
opacity: 1,
221
delay: 50,
222
duration: 150,
···
300
if(photo && !isOpen){
301
viewer.style.display = 'flex';
302
303
-
anime({
304
-
targets: viewer,
305
opacity: 1,
306
easing: 'easeInOutQuad',
307
duration: 150
308
});
309
-
310
-
anime({
311
-
targets: '.navbar',
312
-
top: '-50px'
313
-
})
314
315
-
anime.set('.prev-button', { left: '-50px', top: '50%' });
316
-
anime.set('.next-button', { right: '-50px', top: '50%' });
317
318
-
anime({ targets: '.prev-button', left: '0', easing: 'easeInOutQuad', duration: 100 });
319
-
anime({ targets: '.next-button', right: '0', easing: 'easeInOutQuad', duration: 100 });
320
321
window.CloseAllPopups.forEach(p => p());
322
} else if(!photo && isOpen){
323
-
anime({
324
-
targets: viewer,
325
opacity: 0,
326
easing: 'easeInOutQuad',
327
duration: 150,
328
-
complete: () => {
329
viewer.style.display = 'none';
330
}
331
});
332
-
333
-
anime({
334
-
targets: '.navbar',
335
-
top: '0px'
336
-
})
337
338
window.CloseAllPopups.forEach(p => p());
339
340
-
anime({ targets: '.prev-button', top: '75%', easing: 'easeInOutQuad', duration: 100 });
341
-
anime({ targets: '.next-button', top: '75%', easing: 'easeInOutQuad', duration: 100 });
342
}
343
344
isOpen = photo != null;
···
387
</div>
388
389
<div class="viewer-close viewer-button" onClick={() => window.PhotoViewerManager.Close()}>
390
-
<div class="icon" style={{ width: '10px', margin: '0' }}>
391
<img draggable="false" src="/icon/x-solid.svg"></img>
392
</div>
393
</div>
···
397
window.CloseAllPopups.forEach(p => p());
398
window.PhotoViewerManager.PreviousPhoto();
399
}}>
400
-
<div class="icon" style={{ width: '15px', margin: '0' }}>
401
<img draggable="false" src="/icon/arrow-left-solid.svg"></img>
402
</div>
403
</div>
···
406
window.CloseAllPopups.forEach(p => p());
407
window.PhotoViewerManager.NextPhoto();
408
}}>
409
-
<div class="icon" style={{ width: '15px', margin: '0' }}>
410
<img draggable="false" src="/icon/arrow-right-solid.svg"></img>
411
</div>
412
</div>
···
417
onClick={() => closeTray()}
418
ref={( el ) => photoTrayCloseBtn = el}
419
>
420
-
<div class="icon" style={{ width: '12px', margin: '0' }}>
421
<img draggable="false" src="/icon/angle-down-solid.svg"></img>
422
</div>
423
</div>
424
425
<div class="control-buttons" ref={( el ) => photoControls = el}>
426
<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' })}
429
onClick={() => { copyImage(); }}>
430
-
<div class="icon" style={{ width: '12px', margin: '0' }}>
431
<img draggable="false" src="/icon/copy-solid.svg"></img>
432
</div>
433
</div>
434
<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' })}
437
ref={( el ) => trayButton = el}
438
onClick={() => openTray()}
439
>
440
-
<div class="icon" style={{ width: '12px', margin: '0' }}>
441
<img draggable="false" src="/icon/angle-up-solid.svg"></img>
442
</div>
443
</div>
444
445
<div class="viewer-button"
446
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' })}
449
>
450
-
<div class="icon" style={{ width: '12px', margin: '0' }}>
451
<img draggable="false" src="/icon/user-solid.svg"></img>
452
</div>
453
</div>
454
455
<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' })}
458
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",
461
});
462
})}>
463
-
<div class="icon" style={{ width: '12px', margin: '0' }}>
464
<img draggable="false" src="/icon/trash-solid.svg"></img>
465
</div>
466
</div>
···
1
import { For, Show, createEffect, onCleanup, onMount } from "solid-js";
2
import { invoke } from '@tauri-apps/api/core';
3
import { WorldCache } from "./Structs/WorldCache";
4
+
import { animate, JSAnimation, utils } from "animejs";
5
6
let PhotoViewer = () => {
7
let viewer: HTMLElement;
···
21
let viewerContextMenuButtons: HTMLElement[] = [];
22
23
let allowedToOpenTray = false;
24
25
let authorProfileButton: HTMLDivElement;
26
···
51
}
52
}
53
54
+
let trayAnimation: JSAnimation[] = [];
55
+
56
let openTray = () => {
57
+
if(trayOpen)return;
58
+
trayOpen = true;
59
60
+
trayAnimation.forEach(anim => anim.cancel());
61
62
window.CloseAllPopups.forEach(p => p());
63
+
trayAnimation[0] = animate(photoTray, { bottom: '-150px', duration: 500, ease: 'outElastic' });
64
65
+
trayAnimation[1] = animate(photoControls, {
66
bottom: '160px',
67
+
ease: 'outElastic',
68
scale: '0.75',
69
opacity: 0,
70
duration: 500,
71
+
onComplete: () => {
72
photoControls.style.display = 'none';
73
}
74
});
75
76
photoTrayCloseBtn.style.display = 'flex';
77
+
trayAnimation[2] = animate(photoTrayCloseBtn, {
78
bottom: '160px',
79
+
ease: 'outElastic',
80
opacity: 1,
81
scale: 1,
82
duration: 500
···
86
let copyImage = () => {
87
invoke('copy_image', { path: window.PhotoViewerManager.CurrentPhoto()!.path })
88
.then(() => {
89
+
utils.set('.copy-notif', { translateX: '-50%', translateY: '-100px' });
90
+
animate('.copy-notif', {
91
+
ease: 'outElastic',
92
opacity: 1,
93
translateY: '0px'
94
});
95
96
setTimeout(() => {
97
+
animate('.copy-notif', {
98
+
ease: 'outElastic',
99
opacity: 0,
100
translateY: '-100px'
101
});
···
104
}
105
106
let closeTray = () => {
107
+
if(!trayOpen)return;
108
+
trayOpen = false;
109
+
110
+
trayAnimation.forEach(anim => anim.cancel());
111
112
window.CloseAllPopups.forEach(p => p());
113
+
trayAnimation[0] = animate(photoTray, { bottom: '-300px', duration: 500, ease: 'outElastic' });
114
115
+
trayAnimation[2] = animate(photoTrayCloseBtn, {
116
bottom: '10px',
117
scale: '0.75',
118
+
ease: 'outElastic',
119
opacity: 0,
120
duration: 500,
121
+
onComplete: () => {
122
photoTrayCloseBtn.style.display = 'none';
123
}
124
});
125
126
photoControls.style.display = 'flex';
127
+
trayAnimation[1] = animate(photoControls, {
128
bottom: '10px',
129
+
ease: 'outElastic',
130
opacity: 1,
131
scale: 1,
132
duration: 500,
···
134
}
135
136
onMount(() => {
137
+
utils.set(photoControls, { translateX: '-50%' });
138
+
utils.set(photoTrayCloseBtn, { translateX: '-50%', opacity: 0, scale: '0.75', bottom: '10px' });
139
140
window.addEventListener('keyup', switchPhotoWithKey);
141
142
let contextMenuOpen = false;
143
window.CloseAllPopups.push(() => {
144
contextMenuOpen = false;
145
+
utils.set(viewerContextMenu, { opacity: 1, rotate: '0deg' });
146
147
+
animate(viewerContextMenu, {
148
opacity: 0,
149
easing: 'easeInOutQuad',
150
rotate: '30deg',
151
duration: 100,
152
+
onComplete: () => {
153
viewerContextMenu.style.display = 'none';
154
}
155
})
···
173
if(contextMenuOpen){
174
contextMenuOpen = false;
175
176
+
utils.set(viewerContextMenu, { opacity: 1, rotate: '0deg' });
177
178
+
animate(viewerContextMenu, {
179
opacity: 0,
180
rotate: '30deg',
181
easing: 'easeInOutQuad',
182
duration: 100,
183
+
onComplete: () => {
184
viewerContextMenu.style.display = 'none';
185
}
186
})
···
191
viewerContextMenu.style.left = e.clientX + 'px';
192
viewerContextMenu.style.display = 'block';
193
194
+
utils.set(viewerContextMenu, { opacity: 0, rotate: '-30deg' });
195
196
+
animate(viewerContextMenu, {
197
opacity: 1,
198
rotate: '0deg',
199
easing: 'easeInOutQuad',
···
212
imageViewer.src = (window.OS === "windows" ? "http://photo.localhost/" : 'photo://localhost/') + window.PhotoViewerManager.CurrentPhoto()?.path.split('\\').join('/') + "?full";
213
imageViewer.crossOrigin = 'anonymous';
214
215
+
animate(imageViewer, {
216
opacity: 1,
217
delay: 50,
218
duration: 150,
···
296
if(photo && !isOpen){
297
viewer.style.display = 'flex';
298
299
+
animate(viewer, {
300
opacity: 1,
301
easing: 'easeInOutQuad',
302
duration: 150
303
});
304
305
+
utils.set('.prev-button', { left: '-50px', top: '50%' });
306
+
utils.set('.next-button', { right: '-50px', top: '50%' });
307
308
+
animate('.prev-button', { left: '0', easing: 'easeInOutQuad', duration: 100 });
309
+
animate('.next-button', { right: '0', easing: 'easeInOutQuad', duration: 100 });
310
311
window.CloseAllPopups.forEach(p => p());
312
} else if(!photo && isOpen){
313
+
animate(viewer, {
314
opacity: 0,
315
easing: 'easeInOutQuad',
316
duration: 150,
317
+
onComplete: () => {
318
viewer.style.display = 'none';
319
}
320
});
321
322
window.CloseAllPopups.forEach(p => p());
323
324
+
animate('.prev-button', { top: '75%', easing: 'easeInOutQuad', duration: 100 });
325
+
animate('.next-button', { top: '75%', easing: 'easeInOutQuad', duration: 100 });
326
}
327
328
isOpen = photo != null;
···
371
</div>
372
373
<div class="viewer-close viewer-button" onClick={() => window.PhotoViewerManager.Close()}>
374
+
<div class="icon-small" style={{ width: '10px', margin: '0' }}>
375
<img draggable="false" src="/icon/x-solid.svg"></img>
376
</div>
377
</div>
···
381
window.CloseAllPopups.forEach(p => p());
382
window.PhotoViewerManager.PreviousPhoto();
383
}}>
384
+
<div class="icon-small" style={{ width: '15px', margin: '0' }}>
385
<img draggable="false" src="/icon/arrow-left-solid.svg"></img>
386
</div>
387
</div>
···
390
window.CloseAllPopups.forEach(p => p());
391
window.PhotoViewerManager.NextPhoto();
392
}}>
393
+
<div class="icon-small" style={{ width: '15px', margin: '0' }}>
394
<img draggable="false" src="/icon/arrow-right-solid.svg"></img>
395
</div>
396
</div>
···
401
onClick={() => closeTray()}
402
ref={( el ) => photoTrayCloseBtn = el}
403
>
404
+
<div class="icon-small" style={{ width: '12px', margin: '0' }}>
405
<img draggable="false" src="/icon/angle-down-solid.svg"></img>
406
</div>
407
</div>
408
409
<div class="control-buttons" ref={( el ) => photoControls = el}>
410
<div class="viewer-button"
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' })}
413
onClick={() => { copyImage(); }}>
414
+
<div class="icon-small" style={{ width: '12px', margin: '0' }}>
415
<img draggable="false" src="/icon/copy-solid.svg"></img>
416
</div>
417
</div>
418
<div class="viewer-button" style={{ width: '50px' }}
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' })}
421
ref={( el ) => trayButton = el}
422
onClick={() => openTray()}
423
>
424
+
<div class="icon-small" style={{ width: '12px', margin: '0' }}>
425
<img draggable="false" src="/icon/angle-up-solid.svg"></img>
426
</div>
427
</div>
428
429
<div class="viewer-button"
430
ref={authorProfileButton!}
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' })}
433
>
434
+
<div class="icon-small" style={{ width: '12px', margin: '0' }}>
435
<img draggable="false" src="/icon/user-solid.svg"></img>
436
</div>
437
</div>
438
439
<div class="viewer-button"
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' })}
442
onClick={() => window.ConfirmationBoxManager.SetConfirmationBox("Are you sure you want to delete this photo?", async () => { invoke("delete_photo", {
443
+
path: window.PhotoViewerManager.CurrentPhoto()?.path
444
});
445
})}>
446
+
<div class="icon-small" style={{ width: '12px', margin: '0' }}>
447
<img draggable="false" src="/icon/trash-solid.svg"></img>
448
</div>
449
</div>
+40
-27
src/Components/SettingsMenu.tsx
+40
-27
src/Components/SettingsMenu.tsx
···
1
import { onCleanup, onMount, Show } from "solid-js";
2
import { bytesToFormatted } from "../utils";
3
import { invoke } from '@tauri-apps/api/core';
4
-
import anime from "animejs";
5
import { ViewState } from "./Managers/ViewManager";
6
7
let SettingsMenu = () => {
8
let sliderBar: HTMLElement;
···
17
let closeWithKey = ( e: KeyboardEvent ) => {
18
if(e.key === 'Escape'){
19
window.ViewManager.ChangeState(ViewState.PHOTO_LIST);
20
-
anime({
21
-
targets: '.settings',
22
opacity: 0,
23
translateX: '500px',
24
easing: 'easeInOutQuad',
25
duration: 250,
26
-
complete: () => {
27
-
anime.set('.settings', { display: 'none' });
28
}
29
})
30
}
···
34
if(await invoke('get_config_value_string', { key: 'transparent' }) === "true"){
35
invoke('set_config_value_string', { key: 'transparent', value: 'true' });
36
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 });
39
} else{
40
invoke('set_config_value_string', { key: 'transparent', value: 'false' });
41
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 });
44
}
45
46
let sliderMouseDown = false;
···
57
58
if(!sliderMouseDown){
59
sliderPos = sliderPos + (width / 2 - buttons[currentButton] - sliderPos) * 0.25;
60
-
anime.set(sliderBar, { translateX: sliderPos });
61
62
settingsContainer.style.left = (sliderPos - (width / 2 - buttons[0])) * sliderScale + 'px';
63
}
64
}
65
66
render();
67
-
anime.set(sliderBar, { translateX: sliderPos });
68
69
sliderBar.addEventListener('touchstart', ( e: TouchEvent ) => {
70
sliderMouseDown = true;
···
73
74
window.addEventListener('touchmove', ( e: TouchEvent ) => {
75
if(sliderMouseDown){
76
-
anime.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) });
77
settingsContainer.style.left = (sliderPos - (mouseStartX - e.touches[0].clientX) - (width / 2 - buttons[0])) * sliderScale + 'px';
78
}
79
})
···
84
if(sliderMouseDown){
85
sliderPos = sliderPos - (mouseStartX - e.touches[0].clientX);
86
87
-
anime.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) });
88
sliderMouseDown = false;
89
90
if(Math.abs(mouseStartX - e.touches[0].clientX) > 50){
···
118
119
window.addEventListener('mousemove', ( e: MouseEvent ) => {
120
if(sliderMouseDown){
121
-
anime.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) });
122
settingsContainer.style.left = sliderPos - (mouseStartX - e.clientX) + 'px';
123
settingsContainer.style.left = (sliderPos - (mouseStartX - e.clientX) - (width / 2 - buttons[0])) * sliderScale + 'px';
124
}
···
128
if(sliderMouseDown){
129
sliderPos = sliderPos - (mouseStartX - e.clientX);
130
131
-
anime.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) });
132
sliderMouseDown = false;
133
134
if(Math.abs(mouseStartX - e.clientX) > 50){
···
160
sliderPos = width / 2 - buttons[currentButton];
161
sliderScale = width / (buttons[1] - buttons[0]);
162
163
-
anime.set(sliderBar, { translateX: sliderPos });
164
})
165
166
sliderBar.addEventListener('wheel', ( e: WheelEvent ) => {
···
180
181
return (
182
<div class="settings">
183
<div class="settings-container" ref={( el ) => settingsContainer = el}>
184
<div class="settings-block">
185
<h1>Storage Settings</h1>
···
199
200
<label for="start-in-bg-check">
201
<div class="selection-box">
202
-
<div class="icon" style={{ width: '10px', margin: '0', display: 'inline-flex' }}>
203
<img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img>
204
</div>
205
</div>
···
223
224
<label for="start-with-win-check">
225
<div class="selection-box">
226
-
<div class="icon" style={{ width: '10px', margin: '0', display: 'inline-flex' }}>
227
<img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img>
228
</div>
229
</div>
···
238
if(el.target.checked){
239
invoke('set_config_value_string', { key: 'transparent', value: 'true' });
240
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 });
243
} else{
244
invoke('set_config_value_string', { key: 'transparent', value: 'false' });
245
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 });
248
}
249
}} />
250
Window Transparency
251
252
<label for="transparent-check">
253
<div class="selection-box">
254
-
<div class="icon" style={{ width: '10px', margin: '0', display: 'inline-flex' }}>
255
<img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img>
256
</div>
257
</div>
···
282
await invoke('change_final_path', { newPath: finalPathData });
283
window.location.reload();
284
285
-
anime({
286
-
targets: '.settings',
287
opacity: 0,
288
translateX: '500px',
289
easing: 'easeInOutQuad',
290
duration: 250,
291
-
complete: () => {
292
-
anime.set('.settings', { display: 'none' });
293
}
294
})
295
···
1
import { onCleanup, onMount, Show } from "solid-js";
2
import { bytesToFormatted } from "../utils";
3
import { invoke } from '@tauri-apps/api/core';
4
import { ViewState } from "./Managers/ViewManager";
5
+
import { animate, utils } from "animejs";
6
7
let SettingsMenu = () => {
8
let sliderBar: HTMLElement;
···
17
let closeWithKey = ( e: KeyboardEvent ) => {
18
if(e.key === 'Escape'){
19
window.ViewManager.ChangeState(ViewState.PHOTO_LIST);
20
+
animate('.settings', {
21
opacity: 0,
22
translateX: '500px',
23
easing: 'easeInOutQuad',
24
duration: 250,
25
+
onComplete: () => {
26
+
utils.set('.settings', { display: 'none' });
27
}
28
})
29
}
···
33
if(await invoke('get_config_value_string', { key: 'transparent' }) === "true"){
34
invoke('set_config_value_string', { key: 'transparent', value: 'true' });
35
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 });
38
} else{
39
invoke('set_config_value_string', { key: 'transparent', value: 'false' });
40
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 });
43
}
44
45
let sliderMouseDown = false;
···
56
57
if(!sliderMouseDown){
58
sliderPos = sliderPos + (width / 2 - buttons[currentButton] - sliderPos) * 0.25;
59
+
utils.set(sliderBar, { translateX: sliderPos });
60
61
settingsContainer.style.left = (sliderPos - (width / 2 - buttons[0])) * sliderScale + 'px';
62
}
63
}
64
65
render();
66
+
utils.set(sliderBar, { translateX: sliderPos });
67
68
sliderBar.addEventListener('touchstart', ( e: TouchEvent ) => {
69
sliderMouseDown = true;
···
72
73
window.addEventListener('touchmove', ( e: TouchEvent ) => {
74
if(sliderMouseDown){
75
+
utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) });
76
settingsContainer.style.left = (sliderPos - (mouseStartX - e.touches[0].clientX) - (width / 2 - buttons[0])) * sliderScale + 'px';
77
}
78
})
···
83
if(sliderMouseDown){
84
sliderPos = sliderPos - (mouseStartX - e.touches[0].clientX);
85
86
+
utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.touches[0].clientX) });
87
sliderMouseDown = false;
88
89
if(Math.abs(mouseStartX - e.touches[0].clientX) > 50){
···
117
118
window.addEventListener('mousemove', ( e: MouseEvent ) => {
119
if(sliderMouseDown){
120
+
utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) });
121
settingsContainer.style.left = sliderPos - (mouseStartX - e.clientX) + 'px';
122
settingsContainer.style.left = (sliderPos - (mouseStartX - e.clientX) - (width / 2 - buttons[0])) * sliderScale + 'px';
123
}
···
127
if(sliderMouseDown){
128
sliderPos = sliderPos - (mouseStartX - e.clientX);
129
130
+
utils.set(sliderBar, { translateX: sliderPos - (mouseStartX - e.clientX) });
131
sliderMouseDown = false;
132
133
if(Math.abs(mouseStartX - e.clientX) > 50){
···
159
sliderPos = width / 2 - buttons[currentButton];
160
sliderScale = width / (buttons[1] - buttons[0]);
161
162
+
utils.set(sliderBar, { translateX: sliderPos });
163
})
164
165
sliderBar.addEventListener('wheel', ( e: WheelEvent ) => {
···
179
180
return (
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>
197
<div class="settings-container" ref={( el ) => settingsContainer = el}>
198
<div class="settings-block">
199
<h1>Storage Settings</h1>
···
213
214
<label for="start-in-bg-check">
215
<div class="selection-box">
216
+
<div class="icon-small" style={{ margin: '0', display: 'inline-flex' }}>
217
<img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img>
218
</div>
219
</div>
···
237
238
<label for="start-with-win-check">
239
<div class="selection-box">
240
+
<div class="icon-small" style={{ margin: '0', display: 'inline-flex' }}>
241
<img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img>
242
</div>
243
</div>
···
252
if(el.target.checked){
253
invoke('set_config_value_string', { key: 'transparent', value: 'true' });
254
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 });
257
} else{
258
invoke('set_config_value_string', { key: 'transparent', value: 'false' });
259
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 });
262
}
263
}} />
264
Window Transparency
265
266
<label for="transparent-check">
267
<div class="selection-box">
268
+
<div class="icon-small" style={{ margin: '0', display: 'inline-flex' }}>
269
<img draggable="false" width="10" height="10" src="/icon/check-solid.svg"></img>
270
</div>
271
</div>
···
296
await invoke('change_final_path', { newPath: finalPathData });
297
window.location.reload();
298
299
+
animate('.settings', {
300
opacity: 0,
301
translateX: '500px',
302
easing: 'easeInOutQuad',
303
duration: 250,
304
+
onComplete: () => {
305
+
utils.set('.settings', { display: 'none' });
306
}
307
})
308
+71
src/css/filters.css
+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
+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
+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
+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
+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
+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
+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
+9
src/index.tsx
···
22
23
window.oncontextmenu = ( e ) => e.preventDefault();
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
+
33
import "./styles.css";
34
+
35
import App from "./Components/App";
36
import { invoke } from "@tauri-apps/api/core";
37
+6
-779
src/styles.css
+6
-779
src/styles.css
···
7
background: #000;
8
margin: 0;
9
font-family: Rubik, 'Courier New';
10
}
11
12
.loading{
···
24
align-items: center;
25
}
26
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
.confirmation-box{
486
position: fixed;
487
top: 0;
···
489
width: 100%;
490
height: 100%;
491
z-index: 15;
492
-
background: #0005;
493
transition: 0.25s;
494
-
backdrop-filter: blur(10px);
495
-
-webkit-backdrop-filter: blur(10px);
496
}
497
498
.confirmation-box-container{
···
550
551
.button-danger:hover{
552
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
}
872
873
img{
···
7
background: #000;
8
margin: 0;
9
font-family: Rubik, 'Courier New';
10
+
overflow: hidden;
11
+
}
12
+
13
+
* {
14
+
box-sizing: border-box;
15
}
16
17
.loading{
···
29
align-items: center;
30
}
31
32
.confirmation-box{
33
position: fixed;
34
top: 0;
···
36
width: 100%;
37
height: 100%;
38
z-index: 15;
39
+
background: rgba(0, 0, 0, 0.76);
40
transition: 0.25s;
41
}
42
43
.confirmation-box-container{
···
95
96
.button-danger:hover{
97
box-shadow: #000a inset 0 0 10px;
98
}
99
100
img{