+41
-72
package-lock.json
+41
-72
package-lock.json
···
376
376
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz",
377
377
"integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==",
378
378
"license": "MIT",
379
+
"peer": true,
379
380
"dependencies": {
380
381
"@ampproject/remapping": "^2.2.0",
381
382
"@babel/code-frame": "^7.27.1",
···
883
884
}
884
885
],
885
886
"license": "MIT",
887
+
"peer": true,
886
888
"engines": {
887
889
"node": ">=18"
888
890
},
···
906
908
}
907
909
],
908
910
"license": "MIT",
911
+
"peer": true,
909
912
"engines": {
910
913
"node": ">=18"
911
914
}
···
1494
1497
"integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
1495
1498
"dev": true,
1496
1499
"license": "Apache-2.0",
1497
-
"peer": true,
1498
1500
"dependencies": {
1499
1501
"@eslint/object-schema": "^2.1.6",
1500
1502
"debug": "^4.3.1",
···
1510
1512
"integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==",
1511
1513
"dev": true,
1512
1514
"license": "Apache-2.0",
1513
-
"peer": true,
1514
1515
"dependencies": {
1515
1516
"@eslint/core": "^0.16.0"
1516
1517
},
···
1524
1525
"integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==",
1525
1526
"dev": true,
1526
1527
"license": "Apache-2.0",
1527
-
"peer": true,
1528
1528
"dependencies": {
1529
1529
"@types/json-schema": "^7.0.15"
1530
1530
},
···
1538
1538
"integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
1539
1539
"dev": true,
1540
1540
"license": "MIT",
1541
-
"peer": true,
1542
1541
"dependencies": {
1543
1542
"ajv": "^6.12.4",
1544
1543
"debug": "^4.3.2",
···
1563
1562
"integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==",
1564
1563
"dev": true,
1565
1564
"license": "MIT",
1566
-
"peer": true,
1567
1565
"engines": {
1568
1566
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1569
1567
},
···
1577
1575
"integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
1578
1576
"dev": true,
1579
1577
"license": "Apache-2.0",
1580
-
"peer": true,
1581
1578
"engines": {
1582
1579
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1583
1580
}
···
1588
1585
"integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==",
1589
1586
"dev": true,
1590
1587
"license": "Apache-2.0",
1591
-
"peer": true,
1592
1588
"dependencies": {
1593
1589
"@eslint/core": "^0.16.0",
1594
1590
"levn": "^0.4.1"
···
1637
1633
"integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
1638
1634
"dev": true,
1639
1635
"license": "Apache-2.0",
1640
-
"peer": true,
1641
1636
"engines": {
1642
1637
"node": ">=18.18.0"
1643
1638
}
···
1648
1643
"integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
1649
1644
"dev": true,
1650
1645
"license": "Apache-2.0",
1651
-
"peer": true,
1652
1646
"dependencies": {
1653
1647
"@humanfs/core": "^0.19.1",
1654
1648
"@humanwhocodes/retry": "^0.4.0"
···
1663
1657
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
1664
1658
"dev": true,
1665
1659
"license": "Apache-2.0",
1666
-
"peer": true,
1667
1660
"engines": {
1668
1661
"node": ">=12.22"
1669
1662
},
···
1678
1671
"integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
1679
1672
"dev": true,
1680
1673
"license": "Apache-2.0",
1681
-
"peer": true,
1682
1674
"engines": {
1683
1675
"node": ">=18.18"
1684
1676
},
···
3856
3848
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
3857
3849
"dev": true,
3858
3850
"license": "MIT",
3851
+
"peer": true,
3859
3852
"dependencies": {
3860
3853
"@babel/core": "^7.21.3",
3861
3854
"@svgr/babel-preset": "8.1.0",
···
4330
4323
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.85.6.tgz",
4331
4324
"integrity": "sha512-VUAag4ERjh+qlmg0wNivQIVCZUrYndqYu3/wPCVZd4r0E+1IqotbeyGTc+ICroL/PqbpSaGZg02zSWYfcvxbdA==",
4332
4325
"license": "MIT",
4326
+
"peer": true,
4333
4327
"dependencies": {
4334
4328
"@tanstack/query-core": "5.85.6"
4335
4329
},
···
4363
4357
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.131.28.tgz",
4364
4358
"integrity": "sha512-vWExhrqHJuT9v+6/2DCQ4pVvPaYoLazMNw8WXiLNuzBXh1FuEoIGaW3jw3DEP0OJCmMiWtTi34NzQnakkQZlQg==",
4365
4359
"license": "MIT",
4360
+
"peer": true,
4366
4361
"dependencies": {
4367
4362
"@tanstack/history": "1.131.2",
4368
4363
"@tanstack/react-store": "^0.7.0",
···
4427
4422
"resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.131.28.tgz",
4428
4423
"integrity": "sha512-f+vdfr3WKSS/BcqgI5s4vZg9xYb7NkvIolkaMELrbz3l+khkw1aTjx8wqCHRY4dqwIAxq+iZBZtMWXA7pztGJg==",
4429
4424
"license": "MIT",
4425
+
"peer": true,
4430
4426
"dependencies": {
4431
4427
"@tanstack/history": "1.131.2",
4432
4428
"@tanstack/store": "^0.7.0",
···
4599
4595
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
4600
4596
"dev": true,
4601
4597
"license": "MIT",
4598
+
"peer": true,
4602
4599
"dependencies": {
4603
4600
"@babel/code-frame": "^7.10.4",
4604
4601
"@babel/runtime": "^7.12.5",
···
4721
4718
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
4722
4719
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
4723
4720
"dev": true,
4724
-
"license": "MIT",
4725
-
"peer": true
4721
+
"license": "MIT"
4726
4722
},
4727
4723
"node_modules/@types/node": {
4728
4724
"version": "24.3.0",
···
4730
4726
"integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
4731
4727
"devOptional": true,
4732
4728
"license": "MIT",
4729
+
"peer": true,
4733
4730
"dependencies": {
4734
4731
"undici-types": "~7.10.0"
4735
4732
}
···
4739
4736
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz",
4740
4737
"integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==",
4741
4738
"license": "MIT",
4739
+
"peer": true,
4742
4740
"dependencies": {
4743
4741
"csstype": "^3.0.2"
4744
4742
}
···
4748
4746
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz",
4749
4747
"integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==",
4750
4748
"license": "MIT",
4749
+
"peer": true,
4751
4750
"peerDependencies": {
4752
4751
"@types/react": "^19.0.0"
4753
4752
}
···
4765
4764
"integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==",
4766
4765
"dev": true,
4767
4766
"license": "MIT",
4767
+
"peer": true,
4768
4768
"dependencies": {
4769
4769
"@eslint-community/regexpp": "^4.10.0",
4770
4770
"@typescript-eslint/scope-manager": "8.46.1",
···
4805
4805
"integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==",
4806
4806
"dev": true,
4807
4807
"license": "MIT",
4808
+
"peer": true,
4808
4809
"dependencies": {
4809
4810
"@typescript-eslint/scope-manager": "8.46.1",
4810
4811
"@typescript-eslint/types": "8.46.1",
···
5187
5188
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
5188
5189
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
5189
5190
"license": "MIT",
5191
+
"peer": true,
5190
5192
"bin": {
5191
5193
"acorn": "bin/acorn"
5192
5194
},
···
5200
5202
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
5201
5203
"dev": true,
5202
5204
"license": "MIT",
5203
-
"peer": true,
5204
5205
"peerDependencies": {
5205
5206
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
5206
5207
}
···
5221
5222
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
5222
5223
"dev": true,
5223
5224
"license": "MIT",
5224
-
"peer": true,
5225
5225
"dependencies": {
5226
5226
"fast-deep-equal": "^3.1.1",
5227
5227
"fast-json-stable-stringify": "^2.0.0",
···
5627
5627
}
5628
5628
],
5629
5629
"license": "MIT",
5630
+
"peer": true,
5630
5631
"dependencies": {
5631
5632
"caniuse-lite": "^1.0.30001737",
5632
5633
"electron-to-chromium": "^1.5.211",
···
5784
5785
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
5785
5786
"dev": true,
5786
5787
"license": "MIT",
5787
-
"peer": true,
5788
5788
"dependencies": {
5789
5789
"ansi-styles": "^4.1.0",
5790
5790
"supports-color": "^7.1.0"
···
5802
5802
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
5803
5803
"dev": true,
5804
5804
"license": "MIT",
5805
-
"peer": true,
5806
5805
"dependencies": {
5807
5806
"color-convert": "^2.0.1"
5808
5807
},
···
5883
5882
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
5884
5883
"dev": true,
5885
5884
"license": "MIT",
5886
-
"peer": true,
5887
5885
"dependencies": {
5888
5886
"color-name": "~1.1.4"
5889
5887
},
···
5896
5894
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
5897
5895
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
5898
5896
"dev": true,
5899
-
"license": "MIT",
5900
-
"peer": true
5897
+
"license": "MIT"
5901
5898
},
5902
5899
"node_modules/compare-versions": {
5903
5900
"version": "6.1.1",
···
5976
5973
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
5977
5974
"dev": true,
5978
5975
"license": "MIT",
5979
-
"peer": true,
5980
5976
"dependencies": {
5981
5977
"path-key": "^3.1.0",
5982
5978
"shebang-command": "^2.0.0",
···
6004
6000
"version": "3.1.3",
6005
6001
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
6006
6002
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
6007
-
"license": "MIT"
6003
+
"license": "MIT",
6004
+
"peer": true
6008
6005
},
6009
6006
"node_modules/custom-media-element": {
6010
6007
"version": "1.4.5",
···
6147
6144
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
6148
6145
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
6149
6146
"dev": true,
6150
-
"license": "MIT",
6151
-
"peer": true
6147
+
"license": "MIT"
6152
6148
},
6153
6149
"node_modules/define-data-property": {
6154
6150
"version": "1.1.4",
···
6556
6552
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
6557
6553
"dev": true,
6558
6554
"license": "MIT",
6559
-
"peer": true,
6560
6555
"engines": {
6561
6556
"node": ">=10"
6562
6557
},
···
6848
6843
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
6849
6844
"dev": true,
6850
6845
"license": "BSD-2-Clause",
6851
-
"peer": true,
6852
6846
"dependencies": {
6853
6847
"esrecurse": "^4.3.0",
6854
6848
"estraverse": "^5.2.0"
···
6879
6873
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
6880
6874
"dev": true,
6881
6875
"license": "ISC",
6882
-
"peer": true,
6883
6876
"dependencies": {
6884
6877
"is-glob": "^4.0.3"
6885
6878
},
···
6893
6886
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
6894
6887
"dev": true,
6895
6888
"license": "BSD-2-Clause",
6896
-
"peer": true,
6897
6889
"dependencies": {
6898
6890
"acorn": "^8.15.0",
6899
6891
"acorn-jsx": "^5.3.2",
···
6925
6917
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
6926
6918
"dev": true,
6927
6919
"license": "BSD-3-Clause",
6928
-
"peer": true,
6929
6920
"dependencies": {
6930
6921
"estraverse": "^5.1.0"
6931
6922
},
···
6939
6930
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
6940
6931
"dev": true,
6941
6932
"license": "BSD-2-Clause",
6942
-
"peer": true,
6943
6933
"dependencies": {
6944
6934
"estraverse": "^5.2.0"
6945
6935
},
···
7028
7018
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
7029
7019
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
7030
7020
"dev": true,
7031
-
"license": "MIT",
7032
-
"peer": true
7021
+
"license": "MIT"
7033
7022
},
7034
7023
"node_modules/fast-levenshtein": {
7035
7024
"version": "2.0.6",
7036
7025
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
7037
7026
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
7038
7027
"dev": true,
7039
-
"license": "MIT",
7040
-
"peer": true
7028
+
"license": "MIT"
7041
7029
},
7042
7030
"node_modules/fastq": {
7043
7031
"version": "1.19.1",
···
7055
7043
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
7056
7044
"dev": true,
7057
7045
"license": "MIT",
7058
-
"peer": true,
7059
7046
"dependencies": {
7060
7047
"flat-cache": "^4.0.0"
7061
7048
},
···
7081
7068
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
7082
7069
"dev": true,
7083
7070
"license": "MIT",
7084
-
"peer": true,
7085
7071
"dependencies": {
7086
7072
"locate-path": "^6.0.0",
7087
7073
"path-exists": "^4.0.0"
···
7099
7085
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
7100
7086
"dev": true,
7101
7087
"license": "MIT",
7102
-
"peer": true,
7103
7088
"dependencies": {
7104
7089
"flatted": "^3.2.9",
7105
7090
"keyv": "^4.5.4"
···
7113
7098
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
7114
7099
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
7115
7100
"dev": true,
7116
-
"license": "ISC",
7117
-
"peer": true
7101
+
"license": "ISC"
7118
7102
},
7119
7103
"node_modules/for-each": {
7120
7104
"version": "0.3.5",
···
7301
7285
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
7302
7286
"dev": true,
7303
7287
"license": "MIT",
7304
-
"peer": true,
7305
7288
"engines": {
7306
7289
"node": ">=18"
7307
7290
},
···
7379
7362
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
7380
7363
"dev": true,
7381
7364
"license": "MIT",
7382
-
"peer": true,
7383
7365
"engines": {
7384
7366
"node": ">=8"
7385
7367
}
···
7592
7574
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
7593
7575
"dev": true,
7594
7576
"license": "MIT",
7595
-
"peer": true,
7596
7577
"engines": {
7597
7578
"node": ">= 4"
7598
7579
}
···
7635
7616
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
7636
7617
"dev": true,
7637
7618
"license": "MIT",
7638
-
"peer": true,
7639
7619
"engines": {
7640
7620
"node": ">=0.8.19"
7641
7621
}
···
8141
8121
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
8142
8122
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
8143
8123
"dev": true,
8144
-
"license": "ISC",
8145
-
"peer": true
8124
+
"license": "ISC"
8146
8125
},
8147
8126
"node_modules/iso-datestring-validator": {
8148
8127
"version": "2.2.2",
···
8240
8219
"integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==",
8241
8220
"dev": true,
8242
8221
"license": "MIT",
8222
+
"peer": true,
8243
8223
"dependencies": {
8244
8224
"cssstyle": "^4.2.1",
8245
8225
"data-urls": "^5.0.0",
···
8291
8271
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
8292
8272
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
8293
8273
"dev": true,
8294
-
"license": "MIT",
8295
-
"peer": true
8274
+
"license": "MIT"
8296
8275
},
8297
8276
"node_modules/json-parse-even-better-errors": {
8298
8277
"version": "2.3.1",
···
8306
8285
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
8307
8286
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
8308
8287
"dev": true,
8309
-
"license": "MIT",
8310
-
"peer": true
8288
+
"license": "MIT"
8311
8289
},
8312
8290
"node_modules/json-stable-stringify-without-jsonify": {
8313
8291
"version": "1.0.1",
8314
8292
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
8315
8293
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
8316
8294
"dev": true,
8317
-
"license": "MIT",
8318
-
"peer": true
8295
+
"license": "MIT"
8319
8296
},
8320
8297
"node_modules/json5": {
8321
8298
"version": "2.2.3",
···
8351
8328
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
8352
8329
"dev": true,
8353
8330
"license": "MIT",
8354
-
"peer": true,
8355
8331
"dependencies": {
8356
8332
"json-buffer": "3.0.1"
8357
8333
}
···
8369
8345
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
8370
8346
"dev": true,
8371
8347
"license": "MIT",
8372
-
"peer": true,
8373
8348
"dependencies": {
8374
8349
"prelude-ls": "^1.2.1",
8375
8350
"type-check": "~0.4.0"
···
8655
8630
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
8656
8631
"dev": true,
8657
8632
"license": "MIT",
8658
-
"peer": true,
8659
8633
"dependencies": {
8660
8634
"p-locate": "^5.0.0"
8661
8635
},
···
8677
8651
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
8678
8652
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
8679
8653
"dev": true,
8680
-
"license": "MIT",
8681
-
"peer": true
8654
+
"license": "MIT"
8682
8655
},
8683
8656
"node_modules/loose-envify": {
8684
8657
"version": "1.4.0",
···
11138
11111
"version": "4.0.3",
11139
11112
"inBundle": true,
11140
11113
"license": "MIT",
11114
+
"peer": true,
11141
11115
"engines": {
11142
11116
"node": ">=12"
11143
11117
},
···
11471
11445
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
11472
11446
"dev": true,
11473
11447
"license": "MIT",
11474
-
"peer": true,
11475
11448
"dependencies": {
11476
11449
"deep-is": "^0.1.3",
11477
11450
"fast-levenshtein": "^2.0.6",
···
11508
11481
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
11509
11482
"dev": true,
11510
11483
"license": "MIT",
11511
-
"peer": true,
11512
11484
"dependencies": {
11513
11485
"yocto-queue": "^0.1.0"
11514
11486
},
···
11525
11497
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
11526
11498
"dev": true,
11527
11499
"license": "MIT",
11528
-
"peer": true,
11529
11500
"dependencies": {
11530
11501
"p-limit": "^3.0.2"
11531
11502
},
···
11600
11571
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
11601
11572
"dev": true,
11602
11573
"license": "MIT",
11603
-
"peer": true,
11604
11574
"engines": {
11605
11575
"node": ">=8"
11606
11576
}
···
11611
11581
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
11612
11582
"dev": true,
11613
11583
"license": "MIT",
11614
-
"peer": true,
11615
11584
"engines": {
11616
11585
"node": ">=8"
11617
11586
}
···
11740
11709
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
11741
11710
"dev": true,
11742
11711
"license": "MIT",
11743
-
"peer": true,
11744
11712
"engines": {
11745
11713
"node": ">= 0.8.0"
11746
11714
}
···
11921
11889
"resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
11922
11890
"integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==",
11923
11891
"license": "MIT",
11892
+
"peer": true,
11924
11893
"engines": {
11925
11894
"node": ">=0.10.0"
11926
11895
}
···
11930
11899
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
11931
11900
"integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
11932
11901
"license": "MIT",
11902
+
"peer": true,
11933
11903
"dependencies": {
11934
11904
"scheduler": "^0.26.0"
11935
11905
},
···
12350
12320
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz",
12351
12321
"integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==",
12352
12322
"license": "MIT",
12323
+
"peer": true,
12353
12324
"engines": {
12354
12325
"node": ">=10"
12355
12326
}
···
12421
12392
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
12422
12393
"dev": true,
12423
12394
"license": "MIT",
12424
-
"peer": true,
12425
12395
"dependencies": {
12426
12396
"shebang-regex": "^3.0.0"
12427
12397
},
···
12435
12405
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
12436
12406
"dev": true,
12437
12407
"license": "MIT",
12438
-
"peer": true,
12439
12408
"engines": {
12440
12409
"node": ">=8"
12441
12410
}
···
12539
12508
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.9.tgz",
12540
12509
"integrity": "sha512-A0ZBPJQldAeGCTW0YRYJmt7RCeh5rbFfPZ2aOttgYnctHE7HgKeHCBB/PVc2P7eOfmNXqMFFFoYYdm3S4dcbkA==",
12541
12510
"license": "MIT",
12511
+
"peer": true,
12542
12512
"dependencies": {
12543
12513
"csstype": "^3.1.0",
12544
12514
"seroval": "~1.3.0",
···
12708
12678
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
12709
12679
"dev": true,
12710
12680
"license": "MIT",
12711
-
"peer": true,
12712
12681
"engines": {
12713
12682
"node": ">=8"
12714
12683
},
···
12748
12717
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
12749
12718
"dev": true,
12750
12719
"license": "MIT",
12751
-
"peer": true,
12752
12720
"dependencies": {
12753
12721
"has-flag": "^4.0.0"
12754
12722
},
···
12848
12816
"version": "1.3.3",
12849
12817
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
12850
12818
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
12851
-
"license": "MIT"
12819
+
"license": "MIT",
12820
+
"peer": true
12852
12821
},
12853
12822
"node_modules/tiny-warning": {
12854
12823
"version": "1.0.3",
···
12908
12877
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
12909
12878
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
12910
12879
"license": "MIT",
12880
+
"peer": true,
12911
12881
"engines": {
12912
12882
"node": ">=12"
12913
12883
},
···
13105
13075
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
13106
13076
"dev": true,
13107
13077
"license": "MIT",
13108
-
"peer": true,
13109
13078
"dependencies": {
13110
13079
"prelude-ls": "^1.2.1"
13111
13080
},
···
13197
13166
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
13198
13167
"dev": true,
13199
13168
"license": "Apache-2.0",
13169
+
"peer": true,
13200
13170
"bin": {
13201
13171
"tsc": "bin/tsc",
13202
13172
"tsserver": "bin/tsserver"
···
13533
13503
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
13534
13504
"dev": true,
13535
13505
"license": "BSD-2-Clause",
13536
-
"peer": true,
13537
13506
"dependencies": {
13538
13507
"punycode": "^2.1.0"
13539
13508
}
···
13602
13571
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
13603
13572
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
13604
13573
"license": "MIT",
13574
+
"peer": true,
13605
13575
"dependencies": {
13606
13576
"esbuild": "^0.25.0",
13607
13577
"fdir": "^6.4.4",
···
13716
13686
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
13717
13687
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
13718
13688
"license": "MIT",
13689
+
"peer": true,
13719
13690
"engines": {
13720
13691
"node": ">=12"
13721
13692
},
···
13897
13868
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
13898
13869
"dev": true,
13899
13870
"license": "ISC",
13900
-
"peer": true,
13901
13871
"dependencies": {
13902
13872
"isexe": "^2.0.0"
13903
13873
},
···
14029
13999
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
14030
14000
"dev": true,
14031
14001
"license": "MIT",
14032
-
"peer": true,
14033
14002
"engines": {
14034
14003
"node": ">=0.10.0"
14035
14004
}
···
14084
14053
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
14085
14054
"dev": true,
14086
14055
"license": "MIT",
14087
-
"peer": true,
14088
14056
"engines": {
14089
14057
"node": ">=10"
14090
14058
},
···
14103
14071
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
14104
14072
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
14105
14073
"license": "MIT",
14074
+
"peer": true,
14106
14075
"funding": {
14107
14076
"url": "https://github.com/sponsors/colinhacks"
14108
14077
}
+31
src/components/placeholders/TextPlaceholder.tsx
+31
src/components/placeholders/TextPlaceholder.tsx
···
1
+
import type { ReactNode } from "react";
2
+
3
+
export function TextPlaceholder({
4
+
className,
5
+
pulse = false,
6
+
}: {
7
+
className?: string;
8
+
pulse?: boolean;
9
+
}) {
10
+
return (
11
+
<span
12
+
className={`bg-gray-100 dark:bg-gray-800 rounded h-4 ${pulse ? "animate-pulse" : ""} ${className ?? ""}`}
13
+
></span>
14
+
);
15
+
}
16
+
17
+
export function ConditionalTextPlaceholder({
18
+
show,
19
+
placeholderClassName,
20
+
children,
21
+
}: {
22
+
show: boolean;
23
+
placeholderClassName?: string;
24
+
children?: ReactNode;
25
+
}) {
26
+
return (
27
+
<>
28
+
{show ? children : <TextPlaceholder className={placeholderClassName} />}
29
+
</>
30
+
);
31
+
}
+531
-535
src/routes/notifications.tsx
+531
-535
src/routes/notifications.tsx
···
7
7
import defaultpfp from "~/../public/favicon.png";
8
8
import { Header } from "~/components/Header";
9
9
import {
10
-
ReusableTabRoute,
11
-
useReusableTabScrollRestore,
10
+
ReusableTabRoute,
11
+
useReusableTabScrollRestore,
12
12
} from "~/components/ReusableTabRoute";
13
13
import {
14
-
MdiCardsHeartOutline,
15
-
MdiCommentOutline,
16
-
MdiRepeat,
17
-
UniversalPostRendererATURILoader,
14
+
MdiCardsHeartOutline,
15
+
MdiCommentOutline,
16
+
MdiRepeat,
17
+
UniversalPostRendererATURILoader,
18
18
} from "~/components/UniversalPostRenderer";
19
19
import { useAuth } from "~/providers/UnifiedAuthProvider";
20
20
import {
21
-
constellationURLAtom,
22
-
enableBitesAtom,
23
-
imgCDNAtom,
24
-
postInteractionsFiltersAtom,
21
+
constellationURLAtom,
22
+
enableBitesAtom,
23
+
imgCDNAtom,
24
+
postInteractionsFiltersAtom,
25
25
} from "~/utils/atoms";
26
26
import {
27
-
useInfiniteQueryAuthorFeed,
28
-
useQueryConstellation,
29
-
useQueryIdentity,
30
-
useQueryProfile,
31
-
yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks,
27
+
useInfiniteQueryAuthorFeed,
28
+
useQueryConstellation,
29
+
useQueryIdentity,
30
+
useQueryProfile,
31
+
yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks,
32
32
} from "~/utils/useQuery";
33
33
34
34
import { FollowButton, Mutual } from "./profile.$did";
35
+
import { ConditionalTextPlaceholder } from "~/components/placeholders/TextPlaceholder";
35
36
36
37
export function NotificationsComponent() {
37
-
return (
38
-
<div className="">
39
-
<Header
40
-
title={`Notifications`}
41
-
backButtonCallback={() => {
42
-
if (window.history.length > 1) {
43
-
window.history.back();
44
-
} else {
45
-
window.location.assign("/");
46
-
}
47
-
}}
48
-
bottomBorderDisabled={true}
49
-
/>
50
-
<NotificationsTabs />
51
-
</div>
52
-
);
38
+
return (
39
+
<div className="">
40
+
<Header
41
+
title={`Notifications`}
42
+
backButtonCallback={() => {
43
+
if (window.history.length > 1) {
44
+
window.history.back();
45
+
} else {
46
+
window.location.assign("/");
47
+
}
48
+
}}
49
+
bottomBorderDisabled={true}
50
+
/>
51
+
<NotificationsTabs />
52
+
</div>
53
+
);
53
54
}
54
55
55
56
export const Route = createFileRoute("/notifications")({
56
-
component: NotificationsComponent,
57
+
component: NotificationsComponent,
57
58
});
58
59
59
60
export default function NotificationsTabs() {
60
-
const [bitesEnabled] = useAtom(enableBitesAtom);
61
-
return (
62
-
<ReusableTabRoute
63
-
route={`Notifications`}
64
-
tabs={{
65
-
Mentions: <MentionsTab />,
66
-
Follows: <FollowsTab />,
67
-
"Post Interactions": <PostInteractionsTab />,
68
-
...bitesEnabled ? {
69
-
Bites: <BitesTab />,
70
-
} : {}
71
-
}}
72
-
/>
73
-
);
61
+
const [bitesEnabled] = useAtom(enableBitesAtom);
62
+
return (
63
+
<ReusableTabRoute
64
+
route={`Notifications`}
65
+
tabs={{
66
+
Mentions: <MentionsTab />,
67
+
Follows: <FollowsTab />,
68
+
"Post Interactions": <PostInteractionsTab />,
69
+
...(bitesEnabled
70
+
? {
71
+
Bites: <BitesTab />,
72
+
}
73
+
: {}),
74
+
}}
75
+
/>
76
+
);
74
77
}
75
78
76
79
function MentionsTab() {
77
-
const { agent } = useAuth();
78
-
const [constellationurl] = useAtom(constellationURLAtom);
79
-
const infinitequeryresults = useInfiniteQuery({
80
-
...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(
81
-
{
82
-
constellation: constellationurl,
83
-
method: "/links",
84
-
target: agent?.did,
85
-
collection: "app.bsky.feed.post",
86
-
path: ".facets[app.bsky.richtext.facet].features[app.bsky.richtext.facet#mention].did",
87
-
}
88
-
),
89
-
enabled: !!agent?.did,
90
-
});
80
+
const { agent } = useAuth();
81
+
const [constellationurl] = useAtom(constellationURLAtom);
82
+
const infinitequeryresults = useInfiniteQuery({
83
+
...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(
84
+
{
85
+
constellation: constellationurl,
86
+
method: "/links",
87
+
target: agent?.did,
88
+
collection: "app.bsky.feed.post",
89
+
path: ".facets[app.bsky.richtext.facet].features[app.bsky.richtext.facet#mention].did",
90
+
}
91
+
),
92
+
enabled: !!agent?.did,
93
+
});
91
94
92
-
const {
93
-
data: infiniteMentionsData,
94
-
fetchNextPage,
95
-
hasNextPage,
96
-
isFetchingNextPage,
97
-
isLoading,
98
-
isError,
99
-
error,
100
-
} = infinitequeryresults;
95
+
const {
96
+
data: infiniteMentionsData,
97
+
fetchNextPage,
98
+
hasNextPage,
99
+
isFetchingNextPage,
100
+
isLoading,
101
+
isError,
102
+
error,
103
+
} = infinitequeryresults;
101
104
102
-
const mentionsAturis = React.useMemo(() => {
103
-
// Get all replies from the standard infinite query
104
-
return (
105
-
infiniteMentionsData?.pages.flatMap(
106
-
(page) =>
107
-
page?.linking_records.map(
108
-
(r) => `at://${r.did}/${r.collection}/${r.rkey}`
109
-
) ?? []
110
-
) ?? []
111
-
);
112
-
}, [infiniteMentionsData]);
105
+
const mentionsAturis = React.useMemo(() => {
106
+
// Get all replies from the standard infinite query
107
+
return (
108
+
infiniteMentionsData?.pages.flatMap(
109
+
(page) =>
110
+
page?.linking_records.map(
111
+
(r) => `at://${r.did}/${r.collection}/${r.rkey}`
112
+
) ?? []
113
+
) ?? []
114
+
);
115
+
}, [infiniteMentionsData]);
113
116
114
-
useReusableTabScrollRestore("Notifications");
117
+
useReusableTabScrollRestore("Notifications");
115
118
116
-
if (isLoading) return <LoadingState text="Loading mentions..." />;
117
-
if (isError) return <ErrorState error={error} />;
119
+
if (isLoading) return <LoadingState text="Loading mentions..." />;
120
+
if (isError) return <ErrorState error={error} />;
118
121
119
-
if (!mentionsAturis?.length) return <EmptyState text="No mentions yet." />;
122
+
if (!mentionsAturis?.length) return <EmptyState text="No mentions yet." />;
120
123
121
-
return (
122
-
<>
123
-
{mentionsAturis.map((m) => (
124
-
<UniversalPostRendererATURILoader key={m} atUri={m} />
125
-
))}
124
+
return (
125
+
<>
126
+
{mentionsAturis.map((m) => (
127
+
<UniversalPostRendererATURILoader key={m} atUri={m} />
128
+
))}
126
129
127
-
{hasNextPage && (
128
-
<button
129
-
onClick={() => fetchNextPage()}
130
-
disabled={isFetchingNextPage}
131
-
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
132
-
>
133
-
{isFetchingNextPage ? "Loading..." : "Load More"}
134
-
</button>
135
-
)}
136
-
</>
137
-
);
130
+
{hasNextPage && (
131
+
<button
132
+
onClick={() => fetchNextPage()}
133
+
disabled={isFetchingNextPage}
134
+
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
135
+
>
136
+
{isFetchingNextPage ? "Loading..." : "Load More"}
137
+
</button>
138
+
)}
139
+
</>
140
+
);
138
141
}
139
142
140
-
export function FollowsTab({did}:{did?:string}) {
141
-
const { agent } = useAuth();
142
-
const userdidunsafe = did ?? agent?.did;
143
-
const { data: identity} = useQueryIdentity(userdidunsafe);
144
-
const userdid = identity?.did;
145
-
146
-
const [constellationurl] = useAtom(constellationURLAtom);
147
-
const infinitequeryresults = useInfiniteQuery({
148
-
...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(
149
-
{
150
-
constellation: constellationurl,
151
-
method: "/links",
152
-
target: userdid,
153
-
collection: "app.bsky.graph.follow",
154
-
path: ".subject",
155
-
}
156
-
),
157
-
enabled: !!userdid,
158
-
});
143
+
export function FollowsTab({ did }: { did?: string }) {
144
+
const { agent } = useAuth();
145
+
const userdidunsafe = did ?? agent?.did;
146
+
const { data: identity } = useQueryIdentity(userdidunsafe);
147
+
const userdid = identity?.did;
159
148
160
-
const {
161
-
data: infiniteFollowsData,
162
-
fetchNextPage,
163
-
hasNextPage,
164
-
isFetchingNextPage,
165
-
isLoading,
166
-
isError,
167
-
error,
168
-
} = infinitequeryresults;
149
+
const [constellationurl] = useAtom(constellationURLAtom);
150
+
const infinitequeryresults = useInfiniteQuery({
151
+
...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(
152
+
{
153
+
constellation: constellationurl,
154
+
method: "/links",
155
+
target: userdid,
156
+
collection: "app.bsky.graph.follow",
157
+
path: ".subject",
158
+
}
159
+
),
160
+
enabled: !!userdid,
161
+
});
162
+
163
+
const {
164
+
data: infiniteFollowsData,
165
+
fetchNextPage,
166
+
hasNextPage,
167
+
isFetchingNextPage,
168
+
isLoading,
169
+
isError,
170
+
error,
171
+
} = infinitequeryresults;
169
172
170
-
const followsAturis = React.useMemo(() => {
171
-
// Get all replies from the standard infinite query
172
-
return (
173
-
infiniteFollowsData?.pages.flatMap(
174
-
(page) =>
175
-
page?.linking_records.map(
176
-
(r) => `at://${r.did}/${r.collection}/${r.rkey}`
177
-
) ?? []
178
-
) ?? []
179
-
);
180
-
}, [infiniteFollowsData]);
173
+
const followsAturis = React.useMemo(() => {
174
+
// Get all replies from the standard infinite query
175
+
return (
176
+
infiniteFollowsData?.pages.flatMap(
177
+
(page) =>
178
+
page?.linking_records.map(
179
+
(r) => `at://${r.did}/${r.collection}/${r.rkey}`
180
+
) ?? []
181
+
) ?? []
182
+
);
183
+
}, [infiniteFollowsData]);
181
184
182
-
useReusableTabScrollRestore("Notifications");
185
+
useReusableTabScrollRestore("Notifications");
183
186
184
-
if (isLoading) return <LoadingState text="Loading follows..." />;
185
-
if (isError) return <ErrorState error={error} />;
187
+
if (isLoading) return <LoadingState text="Loading follows..." />;
188
+
if (isError) return <ErrorState error={error} />;
186
189
187
-
if (!followsAturis?.length) return <EmptyState text="No follows yet." />;
190
+
if (!followsAturis?.length) return <EmptyState text="No follows yet." />;
188
191
189
-
return (
190
-
<>
191
-
{followsAturis.map((m) => (
192
-
<NotificationItem key={m} notification={m} />
193
-
))}
192
+
return (
193
+
<>
194
+
{followsAturis.map((m) => (
195
+
<NotificationItem key={m} notification={m} />
196
+
))}
194
197
195
-
{hasNextPage && (
196
-
<button
197
-
onClick={() => fetchNextPage()}
198
-
disabled={isFetchingNextPage}
199
-
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
200
-
>
201
-
{isFetchingNextPage ? "Loading..." : "Load More"}
202
-
</button>
203
-
)}
204
-
</>
205
-
);
198
+
{hasNextPage && (
199
+
<button
200
+
onClick={() => fetchNextPage()}
201
+
disabled={isFetchingNextPage}
202
+
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
203
+
>
204
+
{isFetchingNextPage ? "Loading..." : "Load More"}
205
+
</button>
206
+
)}
207
+
</>
208
+
);
206
209
}
207
210
211
+
export function BitesTab({ did }: { did?: string }) {
212
+
const { agent } = useAuth();
213
+
const userdidunsafe = did ?? agent?.did;
214
+
const { data: identity } = useQueryIdentity(userdidunsafe);
215
+
const userdid = identity?.did;
208
216
209
-
export function BitesTab({did}:{did?:string}) {
210
-
const { agent } = useAuth();
211
-
const userdidunsafe = did ?? agent?.did;
212
-
const { data: identity} = useQueryIdentity(userdidunsafe);
213
-
const userdid = identity?.did;
214
-
215
-
const [constellationurl] = useAtom(constellationURLAtom);
216
-
const infinitequeryresults = useInfiniteQuery({
217
-
...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(
218
-
{
219
-
constellation: constellationurl,
220
-
method: "/links",
221
-
target: "at://"+userdid,
222
-
collection: "net.wafrn.feed.bite",
223
-
path: ".subject",
224
-
staleMult: 0 // safe fun
225
-
}
226
-
),
227
-
enabled: !!userdid,
228
-
});
217
+
const [constellationurl] = useAtom(constellationURLAtom);
218
+
const infinitequeryresults = useInfiniteQuery({
219
+
...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(
220
+
{
221
+
constellation: constellationurl,
222
+
method: "/links",
223
+
target: "at://" + userdid,
224
+
collection: "net.wafrn.feed.bite",
225
+
path: ".subject",
226
+
staleMult: 0, // safe fun
227
+
}
228
+
),
229
+
enabled: !!userdid,
230
+
});
229
231
230
-
const {
231
-
data: infiniteFollowsData,
232
-
fetchNextPage,
233
-
hasNextPage,
234
-
isFetchingNextPage,
235
-
isLoading,
236
-
isError,
237
-
error,
238
-
} = infinitequeryresults;
232
+
const {
233
+
data: infiniteFollowsData,
234
+
fetchNextPage,
235
+
hasNextPage,
236
+
isFetchingNextPage,
237
+
isLoading,
238
+
isError,
239
+
error,
240
+
} = infinitequeryresults;
239
241
240
-
const followsAturis = React.useMemo(() => {
241
-
// Get all replies from the standard infinite query
242
-
return (
243
-
infiniteFollowsData?.pages.flatMap(
244
-
(page) =>
245
-
page?.linking_records.map(
246
-
(r) => `at://${r.did}/${r.collection}/${r.rkey}`
247
-
) ?? []
248
-
) ?? []
249
-
);
250
-
}, [infiniteFollowsData]);
242
+
const followsAturis = React.useMemo(() => {
243
+
// Get all replies from the standard infinite query
244
+
return (
245
+
infiniteFollowsData?.pages.flatMap(
246
+
(page) =>
247
+
page?.linking_records.map(
248
+
(r) => `at://${r.did}/${r.collection}/${r.rkey}`
249
+
) ?? []
250
+
) ?? []
251
+
);
252
+
}, [infiniteFollowsData]);
251
253
252
-
useReusableTabScrollRestore("Notifications");
254
+
useReusableTabScrollRestore("Notifications");
253
255
254
-
if (isLoading) return <LoadingState text="Loading bites..." />;
255
-
if (isError) return <ErrorState error={error} />;
256
+
if (isLoading) return <LoadingState text="Loading bites..." />;
257
+
if (isError) return <ErrorState error={error} />;
256
258
257
-
if (!followsAturis?.length) return <EmptyState text="No bites yet." />;
259
+
if (!followsAturis?.length) return <EmptyState text="No bites yet." />;
258
260
259
-
return (
260
-
<>
261
-
{followsAturis.map((m) => (
262
-
<NotificationItem key={m} notification={m} />
263
-
))}
261
+
return (
262
+
<>
263
+
{followsAturis.map((m) => (
264
+
<NotificationItem key={m} notification={m} />
265
+
))}
264
266
265
-
{hasNextPage && (
266
-
<button
267
-
onClick={() => fetchNextPage()}
268
-
disabled={isFetchingNextPage}
269
-
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
270
-
>
271
-
{isFetchingNextPage ? "Loading..." : "Load More"}
272
-
</button>
273
-
)}
274
-
</>
275
-
);
267
+
{hasNextPage && (
268
+
<button
269
+
onClick={() => fetchNextPage()}
270
+
disabled={isFetchingNextPage}
271
+
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
272
+
>
273
+
{isFetchingNextPage ? "Loading..." : "Load More"}
274
+
</button>
275
+
)}
276
+
</>
277
+
);
276
278
}
277
279
278
280
function PostInteractionsTab() {
279
-
const { agent } = useAuth();
280
-
const { data: identity } = useQueryIdentity(agent?.did);
281
-
const queryClient = useQueryClient();
282
-
const {
283
-
data: postsData,
284
-
fetchNextPage,
285
-
hasNextPage,
286
-
isFetchingNextPage,
287
-
isLoading: arePostsLoading,
288
-
} = useInfiniteQueryAuthorFeed(agent?.did, identity?.pds);
281
+
const { agent } = useAuth();
282
+
const { data: identity } = useQueryIdentity(agent?.did);
283
+
const queryClient = useQueryClient();
284
+
const {
285
+
data: postsData,
286
+
fetchNextPage,
287
+
hasNextPage,
288
+
isFetchingNextPage,
289
+
isLoading: arePostsLoading,
290
+
} = useInfiniteQueryAuthorFeed(agent?.did, identity?.pds);
289
291
290
-
React.useEffect(() => {
291
-
if (postsData) {
292
-
postsData.pages.forEach((page) => {
293
-
page.records.forEach((record) => {
294
-
if (!queryClient.getQueryData(["post", record.uri])) {
295
-
queryClient.setQueryData(["post", record.uri], record);
296
-
}
297
-
});
298
-
});
299
-
}
300
-
}, [postsData, queryClient]);
292
+
React.useEffect(() => {
293
+
if (postsData) {
294
+
postsData.pages.forEach((page) => {
295
+
page.records.forEach((record) => {
296
+
if (!queryClient.getQueryData(["post", record.uri])) {
297
+
queryClient.setQueryData(["post", record.uri], record);
298
+
}
299
+
});
300
+
});
301
+
}
302
+
}, [postsData, queryClient]);
301
303
302
-
const posts = React.useMemo(
303
-
() => postsData?.pages.flatMap((page) => page.records) ?? [],
304
-
[postsData]
305
-
);
304
+
const posts = React.useMemo(
305
+
() => postsData?.pages.flatMap((page) => page.records) ?? [],
306
+
[postsData]
307
+
);
306
308
307
-
useReusableTabScrollRestore("Notifications");
309
+
useReusableTabScrollRestore("Notifications");
308
310
309
-
const [filters] = useAtom(postInteractionsFiltersAtom);
310
-
const empty = (!filters.likes && !filters.quotes && !filters.replies && !filters.reposts);
311
+
const [filters] = useAtom(postInteractionsFiltersAtom);
312
+
const empty =
313
+
!filters.likes && !filters.quotes && !filters.replies && !filters.reposts;
311
314
312
-
return (
313
-
<>
314
-
<PostInteractionsFilterChipBar />
315
-
{!empty && posts.map((m) => (
316
-
<PostInteractionsItem key={m.uri} uri={m.uri} />
317
-
))}
315
+
return (
316
+
<>
317
+
<PostInteractionsFilterChipBar />
318
+
{!empty &&
319
+
posts.map((m) => <PostInteractionsItem key={m.uri} uri={m.uri} />)}
318
320
319
-
{hasNextPage && (
320
-
<button
321
-
onClick={() => fetchNextPage()}
322
-
disabled={isFetchingNextPage}
323
-
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
324
-
>
325
-
{isFetchingNextPage ? "Loading..." : "Load More"}
326
-
</button>
327
-
)}
328
-
</>
329
-
);
321
+
{hasNextPage && (
322
+
<button
323
+
onClick={() => fetchNextPage()}
324
+
disabled={isFetchingNextPage}
325
+
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
326
+
>
327
+
{isFetchingNextPage ? "Loading..." : "Load More"}
328
+
</button>
329
+
)}
330
+
</>
331
+
);
330
332
}
331
333
332
334
function PostInteractionsFilterChipBar() {
333
-
const [filters, setFilters] = useAtom(postInteractionsFiltersAtom);
334
-
// const empty = (!filters.likes && !filters.quotes && !filters.replies && !filters.reposts);
335
+
const [filters, setFilters] = useAtom(postInteractionsFiltersAtom);
336
+
// const empty = (!filters.likes && !filters.quotes && !filters.replies && !filters.reposts);
335
337
336
-
// useEffect(() => {
337
-
// if (empty) {
338
-
// setFilters((prev) => ({
339
-
// ...prev,
340
-
// likes: true,
341
-
// }));
342
-
// }
343
-
// }, [
344
-
// empty,
345
-
// setFilters,
346
-
// ]);
338
+
// useEffect(() => {
339
+
// if (empty) {
340
+
// setFilters((prev) => ({
341
+
// ...prev,
342
+
// likes: true,
343
+
// }));
344
+
// }
345
+
// }, [
346
+
// empty,
347
+
// setFilters,
348
+
// ]);
347
349
348
-
const toggle = (key: keyof typeof filters) => {
349
-
setFilters((prev) => ({
350
-
...prev,
351
-
[key]: !prev[key],
352
-
}));
353
-
};
350
+
const toggle = (key: keyof typeof filters) => {
351
+
setFilters((prev) => ({
352
+
...prev,
353
+
[key]: !prev[key],
354
+
}));
355
+
};
354
356
355
-
return (
356
-
<div className="flex flex-row flex-wrap gap-2 px-4 pt-4">
357
-
<Chip
358
-
state={filters.likes}
359
-
text="Likes"
360
-
onClick={() => toggle("likes")}
361
-
/>
362
-
<Chip
363
-
state={filters.reposts}
364
-
text="Reposts"
365
-
onClick={() => toggle("reposts")}
366
-
/>
367
-
<Chip
368
-
state={filters.replies}
369
-
text="Replies"
370
-
onClick={() => toggle("replies")}
371
-
/>
372
-
<Chip
373
-
state={filters.quotes}
374
-
text="Quotes"
375
-
onClick={() => toggle("quotes")}
376
-
/>
377
-
<Chip
378
-
state={filters.showAll}
379
-
text="Show All Metrics"
380
-
onClick={() => toggle("showAll")}
381
-
/>
382
-
</div>
383
-
);
357
+
return (
358
+
<div className="flex flex-row flex-wrap gap-2 px-4 pt-4">
359
+
<Chip
360
+
state={filters.likes}
361
+
text="Likes"
362
+
onClick={() => toggle("likes")}
363
+
/>
364
+
<Chip
365
+
state={filters.reposts}
366
+
text="Reposts"
367
+
onClick={() => toggle("reposts")}
368
+
/>
369
+
<Chip
370
+
state={filters.replies}
371
+
text="Replies"
372
+
onClick={() => toggle("replies")}
373
+
/>
374
+
<Chip
375
+
state={filters.quotes}
376
+
text="Quotes"
377
+
onClick={() => toggle("quotes")}
378
+
/>
379
+
<Chip
380
+
state={filters.showAll}
381
+
text="Show All Metrics"
382
+
onClick={() => toggle("showAll")}
383
+
/>
384
+
</div>
385
+
);
384
386
}
385
387
386
388
export function Chip({
387
-
state,
388
-
text,
389
-
onClick,
389
+
state,
390
+
text,
391
+
onClick,
390
392
}: {
391
-
state: boolean;
392
-
text: string;
393
-
onClick: React.MouseEventHandler<HTMLButtonElement>;
393
+
state: boolean;
394
+
text: string;
395
+
onClick: React.MouseEventHandler<HTMLButtonElement>;
394
396
}) {
395
-
return (
396
-
<button
397
-
onClick={onClick}
398
-
className={`relative inline-flex items-center px-3 py-1.5 rounded-lg text-sm font-medium transition-all
397
+
return (
398
+
<button
399
+
onClick={onClick}
400
+
className={`relative inline-flex items-center px-3 py-1.5 rounded-lg text-sm font-medium transition-all
399
401
${
400
-
state
401
-
? "bg-primary/20 text-primary bg-gray-200 dark:bg-gray-800 border border-transparent"
402
-
: "bg-surface-container-low text-on-surface-variant border border-outline"
403
-
}
402
+
state
403
+
? "bg-primary/20 text-primary bg-gray-200 dark:bg-gray-800 border border-transparent"
404
+
: "bg-surface-container-low text-on-surface-variant border border-outline"
405
+
}
404
406
hover:bg-primary/30 active:scale-[0.97]
405
407
dark:border-outline-variant
406
408
`}
407
-
>
408
-
{state && (
409
-
<IconMdiCheck
410
-
className="mr-1.5 inline-block w-4 h-4 rounded-full bg-primary"
411
-
aria-hidden
412
-
/>
413
-
)}
414
-
{text}
415
-
</button>
416
-
);
409
+
>
410
+
{state && (
411
+
<IconMdiCheck
412
+
className="mr-1.5 inline-block w-4 h-4 rounded-full bg-primary"
413
+
aria-hidden
414
+
/>
415
+
)}
416
+
{text}
417
+
</button>
418
+
);
417
419
}
418
420
419
421
function PostInteractionsItem({ uri }: { uri: string }) {
420
-
const [filters] = useAtom(postInteractionsFiltersAtom);
421
-
const { data: links } = useQueryConstellation({
422
-
method: "/links/all",
423
-
target: uri,
424
-
});
422
+
const [filters] = useAtom(postInteractionsFiltersAtom);
423
+
const { data: links } = useQueryConstellation({
424
+
method: "/links/all",
425
+
target: uri,
426
+
});
425
427
426
-
const likes =
427
-
links?.links?.["app.bsky.feed.like"]?.[".subject.uri"]?.records || 0;
428
-
const replies =
429
-
links?.links?.["app.bsky.feed.post"]?.[".reply.parent.uri"]?.records || 0;
430
-
const reposts =
431
-
links?.links?.["app.bsky.feed.repost"]?.[".subject.uri"]?.records || 0;
432
-
const quotes1 =
433
-
links?.links?.["app.bsky.feed.post"]?.[".embed.record.uri"]?.records || 0;
434
-
const quotes2 =
435
-
links?.links?.["app.bsky.feed.post"]?.[".embed.record.record.uri"]
436
-
?.records || 0;
437
-
const quotes = quotes1 + quotes2;
428
+
const likes =
429
+
links?.links?.["app.bsky.feed.like"]?.[".subject.uri"]?.records || 0;
430
+
const replies =
431
+
links?.links?.["app.bsky.feed.post"]?.[".reply.parent.uri"]?.records || 0;
432
+
const reposts =
433
+
links?.links?.["app.bsky.feed.repost"]?.[".subject.uri"]?.records || 0;
434
+
const quotes1 =
435
+
links?.links?.["app.bsky.feed.post"]?.[".embed.record.uri"]?.records || 0;
436
+
const quotes2 =
437
+
links?.links?.["app.bsky.feed.post"]?.[".embed.record.record.uri"]
438
+
?.records || 0;
439
+
const quotes = quotes1 + quotes2;
438
440
439
-
const all = likes + replies + reposts + quotes;
441
+
const all = likes + replies + reposts + quotes;
440
442
441
-
//const failLikes = filters.likes && likes < 1;
442
-
//const failReposts = filters.reposts && reposts < 1;
443
-
//const failReplies = filters.replies && replies < 1;
444
-
//const failQuotes = filters.quotes && quotes < 1;
443
+
//const failLikes = filters.likes && likes < 1;
444
+
//const failReposts = filters.reposts && reposts < 1;
445
+
//const failReplies = filters.replies && replies < 1;
446
+
//const failQuotes = filters.quotes && quotes < 1;
445
447
446
-
const showLikes = filters.showAll || filters.likes
447
-
const showReposts = filters.showAll || filters.reposts
448
-
const showReplies = filters.showAll || filters.replies
449
-
const showQuotes = filters.showAll || filters.quotes
448
+
const showLikes = filters.showAll || filters.likes;
449
+
const showReposts = filters.showAll || filters.reposts;
450
+
const showReplies = filters.showAll || filters.replies;
451
+
const showQuotes = filters.showAll || filters.quotes;
450
452
451
-
//const showNone = !showLikes && !showReposts && !showReplies && !showQuotes;
453
+
//const showNone = !showLikes && !showReposts && !showReplies && !showQuotes;
452
454
453
-
//const fail = failLikes || failReposts || failReplies || failQuotes || showNone;
455
+
//const fail = failLikes || failReposts || failReplies || failQuotes || showNone;
454
456
455
-
const matchesLikes = filters.likes && likes > 0;
456
-
const matchesReposts = filters.reposts && reposts > 0;
457
-
const matchesReplies = filters.replies && replies > 0;
458
-
const matchesQuotes = filters.quotes && quotes > 0;
457
+
const matchesLikes = filters.likes && likes > 0;
458
+
const matchesReposts = filters.reposts && reposts > 0;
459
+
const matchesReplies = filters.replies && replies > 0;
460
+
const matchesQuotes = filters.quotes && quotes > 0;
459
461
460
-
const matchesAnything =
461
-
// filters.showAll ||
462
-
matchesLikes ||
463
-
matchesReposts ||
464
-
matchesReplies ||
465
-
matchesQuotes;
462
+
const matchesAnything =
463
+
// filters.showAll ||
464
+
matchesLikes || matchesReposts || matchesReplies || matchesQuotes;
466
465
467
-
if (!matchesAnything) return null;
466
+
if (!matchesAnything) return null;
468
467
469
-
//if (fail) return;
468
+
//if (fail) return;
470
469
471
-
return (
472
-
<div className="flex flex-col">
473
-
{/* <span>fail likes {failLikes ? "true" : "false"}</span>
470
+
return (
471
+
<div className="flex flex-col">
472
+
{/* <span>fail likes {failLikes ? "true" : "false"}</span>
474
473
<span>fail repost {failReposts ? "true" : "false"}</span>
475
474
<span>fail reply {failReplies ? "true" : "false"}</span>
476
475
<span>fail qupte {failQuotes ? "true" : "false"}</span> */}
477
-
<div className="border rounded-xl mx-4 mt-4 overflow-hidden">
478
-
<UniversalPostRendererATURILoader
479
-
isQuote
480
-
key={uri}
481
-
atUri={uri}
482
-
nopics={true}
483
-
concise={true}
484
-
/>
485
-
<div className="flex flex-col divide-x">
486
-
{showLikes &&(<InteractionsButton
487
-
type={"like"}
488
-
uri={uri}
489
-
count={likes}
490
-
/>)}
491
-
{showReposts && (<InteractionsButton
492
-
type={"repost"}
493
-
uri={uri}
494
-
count={reposts}
495
-
/>)}
496
-
{showReplies && (<InteractionsButton
497
-
type={"reply"}
498
-
uri={uri}
499
-
count={replies}
500
-
/>)}
501
-
{showQuotes && (<InteractionsButton
502
-
type={"quote"}
503
-
uri={uri}
504
-
count={quotes}
505
-
/>)}
506
-
{!all && (
507
-
<div className="text-center text-gray-500 dark:text-gray-400 pb-3 pt-2 border-t">
508
-
No interactions yet.
509
-
</div>
510
-
)}
511
-
</div>
512
-
</div>
513
-
</div>
514
-
);
476
+
<div className="border rounded-xl mx-4 mt-4 overflow-hidden">
477
+
<UniversalPostRendererATURILoader
478
+
isQuote
479
+
key={uri}
480
+
atUri={uri}
481
+
nopics={true}
482
+
concise={true}
483
+
/>
484
+
<div className="flex flex-col divide-x">
485
+
{showLikes && (
486
+
<InteractionsButton type={"like"} uri={uri} count={likes} />
487
+
)}
488
+
{showReposts && (
489
+
<InteractionsButton type={"repost"} uri={uri} count={reposts} />
490
+
)}
491
+
{showReplies && (
492
+
<InteractionsButton type={"reply"} uri={uri} count={replies} />
493
+
)}
494
+
{showQuotes && (
495
+
<InteractionsButton type={"quote"} uri={uri} count={quotes} />
496
+
)}
497
+
{!all && (
498
+
<div className="text-center text-gray-500 dark:text-gray-400 pb-3 pt-2 border-t">
499
+
No interactions yet.
500
+
</div>
501
+
)}
502
+
</div>
503
+
</div>
504
+
</div>
505
+
);
515
506
}
516
507
517
508
function InteractionsButton({
518
-
type,
519
-
uri,
520
-
count,
509
+
type,
510
+
uri,
511
+
count,
521
512
}: {
522
-
type: "reply" | "repost" | "like" | "quote";
523
-
uri: string;
524
-
count: number;
513
+
type: "reply" | "repost" | "like" | "quote";
514
+
uri: string;
515
+
count: number;
525
516
}) {
526
-
if (!count) return <></>;
527
-
const aturi = new AtUri(uri);
528
-
return (
529
-
<Link
530
-
to={
531
-
`/profile/$did/post/$rkey` +
532
-
(type === "like"
533
-
? "/liked-by"
534
-
: type === "repost"
535
-
? "/reposted-by"
536
-
: type === "quote"
537
-
? "/quotes"
538
-
: "")
539
-
}
540
-
params={{
541
-
did: aturi.host,
542
-
rkey: aturi.rkey,
543
-
}}
544
-
className="flex-1 border-t py-2 px-4 flex flex-row items-center gap-2 transition-colors hover:bg-gray-100 hover:dark:bg-gray-800"
545
-
>
546
-
{type === "like" ? (
547
-
<MdiCardsHeartOutline height={22} width={22} />
548
-
) : type === "repost" ? (
549
-
<MdiRepeat height={22} width={22} />
550
-
) : type === "reply" ? (
551
-
<MdiCommentOutline height={22} width={22} />
552
-
) : type === "quote" ? (
553
-
<IconMdiMessageReplyTextOutline
554
-
height={22}
555
-
width={22}
556
-
className=" text-gray-400"
557
-
/>
558
-
) : (
559
-
<></>
560
-
)}
561
-
{type === "like"
562
-
? "likes"
563
-
: type === "reply"
564
-
? "replies"
565
-
: type === "quote"
566
-
? "quotes"
567
-
: type === "repost"
568
-
? "reposts"
569
-
: ""}
570
-
<div className="flex-1" /> {count}
571
-
</Link>
572
-
);
517
+
if (!count) return <></>;
518
+
const aturi = new AtUri(uri);
519
+
return (
520
+
<Link
521
+
to={
522
+
`/profile/$did/post/$rkey` +
523
+
(type === "like"
524
+
? "/liked-by"
525
+
: type === "repost"
526
+
? "/reposted-by"
527
+
: type === "quote"
528
+
? "/quotes"
529
+
: "")
530
+
}
531
+
params={{
532
+
did: aturi.host,
533
+
rkey: aturi.rkey,
534
+
}}
535
+
className="flex-1 border-t py-2 px-4 flex flex-row items-center gap-2 transition-colors hover:bg-gray-100 hover:dark:bg-gray-800"
536
+
>
537
+
{type === "like" ? (
538
+
<MdiCardsHeartOutline height={22} width={22} />
539
+
) : type === "repost" ? (
540
+
<MdiRepeat height={22} width={22} />
541
+
) : type === "reply" ? (
542
+
<MdiCommentOutline height={22} width={22} />
543
+
) : type === "quote" ? (
544
+
<IconMdiMessageReplyTextOutline
545
+
height={22}
546
+
width={22}
547
+
className=" text-gray-400"
548
+
/>
549
+
) : (
550
+
<></>
551
+
)}
552
+
{type === "like"
553
+
? "likes"
554
+
: type === "reply"
555
+
? "replies"
556
+
: type === "quote"
557
+
? "quotes"
558
+
: type === "repost"
559
+
? "reposts"
560
+
: ""}
561
+
<div className="flex-1" /> {count}
562
+
</Link>
563
+
);
573
564
}
574
565
575
566
export function NotificationItem({ notification }: { notification: string }) {
576
-
const aturi = new AtUri(notification);
577
-
const bite = aturi.collection === "net.wafrn.feed.bite";
578
-
const navigate = useNavigate();
579
-
const { data: identity } = useQueryIdentity(aturi.host);
580
-
const resolvedDid = identity?.did;
581
-
const profileUri = resolvedDid
582
-
? `at://${resolvedDid}/app.bsky.actor.profile/self`
583
-
: undefined;
584
-
const { data: profileRecord } = useQueryProfile(profileUri);
585
-
const profile = profileRecord?.value;
567
+
const aturi = new AtUri(notification);
568
+
const bite = aturi.collection === "net.wafrn.feed.bite";
569
+
const navigate = useNavigate();
570
+
const { data: identity } = useQueryIdentity(aturi.host);
571
+
const resolvedDid = identity?.did;
572
+
const profileUri = resolvedDid
573
+
? `at://${resolvedDid}/app.bsky.actor.profile/self`
574
+
: undefined;
575
+
const { data: profileRecord } = useQueryProfile(profileUri);
576
+
const profile = profileRecord?.value;
586
577
587
-
const [imgcdn] = useAtom(imgCDNAtom);
578
+
const [imgcdn] = useAtom(imgCDNAtom);
588
579
589
-
function getAvatarUrl(p: typeof profile) {
590
-
const link = p?.avatar?.ref?.["$link"];
591
-
if (!link || !resolvedDid) return null;
592
-
return `https://${imgcdn}/img/avatar/plain/${resolvedDid}/${link}@jpeg`;
593
-
}
580
+
function getAvatarUrl(p: typeof profile) {
581
+
const link = p?.avatar?.ref?.["$link"];
582
+
if (!link || !resolvedDid) return null;
583
+
return `https://${imgcdn}/img/avatar/plain/${resolvedDid}/${link}@jpeg`;
584
+
}
594
585
595
-
const avatar = getAvatarUrl(profile);
586
+
const avatar = getAvatarUrl(profile);
596
587
597
-
return (
598
-
<div
599
-
className="flex items-center p-4 cursor-pointer gap-3 justify-around border-b flex-row"
600
-
onClick={() =>
601
-
aturi &&
602
-
navigate({
603
-
to: "/profile/$did",
604
-
params: { did: aturi.host },
605
-
})
606
-
}
607
-
>
608
-
{/* <div>
588
+
return (
589
+
<div
590
+
className="flex items-center p-4 cursor-pointer gap-3 justify-around border-b flex-row"
591
+
onClick={() =>
592
+
aturi &&
593
+
navigate({
594
+
to: "/profile/$did",
595
+
params: { did: aturi.host },
596
+
})
597
+
}
598
+
>
599
+
{/* <div>
609
600
{aturi.collection === "app.bsky.graph.follow" ? (
610
601
<IconMdiAccountPlus />
611
602
) : aturi.collection === "app.bsky.feed.like" ? (
···
614
605
<></>
615
606
)}
616
607
</div> */}
617
-
{profile ? (
618
-
<img
619
-
src={avatar || defaultpfp}
620
-
alt={identity?.handle}
621
-
className="w-10 h-10 rounded-full"
622
-
/>
623
-
) : (
624
-
<div className="w-10 h-10 rounded-full bg-gray-300 dark:bg-gray-700" />
625
-
)}
626
-
<div className="flex flex-col min-w-0">
627
-
<div className="flex flex-row gap-2 overflow-hidden text-ellipsis whitespace-nowrap min-w-0">
628
-
<span className="font-medium text-gray-900 dark:text-gray-100 truncate">
629
-
{profile?.displayName || identity?.handle || "Someone"}
630
-
</span>
631
-
<span className="text-gray-700 dark:text-gray-400 truncate">
632
-
@{identity?.handle}
633
-
</span>
634
-
</div>
635
-
<div className="flex flex-row gap-2">
636
-
{identity?.did && <Mutual targetdidorhandle={identity?.did} />}
637
-
{/* <span className="text-sm text-gray-600 dark:text-gray-400">
608
+
{profile ? (
609
+
<img
610
+
src={avatar || defaultpfp}
611
+
alt={identity?.handle}
612
+
className="w-10 h-10 rounded-full"
613
+
/>
614
+
) : (
615
+
<div className="w-10 h-10 rounded-full bg-gray-300 dark:bg-gray-700" />
616
+
)}
617
+
<div className="flex flex-col min-w-0 flex-grow">
618
+
<div className="flex flex-row gap-2 items-center overflow-hidden text-ellipsis whitespace-nowrap min-w-0">
619
+
<ConditionalTextPlaceholder
620
+
show={profile != undefined}
621
+
placeholderClassName="flex-grow"
622
+
>
623
+
<span className="font-medium text-gray-900 dark:text-gray-100 truncate">
624
+
{profile?.displayName || identity?.handle}
625
+
</span>
626
+
</ConditionalTextPlaceholder>
627
+
<span className="text-gray-700 dark:text-gray-400 truncate">
628
+
@{identity?.handle}
629
+
</span>
630
+
</div>
631
+
<div className="flex flex-row gap-2">
632
+
{identity?.did && <Mutual targetdidorhandle={identity?.did} />}
633
+
{/* <span className="text-sm text-gray-600 dark:text-gray-400">
638
634
followed you
639
635
</span> */}
640
-
</div>
641
-
</div>
642
-
<div className="flex-1" />
643
-
{identity?.did && <FollowButton targetdidorhandle={identity?.did} />}
644
-
</div>
645
-
);
636
+
</div>
637
+
</div>
638
+
<div className="flex-1" />
639
+
{identity?.did && <FollowButton targetdidorhandle={identity?.did} />}
640
+
</div>
641
+
);
646
642
}
647
643
648
644
export const EmptyState = ({ text }: { text: string }) => (
649
-
<div className="py-10 text-center text-gray-500 dark:text-gray-400">
650
-
{text}
651
-
</div>
645
+
<div className="py-10 text-center text-gray-500 dark:text-gray-400">
646
+
{text}
647
+
</div>
652
648
);
653
649
654
650
export const LoadingState = ({ text }: { text: string }) => (
655
-
<div className="py-10 text-center text-gray-500 dark:text-gray-400 italic">
656
-
{text}
657
-
</div>
651
+
<div className="py-10 text-center text-gray-500 dark:text-gray-400 italic">
652
+
{text}
653
+
</div>
658
654
);
659
655
660
656
export const ErrorState = ({ error }: { error: unknown }) => (
661
-
<div className="py-10 text-center text-red-600 dark:text-red-400">
662
-
Error: {(error as Error)?.message || "Something went wrong."}
663
-
</div>
657
+
<div className="py-10 text-center text-red-600 dark:text-red-400">
658
+
Error: {(error as Error)?.message || "Something went wrong."}
659
+
</div>
664
660
);