Compare commits

...

630 Commits

Author SHA1 Message Date
dda38ab824 chore: Update translations 2023-12-01 14:25:03 +00:00
e9f70cd040 mobile footer 2023-12-01 16:22:54 +02:00
7443012995 don't show profilecard in searchbox results 2023-11-30 15:28:38 +02:00
a3f9aa2fbf chore: Update translations 2023-11-30 13:13:22 +00:00
07db21d4d0 "not followed by anyone you follow" 2023-11-30 15:12:06 +02:00
d4b343a18c ShortNote fix 2023-11-30 15:03:41 +02:00
4ce15ca1c5 restore graph to navbar on iris 2023-11-30 14:46:38 +02:00
69d47621ac chore: Update translations 2023-11-30 12:42:24 +00:00
91a10024e0 read-only mode nav avatar icon and text 2023-11-30 14:40:46 +02:00
96e49dac41 fix navigating between NostrLinkHandler urls 2023-11-30 13:51:06 +02:00
ce93ee1c41 trending notes bg color 2023-11-30 13:14:29 +02:00
a4f691d260 disable media and line breaks in trending notes 2023-11-30 13:10:46 +02:00
468dc3bae6 smaller trending notes 2023-11-30 12:52:13 +02:00
e8abd5ac09 notifications repost icon color 2023-11-30 11:25:50 +02:00
ad3ec993a6 darker font color in light theme 2023-11-29 16:51:11 +02:00
302aa2ec06 chore: Update translations 2023-11-29 14:01:42 +00:00
67af84e8bb smaller header in mobile size 2023-11-29 16:00:19 +02:00
7c63cf1ab5 chore: Update translations 2023-11-29 13:41:47 +00:00
fa701308c0 chore: Update translations 2023-11-29 13:40:58 +00:00
1febb82c22 chore: Update translations 2023-11-29 13:40:05 +00:00
2bd58a526c chore: Update translations 2023-11-29 13:39:17 +00:00
26e146251c chore: Update translations 2023-11-29 13:38:23 +00:00
b37d2b0fe8 move FollowedBy below bio in profile 2023-11-29 15:36:56 +02:00
902e2dd960 chore: Update translations 2023-11-29 13:27:49 +00:00
d704ded3d8 notif and qr profile link prefixes from config 2023-11-29 15:26:44 +02:00
1f82d38acb img grid paddings 2023-11-29 15:09:51 +02:00
bbcedbd99c
feat: add birthday 2023-11-29 12:44:13 +00:00
d84843a46d no avatar title when profilecard is shown 2023-11-29 14:37:14 +02:00
51e68b1288 ProfileCard: FollowedBy, fix tab selector z-index 2023-11-29 14:25:19 +02:00
3acb2d4d34 chore: Update translations 2023-11-29 12:14:32 +00:00
d2b95375b6 ProfileLink to /npub if profile not present 2023-11-29 14:13:14 +02:00
61e93bd194 remove npub copy from profile (still in qr view) 2023-11-29 14:12:09 +02:00
3a07e2abee hide nip05 in notes on iris 2023-11-29 14:12:09 +02:00
c3a6304573 better "followed by" layout 2023-11-29 14:12:09 +02:00
5be04c86b3 chore: Update translations 2023-11-29 12:08:30 +00:00
8b1745ae08
chore: typo 2023-11-29 12:07:12 +00:00
933ab4a71f
chore: add deck config 2023-11-29 12:06:46 +00:00
511f401367
feat: limit deck to subscribers 2023-11-29 12:05:47 +00:00
96e954d5e7 chore: Update translations 2023-11-29 10:54:49 +00:00
ca472a5756
chore: formatting 2023-11-29 10:53:17 +00:00
b6197f533f
chore: tweak right bar padding 2023-11-29 10:52:42 +00:00
11e3136008
chore: tweak donate page styles 2023-11-29 10:52:42 +00:00
8dc6f2884f
feat: filter nav sidebar 2023-11-29 10:52:42 +00:00
d27045794a
fix: align subscription 2023-11-29 10:52:41 +00:00
11824269f2
chore: tweak proxyimg for avatar 2023-11-29 10:52:41 +00:00
ea5e324793 restore layout overflow-x-hidden 2023-11-29 12:02:58 +02:00
benthecarman
9b5721faa4
Trim Zap comment
We had a bug when trying to parse the json of a comment. It had a \n at the end of it and a browser's json parser couldn't handle it. This should fix
2023-11-29 09:49:49 +00:00
6df3459dba chore: Update translations 2023-11-29 08:27:43 +00:00
de1ad63924 add donate link to navsidebar 2023-11-29 10:26:10 +02:00
37cc990f18 make feed selector sticky 2023-11-29 10:07:40 +02:00
1ffc2c6bf2 LoginSession.feedDisplayAs 2023-11-29 09:47:22 +02:00
83299f2feb rm trending hashtags & users 2023-11-29 09:03:30 +02:00
9299722ac0 fix build 2023-11-29 08:49:16 +02:00
acbe59b7bb chore: Update translations 2023-11-29 06:39:47 +00:00
79095b234b replace Feed / Grid with icons 2023-11-29 08:37:29 +02:00
700decbe06 fix grid img link url 2023-11-28 23:08:26 +02:00
71fcf4f4ac chore: Update translations 2023-11-28 20:53:34 +00:00
65686ae9f3 tighter grid layout on mobile 2023-11-28 22:52:19 +02:00
d240e82a95 correct proxy resize value for grid 2023-11-28 22:52:19 +02:00
ad163625c3 prop to hide displayAs selector 2023-11-28 22:52:19 +02:00
1330db056a DisplayAsSelector.tsx 2023-11-28 22:52:19 +02:00
6d1d1bfc44 init displayAs 2023-11-28 22:52:19 +02:00
bc6bced1b8 navigate to note by grid img click 2023-11-28 22:52:19 +02:00
aecb4408a0 chore: Update translations 2023-11-28 19:43:54 +00:00
ef4667c879 add feed / grid selector to feeds 2023-11-28 21:42:26 +02:00
c4273b9bdf image grid 2023-11-28 21:42:26 +02:00
04fea3e43b chore: Update translations 2023-11-28 18:21:15 +00:00
9393e3342d setting for showing content warning posts 2023-11-28 20:19:11 +02:00
9749883cc1 checkmark hover text 2023-11-28 14:49:49 +02:00
4d57cde8f0 avatar classnames 2023-11-28 14:49:49 +02:00
95aa6f78bb CONFIG.bypassImgProxyError to load directly from origin 2023-11-28 14:49:49 +02:00
07e2c15f54 NavSidebar search for non-logged-in 2023-11-28 14:49:49 +02:00
a06b7ccada tailwind classes for media grid 2023-11-28 14:49:49 +02:00
509228d532 chore: Update translations 2023-11-28 10:24:58 +00:00
ad0f691577 reorganize files & rm unused 2023-11-28 12:05:55 +02:00
79e303f097 hide sign-up/moderation in iris 2023-11-28 11:52:20 +02:00
398ab46e42 note creation file reordering 2023-11-28 11:39:12 +02:00
3541f7fea3 Merge remote-tracking branch 'kieran/main' 2023-11-28 11:23:41 +02:00
d28f287173 new note btn circular 2023-11-28 11:23:02 +02:00
d41e7e5ce0 use CONFIG.defaultRelays for new users 2023-11-28 10:47:57 +02:00
9d0f7f4596 hide NoteBroadcaster in iris 2023-11-28 10:40:36 +02:00
31129fab2c increase right column paddings 2023-11-27 22:57:48 +02:00
6190f3cd9d HasNotificationsMarker for left nav 2023-11-27 21:20:29 +02:00
836af8fbd2 remove some awaits from generateNewLogin 2023-11-27 18:37:11 +02:00
625c8d4d43 chore: Update translations 2023-11-27 15:25:04 +00:00
7dfb7ec363 Merge pull request '3-column layout' (#699) from mmalmi/snort:main into main 2023-11-27 15:22:02 +00:00
8deb27b3e2 increase avatar z-index 2023-11-27 17:19:15 +02:00
e184a96dc9 no navLogo for snort 2023-11-27 16:30:20 +02:00
09dd97111a Merge remote-tracking branch 'kieran/main' 2023-11-27 15:53:01 +02:00
9db117e270 goToEvent target handling 2023-11-27 15:31:45 +02:00
6b3102f30a note hover color 2023-11-27 15:06:51 +02:00
360ca20eba rm dms 4th column 2023-11-27 14:28:44 +02:00
dcd7faa3aa dm rounded corner 2023-11-27 14:26:33 +02:00
77ab39470f remove attachment button from dms 2023-11-27 14:22:48 +02:00
ae73e2b383 chat layout 2023-11-27 14:14:02 +02:00
ecd5ea111d dm layout fix 2023-11-27 11:10:58 +02:00
9043a1851d dm cursor-pointer 2023-11-26 22:58:30 +02:00
edf4c0db99
chore: bump packages 2023-11-26 17:56:04 +00:00
095564d16b chore: Update translations 2023-11-26 17:26:52 +00:00
42a95d8de0 Merge pull request 'More freedom in steps for zap pools sliders' (#701) from vivganes/snort:zap-pool-patch into main
Reviewed-on: Kieran/snort#701
2023-11-26 17:25:36 +00:00
61b4dba008 more freedom in steps for zap pools sliders 2023-11-26 17:13:31 +00:00
1080c4aa0e restore @uidotdev/usehooks 2023-11-26 17:09:35 +02:00
11cdd51eed update yarn.lock 2023-11-26 17:04:26 +02:00
0434ae43d8 hide right column in some views 2023-11-26 16:59:29 +02:00
8bc323489e split MessagesPage into smaller files 2023-11-26 16:45:42 +02:00
2e54104618 relative times 2023-11-26 16:21:56 +02:00
9fd1685fa1 fix mobile logo aspect ratio 2023-11-26 16:09:29 +02:00
c2bd6ae856 Merge remote-tracking branch 'kieran/main' 2023-11-26 15:52:50 +02:00
a612db65c7 add follow distance indicator to profile pages 2023-11-26 12:07:41 +02:00
a592974b93 add ErrorBoundary around layout outlet 2023-11-26 11:28:42 +02:00
920f8ae20d use dynamic imports instead of lazy loading for NetworkGraph 2023-11-26 11:17:59 +02:00
a92fc267c3 close profilecard on mouse leave 2023-11-25 22:54:24 +02:00
561ee94ab0 smaller trending notes 2023-11-25 21:20:18 +02:00
9a0b7c08d9 show more / less for long posts 2023-11-25 20:56:23 +02:00
8d44eb6a09 show ProfilePage settings button only in mobile size 2023-11-24 22:46:28 +02:00
e6be61e12a show own posts in follows feed 2023-11-24 21:17:04 +02:00
602592c424 chore: Update translations 2023-11-24 17:05:42 +00:00
b62519db31
chore: drop twitter embed 2023-11-24 17:04:04 +00:00
4813e4e4f1 smaller trending hashtags listing 2023-11-24 17:18:58 +02:00
b7545295d4 tmp disable tweet embed (require is not defined error) 2023-11-24 17:04:12 +02:00
e0b85b90f9 user?.pubkey 2023-11-24 16:37:12 +02:00
13b76e7709 show "followed by" on profile pages 2023-11-24 16:18:32 +02:00
47aec5437d fuse fuzzy user search 2023-11-24 15:50:40 +02:00
0f9f8ecb95
fix: brave toString weirdness 2023-11-24 12:10:56 +00:00
2c14a8f404 scrollable left navbar 2023-11-24 13:32:19 +02:00
e21e549969 chore: Update translations 2023-11-24 10:41:04 +00:00
edfe9c3697
fix: clear cache on install 2023-11-24 10:39:15 +00:00
365031516d
fix: build 2023-11-23 14:41:31 +00:00
b5606028e0 chore: Update translations 2023-11-23 14:40:23 +00:00
e18500c80b
chore: bump version 2023-11-23 14:37:45 +00:00
68ebe5e7b1
fix: notifications marker 2023-11-23 13:59:46 +00:00
0a3e15df82 chore: Update translations 2023-11-23 13:45:44 +00:00
9cae8ec6eb
chore: formatting 2023-11-23 13:44:30 +00:00
2c414c4a56
feat: backup key task 2023-11-23 13:43:23 +00:00
3e8fe2ca95
fix: live stream embed layout 2023-11-23 13:09:23 +00:00
0f07e75905
fix: modal styles on mobile 2023-11-23 12:43:20 +00:00
29bba9aef3 close graph on esc 2023-11-23 11:51:44 +02:00
6bef3ccf58 remove link directional particles from social graph 2023-11-23 11:43:55 +02:00
a0151745bf mv social graph link from settings menu to nav 2023-11-23 11:41:38 +02:00
6a6accfed6 narrow navbar in deck view 2023-11-23 11:28:30 +02:00
4eb0408c27 use same navbar in deck view 2023-11-23 11:01:17 +02:00
ef77606427 active settings menu item style 2023-11-23 10:57:28 +02:00
7e69e9a42a active nav item style 2023-11-23 10:31:19 +02:00
bfc42bcd36 add search icon to navbar 2023-11-23 10:14:41 +02:00
f3eb414c6a hide right col scrollbar 2023-11-23 09:52:19 +02:00
20c4ecaa0c
fix: topics 2023-11-22 16:16:07 +00:00
62e99a4ed4 right column trending bg 2023-11-22 18:14:34 +02:00
5d9ca5ee39
feat: sync public chats 2023-11-22 16:11:58 +00:00
6fd2741cc0
fix: nip28 chats loading 2023-11-22 15:52:30 +00:00
2884a35b5c
chore: random fixes 2023-11-22 15:34:46 +00:00
90c00c5fa4 TrendingUsers and Hashtags default count Infinity 2023-11-22 17:28:22 +02:00
b52b84e466 deck icon 2023-11-22 17:21:00 +02:00
de524b50fc make whole page element scrollable 2023-11-22 17:10:00 +02:00
1af8316453 add Deck nav link 2023-11-22 16:45:39 +02:00
55fae3aa41 restore useLoginFeed 2023-11-22 16:13:36 +02:00
a67263e5e1
feat: automated outbox model 2023-11-22 13:58:53 +00:00
131e564bd0 left nav layout 2023-11-22 15:24:30 +02:00
c5bc1cdbe7 app icon in navbar 2023-11-22 15:13:33 +02:00
e788e01c6d sticky header in mobile size 2023-11-22 15:02:45 +02:00
28bf0ea581 sticky right column 2023-11-22 14:31:08 +02:00
ced63ab6d1 new note text in sidebar btn 2023-11-22 14:25:43 +02:00
e97b9bdba4 scrollable trending column 2023-11-22 14:13:40 +02:00
f9e7bc8558 add trending stuff to right column 2023-11-22 14:06:42 +02:00
f9d0318f36 rm main-content border 2023-11-22 13:53:59 +02:00
a80c330e5b chore: Update translations 2023-11-22 11:41:32 +00:00
92c26ca609
feat: write reply events to recipients relays 2023-11-22 11:40:28 +00:00
f5bb524628 Revert "lazy load Notifications page"
This reverts commit d8dfc962c1.
2023-11-22 13:32:18 +02:00
77984f9124 right col border 2023-11-22 13:22:39 +02:00
cb5fd78382 sidebar items for non-logged-in user 2023-11-22 13:22:39 +02:00
9aafc329cb home icon 2023-11-22 13:22:38 +02:00
59ffb84458 /new/discover -> /discover 2023-11-22 13:22:38 +02:00
c5d22b84be layout 2023-11-22 13:22:38 +02:00
8e5acc3ea5 settings & notes icons 2023-11-22 13:22:38 +02:00
667bce637f profile link to nav sidebar 2023-11-22 13:22:38 +02:00
4dfa610c87 simplify settings page 2023-11-22 13:22:38 +02:00
dd941ae70e wip 3-col layout 2023-11-22 13:22:38 +02:00
60af57059b use vitest instead of jest 2023-11-22 13:22:38 +02:00
f69e05d8fc rollup visualizer output to build dir 2023-11-22 13:22:38 +02:00
d8dfc962c1 lazy load Notifications page 2023-11-22 13:22:38 +02:00
56db2f652d
use relative paths for resources 2023-11-22 09:49:56 +00:00
756e50f866
chore: fix public dirs 2023-11-21 14:21:47 +00:00
fbd479b4fb
fix: assetlinks 2023-11-21 14:02:42 +00:00
0f5324ccad chore: Update translations 2023-11-21 13:54:06 +00:00
2030cb2061
feat: lazy load notification graph 2023-11-21 13:52:05 +00:00
731d312d92
chore: Update manifest 2023-11-21 13:51:48 +00:00
b64c9fa767
fix: vscode imports 2023-11-20 22:10:34 +00:00
aaa56738b5
fix: about page 2023-11-20 21:51:23 +00:00
7b4e6db306
chore: remove webpack 2023-11-20 21:35:08 +00:00
c44877f780 chore: Update translations 2023-11-20 19:37:56 +00:00
dcbc10686c
chore: use build dir 2023-11-20 19:36:47 +00:00
8dadb77555 chore: Update translations 2023-11-20 19:29:59 +00:00
377061e9d6
chore: re-enable wasm 2023-11-20 19:28:22 +00:00
7c8fff97ce
chore: cleanup / yarn sdks 2023-11-20 19:16:47 +00:00
e8bcba129e
feat: (nip96) nostrcheck.me 2023-11-20 19:09:57 +00:00
c9baf487ae Merge pull request 'Vite build tools' (#695) from mmalmi/snort:main into main
Reviewed-on: Kieran/snort#695
2023-11-20 16:22:07 +00:00
81d4382aba Merge pull request 'Vite build tools' (#695) from mmalmi/snort:main into main 2023-11-20 16:21:46 +00:00
5c0ad1c375 fix import.meta.url in cjs error 2023-11-20 18:19:26 +02:00
5b3680d0df add rollup visualizer plugin 2023-11-20 18:19:26 +02:00
69c97033fb sw works in production build 2023-11-20 18:19:26 +02:00
ef85b47b58 tmp disable sw, add FormattedMessage ids via eslint 2023-11-20 18:19:26 +02:00
6d706717c8 sw loading 2023-11-20 18:19:26 +02:00
52553adabf wip vite 2023-11-20 18:19:24 +02:00
5942d92923
feat: nip96 2023-11-20 15:36:26 +00:00
38277c3252 chore: Update translations 2023-11-20 10:42:06 +00:00
8deec37d15
chore: update readme 2023-11-20 10:39:58 +00:00
1687137572 Merge pull request 'SocialGraph' (#691) from mmalmi/snort:main into main
Reviewed-on: Kieran/snort#691
2023-11-18 11:45:12 +00:00
f2ff2c65be
feat: use blasters for new user metadata 2023-11-17 22:21:43 +00:00
e3cb397d1d chore: Update translations 2023-11-17 21:52:03 +00:00
9721aa506a
fix: random exception on mentions 2023-11-17 21:50:12 +00:00
eba47f085d
fix: preserve tag info in notification context 2023-11-17 20:39:44 +00:00
839f448231 chore: Update translations 2023-11-17 20:24:27 +00:00
3c2bfbb4c6
chore: tweak relays 2023-11-17 20:21:40 +00:00
588c3756fd
feat: use close relays 2023-11-17 20:04:09 +00:00
55c938961f chore: Update translations 2023-11-17 11:31:25 +00:00
aef27bf879 chore: Update translations 2023-11-17 11:30:07 +00:00
541f6164a7
fix: mute words trending 2023-11-17 11:28:57 +00:00
9bec963da2 chore: Update translations 2023-11-17 11:12:34 +00:00
5589e748b5
chore: improve hashtags header 2023-11-17 11:10:55 +00:00
e1f4aab214
fix: muted words 2023-11-17 11:10:55 +00:00
8666467efc feed all follow events to socialGraphInstance.handleFollowEvent 2023-11-17 12:02:08 +02:00
963ce098c6 system/SocialGraph, socialGraphInstance 2023-11-17 11:47:12 +02:00
3e50d34786 chore: Update translations 2023-11-16 15:56:53 +00:00
5a63a21fec
chore: cleanup 2023-11-16 15:54:39 +00:00
981ab5790a
feat: note creator hashtags 2023-11-16 15:54:39 +00:00
95b7cca4cb
feat: trending hashtags 2023-11-16 15:54:39 +00:00
ee0865d9af chore: Update translations 2023-11-16 12:40:34 +00:00
3611af9dce
Merge remote-tracking branch 'mmalmi/main' 2023-11-16 12:37:58 +00:00
83ffe746b1
fix: lockfile 2023-11-16 12:37:58 +00:00
d0bcc59372 Merge pull request 'fix: issue #671 unreadable profile pop-ups' (#673) from jamesmagoo/snort:main into main
Reviewed-on: Kieran/snort#673
2023-11-16 11:43:17 +00:00
985827ba22
fix: pin/bookmark 2023-11-15 11:24:11 +00:00
e65845af6d
feat: include targetEvents in parsedZap 2023-11-14 13:55:15 +00:00
e398bf8e82
chore: bump pkg 2023-11-14 13:48:24 +00:00
a2d084ab70
fix: replyToThis bug 2023-11-14 13:33:54 +00:00
7174ed2502
refactor: simplify useEventReactions hook 2023-11-14 12:55:46 +00:00
c794a9e393
chore: bump system-web 2023-11-14 12:10:42 +00:00
5fea9f3dfb
chore: bump packages 2023-11-14 12:07:25 +00:00
eb47da0417
fix: context 2023-11-14 11:43:50 +00:00
b1e7cf6bf9 chore: Update translations 2023-11-14 11:11:19 +00:00
55ec27cf4a
fix: tweaks 2023-11-14 11:09:54 +00:00
c530e4ba72
feat: topics page 2023-11-14 11:09:54 +00:00
f2a41cb474
refactor: inline hashtag posts 2023-11-14 11:09:53 +00:00
de1b982e93 chore: Update translations 2023-11-14 09:53:04 +00:00
81d6f41050
feat: update topic lists 2023-11-13 22:55:51 +00:00
24978f4e62
feat: appdata 2023-11-13 16:51:29 +00:00
540f29dd69
feat: hashtags header 2023-11-13 15:58:14 +00:00
815fc344f1 Remove media queries 2023-11-12 22:51:09 +00:00
6db13c05c6 Merge remote-tracking branch 'upstream/main' 2023-11-12 22:46:51 +00:00
e9b7c7c6e3
chore: improve logging 2023-11-11 13:39:33 +00:00
6f396c825c
fix: auth 2023-11-11 13:31:38 +00:00
b5df7dbb6e Merge remote-tracking branch 'upstream/main' 2023-11-10 14:44:19 +00:00
04a49755e6
feat: nreq 2023-11-10 13:58:27 +00:00
b765cb29b7
refactor: update nip51 support 2023-11-10 13:17:19 +00:00
e087df2f63
fix: load WebLN wallet later 2023-11-10 10:14:02 +00:00
5b2d8741ba chore: Update translations 2023-11-10 10:02:59 +00:00
e72190b49f
fix: mixing timeline with no posts 2023-11-10 10:02:05 +00:00
36c1d9502c chore: Update translations 2023-11-10 09:57:24 +00:00
70fd872848
feat: lang specific trending 2023-11-10 09:54:08 +00:00
98f6a686b0
feat: mixin hashtags 2023-11-10 09:43:02 +00:00
9082630cc2 flix css class to light as per comment 2023-11-09 18:27:45 +00:00
aa31047c45
fix: missing sent timestamp on force-close query 2023-11-09 14:30:59 +00:00
8014d84b3d fix: issue #671 unreadable profile pop-ups 2023-11-09 12:51:12 +00:00
ff2da6c5fd
feat: timeline fragments 2023-11-09 12:20:53 +00:00
ffda4b1a43 chore: Update translations 2023-11-09 09:42:36 +00:00
9016d21eaa Merge pull request 'allow upload of files using drag and drop' (#670) from fernandoporazzi/snort:drag-and-drop-images into main
Reviewed-on: Kieran/snort#670
2023-11-09 09:41:12 +00:00
Fernando Porazzi
34fa2bb524
allow upload of files using drag and drop 2023-11-08 18:59:21 +01:00
7e590a4ef8 chore: Update translations 2023-11-08 15:44:23 +00:00
7088bee14d
fix: logged out lang 2023-11-08 15:43:18 +00:00
732a895a58 chore: Update translations 2023-11-08 15:18:57 +00:00
2d4d9117bd
fix: events 2023-11-08 15:18:01 +00:00
0e202b12d9 chore: Update translations 2023-11-08 14:49:48 +00:00
d119a5f626
feat: sign up flow v2 2023-11-08 14:47:46 +00:00
a2bcb936ef
fix: trim invalid chars from NostrLink 2023-11-08 14:47:46 +00:00
b4697d1e04 chore: Update translations 2023-11-08 09:47:27 +00:00
c9935a275e
feat: system on-event 2023-11-08 09:45:47 +00:00
3326aedc52
feat: collect relay metrics 2023-11-08 09:45:47 +00:00
8dbbb24729 chore: Update translations 2023-11-07 14:23:15 +00:00
b234762f62
chore: fetch tags in ci 2023-11-07 14:21:44 +00:00
cf6aa6b134
feat: default zap pool amount 2023-11-07 14:21:44 +00:00
e627cddd24
feat: relays cleanup 2023-11-07 14:21:44 +00:00
fcd2c8a3a0
feat: event emitter 2023-11-07 14:21:44 +00:00
fc3d196f48
chore: formatting 2023-11-07 14:21:43 +00:00
b166427f28
fix: relays tab on profile 2023-11-07 14:21:43 +00:00
d60862da11
fix: render less on notifications page 2023-11-07 14:21:43 +00:00
758107fd50
bug: parse legacy tag refs 2023-11-07 14:21:43 +00:00
e248889170
feat: select forward type 2023-11-07 14:21:43 +00:00
c689bd39dc
feat: add leo to contributors 2023-11-07 14:21:43 +00:00
f2456e060e chore: Update translations 2023-11-06 14:17:23 +00:00
de0e58b657
feat: autoTranslate preferences 2023-11-06 14:16:19 +00:00
3d69762359
chore: update prod script 2023-11-06 14:04:03 +00:00
9d91cc6ec9
fix: no subs error 2023-11-06 14:02:40 +00:00
6ca8f8f339
chore: auto translate for pro 2023-11-06 13:40:18 +00:00
5fe8a5e3b6 chore: Update translations 2023-11-06 13:34:09 +00:00
6e349051a2
feat: auto translate 2023-11-06 13:32:02 +00:00
e0b68ae817
chore: more relay info 2023-11-06 12:46:17 +00:00
b3c8ee982d
feat: get country from timezone 2023-11-05 13:48:33 +09:00
d59c3ebdcb
chore: remove unused 2023-11-05 11:42:06 +09:00
58e6be94fa
chore: remove nostr.watch 2023-11-05 11:41:11 +09:00
4ccb052edb chore: Update translations 2023-11-05 02:31:26 +00:00
f482c004b3
chore: stop loading kind3 for relay info 2023-11-03 14:48:26 +09:00
0ebd2f167a
chore: formatting 2023-11-03 14:30:54 +09:00
930b493a12
fix: write relays only in relay metadata 2023-11-03 14:30:22 +09:00
9eb029e1dc
fix: zapper for zap goals 2023-11-03 10:07:06 +09:00
0cef163eb9
fix: zap goal embed 2023-11-03 09:56:17 +09:00
71a05dd13c
feat: about 2023-11-03 02:40:02 +09:00
2f1d48792a chore: Update translations 2023-11-02 16:46:51 +00:00
ed3b6c84cf
fix: remove relay tag from zap e/a tag 2023-11-03 01:43:34 +09:00
f252087f6b
fix: startup relay race condition 2023-11-02 07:24:57 +09:00
d4bf929e60
fix: upgrade existing connection to non-ephemeral 2023-11-02 06:48:07 +09:00
32c80ed1c5 chore: Update translations 2023-11-01 21:12:59 +00:00
83a085a343
feat: deepl translate 2023-11-02 06:11:00 +09:00
f994f8722d chore: Update translations 2023-10-31 15:43:19 +00:00
6f15580682
chore: formatting 2023-11-01 00:40:57 +09:00
c65bb7a992
chore: cleanup 2023-11-01 00:40:12 +09:00
8f90daa840 chore: Update translations 2023-10-22 13:12:00 +00:00
46d7c000ac
fix: sub renew 2023-10-22 14:10:11 +01:00
454f957653
chore: print notification payload 2023-10-21 23:05:06 +01:00
c2991b8e26
fix: note creator mobile 2023-10-21 22:26:04 +01:00
63950f1e6b
chore: formatting 2023-10-21 21:46:15 +01:00
0e3661afc6
fix: note broadcaster bug / createPortal for modal 2023-10-21 21:45:50 +01:00
c1ea68b296
fix: Remove default lang 2023-10-20 13:55:50 +01:00
22224cb4f2 chore: Update translations 2023-10-20 12:47:54 +00:00
548247f39c
fix: notification badge 2023-10-20 13:46:50 +01:00
083f8a9edb chore: Update translations 2023-10-20 12:34:54 +00:00
6f1c36d53e chore: Update translations 2023-10-20 12:33:57 +00:00
b379550827
fix: wrong url in notifications 2023-10-20 13:33:06 +01:00
7b29290420
fix: service worker build 2023-10-20 13:26:53 +01:00
d06a914e01 chore: Update translations 2023-10-20 12:23:54 +00:00
76ec08a251 chore: Update translations 2023-10-20 12:22:25 +00:00
938bc84fb3 chore: Update translations 2023-10-20 12:21:03 +00:00
74480af85b chore: Update translations 2023-10-20 12:19:51 +00:00
2dd84bd280
fix: open note1 links from notification 2023-10-20 13:18:28 +01:00
fd746440b6
fix: open correct url for notifications 2023-10-20 13:13:18 +01:00
a5ae474c8b
chore: cleanup notification body 2023-10-20 12:54:49 +01:00
c68565c484 chore: Update translations 2023-10-20 11:32:48 +00:00
9f763fccba
feat: render other notification types 2023-10-20 12:31:21 +01:00
12c678ca7a chore: Update translations 2023-10-20 10:59:31 +00:00
bee0cc1188
feat: add scope to push notifications 2023-10-20 11:58:07 +01:00
15795d442f chore: Update translations 2023-10-19 18:26:53 +00:00
824b6fdce4
feat: cache in settings 2023-10-19 19:25:33 +01:00
c96ea94bb3
chore: remove big E 2023-10-19 16:46:05 +01:00
234d354062
fix: compact push notifications 2023-10-19 16:38:14 +01:00
3f28c94a56
chore: cleanup 2023-10-19 16:07:37 +01:00
1a984a8075
fix: use notification tag 2023-10-19 16:06:44 +01:00
748fe22101
feat: click notification 2023-10-19 15:22:07 +01:00
b5e9203742
feat: push notifications 2023-10-19 13:28:23 +01:00
c823cd314d chore: Update translations 2023-10-18 21:28:17 +00:00
8ea5be1504
fix: docker nginx config 2023-10-18 22:26:36 +01:00
ccd98bef1b
fix: center images 2023-10-18 15:50:29 +01:00
3b3a920124
fix: tests 2023-10-18 15:36:39 +01:00
4d4106a3ff
fix: center avatars 2023-10-18 15:18:19 +01:00
3714867b98
chore: drop nostrplebs 2023-10-18 15:12:48 +01:00
4be93c8f51
fix: always encode as naddr for PRE 2023-10-18 15:06:35 +01:00
ce09b92518 chore: Update translations 2023-10-18 14:00:38 +00:00
c0bfe376ed
fix: various 2023-10-18 14:59:14 +01:00
98c3d901ae
feat: renew sub task 2023-10-18 14:47:50 +01:00
0ba1ba05ac
fix: spotlight media styles 2023-10-18 14:47:50 +01:00
09cdd501c3
fix: max-height images 2023-10-18 14:47:50 +01:00
d954b90bfd
fix: fast zap not working 2023-10-18 14:47:50 +01:00
c565dbc993
chore: css fixes / rename subscription to pro 2023-10-18 14:47:49 +01:00
51f0d2ed15 chore: Update translations 2023-10-18 13:01:37 +00:00
63d3645dda Merge pull request 'Search dropdown' (#655) from mmalmi/snort:main into main 2023-10-18 13:00:23 +00:00
190dd92f9a fix esc handler 2023-10-18 15:44:03 +03:00
a331e43b4e search dropdown 2023-10-18 15:44:03 +03:00
5535614455 SearchBox.css 2023-10-18 15:44:03 +03:00
8e9e75c5f0 fix NoteFooter reacted colors 2023-10-18 15:44:03 +03:00
e3d17254f8 move nav search to its own component 2023-10-18 15:44:03 +03:00
cf60dcb654 chore: Update translations 2023-10-18 10:40:17 +00:00
c4bbafb9d7
feat: seasonal features 2023-10-18 11:39:15 +01:00
ab50afe917
fix: note creator styles 2023-10-18 11:21:25 +01:00
2ff072f442 chore: Update translations 2023-10-18 10:15:02 +00:00
0e0d768eec
feat: toggle switch 2023-10-18 11:13:11 +01:00
a081f9655e
chore: always add prefix on encode 2023-10-18 09:50:26 +01:00
81df18ea4e Merge pull request 'Event & profile links' (#653) from mmalmi/snort:main into main
Reviewed-on: Kieran/snort#653
2023-10-18 07:06:41 +00:00
2e663dcb4c NostrLink.encode(prefix: NostrPrefix) 2023-10-18 10:01:25 +03:00
52f70056f8 chore: Update translations 2023-10-17 22:06:33 +00:00
7a1df4a178
feat: profile cards on mentions 2023-10-17 23:01:53 +01:00
d50979b8ae
fix: add default robohash image path 2023-10-17 22:32:06 +01:00
9b3cc94d18
chore: robohash set2 2023-10-17 22:31:18 +01:00
700db8f62c "share note" url 2023-10-17 22:02:41 +03:00
2c7878ac7f CONFIG.profileLinkSuffix 2023-10-17 21:50:11 +03:00
d9bd198e8d CONFIG.eventLinkPrefix 2023-10-17 21:36:22 +03:00
ca18cf25e3 rm /e/ and /p/ from event & profile links 2023-10-17 20:02:32 +03:00
089c40d816
fix: load more subscription events 2023-10-17 16:36:12 +01:00
3f82b31b6b
fix: flex fixes 2023-10-17 16:33:29 +01:00
0548e1a9e1
fix: flex styles 2023-10-17 16:33:29 +01:00
2b09da6959 chore: Update translations 2023-10-17 13:06:06 +00:00
a0d14b158b
chore: formatting 2023-10-17 14:04:48 +01:00
faaeb6af4a
refactor: flex styles / fixes / profile links 2023-10-17 14:04:48 +01:00
6479a18cb2
feat: sub renew months 2023-10-17 14:04:48 +01:00
9f6a030a11 chore: Update translations 2023-10-17 09:56:28 +00:00
88c146d729
fix: lock file 2023-10-17 10:55:37 +01:00
281785952d
feat: more feature flags 2023-10-17 10:54:34 +01:00
1a507679f3
chore: add all reactions 2023-10-16 21:37:15 +01:00
f34ccf72cb
fix: cleanup 2023-10-16 21:33:01 +01:00
5e42c5e70c
feat: add useEventReactions to system-react 2023-10-16 21:24:54 +01:00
3b427338f4
chore: bump packages 2023-10-16 20:31:12 +01:00
725d6d11f0 chore: Update translations 2023-10-16 16:10:42 +00:00
f24d9982f4
feat: upload stage 2023-10-16 17:09:17 +01:00
dec2b9ce2e
chore: cleanup AsyncIcon element 2023-10-16 17:09:16 +01:00
497ef7bf9a chore: Update translations 2023-10-16 15:15:03 +00:00
0f40b9a426
chore: remove "popular" accounts list 2023-10-16 16:14:08 +01:00
a168465bdb Merge pull request 'tailwind' (#651) from mmalmi/snort:main into main 2023-10-16 15:12:04 +00:00
28fa0b4bc8
feat: use imgproxy to generate video posters 2023-10-16 15:53:31 +01:00
2ce5bd153b
feat: classnames 2023-10-16 15:48:56 +01:00
7129ffa1c7
don't close publish modal automatically.
even if all relays responded with an OK the modal will still remain open so the
user can look at the list of relays the note was published to.
2023-10-16 14:44:56 +01:00
227b3b8dd7
add trailingComma to prettier settings.
because my system was still using the old defaults and that was bad.
2023-10-16 14:44:55 +01:00
f0110e9009
feat: note creator button on deck 2023-10-16 14:44:55 +01:00
65552e126b
fix: spotlight bugs 2023-10-16 14:44:55 +01:00
5162887807 chore: Update translations 2023-10-16 12:47:11 +00:00
e378a53b21
feat: long form deck modal 2023-10-16 13:46:09 +01:00
d9fc4f37b0 chore: Update translations 2023-10-16 10:09:08 +00:00
6448996529
feat: file upload progress / imeta 2023-10-16 11:07:13 +01:00
a29d82bd56
fix: memoize note inner to prevent video reloading 2023-10-15 23:19:22 +01:00
3a95689792 chore: Update translations 2023-10-15 20:42:11 +00:00
10e83a5f55
Big E tag
https://github.com/nostr-protocol/nips/issues/812
2023-10-15 21:40:20 +01:00
4bf868c05a
chore: default sig checks off 2023-10-14 08:29:36 +01:00
cf7d9b8883 chore: Update translations 2023-10-13 21:24:42 +00:00
70925e6f08
feat: auth file uploaders 2023-10-13 22:22:21 +01:00
94058efb60 chore: Update translations 2023-10-13 15:43:58 +00:00
55d089072d
chore: disable code blocks 2023-10-13 16:43:11 +01:00
ce550eb206 chore: Update translations 2023-10-13 15:35:46 +00:00
93e8e0bbae
feat: make sig checks optional 2023-10-13 16:34:31 +01:00
87bb9dafeb
fix: check all sigs 2023-10-13 14:39:37 +01:00
9251d5b90a chore: Update translations 2023-10-13 11:42:15 +00:00
a647fd09b3
feat: quote repost
closes #217
2023-10-13 12:40:39 +01:00
ddb8e623f4
feat: show replies count 2023-10-13 11:22:58 +01:00
9b66b7b1da
fix: hide blocked replies 2023-10-13 11:16:44 +01:00
3b363d988e chore: Update translations 2023-10-13 10:12:26 +00:00
430763478f
fix: use last e/a tag for reply context 2023-10-13 11:10:55 +01:00
85faf528c5
fix: hide muted dms 2023-10-12 22:07:18 +01:00
2e38ac0d4f
feat: respond to auth only when expected 2023-10-12 22:02:05 +01:00
a080f0bb0c chore: Update translations 2023-10-12 15:29:54 +00:00
f5aa898631
feat: list feed rendering 2023-10-12 16:28:42 +01:00
01af3a3a58
fix: timeline feed reactions 2023-10-12 16:28:42 +01:00
733fb6da30
fix: filter expired status 2023-10-12 16:28:42 +01:00
81642b906e chore: Update translations 2023-10-12 14:56:59 +00:00
8f401c07bc
fix: typo 2023-10-12 15:55:36 +01:00
6e73e51501
feat: render kind 3 2023-10-12 15:54:46 +01:00
6650c48c98
fix: remove extra hashtag space 2023-10-12 15:16:35 +01:00
95a715839d
fix: disable WASM when not available 2023-10-12 15:12:06 +01:00
7513d4cdd3
chore: add avatar gradients to iris.to domain 2023-10-12 15:02:08 +01:00
a0207e8874
fix: use correct hostname in analytics script 2023-10-12 14:45:30 +01:00
a8964a2248
ci: checkout app from tag 2023-10-11 21:36:54 +01:00
102134d47f chore: Update translations 2023-10-11 20:00:46 +00:00
5a67edaf0b
fix: typo 2023-10-11 20:59:35 +01:00
2155d00a07 chore: Update translations 2023-10-11 18:26:44 +00:00
5360c5ad3b Merge pull request 'feat: add keyboard shortcuts' (#649) from fernandoporazzi/snort:scroll-up-shortcut into main
Reviewed-on: Kieran/snort#649
2023-10-11 18:25:07 +00:00
a0c8012f8e
Add retry/delete to note broadcaster 2023-10-11 19:24:11 +01:00
88ac4063cd
validate events on receive 2023-10-11 19:24:10 +01:00
022296fa18 chore: Update translations 2023-10-11 14:43:31 +00:00
0e4a040750
feat: note publishing progress 2023-10-11 15:41:36 +01:00
c239fba3df
fix: Filter a tagged as replies on timeline 2023-10-11 11:47:58 +01:00
ece4219180 chore: Update translations 2023-10-11 10:46:33 +00:00
6eca5a632d
feat: long form rendering 2023-10-11 11:45:10 +01:00
3b505f6c3e
relax zaps validation 2023-10-11 11:45:10 +01:00
bcaaba3fd4 chore: Update translations 2023-10-11 08:42:34 +00:00
09a9364163
fix: follow button response 2023-10-11 09:40:54 +01:00
Fernando Porazzi
5d137f281f
solve conflicts 2023-10-10 23:37:37 +02:00
Fernando Porazzi
b0d84779c8
feat: add keyboard shortcuts 2023-10-10 23:27:27 +02:00
2c31a37b6a
fix: gallery skip empty text elements 2023-10-10 12:40:18 +01:00
50bfd9eaa0
setup stalker mode 2023-10-10 12:20:49 +01:00
672255187f chore: Update translations 2023-10-10 09:43:20 +00:00
9d33abbf1e
feature flags config / typed app config 2023-10-10 10:37:53 +01:00
c023a89271 Merge pull request 'Profile urls, scrollbar, ProfilePage refactoring' (#646) from mmalmi/snort:main into main
Reviewed-on: Kieran/snort#646
2023-10-09 18:41:22 +00:00
b59c5685f9 Merge remote-tracking branch 'kieran/main' 2023-10-09 19:12:43 +03:00
8d882a0844
Profile hover cards 2023-10-09 16:32:14 +01:00
b62b877f5a
fix: build command order 2023-10-09 14:55:04 +01:00
01234d7be7 chore: Update translations 2023-10-09 13:52:12 +00:00
b5499f516c
fix: build scripts 2023-10-09 14:51:07 +01:00
8f153b0428 chore: Update translations 2023-10-09 13:36:42 +00:00
b27bb47007
Notification summary 2023-10-09 14:35:21 +01:00
15fb4cabdf css selector based margin-top 2023-10-09 16:06:47 +03:00
dbaad8bbb3 make useIsVerified pubkey param optional 2023-10-09 15:58:01 +03:00
79ef147023 simpler profile url nip05 replacement 2023-10-09 15:44:47 +03:00
237ce498b7
Add snort asset links 2023-10-09 11:01:44 +01:00
226b0632a3 chore: Update translations 2023-10-09 09:11:47 +00:00
12723cf54b Merge pull request 'Highlight code blocks' (#645) from fernandoporazzi/snort:code-highlighter into main
Reviewed-on: Kieran/snort#645
2023-10-09 09:10:35 +00:00
d2f786c98e
Run only test/lint on pr 2023-10-09 10:09:39 +01:00
Fernando Porazzi
9c4871d3c1
feat: highlight code blocks 2023-10-09 11:05:53 +02:00
224960a11f add spacing before media and link embeds 2023-10-08 16:40:23 +03:00
091169ae7d return note or profile component directly from NostrLinkHandler 2023-10-08 16:21:56 +03:00
5ed096509a use DisplayName on profile page 2023-10-08 15:27:41 +03:00
3f7ac9e2d4 if username@{NIP05_DOMAIN} valid, change profile page url to /username 2023-10-08 11:04:23 +03:00
9f5d467745 body overflow-y: scroll to reduce layout shift 2023-10-08 11:04:23 +03:00
e949708cec extract ProfileTab from ProfilePage 2023-10-08 11:04:23 +03:00
585f031ce1
fix: bad tsconfig 2023-10-06 14:17:28 +01:00
0ff3aad6cb
ci: fix import 2023-10-06 13:59:44 +01:00
bc8e08ba47
ci: fix Dockerfile build 2023-10-06 13:56:41 +01:00
92c90b40ee
use unprivileged nginx image
closes https://github.com/v0l/snort/pull/567
2023-10-06 13:42:19 +01:00
2a6433a6b4
ci: invert if 2023-10-06 13:31:10 +01:00
fb28f5d7df
Fix crowdin command to ignore no-changes 2023-10-06 13:26:36 +01:00
cb8fec85c3 chore: Update translations 2023-10-06 12:20:20 +00:00
aa1ab7023f
Remove useless test 2023-10-06 13:19:33 +01:00
74c61ca9ba
Fix tests 2023-10-06 13:16:28 +01:00
e583770518
add missing config 2023-10-06 10:41:37 +01:00
71f5af649c chore: Update translations 2023-10-06 09:39:08 +00:00
873ba0a1d2 Merge pull request 'Modal, process.env.HTTP_CACHE' (#643) from mmalmi/snort:main into main
Reviewed-on: Kieran/snort#643
2023-10-06 09:38:25 +00:00
90ac55d561 extract some Note parts into separate files 2023-10-06 12:11:32 +03:00
efa303b68f rm unused const and comment 2023-10-06 12:00:22 +03:00
4e2b7e6bb9 check name.length > 0 2023-10-06 11:57:46 +03:00
40e05480e6 animal name placeholder in all getDisplayName calls 2023-10-06 11:30:46 +03:00
ef7fc458f6 optional animal name placeholders for profile names 2023-10-06 11:30:46 +03:00
0b5dc2d290 proper error handling in profile http cache 2023-10-06 10:20:29 +03:00
bf0af2d14e show modal gallery length only if greater than 1 2023-10-06 08:17:15 +03:00
58ba714d36 get uncached profiles from process.env.HTTP_CACHE 2023-10-06 08:13:08 +03:00
234167b749 close image modal on image click 2023-10-06 08:12:32 +03:00
d4a3e11d03 rm ProfileImage z-index 2023-10-06 08:12:32 +03:00
3f9805c48a chore: Update translations 2023-10-05 13:44:05 +00:00
b48ea3167a
fix: add space after hashtags 2023-10-05 14:43:10 +01:00
7f2149b8f1 Merge pull request 'Modal quick keys, profile picture & banner modal' (#640) from mmalmi/snort:main into main
Reviewed-on: Kieran/snort#640
2023-10-05 13:37:54 +00:00
bef8b40c8b open also profile banner in modal 2023-10-05 16:36:33 +03:00
23b45961aa click to open profile photo on profile page 2023-10-05 16:36:33 +03:00
11c32c2745 navigate modal images with left / right / up / down keys 2023-10-05 16:36:33 +03:00
7587db9c8b close modal with esc 2023-10-05 16:36:33 +03:00
38b647938e iris apple-touch-icon 2023-10-05 16:36:33 +03:00
89982793ed iris webmanifest img url fix 2023-10-05 16:36:33 +03:00
88d5ff73e0 iris webmanifest, images and .well-known 2023-10-05 16:36:32 +03:00
77016cfbc7
fix: render single images without gallery 2023-10-05 14:36:29 +01:00
4d12de302d chore: Update translations 2023-10-05 13:11:27 +00:00
7c839ae3a8 Merge pull request 'feat: group images into a gallery' (#639) from fernandoporazzi/snort:group-post-images into main
Reviewed-on: Kieran/snort#639
2023-10-05 13:10:43 +00:00
15ee38c24f chore: Update translations 2023-10-05 13:03:54 +00:00
4342669896
Make pin optional 2023-10-05 14:02:41 +01:00
Fernando Porazzi
8e34a7a078
feat: group images into a gallery 2023-10-05 14:18:15 +02:00
c162ac6428 chore: Update translations 2023-10-04 11:07:17 +00:00
c3ab453022
Replace "Snort" with {site} in formatted messages 2023-10-04 12:06:23 +01:00
a47e44d492 chore: Update translations 2023-10-04 10:45:37 +00:00
0a0c67dc89 Merge pull request 'Iris nip-05 registration' (#638) from mmalmi/snort:main into main
Reviewed-on: Kieran/snort#638
2023-10-04 10:44:11 +00:00
1eb2fa4b90 gap-2 -> g8 2023-10-04 13:39:59 +03:00
9d19d02636 error and success classNames 2023-10-04 13:37:38 +03:00
2efef99c95 use FormattedMessage for Iris account strings 2023-10-04 13:22:55 +03:00
e191528c4c catch idb write error in set and bulkSet 2023-09-30 19:03:11 +03:00
317b58b298 rm commented-out line 2023-09-30 18:02:49 +03:00
f33961232b add challenges.cloudflare.com to content security policy 2023-09-30 17:52:11 +03:00
ecb0f0e78a iris account registration 2023-09-30 11:14:12 +03:00
fc38049b87 chore: Update translations 2023-09-29 15:55:55 +00:00
1d1e8889dc Merge pull request 'feat: highlight search results' (#625) from fernandoporazzi/snort:highlight-searched-word into main
Reviewed-on: Kieran/snort#625
2023-09-29 15:54:15 +00:00
Fernando Porazzi
a0824646eb
feat: solve conflicts 2023-09-29 17:15:27 +02:00
60326ea17f
Add martti to donate page 2023-09-29 11:20:05 +01:00
c4f40b5c8a
Add missing await 2023-09-29 10:07:27 +01:00
e165ce232a
Fix copy for insecure context 2023-09-29 09:59:58 +01:00
b239bc65d8 Merge pull request 'src/Element subdirectories' (#637) from mmalmi/snort:main into main
Reviewed-on: Kieran/snort#637
2023-09-28 11:27:05 +00:00
b993c3ff3c use ForwardedRef in AsyncButton 2023-09-28 12:52:32 +03:00
8b9f55493e more Element subdirectories 2023-09-28 12:46:41 +03:00
3b4f17dddf Element/Embed directory 2023-09-28 12:20:39 +03:00
1d3db500a6 chore: Update translations 2023-09-27 10:36:37 +00:00
a780b9554d Merge pull request 'Rebranding features' (#636) from mmalmi/snort:main into main
Reviewed-on: Kieran/snort#636
2023-09-27 10:35:45 +00:00
5c35d7af79 Merge remote-tracking branch 'kieran/main' 2023-09-27 12:33:11 +03:00
ea6b853057 shorter Element/FormattedMessage path 2023-09-27 12:09:26 +03:00
03e61a7d4a chore: Update translations 2023-09-27 08:43:31 +00:00
cca17284ef Snort -> process.env.APP_NAME in login view 2023-09-27 11:43:20 +03:00
03d6e13226 submit pin prompt by pressing enter 2023-09-27 11:43:20 +03:00
d1085410ec autologin with iris.myKey pin 1234 2023-09-27 11:43:20 +03:00
a06dc977bc appConfig.nip05Domain for /username route 2023-09-27 11:43:20 +03:00
b3ede123b5 add favicon to config 2023-09-27 11:43:20 +03:00
3c812cb51a FormattedMessage: replace Snort -> APP_NAME_CAPITALIZED 2023-09-27 11:43:20 +03:00
1f6e1886b3 appName from config.json 2023-09-27 11:43:20 +03:00
5d698e550e
testing: move signed apks 2023-09-27 09:41:31 +01:00
820844eeb5
test: rename files 2023-09-26 21:38:20 +01:00
bfdcfa580a
test: mkdir assets 2023-09-26 21:19:50 +01:00
2e1efc3318 chore: Update translations 2023-09-26 20:13:44 +00:00
3541d1ab57
testing: use manual clone 2023-09-26 21:12:38 +01:00
d7c79e8fde chore: Update translations 2023-09-26 18:25:52 +00:00
c611de2096
Try build android app from release 2023-09-26 19:24:41 +01:00
07e62368f9 chore: Update translations 2023-09-26 15:33:48 +00:00
cd8fce15a9
on-chain donation option 2023-09-26 16:31:42 +01:00
87f279bd77
css fixes 2023-09-25 22:39:26 +01:00
566f086191
Fix login redirect 2023-09-25 21:28:35 +01:00
2f20b90dd9 chore: Update translations 2023-09-25 13:02:13 +00:00
1eb7216177
Snort deck improvements 2023-09-25 14:00:32 +01:00
5b9f4b0b8d chore: Update translations 2023-09-25 11:14:02 +00:00
875348cc03
fix: readonly feed loading 2023-09-25 12:12:13 +01:00
8e414a10c5
feat: nip-28 2023-09-25 12:12:13 +01:00
2833813ef3
Patch empty appData 2023-09-25 12:12:13 +01:00
80736cc5dd chore: Update translations 2023-09-24 20:31:28 +00:00
6bcb5f3f80
Intl 2023-09-24 21:29:39 +01:00
6e7a28a42b
WASM: PoW 2023-09-24 21:28:43 +01:00
9f731da5be chore: Update translations 2023-09-24 12:36:51 +00:00
0e9ca7e2e3
Muted words: phase 1 2023-09-24 13:33:12 +01:00
4d629f5087 chore: Update translations 2023-09-23 21:31:49 +00:00
5692423e3c
Fix thread reactions 2023-09-23 22:29:38 +01:00
94da60ebfa
readonly login sessions 2023-09-23 22:29:37 +01:00
3efb5321f6 chore: Update translations 2023-09-23 16:09:31 +00:00
58d5983316
Manually submit pin 2023-09-23 17:08:03 +01:00
ef6714f856 chore: Update translations 2023-09-22 20:28:46 +00:00
60c5dd7a2c
Commit system-wasm 2023-09-22 21:25:56 +01:00
c12703791a
Fix search 2023-09-22 21:24:44 +01:00
d3c0b866f2
Rename system-query to system-wasm 2023-09-22 20:28:56 +01:00
200727635c
Fix pin input for mobile 2023-09-22 17:18:49 +01:00
9ec2e8b2e6 chore: Update translations 2023-09-22 16:01:30 +00:00
8ab3c16eed Merge pull request 'pin' (#635) from pin into main
Reviewed-on: Kieran/snort#635
2023-09-22 16:00:14 +00:00
8c7fbed191
Bugfixes 2023-09-22 16:55:26 +01:00
e8519daa47
Thread loading fixes 2023-09-22 15:09:13 +01:00
4a2aa2aced
Long form thread fixes 2023-09-22 13:18:14 +01:00
5182b65591
Cleanup 2023-09-22 12:17:33 +01:00
dadf5159bd
Cashu token styles 2023-09-22 12:17:02 +01:00
554bfa45f0
Live stream styles 2023-09-22 11:24:08 +01:00
2b1226ce75
Fix dms link 2023-09-22 10:26:17 +01:00
eef4270f84
Fix NIP46 flow 2023-09-22 09:53:39 +01:00
01b3fd559b
Replace usages of privateKey 2023-09-22 09:53:38 +01:00
96d4e4bcc5
Cleanup 2023-09-22 09:53:37 +01:00
8244441929
scrypt async 2023-09-22 09:53:15 +01:00
3e0c4e5064
Use scrypt instead of pbkdf2 2023-09-22 09:53:14 +01:00
30f7f28f23
Fix pin encrypted storage 2023-09-22 09:53:14 +01:00
71f7f728fd
Various 2023-09-22 09:53:12 +01:00
4b57d57f94 chore: Update translations 2023-09-22 08:38:10 +00:00
0a22d67702
Fix yarn.lock 2023-09-22 09:36:38 +01:00
a3896cf55a
Squashed commit of the following:
commit 87cda09ac6442820a0b16933989525dcb53a4425
Merge: 02d9bbf7 2bec5d95
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Tue Sep 19 23:13:32 2023 +0900

    Merge branch 'css-fixes'

commit 2bec5d95c00476537dc5460f01557af12c1baa7b
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Tue Sep 19 22:40:27 2023 +0900

    minor tweak on tabs

commit 776005e5eaafd5a8bc94cbf7821579a5bb831b1c
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Tue Sep 19 00:28:53 2023 +0900

    added subscription tier borders in light mode

commit 66a55feb9950f433787d2a6966b200339462c4c6
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Tue Sep 19 00:28:43 2023 +0900

    fixed tab colors in light mode

commit 830cc3c973301d2ce63745e1e328c69a219db1ef
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Tue Sep 19 00:28:29 2023 +0900

    secondary color adjustment

commit 8c9939f3484c2dd5678ac72795dba7fa7f970402
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Tue Sep 19 00:12:46 2023 +0900

    szh menu shadow fix

commit a59124f91055a4a9a3758823dee76e8bc44c5e83
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Tue Sep 19 00:01:34 2023 +0900

    misc fixes

commit a4da5d86677eadace1b86df2d72e35255178a5f0
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Mon Sep 18 17:50:15 2023 +0900

    Re-ordered reactions for consistency

commit 665162b6918b1666f1413884d4b4185d4df0f74a
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Mon Sep 18 13:25:55 2023 +0900

    styled light load more button

commit a3058168d6df685cdf9d2871f8e3b335318eedcb
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Mon Sep 18 00:38:16 2023 +0900

    styled subscriptions a bit

commit dcc940d96cefeca476e16891c148e2058fb48fd7
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Mon Sep 18 00:22:39 2023 +0900

    adjusted input border to 2px and font size 15

commit 690e1662eeded6eab9f3029ce168d44b35604dca
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Mon Sep 18 00:22:12 2023 +0900

    fixed settings tabs paddings

commit a5809c4c7d502da42788c6c758d6025e79699cf5
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Mon Sep 18 00:05:45 2023 +0900

    removed some double borders

commit d1e0c331ed665c63160c2ae83f9e010b666c39df
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Mon Sep 18 00:05:28 2023 +0900

    follow is primary now

commit 338bc03aa3616906326fe0a777a63c04dc4a7f48
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Mon Sep 18 00:05:10 2023 +0900

    made follow button a primary

commit 4b5eb0c4fc71e0a8cf822ba8cac8facc53301e1e
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sun Sep 17 23:43:12 2023 +0900

    made follows you into a label

commit 0a9d616402528311f4feba53f0ba9171b0640274
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sun Sep 17 23:35:07 2023 +0900

    created secondary button bg variable

commit 2abcab804adf392e8f7ff2907762bc35c77f0297
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sun Sep 17 23:34:41 2023 +0900

    added gap to profile buttons

commit 04a54ddb0d7b19c5ea7f420645c6bd3d37747c17
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sun Sep 17 23:34:26 2023 +0900

    change new note button color

commit 2d2401586af70187785cff693061666d1de343f2
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sun Sep 17 22:57:01 2023 +0900

    forget what I did here

commit 14d8bd255cc41e5450b18908b807e3d745c10fbe
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sun Sep 17 22:35:32 2023 +0900

    adjusted new note button position

commit e3a6143626424b898aad43fc2eb1625336342c16
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sun Sep 17 22:32:37 2023 +0900

    added primary button colors

commit 4d02bfef54668d1a09f0615634d6be540c9837ea
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sun Sep 17 18:51:37 2023 +0900

    cleaned up modal reactions

commit 891f7985c6cf674d03188a95b3ca807ecb16c0bc
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sun Sep 17 00:10:46 2023 +0900

    minimized error text from scary to less scary

commit dc563e7ded8794e43ed14409d5ffeb917172b800
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sat Sep 16 23:50:27 2023 +0900

    adjusted search colors in light mode

commit 328cc853794c9b32abf8eab067bfd3f9b1a76aee
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sat Sep 16 22:59:33 2023 +0900

    revert main font size, adjust thread root size

commit 2e55cbcbc1bc6e9494410ec77052adb3fd8bbbcf
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sat Sep 16 22:49:09 2023 +0900

    re-styled quoted replies note creator

commit a3257eecff0a028a22d975eec778daeb73d8ec2e
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sat Sep 16 22:38:00 2023 +0900

    got rid of weird filter menu shadow and radius

commit 258d51c6fddb65d3afecd595a1fd9352c2cfa13e
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sat Sep 16 22:12:03 2023 +0900

    adjusted header bottom spacing per design to 8px

commit 03669925086e8a4995124d6e9077d61373fa89d3
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sat Sep 16 22:00:34 2023 +0900

    adjusted gap to 16 per design

commit 9a1c77b0dd876632ecd313d25ce163204ff89897
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sat Sep 16 21:56:50 2023 +0900

    set root font size to 16px per design

commit 4d0a91317d8946465b0d591db3d13c2e3df63ff8
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sat Sep 16 21:50:57 2023 +0900

    made search full width

commit 3ea6b4ca005b27003f1554d53def14337620af2a
Author: Karnage <karnagebitcoin@gmail.com>
Date:   Sat Sep 16 21:47:29 2023 +0900

    fixed line height on thread root note
2023-09-22 09:33:21 +01:00
02d9bbf70d
Fix reactions for thread root 2023-09-19 13:14:57 +01:00
f5617d1b01
Prettier 2023-09-19 13:04:19 +01:00
dde730238d
Cleanup 2023-09-19 13:03:29 +01:00
1c52db933f chore: Update translations 2023-09-19 09:02:40 +00:00
4b2161369d
Prettier 2023-09-19 10:01:13 +01:00
04239123bb
Simplify thread loading 2023-09-19 09:59:02 +01:00
6a9314d513
Update nip list 2023-09-19 09:59:02 +01:00
803c8ee05e
fix zap splits for large lists 2023-09-19 09:59:01 +01:00
9fb6f0dfee
Use NostrLink everywhere 2023-09-19 09:59:01 +01:00
a1cd56292a chore: Update translations 2023-09-18 11:38:33 +00:00
bbbcbc0a92
Deck thread nav 2023-09-18 12:37:30 +01:00
8f9cbcedc8
Following mark 2023-09-18 12:37:30 +01:00
6236d906b6 chore: Update translations 2023-09-18 09:30:37 +00:00
29410ca276
Update load media message 2023-09-18 10:29:37 +01:00
2f9e1eb5c8
New content warning styles 2023-09-18 10:22:32 +01:00
0b9c43cfed chore: Update translations 2023-09-18 09:08:07 +00:00
950b0dbf4d
feat: nip-38 2023-09-18 10:05:36 +01:00
a44a4ab69b
Fix lockfile 2023-09-18 09:30:32 +01:00
e5ecc2aacf
Remove nostr pkg 2023-09-18 09:28:28 +01:00
959ec58ec2 chore: Update translations 2023-09-17 14:03:52 +00:00
4220ae5bdc
Setup system-svelte 2023-09-17 15:02:07 +01:00
1a6df18e8b
Cleanup handlers 2023-09-15 13:14:12 +01:00
Fernando Porazzi
c223c89045
feat: highlight search results 2023-09-01 15:13:58 +02:00
625 changed files with 30689 additions and 23579 deletions

View File

@ -7,9 +7,15 @@ concurrency:
trigger:
branch:
- main
event:
- push
metadata:
namespace: git
steps:
- name: Fetch tags
image: alpine/git
commands:
- git fetch --tags
- name: Build site
image: node:current-bullseye
volumes:
@ -72,6 +78,8 @@ concurrency:
trigger:
branch:
- main
event:
- push
metadata:
namespace: git
steps:
@ -95,8 +103,11 @@ steps:
- npx @crowdin/cli pull -b main -T $CTOKEN
- yarn prettier --write .
- git add .
- 'git commit -a -m "chore: Update translations"'
- git push -u origin main
- >
if output=$(git status --porcelain) && [ -n "$output" ]; then
git commit -a -m "chore: Update translations"
git push -u origin main
fi
volumes:
- name: cache
claim:
@ -113,6 +124,10 @@ trigger:
metadata:
namespace: git
steps:
- name: Fetch tags
image: alpine/git
commands:
- git fetch --tags
- name: Build site
image: node:current-bullseye
volumes:

View File

@ -44,7 +44,77 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tagName: ${{ github.ref_name }}
releaseName: "Snort v__VERSION__"
releaseBody: "See the assets to download and install this version."
releaseDraft: true
prerelease: false
app:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v1
with:
java-version: 17
- name: Cache gradle
uses: actions/cache@v1
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Install frontend dependencies
run: yarn install
- name: Build Site
run: yarn build
- name: Copy files
run: |-
git clone --depth 1 --branch ${{ github.ref_name }} https://git.v0l.io/Kieran/snort_android.git
mkdir -p snort_android/app/src/main/assets/
cp -r packages/app/build/* snort_android/app/src/main/assets/
- name: Build AAB
working-directory: snort_android
run: ./gradlew clean bundleRelease --stacktrace
- name: Build APK
working-directory: snort_android
run: ./gradlew assembleRelease --stacktrace
- name: Sign AAB
uses: r0adkll/sign-android-release@v1
with:
releaseDirectory: snort_android/app/build/outputs/bundle/release
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
alias: ${{ secrets.KEY_ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
- name: Sign APK
uses: r0adkll/sign-android-release@v1
with:
releaseDirectory: snort_android/app/build/outputs/apk/release
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
alias: ${{ secrets.KEY_ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
- name: Rename files
run: |-
mkdir -p snort_android/app/release
mv snort_android/app/build/outputs/bundle/release/app-release.aab snort_android/app/release/snort-${{ github.ref_name }}.aab
mv snort_android/app/build/outputs/apk/release/app-universal-release-unsigned-signed.apk snort_android/app/release/snort-universal-${{ github.ref_name }}.apk
mv snort_android/app/build/outputs/apk/release/app-arm64-v8a-release-unsigned-signed.apk snort_android/app/release/snort-arm64-v8a-${{ github.ref_name }}.apk
mv snort_android/app/build/outputs/apk/release/app-x86_64-release-unsigned-signed.apk snort_android/app/release/snort-x86_64-${{ github.ref_name }}.apk
mv snort_android/app/build/outputs/apk/release/app-armeabi-v7a-release-unsigned-signed.apk snort_android/app/release/snort-armeabi-v7a-${{ github.ref_name }}.apk
- name: Upload assets
uses: softprops/action-gh-release@v1
with:
files: |
snort_android/app/release/snort-${{ github.ref_name }}.aab
snort_android/app/release/snort-universal-${{ github.ref_name }}.apk
snort_android/app/release/snort-arm64-v8a-${{ github.ref_name }}.apk
snort_android/app/release/snort-x86_64-${{ github.ref_name }}.apk
snort_android/app/release/snort-armeabi-v7a-${{ github.ref_name }}.apk

View File

@ -4,4 +4,5 @@ build/
.github/
transifex.yml
dist/
src-tauri/
src-tauri/
target/

View File

@ -1,6 +1,7 @@
{
"recommendations": [
"arcanis.vscode-zipfs",
"dbaeumer.vscode-eslint"
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

View File

@ -15,5 +15,5 @@
"typescript.tsdk": ".yarn/sdks/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"eslint.nodePath": ".yarn/sdks",
"prettier.prettierPath": ".yarn/sdks/prettier/index.js"
"prettier.prettierPath": ".yarn/sdks/prettier/index.cjs"
}

View File

@ -0,0 +1,20 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = createRequire(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require eslint/use-at-your-own-risk
require(absPnpApiPath).setup();
}
}
// Defer to the real eslint/use-at-your-own-risk your application uses
module.exports = absRequire(`eslint/use-at-your-own-risk`);

View File

@ -1,6 +1,14 @@
{
"name": "eslint",
"version": "8.44.0-sdk",
"version": "8.53.0-sdk",
"main": "./lib/api.js",
"type": "commonjs"
"type": "commonjs",
"bin": {
"eslint": "./bin/eslint.js"
},
"exports": {
"./package.json": "./package.json",
".": "./lib/api.js",
"./use-at-your-own-risk": "./lib/unsupported-api.js"
}
}

20
.yarn/sdks/prettier/bin/prettier.cjs vendored Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = createRequire(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require prettier/bin/prettier.cjs
require(absPnpApiPath).setup();
}
}
// Defer to the real prettier/bin/prettier.cjs your application uses
module.exports = absRequire(`prettier/bin/prettier.cjs`);

20
.yarn/sdks/prettier/index.cjs vendored Normal file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = createRequire(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require prettier
require(absPnpApiPath).setup();
}
}
// Defer to the real prettier your application uses
module.exports = absRequire(`prettier`);

7
.yarn/sdks/prettier/package.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"name": "prettier",
"version": "3.1.0-sdk",
"main": "./index.cjs",
"type": "commonjs",
"bin": "./bin/prettier.cjs"
}

View File

@ -11,10 +11,10 @@ const absRequire = createRequire(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require typescript/lib/typescript.js
// Setup the environment to be able to require typescript
require(absPnpApiPath).setup();
}
}
// Defer to the real typescript/lib/typescript.js your application uses
module.exports = absRequire(`typescript/lib/typescript.js`);
// Defer to the real typescript your application uses
module.exports = absRequire(`typescript`);

View File

@ -1,6 +1,10 @@
{
"name": "typescript",
"version": "5.1.6-sdk",
"version": "5.2.2-sdk",
"main": "./lib/typescript.js",
"type": "commonjs"
"type": "commonjs",
"bin": {
"tsc": "./bin/tsc",
"tsserver": "./bin/tsserver"
}
}

View File

@ -1,14 +1,12 @@
FROM node:16 as build
FROM node:19 as build
WORKDIR /app
COPY package.json yarn.lock .
COPY packages/app/package.json packages/app/
COPY packages/nostr/package.json packages/nostr/
RUN yarn install --network-timeout 1000000
COPY . .
COPY package.json yarn.lock .yarnrc.yml .
COPY .yarn .yarn
COPY packages packages
RUN yarn --network-timeout 1000000
RUN yarn build
FROM nginx:mainline-alpine
FROM nginxinc/nginx-unprivileged:mainline-alpine
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/packages/app/build /usr/share/nginx/html

View File

@ -1,3 +1,3 @@
FROM nginx:mainline-alpine
FROM nginxinc/nginx-unprivileged:mainline-alpine
COPY packages/app/build /usr/share/nginx/html
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf

View File

@ -15,21 +15,21 @@ Snort supports the following NIP's:
- [x] NIP-09: Event Deletion
- [x] NIP-10: Conventions for clients' use of `e` and `p` tags in text events
- [x] NIP-11: Relay Information Document
- [x] NIP-12: Generic Tag Queries
- [x] NIP-13: Proof of Work
- [ ] NIP-14: Subject tag in text events
- [x] NIP-15: End of Stored Events Notice
- [x] NIP-18: Reposts
- [x] NIP-19: bech32-encoded entities
- [x] NIP-20: Command Results
- [x] NIP-21: `nostr:` Protocol handler (`web+nostr`)
- [x] NIP-23: Long form content
- [x] NIP-25: Reactions
- [x] NIP-26: Delegated Event Signing (Display delegated signings only)
- [x] NIP-27: Text note references
- [ ] NIP-28: Public Chat
- [x] NIP-28: Public Chat
- [x] NIP-30: Custom Emoji
- [x] NIP-31: Alt tag for unknown events
- [x] NIP-36: Sensitive Content
- [x] NIP-38: User Statuses
- [ ] NIP-39: External Identities
- [ ] NIP-40: Expiration Timestamp
- [x] NIP-42: Authentication of clients to relays
- [x] NIP-44: Versioned encryption
@ -38,11 +38,15 @@ Snort supports the following NIP's:
- [x] NIP-50: Search
- [x] NIP-51: Lists
- [x] NIP-53: Live Events
- [x] NIP-57: Zaps
- [x] NIP-58: Badges
- [x] NIP-59: Gift Wrap
- [x] NIP-65: Relay List Metadata
- [ ] NIP-78: App specific data
- [x] NIP-94: File header
- [x] NIP-75: Zap Goals
- [x] NIP-78: App specific data
- [ ] NIP-89: App handlers
- [x] NIP-94: File Metadata
- [x] NIP-96: HTTP File Storage Integration (Draft)
- [x] NIP-98: HTTP Auth
### Running
@ -55,7 +59,7 @@ To run the application, use
$ yarn start
```
To build the application and nostr package, use
To build the application and system packages, use
```
$ yarn build
@ -70,8 +74,7 @@ Translations are managed on [Crowdin](https://crowdin.com/project/snort)
To extract translations run:
```bash
yarn workspace @snort/app intl-extract
yarn workspace @snort/app intl-compile
yarn pre:commit
```
This will create the source file `packages/app/src/translations/en.json`

View File

@ -1,5 +1,5 @@
server {
listen 80 default_server;
listen 8080 default_server;
server_name _;
root /usr/share/nginx/html;
index index.html;

View File

@ -4,23 +4,24 @@
"packages/*"
],
"scripts": {
"build": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/system-react build && yarn workspace @snort/app build",
"start": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/system-react build && yarn workspace @snort/app start",
"test": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/app test && yarn workspace @snort/system test"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20230307.0",
"@tauri-apps/cli": "^1.2.3",
"prettier": "^3.0.0"
"build": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/system-web build && yarn workspace @snort/system-react build && yarn workspace @snort/app build",
"start": "yarn build && yarn workspace @snort/app start",
"test": "yarn build && yarn workspace @snort/app test && yarn workspace @snort/system test",
"pre:commit": "yarn workspace @snort/app intl-extract && yarn workspace @snort/app intl-compile && yarn prettier --write .",
"push-prod": "git checkout snort-prod && git merge --ff-only main && git push && git checkout main"
},
"prettier": {
"printWidth": 120,
"bracketSameLine": true,
"arrowParens": "avoid"
"arrowParens": "avoid",
"trailingComma": "all"
},
"packageManager": "yarn@3.6.3",
"dependencies": {
"@cloudflare/workers-types": "^4.20230307.0",
"@tauri-apps/cli": "^1.2.3",
"eslint": "^8.48.0",
"prettier": "^3.0.3",
"typescript": "^5.2.2"
}
}

View File

@ -1,7 +1,15 @@
module.exports = {
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
plugins: ["@typescript-eslint", "formatjs"],
rules: {
"formatjs/enforce-id": [
"error",
{
idInterpolationPattern: "[sha512:contenthash:base64:6]",
},
],
},
root: true,
ignorePatterns: ["build/", "*.test.ts", "*.js"],
env: {

View File

@ -25,3 +25,4 @@ yarn-error.log*
.idea
dist/
dev-dist/

View File

@ -0,0 +1,47 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEApyUVkYJVwV7XgluUnllgCtrsdq1ctRICm5gQy8nd+aEdDQjA
CKPOWh5miLl/fAQVZGZy/JxavzXulwXo8238E6n6bmNB1Us2nuw7a0aW4iUSQ1Pt
P4ZhPpcrqeqMf+hp7iBW0nAHFy/aa2UR84d7tBmSk5J3NNrfBsZdUex/7FqF1EVv
mEzlc8kepU9lRXWFQDtZCllEZ1kY3SBJPm10h0g9saI8YIVRxUuNII5GHDYAE3hb
EmoY6fuSEoiXA8u0Yt9soBQxgxIhQVKSRPPoIPjGFOxsGHY6h8R9nx1kxhHKFRuV
nwsn0uWl/7yjhwyHanogJu73/WgelPcgP/hMDQIDAQABAoIBAAru+xU0oGVwzcoi
MXuWPxkWrwcoWfsiPXduIBMklleg+WSD4QPvqyzr9isVb0huf/O8W+M4WxtM7NmG
MnHSDP5ATThxV7obHGyS6WQgDvimEibDU66nHK9adim8RQqM6nkANo23dE9I+xGx
X9Y9U5M5ZQQwPYoAkzw/N5WHUerk+cSEYWYV8jDtO7wJhYOMu5qliPeuNOaWZ1W6
1uwr8A4ih69WwzugPuBSgBrPAW1c84zWIFN+njAugqPF5x8xp2uM3tUO9s5UlHJC
FWEuU40KcDT2utSUY+2HXSHbycF4KLKT5jAKSa4sPziLfo+YifrlN0Y3rhofUlZT
jCaeZ8ECgYEA5/xpk8aVhCEvv5iCghv0p/IHcjdXjx5+PCWh3Adx0fF91UvU5oqn
okdyYZDShZMuLDfJ0lG+OMKZd01JapnbTtiVNceVRMnraIdoWEM2/4bTXTSZGtdA
8gh/Kc/PMbPf5ppVWwqTCbUkPOSyGHyGc7+DQquq1w6yZu04A3x9vHECgYEAuHJk
uz8YKY5ZUR7CZ3y7YFuwq5Lcpl43AfiiCasjRch0P8yLrITc/6fORsXyy64XW9fC
h3YmXvEPaM03W2dxw2aQDvXEvXiEITzmILs7SE3UmZR9m7OMy7Jeqr3+JOc0ckZe
Rz5FfuMt1IvNB6lrpfHVtoVrpCOXpzHgC/k/x10CgYA6lU18GfwL/+107uiWPsUL
3FzxBPTBmau7OK2lSOP/ZoKmaJ39Eiq/GlfSN6ZSQRa55+S5jhcBcnMa45OUrgHp
6VvU1u/lDTC7luZM07yBzuR1dyDq3Ez0Uhz6zBXAsXHrZDIF6ae0HeBm2EH5WQkD
Fevp3DwqTvXSdDle+AMwoQKBgQCBSlaH1rNmNc0wCsK07f8ejUcrDZgz2mjurc1P
v7HK8bdjHUtvE/ciEguLGqiV06O2EmjesZg2Bv4JNYivPrTFBrjGc8qEEd10uw6J
NRVaGoyDV04w/UwdYRvwzZs/XP4reF4PzHvEdRSkH5cJ3t2BhiKLfby1YumkHlbx
rbbiVQKBgB02jyZUiB6pPTCP8vXZCJbZELgqNyS04ALhBBpdfGMcU1+0hRLJFBaE
tClJPGARFXl+MPkY032vmJZOuH3LrcTCm8DmMLzM/hT1EWawQ8BJkkwiIokE4lqc
Bi8CrkvuQs2cuCStK6C3Nkyr1lTkDge46trsb7KTcfHdtLsS7EPj
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDWzCCAkOgAwIBAgIJDji8iiceMvQlMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMTCWxvY2FsaG9zdDAeFw0yMzEwMTYwOTI0MThaFw0yMzExMTUxMDI0MThaMBQx
EjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKclFZGCVcFe14JblJ5ZYAra7HatXLUSApuYEMvJ3fmhHQ0IwAijzloeZoi5
f3wEFWRmcvycWr817pcF6PNt/BOp+m5jQdVLNp7sO2tGluIlEkNT7T+GYT6XK6nq
jH/oae4gVtJwBxcv2mtlEfOHe7QZkpOSdzTa3wbGXVHsf+xahdRFb5hM5XPJHqVP
ZUV1hUA7WQpZRGdZGN0gST5tdIdIPbGiPGCFUcVLjSCORhw2ABN4WxJqGOn7khKI
lwPLtGLfbKAUMYMSIUFSkkTz6CD4xhTsbBh2OofEfZ8dZMYRyhUblZ8LJ9Llpf+8
o4cMh2p6ICbu9/1oHpT3ID/4TA0CAwEAAaOBrzCBrDAMBgNVHRMEBTADAQH/MAsG
A1UdDwQEAwIC9DAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUF
BwMDBggrBgEFBQcDCDBcBgNVHREEVTBTgglsb2NhbGhvc3SCFWxvY2FsaG9zdC5s
b2NhbGRvbWFpboIGbHZoLm1lgggqLmx2aC5tZYIFWzo6MV2HBH8AAAGHEP6AAAAA
AAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggEBABY0rgWuzLYvVtvoVvWKS9cg
8rVhBRIFvpYO814ocN1iaxYQ9t9uLRsJXj0K+z1BHWf0zBiw4mB3dD9VpiKpuliL
4tRT+vATA96OYCd9G5k7DFQascAau40H3jxckh9rimIWa45FUSd7FIcddo1jeciv
gdAdiNUuHBen82O8KHJb+1PCBdA8RYeO5EGKfJM2yrOovu7dAFilf1ZPkXWgXnfG
nN6YfDDo9rAVDbvNXImrkwmGqEcN3Pq909IHiM/VETlU5lP4AbTNgrDa/aaZ+I+b
1MC1p87MvnibyXs+rTlK5+j8E6noNcD7tsHNd4ufkVCqr+pvSpuA3OvnXjbbm54=
-----END CERTIFICATE-----

748
packages/app/CHANGELOG.md Normal file
View File

@ -0,0 +1,748 @@
# v0.1.23
## Added
- DeepL translate api (Automatic for PRO subscribers)
- Add nostr:nprofile1qqsydl97xpj74udw0qg5vkfyujyjxd3l706jd0t0w0turp93d0vvungfgfewr to contributors
- Proxy LN address type enabled on Nostr Address settings pages
- Infinite scrol on notifications page
- Default 0.5% ZapPool rate for Snort donation address
- Collect relay metrics in `@snort/system` for better relay selection algo in Outbox Model (NIP-65)
- New sign up / login flow!
- Topics / Mute words on sign up for easier onboarding
- Drag & Drop for uploads on note creator - nostr:nprofile1qqs8tchhwf5smv3r2g0vkswz58c837uu456x59m3dh380gtrhqzydeqz4wlka
- Mixin topics (hashtags) into timeline feed
- Language specific trending posts
- Show following info for hashtags
- Sync preferences to network (`NIP-78` support)
- Trending hashtags page
- Note creator hashtag input
- Top trending hashtags on note creator
- Social Graph - nostr:nprofile1qqsy2ga7trfetvd3j65m3jptqw9k39wtq2mg85xz2w542p5dhg06e5qpr9mhxue69uhhyetvv9ujuumwdae8gtnnda3kjctv9uh8am0r
- New users relay list based off "close" relays
- `NIP-96` support for nostr native image/file uploaders
- Write replies/reactions to `p` tagged users read relays (Outbox model)
- Sync joined public chats (`NIP-28`) using `PublicChatList` kind `10_005`
## Changed
- Read/Write relays only on kind `10_002` (NIP-65)
- Removed `nostr.watch` code for adding new users to random relays
- Render kind `10_002` on profile relays tab
- `@snort/system` using eventemitter3 for triggering events
- Use latest `NIP-51` spec (Bookmarks/Interests/`NIP-28` PublicChatList)
- `nreq` support (Demo)
- Write profile/relays to blasters
- `@snort/system` automated outbox model (automatic fetching of relay metadata)
## Fixes
- Upgrade ephermal connection to non-ephemeral
- Remove relay tag from zaps (Some zap services dont support it)
- Fix zap parsing for goals
- Remove extra chars from quoted events to fix loading (`'s` etc)
- CSS Fixes for profile card on light theme
- Zap counting on replacable events
- `NIP-28` chats loading
- Overflowing modal UI
- Live stream widget layout with long titles
- Notifications marker has returned from its long slumber
---
# v0.1.22
## Fixes
- Note creator too wide on mobile
- Sending notes dialog duplicated when replying
---
# v0.1.21
## Added
- Add gradients to iris.to domain
- Render referenced kind-3 (ContactList) as pubkey list
- List feed page renders the posts of a given list `/list-feed/{naddr-of-nip51-list-or-nevent-of-kind3}`
- Respond to AUTH when expected (Requesting DM's/GiftWrap)
- Show reply counts on threads
- Quote Repost
- Signature checks can be enabled in preferences
- NIP-98 auth for void.cat / nostr.build file uploaders
- Add `E` tag for direct replies
- File upload progress bar (void.cat only)
- Long form modal for deck layout (WIP still)
- Video thumbnails using ImgProxy
- Renew subscriptions for X months
- Tailwind CSS migration @mmalmi
- Seasonal features
- Profile cards on hover for mentions
- Dropdown search results on search bar @mmalmi
- Renew subscription task on task list
## Changed
- Disable highligher.js code blocks (for now)
- Removed "Popular Accounts" from new user flow, replaced with "Snort Devs" only
- Moved "Show Preview" on note creator to preview toggle switch
- Premium subscription renamed to PRO
- Limit images in posts to 800px high
- Nostrplebs colors removed
## Fixed
- Use correct hostname when submitting analytics
- Disable WASM when not supported on device
- Typo on "Nostr Address" in account settings
- Hide expired user status on profiles
- Hide muted dm chats
- Hide blocked replies
---
# v0.1.20
## Added
- Highlight text in search results - @fernandoporazzi
- Iris/Snort build configuration - @mmalmi
- Iris free NIP-05 on Profile page - @mmalmi
- Image galleries on posts - @fernandoporazzi
- Close modal with ESC - @mmalmi
- Navigate image spotlight with LR direction keys - @mmalmi
- Spotlight preview profile/banner on click - @mmalmi
- Fetch profiles from HTTP cache (Iris) - @mmalmi
- Animal names for empty profile accounts (Iris) - @mmalmi
- Redirect to NIP-05 short links for iris/snort accounts - @mmalmi
- Code block highlighting - @fernandoporazzi
- Notification summary graph - @Kieran
- Profile hover cards - @Kieran
- Keyboard shortcuts for new post/focus/search - @fernandoporazzi
- Markdown rendering for long form content - @Kieran
- Show relay response when publishing - @Kieran
## Fixed
- Copy buttons on insecure context - @Kieran
---
# v0.1.19
## Added
- Highlight search results
## Fixes
- Copy to clipboard on insecure context (Umbrel)
---
# v0.1.16
## Fixes
- Login bugs
---
# v0.1.15
## Added
- User status on profile pages (Music only [NIP-38])
- Following mark on avatars, if you follow the pubkey you will see a green tick on their avatar
- Pin encryption, encrypted private key storage for nsec login
- Pubkey (readonly) logins hide buttons which cannot be used (reactions, reply, save profiles, dms etc)
- Muted words feature (phase 1)
- NIP-28 public chats
## Changed
- Styles changes for Content warnings
- Live stream embed styles
- Cashu token embed styles
- Snort Deck thread navigation in modal from timeline
- PoW miner moved to WASM module for faster hashing
## Fixed
- Profile link to dms
- Long form content loading and replies
- Search function restored
---
# v0.1.14
## Added
- Timeline cache: faster page loads and much lower data usage
- WASM module: Some code moved to Rust WASM module for faster execution
- Zap Splits: NIP-57.G
- New Languages:
- Finnish
- Dutch
- Portuguese Brazilian
## Changed
- Count polls by pubkey
---
# v0.1.13
# Added
- Snort V2 Design
- NIP-24 Encrypted secret chats (nsec login only)
- NIP-13 Proof of Work (POW)
- NIP-31 Alt tag spec for unknown event kinds
- Render mentioned zap goals (Kind 9041)
- Embed fonts in src (No more google fonts requests)
- Native key storage for Android app (`Nip7os` interface)
- Swahili translations
- Thai translations
# Changed
- PWA pre-cache setup (Faster PWA loading)
- Show note creator button on profile pages
# Fixed
- Umlauts in urls
- Reject events which don't match request filter
---
# v0.1.12
# Added
- nsecBunker support (connection string `bunker://<pubkey>?relay=wss://realy.com[#token]`)
# Changed
- New snort logo by Bitko
- Infinite scroll changed to manual action (temperarily to fix performance issues)
# Fixed
- Note to self containing all DMS
- Media spotlight disabled for poll options containing images
- Badge image sizes oversize when bypassing imgproxy due to loading error
---
# v0.1.11
## Added
- `@snort/system` package
- `@snort/system-react` package
- Live streaming page (NIP-102)
- Chat system refactor (adding new chat systems much easier now, NIP-29 first candidate)
- NIP-29 simple group chat support
## Fixed
- Profile links with incorrect hrp fixed in some places
- `naddr` event loading fixed
- Relay specific requests fixed (Global tab / Search page)
- NWC connection responds to AUTH requests now
https://git.v0l.io/Kieran/snort/compare/v0.1.10...v0.1.11
---
# v0.1.10
## Added
- Gossip model, query follows write relays for events
- @snort/system NPM package containing Snort core nostr code
- NIP-44 Encryption scheme support
- NIP-59 Gift Wrap support
## Fixed
- Unmarked thread events replies out of order
https://git.v0l.io/Kieran/snort/compare/v0.1.9...v0.1.10
---
# v0.1.9
## Added
- Discover tab, shows trending users/posts from nostr.build
- New DM styles
- Mentioned Zapstr tracks are previewed on Snort with player
- Custom emoji rendering in posts (NIP-30)
- Lanaguage selector on new user flow
- ZapPool, support nostr ecosystem by donating a percentage of your zaps
- Alby NWC link added to NWC connect page
- SemisolDev follow recommendations on Discover tab
- Pubkey lists (NIP-51) render inline when mentioned in notes
- Persian language
- OpenGraph Image/Video media rendered inside link preview box
- Option to zap everybody on mentioned pubkey list
- L402 support for inline media (paywall content)
## Changed
- Error page shows actual error message now, also a button to reset app cache
- Massivly improved profile loading
- Improved JS bundle size by ejecting CRA and using dynamic modules
- Switched to `@void-cat/api` package for void.cat uploads
---
# v0.1.8
## Added
- Tamil Language support
- Quoted notes are rendered embedded
- Multi-account support for subscribers
- Zapper key loading processing in background to speed up profile loading
- Export keys page added to settings
- NIP-94 support for rendering quoted file metadata events
- Interactions cache (zaps/likes/reports) for better UX
- Full screen image/video previews in modal
- Re-broadcast own events dialog
- Nostr wallet connect support
- Cashu token parsing preview with redeem link
- Trending notes/people tabs added to search page
## Changed
- Profile page loads only 200 latest notes, improving profile load times for accounts with less activity
- New user flow has been tweaked to be shorter with NIP5 & Twitter import steps removed
## Fixed
- Thread navigation without page reload
- NIP-42 functionality restored
- `a` tagged kind 1 replies render properly under root event
**Full Changelog**: https://github.com/v0l/snort/compare/v0.1.7...v0.1.8
---
# v0.1.7
## Added
- Per event zap targets by @v0l
- Content warning (NIP-36) support by @v0l
- Polls (NIP-69) by @v0l
- Snort subscriptions by @v0l
- NIP-94 File header support by @v0l
- Link previews by @ghobs91 & @v0l
- Cmd+Enter to post note by @v0l
- `nostr:` links (NIP-27) by @v0l
- Tending users on Search page by @ghobs91 & @v0l
## Changed
- Paste image upload by @vivganes
- Note creator note preview by @v0l
- Login private key input masking by @vivganes
## Fixed
- Fix note creator closing on thread when new replies load by @SamSamskies
- Follow hashtag tab highlighting by @SamSamskies
- Language dropdown defaults to Arabic by @vivganes
- Bookmarks showing reactions by @vivganes
- Single zapper on note only shows name by @vivganes
- Broken link previews show empty box by @vivganes
- Render jfif images by @v0l
## PR List
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/476
- `nostr` package: implement NIP-05 by @sistemd in https://github.com/v0l/snort/pull/474
- `nostr` package: NIP-09 event deletion by @sistemd in https://github.com/v0l/snort/pull/478
- fix #484 by @vivganes in https://github.com/v0l/snort/pull/486
- fix #485 by @vivganes in https://github.com/v0l/snort/pull/487
- Per event zap targets by @v0l in https://github.com/v0l/snort/pull/466
- feat: nip-36 by @v0l in https://github.com/v0l/snort/pull/497
- fix #496 by @vivganes in https://github.com/v0l/snort/pull/498
- use redux for NoteCreator state management by @SamSamskies in https://github.com/v0l/snort/pull/494
- fix #495 by @vivganes in https://github.com/v0l/snort/pull/499
- Polls (NIP-69) by @v0l in https://github.com/v0l/snort/pull/489
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/483
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/508
- add ability to paste image from clipboard by @vivganes in https://github.com/v0l/snort/pull/510
- Subscriptions by @v0l in https://github.com/v0l/snort/pull/506
- feat: multi-account system by @v0l in https://github.com/v0l/snort/pull/514
- fix followed tag active tab highlighting by @SamSamskies in https://github.com/v0l/snort/pull/516
- NIP-94 file headers by @v0l in https://github.com/v0l/snort/pull/488
- fix #517 by @vivganes in https://github.com/v0l/snort/pull/518
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/511
- `nostr` package: get tests passing in the browser by @sistemd in https://github.com/v0l/snort/pull/490
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/519
- Subscription handle by @v0l in https://github.com/v0l/snort/pull/522
## New Contributors
- @vivganes made their first contribution in https://github.com/v0l/snort/pull/486
**Full Changelog**: https://github.com/v0l/snort/compare/v0.1.6...v0.1.7
---
# v0.1.6
## 🏷️ Summary
- Snort NIP5 management page (for transfers to new pubkeys)
- Short links for Snort NIP5 owners (ie. https://snort.social/kieran)
## Other Changes
- Update Wavlake embed to support .com links by @blastshielddown in https://github.com/v0l/snort/pull/469
- Bug fixes for save profile & relay connection on clean browser
**Full Changelog**: https://github.com/v0l/snort/compare/v0.1.5...v0.1.6
---
# v0.1.5
## 🏷️ Short Summary
- Completely rebuilt "core" subscription management system
- Option to rewrite Twitter links to Nitter links
- Tarui app setup, Mac/Windows/Linux desktop apps (coming soon)
- OpenGraph tagging for profiles and events (Only for https://snort.social)
- NIP-27 `nostr:` link parsing
- Global tab full relay names
## What's Changed
- `nostr` package: add direct messages by @sistemd in https://github.com/v0l/snort/pull/399
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/445
- Display search property alongside host in relay name by @h3y6e in https://github.com/v0l/snort/pull/452
- Shorten long relay name by @h3y6e in https://github.com/v0l/snort/pull/455
- Nostr links by @v0l in https://github.com/v0l/snort/pull/461
- `nostr` package: vastly simplify the API by @sistemd in https://github.com/v0l/snort/pull/412
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/453
- Fix: invisible <option> text in dark theme by @jiftechnify in https://github.com/v0l/snort/pull/454
- add setting for rewriting twitter links to nitter by @w3irdrobot in https://github.com/v0l/snort/pull/459
- RequestBuilder / Core Refactor by @v0l in https://github.com/v0l/snort/pull/326
- Tauri setup by @v0l in https://github.com/v0l/snort/pull/462
- Prevents adding ws relay when over https by @ivanacostarubio in https://github.com/v0l/snort/pull/463
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/465
- OpenGraph tag injection by @v0l in https://github.com/v0l/snort/pull/470
## New Contributors
- @jiftechnify made their first contribution in https://github.com/v0l/snort/pull/454
**Full Changelog**: https://github.com/v0l/snort/compare/v0.1.4...v0.1.5
---
# v0.1.4
**Full Changelog**: https://github.com/v0l/snort/compare/v0.1.3...v0.1.4
---
# v0.1.3
## What's Changed
- only replace note ID when note ID starts with `@` character by @SamSamskies in https://github.com/v0l/snort/pull/441
**Full Changelog**: https://github.com/v0l/snort/compare/v0.1.2...v0.1.3
---
# v0.1.2
## What's Changed
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/309
- UI bugs by @verbiricha in https://github.com/v0l/snort/pull/301
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/311
- Add build command to readme by @joshr4 in https://github.com/v0l/snort/pull/300
- fix(fotter-actions): add highlighting and min-width by @fernandolguevara in https://github.com/v0l/snort/pull/312
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/313
- `nostr` package part 1 by @fcked in https://github.com/v0l/snort/pull/315
- Reduce space between the texts for selecting relays by @h3y6e in https://github.com/v0l/snort/pull/316
- fix(profile): convert page id to npub bech32 by @fernandolguevara in https://github.com/v0l/snort/pull/322
- Improve overflow menu button by @joshr4 in https://github.com/v0l/snort/pull/304
- German translations for snort by @gandlafbtc in https://github.com/v0l/snort/pull/323
- fix: send all relays when zapping by @verbiricha in https://github.com/v0l/snort/pull/324
- Add default page selector by @jacany in https://github.com/v0l/snort/pull/321
- UI fixes by @verbiricha in https://github.com/v0l/snort/pull/318
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/319
- feat: render kind 1 reposts by @kphrx in https://github.com/v0l/snort/pull/314
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/330
- Use inner note content as comment by @Semisol in https://github.com/v0l/snort/pull/333
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/331
- Fix stale relays by @SamSamskies in https://github.com/v0l/snort/pull/337
- Feed cache rework by @v0l in https://github.com/v0l/snort/pull/339
- fix long zap comment text overflow by @SamSamskies in https://github.com/v0l/snort/pull/344
- fix links in parentheses by @SamSamskies in https://github.com/v0l/snort/pull/347
- Revert "Merge pull request #347 from v0l/fix-links-in-parentheses" by @SamSamskies in https://github.com/v0l/snort/pull/350
- Update thread detection to not include mentions by @w3irdrobot in https://github.com/v0l/snort/pull/351
- Small settings page stuff by @w3irdrobot in https://github.com/v0l/snort/pull/353
- Change message unread color to purple by @w3irdrobot in https://github.com/v0l/snort/pull/354
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/356
- Remove unread message dot when messages all read by @w3irdrobot in https://github.com/v0l/snort/pull/355
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/359
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/362
- `nostr` package part 2 by @fcked in https://github.com/v0l/snort/pull/346
- feat: add search page field autofocus by @lujakob in https://github.com/v0l/snort/pull/363
- fix URL parsing edge cases by @SamSamskies in https://github.com/v0l/snort/pull/360
- Fast Zaps ⚡ by @v0l in https://github.com/v0l/snort/pull/370
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/364
- Feat/add spinner to button by @lujakob in https://github.com/v0l/snort/pull/368
- Update mark all read dm button to be disabled when no unreads by @w3irdrobot in https://github.com/v0l/snort/pull/373
- `nostr` package part 3 by @fcked in https://github.com/v0l/snort/pull/365
- LNDHub/LNC wallet by @v0l in https://github.com/v0l/snort/pull/219
- Proposal: Remove SVGs from JSX by @enjikaka in https://github.com/v0l/snort/pull/382
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/374
- add Nostr Nests embed by @SamSamskies in https://github.com/v0l/snort/pull/377
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/387
- fix icons by @h3y6e in https://github.com/v0l/snort/pull/392
- Fix broken note links by @SamSamskies in https://github.com/v0l/snort/pull/380
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/391
- fix(BackButton): vertical align styles by @lujakob in https://github.com/v0l/snort/pull/397
- feat(note): open note in new tab on cmd press by @lujakob in https://github.com/v0l/snort/pull/395
- fix(skeleton): dark theme styles by @lujakob in https://github.com/v0l/snort/pull/393
- fix HyperText matching by @mattn in https://github.com/v0l/snort/pull/405
- Makes entire note clickable by @d-r-w in https://github.com/v0l/snort/pull/371
- render webm links as inline videos by @SamSamskies in https://github.com/v0l/snort/pull/410
- render embed for youtube live links by @SamSamskies in https://github.com/v0l/snort/pull/407
- do not render reposts of badge award events in timelines by @SamSamskies in https://github.com/v0l/snort/pull/406
- `nostr` package: use `EventEmitter` by @fcked in https://github.com/v0l/snort/pull/384
- `nostr` pacakge: implement basic NIP-20 `OK` functionality by @fcked in https://github.com/v0l/snort/pull/385
- feat: read nip-58 badges by @verbiricha in https://github.com/v0l/snort/pull/394
- Add Wavlake embed by @blastshielddown in https://github.com/v0l/snort/pull/416
- display search results on page load if query in url by @SamSamskies in https://github.com/v0l/snort/pull/415
- Fix event mention bug by @SamSamskies in https://github.com/v0l/snort/pull/421
- fix NaN when parsing empty string by @SamSamskies in https://github.com/v0l/snort/pull/422
- NIP06 support by @w3irdrobot in https://github.com/v0l/snort/pull/425
- Added key attr to Tabs to remove React warning by @w3irdrobot in https://github.com/v0l/snort/pull/424
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/426
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/436
- Update Wavlake embed URL, add support for album & artist links by @blastshielddown in https://github.com/v0l/snort/pull/439
- build(deps): bump webpack from 5.75.0 to 5.76.1 by @dependabot in https://github.com/v0l/snort/pull/442
## New Contributors
- @joshr4 made their first contribution in https://github.com/v0l/snort/pull/300
- @gandlafbtc made their first contribution in https://github.com/v0l/snort/pull/323
- @jacany made their first contribution in https://github.com/v0l/snort/pull/321
- @kphrx made their first contribution in https://github.com/v0l/snort/pull/314
- @lujakob made their first contribution in https://github.com/v0l/snort/pull/363
- @mattn made their first contribution in https://github.com/v0l/snort/pull/405
- @d-r-w made their first contribution in https://github.com/v0l/snort/pull/371
- @blastshielddown made their first contribution in https://github.com/v0l/snort/pull/416
- @dependabot made their first contribution in https://github.com/v0l/snort/pull/442
**Full Changelog**: https://github.com/v0l/snort/compare/v0.1.1...v0.1.2
---
# v0.1.1
## What's Changed
- React Map Optimization, [missing map keys ] by @ahmedrowaihi in https://github.com/v0l/snort/pull/283
- Translate '/src/lang.json' in 'ar' by @transifex-integration in https://github.com/v0l/snort/pull/287
- HTML auto direction for specific textual content by @verbiricha in https://github.com/v0l/snort/pull/286
- Translate '/src/lang.json' in 'hu' by @transifex-integration in https://github.com/v0l/snort/pull/288
- feat: twitch embed by @v0l in https://github.com/v0l/snort/pull/289
- fix: don't show 0 if there is no description by @verbiricha in https://github.com/v0l/snort/pull/290
- feat: pinned notes and bookmarks by @verbiricha in https://github.com/v0l/snort/pull/255
- Translate '/src/lang.json' in 'ja' by @transifex-integration in https://github.com/v0l/snort/pull/293
- fix: set auto to whole text content instead of individual paragraphs by @verbiricha in https://github.com/v0l/snort/pull/292
- protocol handler by @v0l in https://github.com/v0l/snort/pull/164
- feat: read global from specific (paid) relays by @v0l in https://github.com/v0l/snort/pull/249
- SUPPORT RTL/LTR ON LOGIN PAGE by @ahmedrowaihi in https://github.com/v0l/snort/pull/291
- Add Apple Music embed by @SamSamskies in https://github.com/v0l/snort/pull/294
- Workspace with decoupled `nostr` package by @ennmichael in https://github.com/v0l/snort/pull/274
- Translate '/src/lang.json' in 'ar' by @transifex-integration in https://github.com/v0l/snort/pull/296
- UI fixes + counts on profile page tabs by @verbiricha in https://github.com/v0l/snort/pull/282
- Fix blackout when selecting global tab by @h3y6e in https://github.com/v0l/snort/pull/297
- Prevent profile text from overflowing flex container when it is too long by @h3y6e in https://github.com/v0l/snort/pull/298
## New Contributors
- @ahmedrowaihi made their first contribution in https://github.com/v0l/snort/pull/283
**Full Changelog**: https://github.com/v0l/snort/compare/v0.1.0...v0.1.1
---
# v0.1.0
## What's Changed
- Add global tab to Root by @p2pseed in https://github.com/v0l/snort/pull/3
- UI improvements by @verbiricha in https://github.com/v0l/snort/pull/4
- fix: dedupe thread pubkeys by @verbiricha in https://github.com/v0l/snort/pull/7
- Note creator improvement by @verbiricha in https://github.com/v0l/snort/pull/6
- fix: correctly follow user mention links by @verbiricha in https://github.com/v0l/snort/pull/5
- fix: force timeline rerender on tab change by @verbiricha in https://github.com/v0l/snort/pull/8
- feat: add mov to video files by @verbiricha in https://github.com/v0l/snort/pull/9
- feat: copy npub on profile by @verbiricha in https://github.com/v0l/snort/pull/10
- fix: display full lightning address, is trimmed if too long by @verbiricha in https://github.com/v0l/snort/pull/12
- feat: embed youtube videos by @verbiricha in https://github.com/v0l/snort/pull/13
- feat: add support for positive and negative reactions by @verbiricha in https://github.com/v0l/snort/pull/11
- feat: nip05 on profile page by @verbiricha in https://github.com/v0l/snort/pull/21
- UI improvements by @verbiricha in https://github.com/v0l/snort/pull/24
- Home tabs by @v0l in https://github.com/v0l/snort/pull/25
- fix: support m.youtube.com subdomain links by @verbiricha in https://github.com/v0l/snort/pull/27
- fix: use all available width for note creator text area by @verbiricha in https://github.com/v0l/snort/pull/28
- highlight hashtags by @verbiricha in https://github.com/v0l/snort/pull/29
- UI tweaks by @verbiricha in https://github.com/v0l/snort/pull/30
- Improve regexes by @verbiricha in https://github.com/v0l/snort/pull/32
- Shows QR code first by @ivanacostarubio in https://github.com/v0l/snort/pull/23
- feat: embed tweets by @verbiricha in https://github.com/v0l/snort/pull/33
- Nip5 shop by @v0l in https://github.com/v0l/snort/pull/50
- Activate snort.social NIP-5 service by @v0l in https://github.com/v0l/snort/pull/51
- feat: add avatar borders with color gradients to partner nip05 providers by @verbiricha in https://github.com/v0l/snort/pull/52
- DM's by @v0l in https://github.com/v0l/snort/pull/54
- feat: display banner in profile by @verbiricha in https://github.com/v0l/snort/pull/53
- add max width to details by @verbiricha in https://github.com/v0l/snort/pull/59
- Markdown by @verbiricha in https://github.com/v0l/snort/pull/55
- feat: mentions by @verbiricha in https://github.com/v0l/snort/pull/56
- Minor UI fixes by @verbiricha in https://github.com/v0l/snort/pull/63
- add user DB and cache nip-05 verifications by @verbiricha in https://github.com/v0l/snort/pull/65
- fix: adjust nip05 size by @verbiricha in https://github.com/v0l/snort/pull/66
- fix: dont display display_name as nip user when username is default by @verbiricha in https://github.com/v0l/snort/pull/67
- fix: don't retry errored verifications by @verbiricha in https://github.com/v0l/snort/pull/71
- UI improvements by @verbiricha in https://github.com/v0l/snort/pull/70
- refactor: TS by @v0l in https://github.com/v0l/snort/pull/69
- More TSX by @v0l in https://github.com/v0l/snort/pull/74
- Moar UI fixes by @verbiricha in https://github.com/v0l/snort/pull/73
- fix: autocomplete colors by @verbiricha in https://github.com/v0l/snort/pull/75
- feat: query for autocompletion using local db by @verbiricha in https://github.com/v0l/snort/pull/76
- fix: rerender user timeline on pubkey change by @verbiricha in https://github.com/v0l/snort/pull/77
- feat: follows you on profile page by @ivanacostarubio in https://github.com/v0l/snort/pull/64
- autocomplete improvements by @verbiricha in https://github.com/v0l/snort/pull/83
- filter for self dms by @LiranCohen in https://github.com/v0l/snort/pull/86
- Notifications by @v0l in https://github.com/v0l/snort/pull/88
- Theme by @verbiricha in https://github.com/v0l/snort/pull/87
- Modified self-dm to be a "Note to Self" by @LiranCohen in https://github.com/v0l/snort/pull/89
- note footer ordering by @verbiricha in https://github.com/v0l/snort/pull/91
- Hashtags by @v0l in https://github.com/v0l/snort/pull/92
- Make logo cursor a pointer by @w3irdrobot in https://github.com/v0l/snort/pull/99
- fix: active note colors by @verbiricha in https://github.com/v0l/snort/pull/102
- Tidal embeds by @v0l in https://github.com/v0l/snort/pull/95
- UI improvements by @verbiricha in https://github.com/v0l/snort/pull/103
- User preferences by @v0l in https://github.com/v0l/snort/pull/104
- Add note context menu by @v0l in https://github.com/v0l/snort/pull/105
- feat: soundcloud embed by @ivanacostarubio in https://github.com/v0l/snort/pull/112
- feat: Show latest by @v0l in https://github.com/v0l/snort/pull/113
- light theme fixes by @verbiricha in https://github.com/v0l/snort/pull/116
- add Karnage to contributors by @verbiricha in https://github.com/v0l/snort/pull/117
- feat: note mentions by @verbiricha in https://github.com/v0l/snort/pull/125
- Preferences & Profile changes by @FlannelDipole in https://github.com/v0l/snort/pull/126
- sort bug in the event that your pubkey is the 2nd item in the list by @LiranCohen in https://github.com/v0l/snort/pull/137
- UI updates by @verbiricha in https://github.com/v0l/snort/pull/135
- fix: hide note creator on send by @verbiricha in https://github.com/v0l/snort/pull/139
- fix: add bottom margin to thread by @verbiricha in https://github.com/v0l/snort/pull/140
- adds mixcloud by @ivanacostarubio in https://github.com/v0l/snort/pull/136
- feat: audio player by @verbiricha in https://github.com/v0l/snort/pull/146
- feat: in-memory fallback for storing user profiles by @verbiricha in https://github.com/v0l/snort/pull/110
- Make Markdown more interoperable by @fiatjaf in https://github.com/v0l/snort/pull/153
- fix: default to in-memory db only on db read fail by @verbiricha in https://github.com/v0l/snort/pull/155
- bug: logout reply by @ivanacostarubio in https://github.com/v0l/snort/pull/154
- Search by @v0l in https://github.com/v0l/snort/pull/143
- Nip42 (AUTH) by @v0l in https://github.com/v0l/snort/pull/144
- Muted list via NIP-51 by @verbiricha in https://github.com/v0l/snort/pull/151
- Add more relays (high performance) by @Semisol in https://github.com/v0l/snort/pull/149
- Show absolute time on hover by @wanacode in https://github.com/v0l/snort/pull/166
- nostr.build file uploads by @v0l in https://github.com/v0l/snort/pull/162
- New UI by @v0l in https://github.com/v0l/snort/pull/161
- fix: send d tags as list by @verbiricha in https://github.com/v0l/snort/pull/169
- Image proxy service by @v0l in https://github.com/v0l/snort/pull/174
- Translate notes by @v0l in https://github.com/v0l/snort/pull/179
- Use standard imgproxy by @v0l in https://github.com/v0l/snort/pull/180
- Fix races where Socket is closed before Websocket is created by @brugeman in https://github.com/v0l/snort/pull/186
- feat: nostrimg.com by @v0l in https://github.com/v0l/snort/pull/181
- Add Spotify embed by @SamSamskies in https://github.com/v0l/snort/pull/188
- Ln invoice styling by @verbiricha in https://github.com/v0l/snort/pull/187
- feed cache by @v0l in https://github.com/v0l/snort/pull/184
- bug: prepends https when missing from website by @ivanacostarubio in https://github.com/v0l/snort/pull/194
- Use the current embed player via TIDALs OEmbed API. by @enjikaka in https://github.com/v0l/snort/pull/191
- feat: zaps by @verbiricha in https://github.com/v0l/snort/pull/78
- display note zaps succintly by @verbiricha in https://github.com/v0l/snort/pull/196
- nostr-pub.semisol.dev is now atlas.nostr.land by @Semisol in https://github.com/v0l/snort/pull/198
- Zaps fixes by @verbiricha in https://github.com/v0l/snort/pull/199
- Note creator improvements by @verbiricha in https://github.com/v0l/snort/pull/193
- Settings page and UI tweaks by @verbiricha in https://github.com/v0l/snort/pull/200
- fix avatars by @verbiricha in https://github.com/v0l/snort/pull/203
- Skeleton component on timeline loading for better user experience by @leotuna in https://github.com/v0l/snort/pull/190
- Threads by @verbiricha in https://github.com/v0l/snort/pull/170
- fix: don't stream global feed in notifications tab by @verbiricha in https://github.com/v0l/snort/pull/207
- Zap modal by @verbiricha in https://github.com/v0l/snort/pull/209
- Add prettier formatting by @ennmichael in https://github.com/v0l/snort/pull/214
- react-intl spike by @SamSamskies in https://github.com/v0l/snort/pull/216
- Add support for zh and ja locales by @SamSamskies in https://github.com/v0l/snort/pull/218
- feat: reactions modal by @verbiricha in https://github.com/v0l/snort/pull/215
- Translate '/src/translations/en.json' in 'es' by @transifex-integration in https://github.com/v0l/snort/pull/224
- Translate '/src/translations/en.json' in 'ja' by @transifex-integration in https://github.com/v0l/snort/pull/227
- fix: allow zap comments by @verbiricha in https://github.com/v0l/snort/pull/229
- Eslint by @v0l in https://github.com/v0l/snort/pull/223
- Translate '/src/translations/en.json' in 'fr' by @transifex-integration in https://github.com/v0l/snort/pull/230
- add ability to use babel plugins without ejecting by @SamSamskies in https://github.com/v0l/snort/pull/225
- add prettier pre-commit hook by @SamSamskies in https://github.com/v0l/snort/pull/234
- oversight of intl by @h3y6e in https://github.com/v0l/snort/pull/231
- feat: new login page by @v0l in https://github.com/v0l/snort/pull/235
- feat: onboarding by @verbiricha in https://github.com/v0l/snort/pull/233
- Translate '/src/translations/en.json' in 'ja' by @transifex-integration in https://github.com/v0l/snort/pull/243
- Translate '/src/translations/en.json' in 'fr' by @transifex-integration in https://github.com/v0l/snort/pull/242
- Translate '/src/translations/en.json' in 'es' by @transifex-integration in https://github.com/v0l/snort/pull/241
- feat: break lang by @v0l in https://github.com/v0l/snort/pull/244
- fix(missing-event): avoid redirect by @fernandolguevara in https://github.com/v0l/snort/pull/246
- fix(content): render media content for current pubkey by @fernandolguevara in https://github.com/v0l/snort/pull/240
- remove follow button from reactions modal by @SamSamskies in https://github.com/v0l/snort/pull/247
- NIP-65: Relay list metada by @verbiricha in https://github.com/v0l/snort/pull/238
- Fix DM page UI by @SamSamskies in https://github.com/v0l/snort/pull/250
- Translate '/src/lang.json' in 'es' by @transifex-integration in https://github.com/v0l/snort/pull/252
- Translate '/src/lang.json' in 'es' [manual sync] by @transifex-integration in https://github.com/v0l/snort/pull/258
- Translate '/src/lang.json' in 'fr' [manual sync] by @transifex-integration in https://github.com/v0l/snort/pull/259
- Translate '/src/lang.json' in 'hu' [manual sync] by @transifex-integration in https://github.com/v0l/snort/pull/260
- Translate '/src/lang.json' in 'ja' [manual sync] by @transifex-integration in https://github.com/v0l/snort/pull/261
- Translate '/src/lang.json' in 'zh' [manual sync] by @transifex-integration in https://github.com/v0l/snort/pull/262
- Translate '/src/lang.json' in 'ja' by @transifex-integration in https://github.com/v0l/snort/pull/275
- Translate '/src/lang.json' in 'id' by @transifex-integration in https://github.com/v0l/snort/pull/277
- Translate '/src/lang.json' in 'zh' by @transifex-integration in https://github.com/v0l/snort/pull/278
- Translate '/src/lang.json' in 'es' by @transifex-integration in https://github.com/v0l/snort/pull/279
- Translate '/src/lang.json' in 'hu' by @transifex-integration in https://github.com/v0l/snort/pull/280
- Translate '/src/lang.json' in 'fr' by @transifex-integration in https://github.com/v0l/snort/pull/281
## New Contributors
- @p2pseed made their first contribution in https://github.com/v0l/snort/pull/3
- @v0l made their first contribution in https://github.com/v0l/snort/pull/25
- @ivanacostarubio made their first contribution in https://github.com/v0l/snort/pull/23
- @w3irdrobot made their first contribution in https://github.com/v0l/snort/pull/99
- @FlannelDipole made their first contribution in https://github.com/v0l/snort/pull/126
- @fiatjaf made their first contribution in https://github.com/v0l/snort/pull/153
- @Semisol made their first contribution in https://github.com/v0l/snort/pull/149
- @wanacode made their first contribution in https://github.com/v0l/snort/pull/166
- @SamSamskies made their first contribution in https://github.com/v0l/snort/pull/188
- @enjikaka made their first contribution in https://github.com/v0l/snort/pull/191
- @leotuna made their first contribution in https://github.com/v0l/snort/pull/190
- @transifex-integration made their first contribution in https://github.com/v0l/snort/pull/224
- @h3y6e made their first contribution in https://github.com/v0l/snort/pull/231
- @fernandolguevara made their first contribution in https://github.com/v0l/snort/pull/246
**Full Changelog**: https://github.com/v0l/snort/commits/v0.1.0

View File

@ -1,2 +1,2 @@
/*
Content-Security-Policy: default-src 'self'; manifest-src *; child-src 'none'; worker-src 'self'; frame-src youtube.com www.youtube.com https://platform.twitter.com https://embed.tidal.com https://w.soundcloud.com https://www.mixcloud.com https://open.spotify.com https://player.twitch.tv https://embed.music.apple.com https://nostrnests.com https://embed.wavlake.com; style-src 'self' 'unsafe-inline'; connect-src *; img-src * data: blob:; font-src 'self'; media-src * blob:; script-src 'self' 'wasm-unsafe-eval' https://analytics.v0l.io https://platform.twitter.com https://embed.tidal.com;
Content-Security-Policy: default-src 'self'; manifest-src *; child-src 'none'; worker-src 'self'; frame-src youtube.com www.youtube.com https://platform.twitter.com https://embed.tidal.com https://w.soundcloud.com https://www.mixcloud.com https://open.spotify.com https://player.twitch.tv https://embed.music.apple.com https://nostrnests.com https://embed.wavlake.com https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline'; connect-src *; img-src * data: blob:; font-src 'self'; media-src * blob:; script-src 'self' 'wasm-unsafe-eval' https://analytics.v0l.io https://platform.twitter.com https://embed.tidal.com https://challenges.cloudflare.com;

View File

@ -0,0 +1 @@
Choose config with NODE_CONFIG_ENV: `NODE_CONFIG_ENV=iris yarn start`

View File

@ -0,0 +1,35 @@
{
"appName": "Snort",
"appNameCapitalized": "Snort",
"appTitle": "Snort - Nostr",
"hostname": "snort.social",
"nip05Domain": "snort.social",
"favicon": "public/favicon.ico",
"appleTouchIconUrl": "/nostrich_512.png",
"navLogo": null,
"publicDir": "public/snort",
"httpCache": "",
"animalNamePlaceholders": false,
"showNoteBroadcaster": true,
"defaultZapPoolFee": 0.5,
"bypassImgProxyError": false,
"features": {
"analytics": true,
"subscriptions": true,
"deck": true,
"zapPool": true
},
"signUp": {
"moderation": true
},
"hideFromNavbar": ["/graph"],
"deckSubKind": 1,
"eventLinkPrefix": "nevent",
"profileLinkPrefix": "nprofile",
"defaultRelays": {
"wss://relay.snort.social/": { "read": true, "write": true },
"wss://nostr.wine/": { "read": true, "write": false },
"wss://eden.nostr.land/": { "read": true, "write": false }
},
"showNip05InNotes": true
}

View File

@ -0,0 +1,36 @@
{
"appName": "iris",
"appNameCapitalized": "Iris",
"appTitle": "iris",
"hostname": "iris.to",
"nip05Domain": "iris.to",
"favicon": "public/iris/favicon.ico",
"appleTouchIconUrl": "/img/apple-touch-icon.png",
"navLogo": "/img/icon128.png",
"publicDir": "public/iris",
"httpCache": "https://api.iris.to",
"animalNamePlaceholders": true,
"showNoteBroadcaster": false,
"defaultZapPoolFee": 0.5,
"bypassImgProxyError": true,
"features": {
"analytics": true,
"subscriptions": false,
"deck": true,
"zapPool": true
},
"signUp": {
"moderation": false
},
"hideFromNavbar": [],
"eventLinkPrefix": "note",
"profileLinkPrefix": "npub",
"defaultRelays": {
"wss://relay.snort.social/": { "read": true, "write": true },
"wss://nostr.wine/": { "read": true, "write": false },
"wss://eden.nostr.land/": { "read": true, "write": false },
"wss://relay.nostr.band/": { "read": true, "write": true },
"wss://relay.damus.io/": { "read": true, "write": true }
},
"showNip05InNotes": false
}

View File

@ -30,7 +30,55 @@ declare module "translations/*.json" {
export default value;
}
declare module "*.md" {
const value: string;
export default value;
}
declare module "emojilib" {
const value: Record<string, string>;
export default value;
}
declare const CONFIG: {
appName: string;
appNameCapitalized: string;
appTitle: string;
hostname: string;
nip05Domain: string;
favicon: string;
appleTouchIconUrl: string;
navLogo: string | null;
httpCache: string;
animalNamePlaceholders: boolean;
showNoteBroadcaster: boolean;
defaultZapPoolFee: number;
bypassImgProxyError: boolean;
features: {
analytics: boolean;
subscriptions: boolean;
deck: boolean;
zapPool: boolean;
};
signUp: {
moderation: boolean;
};
// Filter urls from nav sidebar
hideFromNavbar: Array<string>;
// Limit deck to certain subscriber tier
deckSubKind?: number;
eventLinkPrefix: NostrPrefix;
profileLinkPrefix: NostrPrefix;
defaultRelays: Record<string, RelaySettings>;
showNip05InNotes: boolean;
};
/**
* Single relay (Debug)
*/
declare const SINGLE_RELAY: string | undefined;
/**
* Build git hash
*/
declare const __SNORT_VERSION__: string;

View File

@ -9,11 +9,12 @@
name="keywords"
content="nostr snort fast decentralized social media censorship resistant open source software" />
<link rel="preconnect" href="https://imgproxy.snort.social" />
<link rel="apple-touch-icon" href="/nostrich_512.png" />
<link rel="apple-touch-icon" href="" />
<link rel="manifest" href="/manifest.json" />
<title>Snort - Nostr</title>
<title></title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

View File

@ -1,9 +0,0 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
bail: true,
preset: "ts-jest",
testEnvironment: "jsdom",
roots: ["src"],
moduleDirectories: ["src", "node_modules"],
setupFiles: ["./src/setupTests.ts"],
};

View File

@ -1,37 +1,45 @@
{
"name": "@snort/app",
"version": "0.1.10",
"version": "0.1.23",
"dependencies": {
"@cashu/cashu-ts": "^0.6.1",
"@lightninglabs/lnc-web": "^0.2.3-alpha",
"@noble/curves": "^1.0.0",
"@noble/hashes": "^1.2.0",
"@reduxjs/toolkit": "^1.9.1",
"@scure/base": "^1.1.1",
"@scure/bip32": "^1.3.0",
"@scure/bip39": "^1.1.1",
"@snort/shared": "workspace:*",
"@snort/system": "workspace:*",
"@snort/system-query": "workspace:*",
"@snort/system-react": "workspace:*",
"@snort/system-wasm": "workspace:*",
"@snort/system-web": "workspace:*",
"@szhsin/react-menu": "^3.3.1",
"@void-cat/api": "^1.0.4",
"@uidotdev/usehooks": "^2.4.1",
"@void-cat/api": "^1.0.10",
"classnames": "^2.3.2",
"debug": "^4.3.4",
"dexie": "^3.2.4",
"dns-over-http-resolver": "^2.1.1",
"emojilib": "^3.0.10",
"fuse.js": "^7.0.0",
"highlight.js": "^11.8.0",
"light-bolt11-decoder": "^2.1.0",
"marked": "^9.1.0",
"marked-footnote": "^1.0.0",
"match-sorter": "^6.3.1",
"qr-code-styling": "^1.6.0-rc.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-force-graph-3d": "^1.24.0",
"react-intersection-observer": "^9.4.1",
"react-intl": "^6.4.4",
"react-redux": "^8.0.5",
"react-router-dom": "^6.5.0",
"react-tag-input-component": "^2.0.2",
"react-textarea-autosize": "^8.4.0",
"react-twitter-embed": "^4.0.4",
"use-long-press": "^2.0.3",
"recharts": "^2.8.0",
"three": "^0.157.0",
"use-long-press": "^3.2.0",
"use-sync-external-store": "^1.2.0",
"uuid": "^9.0.0",
"workbox-core": "^6.4.2",
"workbox-precaching": "^7.0.0",
@ -39,9 +47,11 @@
"workbox-strategies": "^6.4.2"
},
"scripts": {
"start": "webpack serve --node-env=development --mode=development",
"build": "webpack --node-env=production --mode=production",
"test": "jest --runInBand",
"start": "vite",
"build": "yarn eslint --fix && vite build",
"serve": "vite preview",
"test": "vitest run",
"test:watch": "vitest watch",
"intl-extract": "formatjs extract 'src/**/*.ts*' --ignore='**/*.d.ts' --out-file src/lang.json --flatten true",
"intl-compile": "formatjs compile src/lang.json --out-file src/translations/en.json",
"eslint": "eslint ."
@ -66,49 +76,37 @@
]
},
"devDependencies": {
"@babel/core": "^7.22.9",
"@babel/plugin-syntax-import-assertions": "^7.20.0",
"@babel/preset-env": "^7.21.5",
"@babel/preset-react": "^7.18.6",
"@babel/runtime": "^7.22.6",
"@formatjs/cli": "^6.1.3",
"@formatjs/ts-transformer": "^3.13.3",
"@jest/globals": "^29.6.1",
"@types/config": "^3.3.3",
"@types/debug": "^4.1.8",
"@types/jest": "^29.5.1",
"@types/node": "^20.4.1",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
"@types/three": "^0.157.2",
"@types/use-sync-external-store": "^0.0.4",
"@types/uuid": "^9.0.2",
"@types/webscopeio__react-textarea-autocomplete": "^4.7.2",
"@types/webtorrent": "^0.109.3",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"@vitejs/plugin-react": "^4.2.0",
"@webbtc/webln-types": "^1.0.10",
"@webpack-cli/generators": "^3.0.4",
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
"babel-loader": "^9.1.3",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.3",
"css-minimizer-webpack-plugin": "^5.0.0",
"autoprefixer": "^10.4.16",
"config": "^3.3.9",
"eslint": "^8.48.0",
"eslint-webpack-plugin": "^4.0.1",
"html-webpack-plugin": "^5.5.1",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"mini-css-extract-plugin": "^2.7.5",
"eslint-plugin-formatjs": "^4.11.3",
"postcss": "^8.4.31",
"postcss-preset-env": "^9.2.0",
"prettier": "2.8.3",
"prop-types": "^15.8.1",
"source-map-loader": "^4.0.1",
"terser-webpack-plugin": "^5.3.9",
"tinybench": "^2.5.0",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.4",
"rollup-plugin-visualizer": "^5.9.2",
"tailwindcss": "^3.3.3",
"tinybench": "^2.5.1",
"typescript": "^5.2.2",
"webpack": "^5.88.2",
"webpack-bundle-analyzer": "^4.8.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"workbox-webpack-plugin": "^6.5.4"
"vite": "^5.0.0",
"vite-plugin-pwa": "^0.17.0",
"vite-plugin-version-mark": "^0.0.10",
"vitest": "^0.34.6"
}
}

View File

@ -0,0 +1,3 @@
module.exports = {
plugins: [require("tailwindcss"), require("autoprefixer")],
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,12 @@
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "to.iris.twa",
"sha256_cert_fingerprints": [
"63:B5:70:E8:F1:75:7E:D6:EF:81:11:66:F4:9D:47:AB:49:3C:2E:00:B9:67:92:40:89:A5:03:0B:96:B9:40:09"
]
}
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,41 @@
{
"short_name": "Iris",
"name": "Iris",
"description": "Fast nostr web ui",
"id": "/",
"icons": [
{
"src": "/img/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/img/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/img/maskable_icon.png",
"sizes": "640x640",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/img/maskable_icon_x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
}
],
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#000000",
"protocol_handlers": [
{
"protocol": "web+nostr",
"url": "/%s"
}
]
}

View File

@ -0,0 +1,16 @@
{
"applinks": {
"details": [
{
"appIDs": [
"snort.social.app"
]
}
]
},
"webcredentials": {
"apps": [
"snort.social.app"
]
}
}

View File

@ -0,0 +1,13 @@
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "social.snort.app",
"sha256_cert_fingerprints": [
"78:CE:8A:F7:C1:E2:30:12:77:55:BF:0E:86:E4:5C:BA:99:93:A0:D7:D7:42:F8:27:8B:C9:1B:AC:FC:8A:85:05",
"FC:C1:CA:02:C0:81:81:0C:1F:EC:1E:38:CA:38:61:62:6B:6E:90:88:62:DE:4A:66:FC:EC:08:33:B6:94:EE:3C"
]
}
}
]

View File

@ -24,5 +24,14 @@
"protocol": "web+nostr",
"url": "/%s"
}
],
"screenshots": [],
"display_override": ["fullscreen"],
"related_applications": [
{
"platform": "play",
"url": "https://play.google.com/store/apps/details?id=social.snort.app",
"id": "social.snort.app"
}
]
}

View File

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 146 KiB

View File

Before

Width:  |  Height:  |  Size: 528 KiB

After

Width:  |  Height:  |  Size: 528 KiB

View File

Before

Width:  |  Height:  |  Size: 771 KiB

After

Width:  |  Height:  |  Size: 771 KiB

View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@ -1,6 +1,6 @@
import { NostrEvent } from "@snort/system";
import { FeedCache } from "@snort/shared";
import { db } from "Db";
import { db } from "@/Db";
export class ChatCache extends FeedCache<NostrEvent> {
constructor() {

View File

@ -1,7 +1,7 @@
import { FeedCache } from "@snort/shared";
import { db, EventInteraction } from "Db";
import { LoginStore } from "Login";
import { sha256 } from "SnortUtils";
import { db, EventInteraction } from "@/Db";
import { LoginStore } from "@/Login";
import { sha256 } from "@/SnortUtils";
export class EventInteractionCache extends FeedCache<EventInteraction> {
constructor() {

View File

@ -0,0 +1,47 @@
import { db } from "@/Db";
import { unixNowMs } from "@snort/shared";
import { EventKind, RequestBuilder, socialGraphInstance, TaggedNostrEvent } from "@snort/system";
import { RefreshFeedCache } from "./RefreshFeedCache";
import { LoginSession } from "@/Login";
export class FollowListCache extends RefreshFeedCache<TaggedNostrEvent> {
constructor() {
super("FollowListCache", db.followLists);
}
buildSub(session: LoginSession, rb: RequestBuilder): void {
const since = this.newest();
rb.withFilter()
.kinds([EventKind.ContactList])
.authors(session.follows.item)
.since(since === 0 ? undefined : since);
}
async onEvent(evs: readonly TaggedNostrEvent[]) {
await Promise.all(
evs.map(async e => {
const update = await super.update({
...e,
created: e.created_at,
loaded: unixNowMs(),
});
if (update !== "no_change") {
socialGraphInstance.handleFollowEvent(e);
}
}),
);
}
key(of: TaggedNostrEvent): string {
return of.pubkey;
}
takeSnapshot() {
return [...this.cache.values()];
}
override async preload() {
await super.preload();
this.snapshot().forEach(e => socialGraphInstance.handleFollowEvent(e));
}
}

View File

@ -2,10 +2,10 @@ import debug from "debug";
import { EventKind, RequestBuilder, SystemInterface, TaggedNostrEvent } from "@snort/system";
import { unixNow, unixNowMs } from "@snort/shared";
import { db } from "Db";
import { db } from "@/Db";
import { RefreshFeedCache, TWithCreated } from "./RefreshFeedCache";
import { LoginSession } from "Login";
import { Day, Hour } from "Const";
import { LoginSession } from "@/Login";
import { Day, Hour } from "@/Const";
const WindowSize = Hour * 6;
const MaxCacheWindow = Day * 7;
@ -27,10 +27,12 @@ export class FollowsFeedCache extends RefreshFeedCache<TaggedNostrEvent> {
}
buildSub(session: LoginSession, rb: RequestBuilder): void {
const authors = session.follows.item;
authors.push(session.publicKey);
const since = this.newest();
rb.withFilter()
.kinds(this.#kinds)
.authors(session.follows.item)
.authors(authors)
.since(since === 0 ? unixNow() - WindowSize : since);
}
@ -47,7 +49,7 @@ export class FollowsFeedCache extends RefreshFeedCache<TaggedNostrEvent> {
const keys = (await this.table?.toCollection().primaryKeys()) ?? [];
this.onTable = new Set<string>(keys.map(a => a as string));
// load only latest 10 posts, rest can be loaded on-demand
// load only latest 50 posts, rest can be loaded on-demand
const latest = await this.table?.orderBy("created_at").reverse().limit(50).toArray();
latest?.forEach(v => this.cache.set(this.key(v), v));
@ -67,9 +69,11 @@ export class FollowsFeedCache extends RefreshFeedCache<TaggedNostrEvent> {
async loadMore(system: SystemInterface, session: LoginSession, before: number) {
if (this.#oldest && before <= this.#oldest) {
const rb = new RequestBuilder(`${this.name}-loadmore`);
const authors = session.follows.item;
authors.push(session.publicKey);
rb.withFilter()
.kinds(this.#kinds)
.authors(session.follows.item)
.authors(authors)
.until(before)
.since(before - WindowSize);
await system.Fetch(rb, async evs => {

View File

@ -1,8 +1,8 @@
import { EventKind, EventPublisher, RequestBuilder, TaggedNostrEvent } from "@snort/system";
import { UnwrappedGift, db } from "Db";
import { findTag, unwrap } from "SnortUtils";
import { UnwrappedGift, db } from "@/Db";
import { findTag, unwrap } from "@/SnortUtils";
import { RefreshFeedCache } from "./RefreshFeedCache";
import { LoginSession } from "Login";
import { LoginSession, LoginSessionType } from "@/Login";
export class GiftWrapCache extends RefreshFeedCache<UnwrappedGift> {
constructor() {
@ -15,7 +15,7 @@ export class GiftWrapCache extends RefreshFeedCache<UnwrappedGift> {
buildSub(session: LoginSession, rb: RequestBuilder): void {
const pubkey = session.publicKey;
if (pubkey) {
if (pubkey && session.type === LoginSessionType.PrivateKey) {
rb.withFilter().kinds([EventKind.GiftWrap]).tag("p", [pubkey]).since(this.newest());
}
}
@ -24,7 +24,9 @@ export class GiftWrapCache extends RefreshFeedCache<UnwrappedGift> {
return [...this.cache.values()];
}
override async onEvent(evs: Array<TaggedNostrEvent>, pub: EventPublisher) {
override async onEvent(evs: Array<TaggedNostrEvent>, _: string, pub?: EventPublisher) {
if (!pub) return;
const unwrapped = (
await Promise.all(
evs.map(async v => {

View File

@ -1,11 +1,11 @@
import { EventKind, NostrEvent, RequestBuilder, TaggedNostrEvent } from "@snort/system";
import { RefreshFeedCache, TWithCreated } from "./RefreshFeedCache";
import { LoginSession } from "Login";
import { db } from "Db";
import { Day } from "Const";
import { LoginSession } from "@/Login";
import { NostrEventForSession, db } from "@/Db";
import { Day } from "@/Const";
import { unixNow } from "@snort/shared";
export class NotificationsCache extends RefreshFeedCache<NostrEvent> {
export class NotificationsCache extends RefreshFeedCache<NostrEventForSession> {
#kinds = [EventKind.TextNote, EventKind.Reaction, EventKind.Repost, EventKind.ZapReceipt];
constructor() {
@ -14,7 +14,7 @@ export class NotificationsCache extends RefreshFeedCache<NostrEvent> {
buildSub(session: LoginSession, rb: RequestBuilder) {
if (session.publicKey) {
const newest = this.newest();
const newest = this.newest(v => v.tags.some(a => a[0] === "p" && a[1] === session.publicKey));
rb.withFilter()
.kinds(this.#kinds)
.tag("p", [session.publicKey])
@ -22,10 +22,15 @@ export class NotificationsCache extends RefreshFeedCache<NostrEvent> {
}
}
async onEvent(evs: readonly TaggedNostrEvent[]) {
async onEvent(evs: readonly TaggedNostrEvent[], pubKey: string) {
const filtered = evs.filter(a => this.#kinds.includes(a.kind) && a.tags.some(b => b[0] === "p"));
if (filtered.length > 0) {
await this.bulkSet(filtered);
await this.bulkSet(
filtered.map(v => ({
...v,
forSession: pubKey,
})),
);
this.notifyChange(filtered.map(v => this.key(v)));
}
}
@ -34,7 +39,7 @@ export class NotificationsCache extends RefreshFeedCache<NostrEvent> {
return of.id;
}
takeSnapshot(): TWithCreated<NostrEvent>[] {
takeSnapshot() {
return [...this.cache.values()];
}
}

View File

@ -1,4 +1,4 @@
import { Payment, db } from "Db";
import { Payment, db } from "@/Db";
import { FeedCache } from "@snort/shared";
export class Payments extends FeedCache<Payment> {

View File

@ -1,19 +1,23 @@
import { FeedCache } from "@snort/shared";
import { EventPublisher, RequestBuilder, TaggedNostrEvent } from "@snort/system";
import { LoginSession } from "Login";
import { LoginSession } from "@/Login";
export type TWithCreated<T> = (T | Readonly<T>) & { created_at: number };
export abstract class RefreshFeedCache<T> extends FeedCache<TWithCreated<T>> {
abstract buildSub(session: LoginSession, rb: RequestBuilder): void;
abstract onEvent(evs: Readonly<Array<TaggedNostrEvent>>, pub: EventPublisher): void;
abstract onEvent(evs: Readonly<Array<TaggedNostrEvent>>, pubKey: string, pub?: EventPublisher): void;
/**
* Get latest event
*/
protected newest() {
protected newest(filter?: (e: TWithCreated<T>) => boolean) {
let ret = 0;
this.cache.forEach(v => (ret = v.created_at > ret ? v.created_at : ret));
this.cache.forEach(v => {
if (!filter || filter(v)) {
ret = v.created_at > ret ? v.created_at : ret;
}
});
return ret;
}

View File

@ -1,20 +1,26 @@
import { UserProfileCache, UserRelaysCache, RelayMetricCache } from "@snort/system";
import { SnortSystemDb } from "@snort/system-web";
import { EventInteractionCache } from "./EventInteractionCache";
import { ChatCache } from "./ChatCache";
import { Payments } from "./PaymentsCache";
import { GiftWrapCache } from "./GiftWrapCache";
import { NotificationsCache } from "./Notifications";
import { FollowsFeedCache } from "./FollowsFeed";
import { FollowListCache } from "./FollowListCache";
export const SystemDb = new SnortSystemDb();
export const UserCache = new UserProfileCache(SystemDb.users);
export const UserRelays = new UserRelaysCache(SystemDb.userRelays);
export const RelayMetrics = new RelayMetricCache(SystemDb.relayMetrics);
export const UserCache = new UserProfileCache();
export const UserRelays = new UserRelaysCache();
export const RelayMetrics = new RelayMetricCache();
export const Chats = new ChatCache();
export const PaymentsCache = new Payments();
export const InteractionCache = new EventInteractionCache();
export const GiftsCache = new GiftWrapCache();
export const Notifications = new NotificationsCache();
export const FollowsFeed = new FollowsFeedCache();
export const FollowLists = new FollowListCache();
export async function preload(follows?: Array<string>) {
const preloads = [
@ -26,6 +32,7 @@ export async function preload(follows?: Array<string>) {
GiftsCache.preload(),
Notifications.preload(),
FollowsFeed.preload(),
FollowLists.preload(),
];
await Promise.all(preloads);
}

View File

@ -1,5 +1,3 @@
import { RelaySettings } from "@snort/system";
/**
* 1 Hour in seconds
*/
@ -10,21 +8,16 @@ export const Hour = 60 * 60;
*/
export const Day = Hour * 24;
/**
* Day this project started
*/
export const Birthday = new Date(2022, 11, 17);
/**
* Add-on api for snort features
*/
export const ApiHost = "https://api.snort.social";
/**
* LibreTranslate endpoint
*/
export const TranslateHost = "https://translate.snort.social";
/**
* Void.cat file upload service url
*/
export const VoidCatHost = "https://void.cat";
/**
* Kierans pubkey
*/
@ -35,53 +28,21 @@ export const KieranPubKey = "npub1v0lxxxxutpvrelsksy8cdhgfux9l6a42hsj2qzquu2zk7v
*/
export const SnortPubKey = "npub1sn0rtcjcf543gj4wsg7fa59s700d5ztys5ctj0g69g2x6802npjqhjjtws";
/**
* Websocket re-connect timeout
*/
export const DefaultConnectTimeout = 2000;
/**
* How long profile cache should be considered valid for
*/
export const ProfileCacheExpire = 1_000 * 60 * 60 * 6;
/**
* Default bootstrap relays
*/
export const DefaultRelays = new Map<string, RelaySettings>([
["wss://relay.snort.social/", { read: true, write: true }],
["wss://nostr.wine/", { read: true, write: false }],
["wss://nos.lol/", { read: true, write: true }],
]);
export const DefaultRelays = new Map(Object.entries(CONFIG.defaultRelays));
/**
* Default search relays
*/
export const SearchRelays = ["wss://relay.nostr.band"];
/**
* List of recommended follows for new users
*/
export const RecommendedFollows = [
"82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2", // jack
"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", // fiatjaf
"020f2d21ae09bf35fcdfb65decf1478b846f5f728ab30c5eaabcd6d081a81c3e", // adam3us
"6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93", // gigi
"63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed", // Kieran
"32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245", // jb55
"e33fe65f1fde44c6dc17eeb38fdad0fceaf1cae8722084332ed1e32496291d42", // wiz
"00000000827ffaa94bfea288c3dfce4422c794fbb96625b6b31e9049f729d700", // cameri
"A341F45FF9758F570A21B000C17D4E53A3A497C8397F26C0E6D61E5ACFFC7A98", // Saylor
"E88A691E98D9987C964521DFF60025F60700378A4879180DCBBB4A5027850411", // NVK
"C4EABAE1BE3CF657BC1855EE05E69DE9F059CB7A059227168B80B89761CBC4E0", // jackmallers
"85080D3BAD70CCDCD7F74C29A44F55BB85CBCD3DD0CBB957DA1D215BDB931204", // preston
"C49D52A573366792B9A6E4851587C28042FB24FA5625C6D67B8C95C8751ACA15", // holdonaut
"83E818DFBECCEA56B0F551576B3FD39A7A50E1D8159343500368FA085CCD964B", // jeffbooth
"3F770D65D3A764A9C5CB503AE123E62EC7598AD035D836E2A810F3877A745B24", // DerekRoss
"472F440F29EF996E92A186B8D320FF180C855903882E59D50DE1B8BD5669301E", // MartyBent
"1577e4599dd10c863498fe3c20bd82aafaf829a595ce83c5cf8ac3463531b09b", // yegorpetrov
"04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9", // ODELL
export const DeveloperAccounts = [
"63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed", // kieran
"4523be58d395b1b196a9b8c82b038b6895cb02b683d0c253a955068dba1facd0", // Martti
"7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194", // verbiricha
"1bc70a0148b3f316da33fe3c89f23e3e71ac4ff998027ec712b905cd24f6a411", // Karnage
];
/**
@ -98,6 +59,11 @@ export const DefaultImgProxy = {
*/
export const DerivationPath = "m/44'/1237'/0'/0/0";
/**
* Blaster relays
*/
export const Blasters = ["wss://nostr.mutinywallet.com"];
/**
* Regex to match email address
*/
@ -132,11 +98,6 @@ export const InvoiceRegex = /(lnbc\w+)/i;
export const YoutubeUrlRegex =
/(?:https?:\/\/)?(?:www|m\.)?(?:youtu\.be\/|youtube\.com\/(?:live\/|shorts\/|embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})/;
/**
* Tweet Regex
*/
export const TweetUrlRegex = /https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(?:es)?\/(\d+)/;
/**
* Hashtag regex
*/

View File

@ -2,7 +2,7 @@ import Dexie, { Table } from "dexie";
import { HexKey, NostrEvent, TaggedNostrEvent, u256 } from "@snort/system";
export const NAME = "snortDB";
export const VERSION = 14;
export const VERSION = 16;
export interface SubCache {
id: string;
@ -35,6 +35,10 @@ export interface UnwrappedGift {
tags?: Array<Array<string>>; // some tags extracted
}
export type NostrEventForSession = TaggedNostrEvent & {
forSession: string;
};
const STORES = {
chats: "++id",
eventInteraction: "++id",
@ -42,6 +46,7 @@ const STORES = {
gifts: "++id",
notifications: "++id",
followsFeed: "++id, created_at, kind",
followLists: "++pubkey",
};
export class SnortDB extends Dexie {
@ -50,8 +55,9 @@ export class SnortDB extends Dexie {
eventInteraction!: Table<EventInteraction>;
payments!: Table<Payment>;
gifts!: Table<UnwrappedGift>;
notifications!: Table<NostrEvent>;
notifications!: Table<NostrEventForSession>;
followsFeed!: Table<TaggedNostrEvent>;
followLists!: Table<TaggedNostrEvent>;
constructor() {
super(NAME);

View File

@ -1,14 +0,0 @@
button {
position: relative;
}
.spinner-wrapper {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
}

View File

@ -1,40 +0,0 @@
import "./AsyncButton.css";
import { useState } from "react";
import Spinner from "../Icons/Spinner";
interface AsyncButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
disabled?: boolean;
onClick(e: React.MouseEvent): Promise<void> | void;
children?: React.ReactNode;
}
export default function AsyncButton(props: AsyncButtonProps) {
const [loading, setLoading] = useState<boolean>(false);
async function handle(e: React.MouseEvent) {
e.stopPropagation();
if (loading || props.disabled) return;
setLoading(true);
try {
if (typeof props.onClick === "function") {
const f = props.onClick(e);
if (f instanceof Promise) {
await f;
}
}
} finally {
setLoading(false);
}
}
return (
<button className="spinner-button" type="button" disabled={loading || props.disabled} {...props} onClick={handle}>
<span style={{ visibility: loading ? "hidden" : "visible" }}>{props.children}</span>
{loading && (
<span className="spinner-wrapper">
<Spinner />
</span>
)}
</button>
);
}

View File

@ -1,37 +0,0 @@
import Icon from "Icons/Icon";
import Spinner from "Icons/Spinner";
import { HTMLProps, useState } from "react";
export interface AsyncIconProps extends HTMLProps<HTMLDivElement> {
iconName: string;
iconSize?: number;
loading?: boolean;
onClick?: (e: React.MouseEvent<HTMLDivElement>) => Promise<void>;
}
export function AsyncIcon(props: AsyncIconProps) {
const [loading, setLoading] = useState(props.loading ?? false);
async function handleClick(e: React.MouseEvent<HTMLDivElement>) {
setLoading(true);
try {
if (props.onClick) {
await props.onClick(e);
}
} catch (ex) {
console.error(ex);
}
setLoading(false);
}
const mergedProps = { ...props } as Record<string, unknown>;
delete mergedProps["iconName"];
delete mergedProps["iconSize"];
delete mergedProps["loading"];
return (
<div {...mergedProps} onClick={e => handleClick(e)}>
{loading ? <Spinner /> : <Icon name={props.iconName} size={props.iconSize} />}
{props.children}
</div>
);
}

View File

@ -1,47 +0,0 @@
import "./Avatar.css";
import { CSSProperties, ReactNode, useEffect, useState } from "react";
import type { UserMetadata } from "@snort/system";
import useImgProxy from "Hooks/useImgProxy";
import { getDisplayName } from "Element/ProfileImage";
import { defaultAvatar } from "SnortUtils";
interface AvatarProps {
pubkey: string;
user?: UserMetadata;
onClick?: () => void;
size?: number;
image?: string;
imageOverlay?: ReactNode;
}
const Avatar = ({ pubkey, user, size, onClick, image, imageOverlay }: AvatarProps) => {
const [url, setUrl] = useState("");
const { proxy } = useImgProxy();
useEffect(() => {
const url = image ?? user?.picture;
if (url) {
const proxyUrl = proxy(url, size ?? 120);
setUrl(proxyUrl);
} else {
setUrl(defaultAvatar(pubkey));
}
}, [user, image]);
const backgroundImage = `url(${url})`;
const style = { "--img-url": backgroundImage } as CSSProperties;
const domain = user?.nip05 && user.nip05.split("@")[1];
return (
<div
onClick={onClick}
style={style}
className={`avatar${imageOverlay ? " with-overlay" : ""}`}
data-domain={domain?.toLowerCase()}
title={getDisplayName(user, "")}>
{imageOverlay && <div className="overlay">{imageOverlay}</div>}
</div>
);
};
export default Avatar;

View File

@ -0,0 +1,28 @@
.spinner-wrapper {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.spinner-button > span {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
}
.light .spinner-button {
border: 1px solid var(--border-color);
color: var(--font-secondary);
box-shadow: rgba(0, 0, 0, 0.08) 0 1px 1px;
}
.light .spinner-button:hover {
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 3px;
}
.light .spinner-button > span {
color: black;
}

View File

@ -0,0 +1,32 @@
import "./AsyncButton.css";
import React, { ForwardedRef } from "react";
import Spinner from "../../Icons/Spinner";
import useLoading from "@/Hooks/useLoading";
import classNames from "classnames";
export interface AsyncButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
onClick?: (e: React.MouseEvent) => Promise<void> | void;
}
const AsyncButton = React.forwardRef<HTMLButtonElement, AsyncButtonProps>((props, ref) => {
const { handle, loading } = useLoading(props.onClick, props.disabled);
return (
<button
ref={ref as ForwardedRef<HTMLButtonElement>}
type="button"
disabled={loading || props.disabled}
{...props}
className={classNames("spinner-button", props.className)}
onClick={handle}>
<span style={{ visibility: loading ? "hidden" : "visible" }}>{props.children}</span>
{loading && (
<span className="spinner-wrapper">
<Spinner />
</span>
)}
</button>
);
});
export default AsyncButton;

View File

@ -0,0 +1,24 @@
import Icon from "@/Icons/Icon";
import useLoading from "@/Hooks/useLoading";
import Spinner from "@/Icons/Spinner";
export type AsyncIconProps = React.HTMLProps<HTMLDivElement> & {
iconName: string;
iconSize?: number;
onClick?: (e: React.MouseEvent) => Promise<void> | void;
};
export function AsyncIcon(props: AsyncIconProps) {
const { loading, handle } = useLoading(props.onClick, props.disabled);
const mergedProps = { ...props } as Record<string, unknown>;
delete mergedProps["iconName"];
delete mergedProps["iconSize"];
delete mergedProps["loading"];
return (
<div {...mergedProps} onClick={handle} className={props.className}>
{loading ? <Spinner /> : <Icon name={props.iconName} size={props.iconSize} />}
{props.children}
</div>
);
}

View File

@ -6,18 +6,17 @@
font-size: var(--font-size);
display: flex;
align-items: center;
border: none !important;
box-shadow: none !important;
}
.back-button svg {
margin-right: 0.5em;
}
.back-button:hover {
text-decoration: underline;
}
.back-button:hover {
background: none;
color: var(--font-color);
.back-button:hover:hover,
.light .back-button:hover {
text-decoration: underline;
box-shadow: none !important;
background: none !important;
}

View File

@ -1,9 +1,9 @@
import "./BackButton.css";
import { useIntl } from "react-intl";
import Icon from "Icons/Icon";
import Icon from "@/Icons/Icon";
import messages from "./messages";
import messages from "../messages";
interface BackButtonProps {
text?: string;

View File

@ -0,0 +1,21 @@
import classNames from "classnames";
import Icon, { IconProps } from "@/Icons/Icon";
import type { ReactNode } from "react";
interface IconButtonProps {
onClick?: () => void;
icon: IconProps;
className?: string;
children?: ReactNode;
}
const IconButton = ({ onClick, icon, children, className }: IconButtonProps) => {
return (
<button className={classNames("icon", className)} type="button" onClick={onClick}>
<Icon {...icon} />
{children}
</button>
);
};
export default IconButton;

View File

@ -1,21 +1,21 @@
import { FormattedMessage } from "react-intl";
import { useNavigate } from "react-router-dom";
import { logout } from "Login";
import useLogin from "Hooks/useLogin";
import messages from "./messages";
import { logout } from "@/Login";
import useLogin from "@/Hooks/useLogin";
import messages from "../messages";
export default function LogoutButton() {
const navigate = useNavigate();
const publicKey = useLogin().publicKey;
const login = useLogin(s => ({ publicKey: s.publicKey, id: s.id }));
if (!publicKey) return;
if (!login.publicKey) return;
return (
<button
className="secondary"
type="button"
onClick={() => {
logout(publicKey);
logout(login.id);
navigate("/");
}}>
<FormattedMessage {...messages.Logout} />

View File

@ -1,81 +0,0 @@
import { useEffect, useState } from "react";
import { FormattedMessage } from "react-intl";
import useLogin from "Hooks/useLogin";
import { useUserProfile } from "@snort/system-react";
interface Token {
token: Array<{
mint: string;
proofs: Array<{
amount: number;
}>;
}>;
memo?: string;
}
export default function CashuNuts({ token }: { token: string }) {
const login = useLogin();
const profile = useUserProfile(login.publicKey);
async function copyToken(e: React.MouseEvent<HTMLButtonElement>, token: string) {
e.stopPropagation();
await navigator.clipboard.writeText(token);
}
async function redeemToken(e: React.MouseEvent<HTMLButtonElement>, token: string) {
e.stopPropagation();
const lnurl = profile?.lud16 ?? "";
const url = `https://redeem.cashu.me?token=${encodeURIComponent(token)}&lightning=${encodeURIComponent(
lnurl,
)}&autopay=yes`;
window.open(url, "_blank");
}
const [cashu, setCashu] = useState<Token>();
useEffect(() => {
try {
if (!token.startsWith("cashuA") || token.length < 10) {
return;
}
import("@cashu/cashu-ts").then(({ getDecodedToken }) => {
const tkn = getDecodedToken(token);
setCashu(tkn);
});
} catch {
// ignored
}
}, [token]);
if (!cashu) return <>{token}</>;
return (
<div className="note-invoice">
<div className="flex f-between">
<div>
<h4>
<FormattedMessage defaultMessage="Cashu token" />
</h4>
<p>
<FormattedMessage
defaultMessage="Amount: {amount} sats"
values={{
amount: cashu.token[0].proofs.reduce((acc, v) => acc + v.amount, 0),
}}
/>
</p>
<small className="xs">
<FormattedMessage defaultMessage="Mint: {url}" values={{ url: cashu.token[0].mint }} />
</small>
</div>
<div>
<button onClick={e => copyToken(e, token)} className="mr5">
<FormattedMessage defaultMessage="Copy" description="Button: Copy Cashu token" />
</button>
<button onClick={e => redeemToken(e, token)}>
<FormattedMessage defaultMessage="Redeem" description="Button: Redeem Cashu token" />
</button>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,21 @@
import { MetadataCache } from "@snort/system";
import { ChatParticipant } from "@/chat";
import NoteToSelf from "../User/NoteToSelf";
import ProfileImage from "../User/ProfileImage";
import useLogin from "@/Hooks/useLogin";
export function ChatParticipantProfile({ participant }: { participant: ChatParticipant }) {
const { publicKey } = useLogin(s => ({ publicKey: s.publicKey }));
if (participant.id === publicKey) {
return <NoteToSelf className="grow" />;
}
return (
<ProfileImage
showNip05={false}
pubkey={participant.id}
className="grow"
profile={participant.profile as MetadataCache}
/>
);
}

View File

@ -0,0 +1,7 @@
.dm-gradient {
background: var(--dm-gradient);
}
.other {
background: var(--gray-superdark);
}

View File

@ -1,16 +1,17 @@
import "./DM.css";
import { useEffect, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { useInView } from "react-intersection-observer";
import useEventPublisher from "Feed/EventPublisher";
import NoteTime from "Element/NoteTime";
import Text from "Element/Text";
import useLogin from "Hooks/useLogin";
import { Chat, ChatMessage, ChatType, setLastReadIn } from "chat";
import ProfileImage from "./ProfileImage";
import useEventPublisher from "@/Hooks/useEventPublisher";
import NoteTime from "@/Element/Event/NoteTime";
import Text from "@/Element/Text";
import useLogin from "@/Hooks/useLogin";
import { Chat, ChatMessage, ChatType, setLastReadIn } from "@/chat";
import ProfileImage from "../User/ProfileImage";
import messages from "./messages";
import messages from "../messages";
export interface DMProps {
chat: Chat;
@ -18,14 +19,14 @@ export interface DMProps {
}
export default function DM(props: DMProps) {
const pubKey = useLogin().publicKey;
const publisher = useEventPublisher();
const { publicKey } = useLogin(s => ({ publicKey: s.publicKey }));
const { publisher } = useEventPublisher();
const msg = props.data;
const [content, setContent] = useState<string>();
const { ref, inView } = useInView({ triggerOnce: true });
const { formatMessage } = useIntl();
const isMe = msg.from === pubKey;
const otherPubkey = isMe ? pubKey : msg.from;
const isMe = msg.from === publicKey;
const otherPubkey = isMe ? publicKey : msg.from;
async function decrypt() {
if (publisher) {
@ -55,16 +56,27 @@ export default function DM(props: DMProps) {
}, [inView]);
return (
<div className={isMe ? "dm me" : "dm other"} ref={ref}>
<div>
<div
className={
isMe
? "self-end mt-4 min-w-[100px] max-w-[90%] whitespace-pre-wrap align-self-end"
: "mt-4 min-w-[100px] max-w-[90%] whitespace-pre-wrap"
}
ref={ref}>
<div
className={
isMe
? "p-3 dm-gradient rounded-tl-lg rounded-tr-lg rounded-bl-lg rounded-br-none"
: "p-3 bg-gray-300 rounded-tl-lg rounded-tr-lg rounded-br-lg rounded-bl-none other"
}>
{sender()}
{content ? (
<Text id={msg.id} content={content} tags={[]} creator={otherPubkey} />
) : (
<FormattedMessage defaultMessage="Loading..." />
<FormattedMessage defaultMessage="Loading..." id="gjBiyj" />
)}
</div>
<div>
<div className={isMe ? "text-end text-gray-400 text-sm mt-1" : "text-gray-400 text-sm mt-1"}>
<NoteTime from={msg.created_at * 1000} fallback={formatMessage(messages.JustNow)} />
</div>
</div>

View File

@ -0,0 +1,89 @@
import { useEffect, useMemo, useRef } from "react";
import ProfileImage from "@/Element/User/ProfileImage";
import DM from "@/Element/Chat/DM";
import useLogin from "@/Hooks/useLogin";
import WriteMessage from "@/Element/Chat/WriteMessage";
import { Chat, createEmptyChatObject, useChatSystem } from "@/chat";
import { FormattedMessage } from "react-intl";
import { ChatParticipantProfile } from "./ChatParticipant";
export default function DmWindow({ id }: { id: string }) {
const dms = useChatSystem();
const chat = dms.find(a => a.id === id) ?? createEmptyChatObject(id);
function sender() {
if (chat.participants.length === 1) {
return <ChatParticipantProfile participant={chat.participants[0]} />;
} else {
return (
<div className="flex -space-x-5 mb-2.5">
{chat.participants.map(v => (
<ProfileImage pubkey={v.id} showUsername={false} />
))}
{chat.title ?? <FormattedMessage defaultMessage="Secret Group Chat" id="+Vxixo" />}
</div>
);
}
}
return (
<div className="flex flex-1 flex-col h-[calc(100vh-62px)] md:h-screen">
<div className="p-3">{sender()}</div>
<div className="overflow-y-auto hide-scrollbar p-2.5 flex-grow">
<div className="flex flex-col">{chat && <DmChatSelected chat={chat} />}</div>
</div>
<div className="flex items-center gap-2.5 p-2.5">
<WriteMessage chat={chat} />
</div>
</div>
);
}
function DmChatSelected({ chat }: { chat: Chat }) {
const { publicKey: myPubKey } = useLogin(s => ({ publicKey: s.publicKey }));
const messagesContainerRef = useRef<HTMLDivElement>(null);
const messagesEndRef = useRef<HTMLDivElement>(null);
const sortedDms = useMemo(() => {
const myDms = chat?.messages;
if (myPubKey && myDms) {
// filter dms in this chat, or dms to self
return [...myDms].sort((a, b) => a.created_at - b.created_at);
}
return [];
}, [chat, myPubKey]);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "instant" });
};
useEffect(() => {
const observer = new ResizeObserver(() => {
scrollToBottom();
});
// Start observing the element that you want to keep in view
if (messagesContainerRef.current) {
observer.observe(messagesContainerRef.current);
}
// Make sure to scroll to bottom on initial load
scrollToBottom();
// Clean up the observer on component unmount
return () => {
if (messagesContainerRef.current) {
observer.unobserve(messagesContainerRef.current);
}
};
}, [sortedDms]);
return (
<div className="flex flex-col" ref={messagesContainerRef}>
{sortedDms.map(a => (
<DM data={a} key={a.id} chat={chat} />
))}
<div ref={messagesEndRef} />
</div>
);
}

View File

@ -0,0 +1,49 @@
import { useState } from "react";
import useEventPublisher from "@/Hooks/useEventPublisher";
import Textarea from "../Textarea";
import { Chat } from "@/chat";
import { AsyncIcon } from "@/Element/Button/AsyncIcon";
export default function WriteMessage({ chat }: { chat: Chat }) {
const [msg, setMsg] = useState("");
const { publisher, system } = useEventPublisher();
async function sendMessage() {
if (msg && publisher && chat) {
const ev = await chat.createMessage(msg, publisher);
await chat.sendMessage(ev, system);
setMsg("");
}
}
function onChange(e: React.ChangeEvent<HTMLTextAreaElement>) {
setMsg(e.target.value);
}
async function onEnter(e: React.KeyboardEvent<HTMLTextAreaElement>) {
const isEnter = e.code === "Enter";
if (isEnter && !e.shiftKey) {
e.preventDefault();
await sendMessage();
}
}
return (
<>
<div className="grow">
<Textarea
autoFocus={true}
placeholder=""
className=""
value={msg}
onChange={e => onChange(e)}
onKeyDown={e => onEnter(e)}
onFocus={() => {
// ignored
}}
/>
</div>
<AsyncIcon className="circle flex items-center button" iconName="arrow-right" onClick={() => sendMessage()} />
</>
);
}

View File

@ -1,7 +1,8 @@
import { useState, ReactNode } from "react";
import classNames from "classnames";
import Icon from "Icons/Icon";
import ShowMore from "Element/ShowMore";
import Icon from "@/Icons/Icon";
import ShowMore from "@/Element/Event/ShowMore";
interface CollapsedProps {
text?: string;
@ -38,15 +39,13 @@ interface CollapsedSectionProps {
export const CollapsedSection = ({ title, children, className }: CollapsedSectionProps) => {
const [collapsed, setCollapsed] = useState(true);
const icon = (
<div className={`collapse-icon ${collapsed ? "" : "flip"}`}>
<div className={classNames("collapse-icon", { flip: !collapsed })}>
<Icon name="arrowFront" />
</div>
);
return (
<>
<div
className={`collapsable-section${className ? ` ${className}` : ""}`}
onClick={() => setCollapsed(!collapsed)}>
<div className={classNames("collapsable-section", className)} onClick={() => setCollapsed(!collapsed)}>
{title}
<CollapsedIcon icon={icon} collapsed={collapsed} />
</div>

View File

@ -1,5 +1,4 @@
.copy .copy-body {
font-size: var(--font-size-small);
color: var(--font-color);
margin-right: 6px;
}

View File

@ -1,6 +1,7 @@
import "./Copy.css";
import Icon from "Icons/Icon";
import { useCopy } from "useCopy";
import classNames from "classnames";
import Icon from "@/Icons/Icon";
import { useCopy } from "@/useCopy";
export interface CopyProps {
text: string;
@ -13,7 +14,7 @@ export default function Copy({ text, maxSize = 32, className }: CopyProps) {
const trimmed = text.length > maxSize ? `${text.slice(0, sliceLength)}...${text.slice(-sliceLength)}` : text;
return (
<div className={`copy flex pointer g8${className ? ` ${className}` : ""}`} onClick={() => copy(text)}>
<div className={classNames("copy flex pointer g8 items-center", className)} onClick={() => copy(text)}>
<span className="copy-body">{trimmed}</span>
<span className="icon" style={{ color: copied ? "var(--success)" : "var(--highlight)" }}>
{copied ? <Icon name="check" size={14} /> : <Icon name="copy-solid" size={14} />}

View File

@ -1,37 +0,0 @@
.dm {
margin-top: 16px;
min-width: 100px;
max-width: 90%;
white-space: pre-wrap;
color: var(--font-color);
}
.dm a {
color: var(--font-color) !important;
}
.dm > div:last-child {
color: var(--gray-light);
font-size: small;
margin-top: 3px;
}
.dm.other > div:first-child {
padding: 12px 16px;
background: var(--gray-secondary);
border-radius: 16px 16px 16px 0px;
}
.dm.me {
align-self: flex-end;
}
.dm.me > div:first-child {
padding: 12px 16px;
background: var(--dm-gradient);
border-radius: 16px 16px 0px 16px;
}
.dm.me > div:last-child {
text-align: end;
}

View File

@ -1,14 +0,0 @@
import { useArticles } from "Feed/ArticlesFeed";
import { orderDescending } from "SnortUtils";
import Note from "../Note";
export default function Articles() {
const data = useArticles();
return (
<>
{orderDescending(data.data ?? []).map(a => (
<Note data={a} key={a.id} related={[]} />
))}
</>
);
}

View File

@ -1,12 +0,0 @@
nav.deck {
width: 48px;
height: calc(100vh - 20px);
padding: 10px 8px;
border-right: 1px solid var(--border-color);
text-align: center;
}
nav.deck .avatar {
width: 40px;
height: 40px;
}

View File

@ -1,41 +0,0 @@
import { useUserProfile } from "@snort/system-react";
import Avatar from "Element/Avatar";
import useLogin from "Hooks/useLogin";
import "./Nav.css";
import Icon from "Icons/Icon";
import { Link } from "react-router-dom";
import { profileLink } from "SnortUtils";
export function DeckNav() {
const { publicKey } = useLogin();
const profile = useUserProfile(publicKey);
const unreadDms = 0;
const hasNotifications = false;
return (
<nav className="deck flex-column f-space">
<div className="flex-column f-center g24">
<Link className="btn" to="/messages">
<Icon name="mail" size={24} />
{unreadDms > 0 && <span className="has-unread"></span>}
</Link>
<Link className="btn" to="/notifications">
<Icon name="bell-02" size={24} />
{hasNotifications && <span className="has-unread"></span>}
</Link>
</div>
<div className="flex-column f-center g16">
<Link className="btn" to="/">
<Icon name="grid-01" size={24} />
</Link>
<Link className="btn" to="/settings">
<Icon name="settings-02" size={24} />
</Link>
<Link to={profileLink(publicKey ?? "")}>
<Avatar pubkey={publicKey ?? ""} user={profile} />
</Link>
</div>
</nav>
);
}

View File

@ -1,32 +0,0 @@
.dm-window {
display: flex;
flex-direction: column;
height: 100%;
}
.dm-window > div:nth-child(1) {
padding: 12px 0;
}
.dm-window > div:nth-child(2) {
overflow-y: auto;
padding: 0 10px 10px 10px;
flex-grow: 1;
display: flex;
flex-direction: column-reverse;
}
.dm-window > div:nth-child(3) {
display: flex;
align-items: center;
gap: 10px;
padding: 5px 10px;
}
.pfp-overlap .pfp:not(:last-of-type) {
margin-right: -20px;
}
.pfp-overlap .avatar {
width: 32px;
height: 32px;
}

View File

@ -1,76 +0,0 @@
import "./DmWindow.css";
import { useMemo } from "react";
import ProfileImage from "Element/ProfileImage";
import DM from "Element/DM";
import NoteToSelf from "Element/NoteToSelf";
import useLogin from "Hooks/useLogin";
import WriteMessage from "Element/WriteMessage";
import { Chat, ChatParticipant, createEmptyChatObject, useChatSystem } from "chat";
import { FormattedMessage } from "react-intl";
export default function DmWindow({ id }: { id: string }) {
const pubKey = useLogin().publicKey;
const dms = useChatSystem();
const chat = dms.find(a => a.id === id) ?? createEmptyChatObject(id);
function participant(p: ChatParticipant) {
if (p.id === pubKey) {
return <NoteToSelf className="f-grow mb-10" pubkey={p.id} />;
}
if (p.type === "pubkey") {
return <ProfileImage pubkey={p.id} className="f-grow mb10" />;
}
if (p?.profile) {
return <ProfileImage pubkey={p.id} className="f-grow mb10" profile={p.profile} />;
}
return <ProfileImage pubkey={p.id} className="f-grow mb10" overrideUsername={p.id} />;
}
function sender() {
if (chat.participants.length === 1) {
return participant(chat.participants[0]);
} else {
return (
<div className="flex pfp-overlap mb10">
{chat.participants.map(v => (
<ProfileImage pubkey={v.id} showUsername={false} />
))}
{chat.title ?? <FormattedMessage defaultMessage="Secret Group Chat" />}
</div>
);
}
}
return (
<div className="dm-window">
<div>{sender()}</div>
<div>
<div className="flex f-col">{chat && <DmChatSelected chat={chat} />}</div>
</div>
<div>
<WriteMessage chat={chat} />
</div>
</div>
);
}
function DmChatSelected({ chat }: { chat: Chat }) {
const { publicKey: myPubKey } = useLogin();
const sortedDms = useMemo(() => {
const myDms = chat?.messages;
if (myPubKey && myDms) {
// filter dms in this chat, or dms to self
return [...myDms].sort((a, b) => a.created_at - b.created_at);
}
return [];
}, [chat, myPubKey]);
return (
<>
{sortedDms.map(a => (
<DM data={a} key={a.id} chat={chat} />
))}
</>
);
}

View File

@ -0,0 +1,8 @@
.cashu {
background: var(--cashu-gradient);
}
.cashu h1 {
font-size: 44px;
line-height: 1em;
}

View File

@ -0,0 +1,139 @@
import "./CashuNuts.css";
import { useEffect, useState } from "react";
import { FormattedMessage, FormattedNumber } from "react-intl";
import { useUserProfile } from "@snort/system-react";
import useLogin from "@/Hooks/useLogin";
import Icon from "@/Icons/Icon";
interface Token {
token: Array<{
mint: string;
proofs: Array<{
amount: number;
}>;
}>;
memo?: string;
}
export default function CashuNuts({ token }: { token: string }) {
const { publicKey } = useLogin(s => ({ publicKey: s.publicKey }));
const profile = useUserProfile(publicKey);
async function copyToken(e: React.MouseEvent<HTMLButtonElement>, token: string) {
e.stopPropagation();
await navigator.clipboard.writeText(token);
}
async function redeemToken(e: React.MouseEvent<HTMLButtonElement>, token: string) {
e.stopPropagation();
const lnurl = profile?.lud16 ?? "";
const url = `https://redeem.cashu.me?token=${encodeURIComponent(token)}&lightning=${encodeURIComponent(
lnurl,
)}&autopay=yes`;
window.open(url, "_blank");
}
const [cashu, setCashu] = useState<Token>();
useEffect(() => {
try {
if (!token.startsWith("cashuA") || token.length < 10) {
return;
}
import("@cashu/cashu-ts").then(({ getDecodedToken }) => {
const tkn = getDecodedToken(token);
setCashu(tkn);
});
} catch {
// ignored
}
}, [token]);
if (!cashu) return <>{token}</>;
const amount = cashu.token[0].proofs.reduce((acc, v) => acc + v.amount, 0);
return (
<div className="cashu flex justify-between p24 br">
<div className="flex flex-col g8 f-ellipsis">
<div className="flex items-center g16">
<svg width="30" height="39" viewBox="0 0 30 39" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 47711">
<path
id="Rectangle 585"
d="M29.3809 2.47055L29.3809 11.7277L26.7913 11.021C23.8493 10.2181 20.727 10.3835 17.8863 11.4929C15.5024 12.4238 12.9113 12.6933 10.3869 12.2728L7.11501 11.7277L7.11501 2.47054L10.3869 3.01557C12.9113 3.43607 15.5024 3.1666 17.8863 2.23566C20.727 1.12632 23.8493 0.960876 26.7913 1.7638L29.3809 2.47055Z"
fill="url(#paint0_linear_1976_19241)"
/>
<path
id="Rectangle 587"
d="M29.3809 27.9803L29.3809 37.2375L26.7913 36.5308C23.8493 35.7278 20.727 35.8933 17.8863 37.0026C15.5024 37.9336 12.9113 38.203 10.3869 37.7825L7.11501 37.2375L7.11501 27.9803L10.3869 28.5253C12.9113 28.9458 15.5024 28.6764 17.8863 27.7454C20.727 26.6361 23.8493 26.4706 26.7913 27.2736L29.3809 27.9803Z"
fill="url(#paint1_linear_1976_19241)"
/>
<path
id="Rectangle 586"
d="M8.494e-08 15.2069L4.89585e-07 24.4641L2.5896 23.7573C5.53159 22.9544 8.6539 23.1198 11.4946 24.2292C13.8784 25.1601 16.4695 25.4296 18.9939 25.0091L22.2658 24.4641L22.2658 15.2069L18.9939 15.7519C16.4695 16.1724 13.8784 15.9029 11.4946 14.972C8.6539 13.8627 5.53159 13.6972 2.5896 14.5001L8.494e-08 15.2069Z"
fill="url(#paint2_linear_1976_19241)"
/>
</g>
<defs>
<linearGradient
id="paint0_linear_1976_19241"
x1="29.3809"
y1="6.7213"
x2="7.11501"
y2="6.7213"
gradientUnits="userSpaceOnUse">
<stop stopColor="white" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
<linearGradient
id="paint1_linear_1976_19241"
x1="29.3809"
y1="32.2311"
x2="7.11501"
y2="32.2311"
gradientUnits="userSpaceOnUse">
<stop stopColor="white" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
<linearGradient
id="paint2_linear_1976_19241"
x1="2.70746e-07"
y1="19.4576"
x2="22.2658"
y2="19.4576"
gradientUnits="userSpaceOnUse">
<stop stopColor="white" />
<stop offset="1" stopColor="white" stopOpacity="0.5" />
</linearGradient>
</defs>
</svg>
<FormattedMessage
defaultMessage="<h1>{n}</h1> Cashu sats"
id="6/SF6e"
values={{
h1: c => <h1>{c}</h1>,
n: <FormattedNumber value={amount} />,
}}
/>
</div>
<small className="xs w-max">
<FormattedMessage
defaultMessage="<b>Mint:</b> {url}"
id="zwb6LR"
values={{
b: c => <b>{c}</b>,
url: new URL(cashu.token[0].mint).hostname,
}}
/>
</small>
</div>
<div className="flex g8">
<button onClick={e => copyToken(e, token)}>
<Icon name="copy" />
</button>
<button onClick={e => redeemToken(e, token)}>
<FormattedMessage defaultMessage="Redeem" id="XrSk2j" description="Button: Redeem Cashu token" />
</button>
</div>
</div>
);
}

View File

@ -0,0 +1,3 @@
.hashtag {
color: var(--highlight);
}

View File

@ -1,8 +1,5 @@
import { TwitterTweetEmbed } from "react-twitter-embed";
import {
YoutubeUrlRegex,
TweetUrlRegex,
TidalRegex,
SoundCloudRegex,
MixCloudRegex,
@ -11,31 +8,32 @@ import {
AppleMusicRegex,
NostrNestsRegex,
WavlakeRegex,
} from "Const";
import { magnetURIDecode } from "SnortUtils";
import SoundCloudEmbed from "Element/SoundCloudEmded";
import MixCloudEmbed from "Element/MixCloudEmbed";
import SpotifyEmbed from "Element/SpotifyEmbed";
import TidalEmbed from "Element/TidalEmbed";
import TwitchEmbed from "Element/TwitchEmbed";
import AppleMusicEmbed from "Element/AppleMusicEmbed";
import WavlakeEmbed from "Element/WavlakeEmbed";
import LinkPreview from "Element/LinkPreview";
import NostrLink from "Element/NostrLink";
import MagnetLink from "Element/MagnetLink";
} from "@/Const";
import { magnetURIDecode } from "@/SnortUtils";
import SoundCloudEmbed from "@/Element/Embed/SoundCloudEmded";
import MixCloudEmbed from "@/Element/Embed/MixCloudEmbed";
import SpotifyEmbed from "@/Element/Embed/SpotifyEmbed";
import TidalEmbed from "@/Element/Embed/TidalEmbed";
import TwitchEmbed from "@/Element/Embed/TwitchEmbed";
import AppleMusicEmbed from "@/Element/Embed/AppleMusicEmbed";
import WavlakeEmbed from "@/Element/Embed/WavlakeEmbed";
import LinkPreview from "@/Element/Embed/LinkPreview";
import NostrLink from "@/Element/Embed/NostrLink";
import MagnetLink from "@/Element/Embed/MagnetLink";
import { ReactNode } from "react";
interface HypeTextProps {
link: string;
children?: ReactNode | Array<ReactNode> | null;
depth?: number;
showLinkPreview?: boolean;
}
export default function HyperText({ link, depth, showLinkPreview }: HypeTextProps) {
export default function HyperText({ link, depth, showLinkPreview, children }: HypeTextProps) {
const a = link;
try {
const url = new URL(a);
const youtubeId = YoutubeUrlRegex.test(a) && RegExp.$1;
const tweetId = TweetUrlRegex.test(a) && RegExp.$2;
const tidalId = TidalRegex.test(a) && RegExp.$1;
const soundcloundId = SoundCloudRegex.test(a) && RegExp.$1;
const mixcloudId = MixCloudRegex.test(a) && RegExp.$1;
@ -44,13 +42,8 @@ export default function HyperText({ link, depth, showLinkPreview }: HypeTextProp
const isAppleMusicLink = AppleMusicRegex.test(a);
const isNostrNestsLink = NostrNestsRegex.test(a);
const isWavlakeLink = WavlakeRegex.test(a);
if (tweetId) {
return (
<div className="tweet" key={tweetId}>
<TwitterTweetEmbed tweetId={tweetId} />
</div>
);
} else if (youtubeId) {
if (youtubeId) {
return (
<iframe
className="w-max"
@ -78,7 +71,7 @@ export default function HyperText({ link, depth, showLinkPreview }: HypeTextProp
return (
<>
<a href={a} onClick={e => e.stopPropagation()} target="_blank" rel="noreferrer" className="ext">
{a}
{children ?? a}
</a>
{/*<NostrNestsEmbed link={a} />,*/}
</>
@ -100,7 +93,7 @@ export default function HyperText({ link, depth, showLinkPreview }: HypeTextProp
}
return (
<a href={a} onClick={e => e.stopPropagation()} target="_blank" rel="noreferrer" className="ext">
{a}
{children ?? a}
</a>
);
}

View File

@ -8,6 +8,12 @@
background: var(--invoice-gradient);
}
.note-invoice.error {
padding: 8px 12px !important;
color: #aaa;
background: transparent;
}
.note-invoice.expired {
background: var(--expired-invoice-gradient);
color: var(--font-secondary-color);

View File

@ -3,12 +3,13 @@ import { useState } from "react";
import { useIntl, FormattedMessage } from "react-intl";
import { useMemo } from "react";
import { decodeInvoice } from "@snort/shared";
import classNames from "classnames";
import SendSats from "Element/SendSats";
import Icon from "Icons/Icon";
import { useWallet } from "Wallet";
import SendSats from "@/Element/SendSats";
import Icon from "@/Icons/Icon";
import { useWallet } from "@/Wallet";
import messages from "./messages";
import messages from "../messages";
export interface InvoiceProps {
invoice: string;
@ -60,7 +61,7 @@ export default function Invoice(props: InvoiceProps) {
return (
<>
<div className={`note-invoice flex ${isExpired ? "expired" : ""} ${isPaid ? "paid" : ""}`}>
<div className={classNames("note-invoice flex", { expired: isExpired, paid: isPaid })}>
<div className="invoice-header">{header()}</div>
<p className="invoice-amount">
@ -75,7 +76,7 @@ export default function Invoice(props: InvoiceProps) {
{description && <p>{description}</p>}
{isPaid ? (
<div className="paid">
<FormattedMessage defaultMessage="Paid" />
<FormattedMessage defaultMessage="Paid" id="u/vOPu" />
</div>
) : (
<button disabled={isExpired} type="button" onClick={payInvoice}>

View File

@ -21,6 +21,8 @@
padding: 0;
font-size: 16px;
font-weight: 700;
line-height: initial;
margin: 0.5em 0;
}
.link-preview-container:hover .link-preview-title > h1 {
@ -40,12 +42,23 @@
margin: 0 0 15px 0 !important;
border-radius: 0 !important;
background-image: var(--img-url);
min-height: 250px;
min-height: 220px;
max-height: 500px;
background-size: cover;
background-position: center;
}
.light .link-preview-container {
background: #ddd;
background: #fff;
border: 1px solid var(--border-color);
}
.light .link-preview-container:hover {
box-shadow: rgba(0, 0, 0, 0.08) 0 1px 3px;
}
@media (min-width: 1025px) {
.link-preview-image {
min-height: 342px;
}
}

View File

@ -1,10 +1,10 @@
import "./LinkPreview.css";
import { CSSProperties, useEffect, useState } from "react";
import Spinner from "Icons/Spinner";
import SnortApi, { LinkPreviewData } from "SnortApi";
import useImgProxy from "Hooks/useImgProxy";
import { MediaElement } from "Element/MediaElement";
import Spinner from "@/Icons/Spinner";
import SnortApi, { LinkPreviewData } from "@/External/SnortApi";
import useImgProxy from "@/Hooks/useImgProxy";
import { MediaElement } from "@/Element/Embed/MediaElement";
async function fetchUrlPreviewInfo(url: string) {
const api = new SnortApi();
@ -81,7 +81,7 @@ const LinkPreview = ({ url }: { url: string }) => {
</div>
</a>
)}
{!preview && <Spinner className="f-center" />}
{!preview && <Spinner className="items-center" />}
</div>
);
};

View File

@ -1,6 +1,6 @@
import { FormattedMessage } from "react-intl";
import { Magnet } from "SnortUtils";
import { Magnet } from "@/SnortUtils";
interface MagnetLinkProps {
magnet: Magnet;
@ -10,7 +10,7 @@ const MagnetLink = ({ magnet }: MagnetLinkProps) => {
return (
<div className="note-invoice">
<h4>
<FormattedMessage defaultMessage="Magnet Link" />
<FormattedMessage defaultMessage="Magnet Link" id="Gcn9NQ" />
</h4>
<a href={magnet.raw} rel="noreferrer">
{magnet.dn ?? magnet.infoHash}

View File

@ -1,14 +1,7 @@
import { ProxyImg } from "Element/ProxyImg";
import { ProxyImg } from "@/Element/ProxyImg";
import useImgProxy from "@/Hooks/useImgProxy";
import React from "react";
/*
[
"imeta",
"url https://nostr.build/i/148e3e8cbe29ae268b0d6aad0065a086319d3c3b1fdf8b89f1e2327d973d2d05.jpg",
"blurhash e6A0%UE2t6D*R%?u?a9G?aM|~pM|%LR*RjR-%2NG%2t7_2R*%1IVWB",
"dim 3024x4032"
],
*/
interface MediaElementProps {
mime: string;
url: string;
@ -19,12 +12,14 @@ interface MediaElementProps {
}
export function MediaElement(props: MediaElementProps) {
const { proxy } = useImgProxy();
if (props.mime.startsWith("image/")) {
return <ProxyImg key={props.url} src={props.url} onClick={props.onMediaClick} />;
} else if (props.mime.startsWith("audio/")) {
return <audio key={props.url} src={props.url} controls />;
} else if (props.mime.startsWith("video/")) {
return <video key={props.url} src={props.url} controls />;
return <video key={props.url} src={props.url} controls poster={proxy(props.url)} />;
} else {
return (
<a

View File

@ -0,0 +1,35 @@
import { NostrLink, NostrPrefix } from "@snort/system";
import { useUserProfile } from "@snort/system-react";
import DisplayName from "@/Element/User/DisplayName";
import { ProfileCard } from "@/Element/User/ProfileCard";
import { ProfileLink } from "@/Element/User/ProfileLink";
import { useCallback, useRef, useState } from "react";
export default function Mention({ link }: { link: NostrLink }) {
const profile = useUserProfile(link.id);
const [isHovering, setIsHovering] = useState(false);
const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const handleMouseEnter = useCallback(() => {
hoverTimeoutRef.current && clearTimeout(hoverTimeoutRef.current);
hoverTimeoutRef.current = setTimeout(() => setIsHovering(true), 100); // Adjust timeout as needed
}, []);
const handleMouseLeave = useCallback(() => {
hoverTimeoutRef.current && clearTimeout(hoverTimeoutRef.current);
hoverTimeoutRef.current = setTimeout(() => setIsHovering(false), 300); // Adjust timeout as needed
}, []);
if (link.type !== NostrPrefix.Profile && link.type !== NostrPrefix.PublicKey) return;
return (
<span className="highlight" onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<ProfileLink pubkey={link.id} link={link} user={profile} onClick={e => e.stopPropagation()}>
@<DisplayName user={profile} pubkey={link.id} />
</ProfileLink>
{isHovering && <ProfileCard pubkey={link.id} user={profile} show={true} />}
</span>
);
}

View File

@ -1,11 +1,11 @@
import { MixCloudRegex } from "Const";
import useLogin from "Hooks/useLogin";
import { MixCloudRegex } from "@/Const";
import useLogin from "@/Hooks/useLogin";
const MixCloudEmbed = ({ link }: { link: string }) => {
const feedPath = (MixCloudRegex.test(link) && RegExp.$1) + "%2F" + (MixCloudRegex.test(link) && RegExp.$2);
const lightTheme = useLogin().preferences.theme === "light";
const lightParams = lightTheme ? "light=1" : "light=0";
const theme = useLogin(s => s.appData.item.preferences.theme);
const lightParams = theme === "light" ? "light=1" : "light=0";
return (
<>
<br />

Some files were not shown because too many files have changed in this diff Show More