Compare commits

...

259 commits

Author SHA1 Message Date
Kenneth C
d14c9141db
Update readme (#7755)
Removed my name from the readme as I have no association with this project anymore, and have not touched the Flatpak in ages. 

RIP LBRY.
2023-04-10 12:17:11 -04:00
zeppi
06c350c4db v0.53.9 2023-02-08 15:29:43 -05:00
zeppi
c3a9d9d002 fix changelog 2023-02-08 15:28:26 -05:00
zeppi
aeada6dc74 v0.53.9 2023-02-08 14:38:35 -05:00
zeppi
6ba985fd28 lbrynet version 113, changelog 2023-02-08 14:32:16 -05:00
jessopb
2a0bc85738
bump lbrynet to 113 (#7747) 2023-02-08 10:36:14 -05:00
jessopb
523ea284a2
update signing certificate for 2023 (#7744) 2023-01-25 16:25:45 -05:00
jessopb
a66d7534c2
add csc 2023-01-25 16:05:39 -05:00
zeppi
89ec07622f v0.53.8 2022-11-18 14:15:03 -05:00
zeppi
7e6ad31392 Revert "v0.53.8"
Incorrect Changelog
This reverts commit 4ab23f03fc.
2022-11-18 14:12:52 -05:00
zeppi
4ab23f03fc v0.53.8 2022-11-18 14:05:00 -05:00
zeppi
29cea5cc07 changelog 2022-11-18 14:02:37 -05:00
jessopb
8dd7150d67
fix unfollowing unpublished channels (#7737) 2022-11-18 10:22:32 -05:00
zeppi
f1b1523017 v0.53.8-alpha.1 2022-11-17 13:26:53 -05:00
jessopb
88ac250fee
fix large file uploads (#7736)
* fix large file uploads

* changelog

* update github action xcode version

* update electronbuilder for macos

* try use_hard_links=false

* no USE_HARD_LINKS

* upgrate electron-builder 23_3_3

* revert to electron-builder 22_10_5
electron-builder/issues/6124 says regressions happen after this version.

* try mac install homebrew, python2

* typo and ln /usr/bin/python

* oops

* try sudo

* try PYTHON_PATH

* comment github action mac python hack
2022-11-17 13:20:01 -05:00
zeppi
0a5e9e87ed v0.53.7 2022-11-10 14:45:50 -05:00
zeppi
20413d79b6 changelog 2022-11-10 14:44:54 -05:00
zeppi
ff9011e6ac v0.53.7-alpha.1 2022-11-04 12:37:02 -04:00
jessopb
802139d0a4
upgrade lbrynet to 112 (#7717) 2022-11-04 12:31:44 -04:00
zeppi
68d307fa50 changelog 2022-11-04 10:47:56 -04:00
jessopb
d3900e39b6
fix comment area display (#7716) 2022-11-04 10:44:36 -04:00
jessopb
35769dede6
separate out advanced textarea, fix comment channel selector width, a… (#7634)
* separate out advanced textarea, fix comment channel selector width, add advanced text icon

* fix master conflicts

* fixes

* fix channel description edit
2022-11-04 08:42:36 -04:00
zeppi
ae1e20d131 changelog 2022-11-03 17:46:08 -04:00
jessopb
051af8b6ad
fix post publish erased when confirmation (#7715) 2022-11-03 17:17:56 -04:00
jessopb
5d77b115f9
fix thumbnails disabling publish (#7714) 2022-11-03 15:55:46 -04:00
Byron Eric Perez
7dbeeac112
Add 'Collections' into txo filter (#7711) 2022-10-28 18:31:56 -04:00
zeppi
de062c4aee yarn lock 2022-10-25 13:31:32 -04:00
dependabot[bot]
18a3336714
Bump @xmldom/xmldom from 0.7.5 to 0.7.6 (#7701)
Bumps [@xmldom/xmldom](https://github.com/xmldom/xmldom) from 0.7.5 to 0.7.6.
- [Release notes](https://github.com/xmldom/xmldom/releases)
- [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xmldom/xmldom/compare/0.7.5...0.7.6)

---
updated-dependencies:
- dependency-name: "@xmldom/xmldom"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-25 13:02:03 -04:00
jessopb
ebf35a1df8
remove watchman (and errors!) (#7710) 2022-10-25 12:56:38 -04:00
jm-morani
28e168d5e5
Minor layout fixes depending on window shape (#7709)
Disable theatre mode styles for medium screen (or lower)
Fix the width of the cover in theater mode
Fix conflicting styles when width is 1150px
Remove duplicate from CHANGELOG

Co-authored-by: Jean-Michel Morani <probono+lbry@morani.org>
2022-10-25 10:03:20 -04:00
Byron Eric Perez
7ad66b99e7
Swap comment servers without going to settings page (#7670)
work in progress

added input to select custom and default server when creating comment

the problem of synchronizing the two commentServer of the application was solved

btn moved to the correct component and syncs correctly

Fixed why it didn't show comments

Aligned input

size and location of the refresh btn changed, and added maximum and minimum width for the comment server

margin removed

change using overflow

refresh
2022-10-24 12:36:30 -04:00
jahway603
7eb7c1a5ff
Updated README.md (#7695)
Fixed Arch AUR package name and current maintainer
2022-10-22 15:16:05 -04:00
zeppi
b88e704e6b v0.53.6 2022-10-21 16:54:07 -04:00
zeppi
8d85af8064 changelog 2022-10-21 16:53:03 -04:00
zeppi
f9d7340729 v0.53.6-alpha.1 2022-10-21 12:21:45 -04:00
zeppi
d57300f785 changelog 2022-10-20 14:41:43 -04:00
jessopb
09baf1d9b9
fall back on contentType for extension on file view (#7704) 2022-10-20 14:17:43 -04:00
Franco Montenegro
ce692d38ea
Upgrade to Electron 17.2.0. (#7703) 2022-10-20 14:03:12 -04:00
zeppi
b1ca3b0183 bump electron 17.2 and lbrynet 0.111.0 2022-10-20 13:09:47 -04:00
Franco Montenegro
a4c34d89e2
Sanitize values for CSV. (#7697)
* Sanitize values for CSV.

* Remove unnecessary escape sequence.
2022-10-17 11:07:33 -04:00
Franco Montenegro
d7b9ca3391
7683 upgrade to electron 17 (#7691)
* Upgrade to electron 17.

* Remove unused dependencies.

* Update recommended node version in readme.

* Move all the dependencies back to devDependencies.

* Move dependencies back as they were.
2022-10-07 13:56:33 -04:00
jessopb
55a5c7b051
make thumbnail optional (#7690) 2022-09-19 18:39:45 -04:00
Franco Montenegro
0e2a9a1033
Better handling of uploaded files. (#7688)
* Better handling of uploaded files.

* Read file when uploading it so we can properly read metadata.
2022-09-19 16:42:16 -04:00
Franco Montenegro
3fd38be789
Sort downloads (show newest first) (#7684) 2022-09-05 16:21:01 -04:00
Franco Montenegro
329d434c83
Allow only images in modal image uploader. (#7672)
* Allow only images in modal image uploader.

* Set file path and mime in file selector.

* Refactor WebFile.

* Update get-file-from-path to work with folders; fix file-list component.

* Get rid of File | string for filePath property in components.

* Show instant preview while updating channel thumbnail.

* Fix publish.

* Add jpeg and svg to image filter.
2022-09-02 12:43:35 -04:00
zeppi
6a2939d9fc v0.53.5 2022-08-26 16:31:37 -04:00
zeppi
65781e33f7 sdk 110 release changelog 2022-08-26 16:21:34 -04:00
jessopb
608721c7ac
upgrade lbrynet sdk to 0.110.0 (#7680) 2022-08-26 16:12:08 -04:00
zeppi
2846dd926b changelog 2022-08-26 16:03:32 -04:00
jm-morani
7a8a16cd9c
Fix viewer position and shape in mobile mode (#7677)
Co-authored-by: Jean-Michel Morani <probono+lbry@morani.org>
2022-08-26 15:36:48 -04:00
jessopb
1c17ff5dd9
doFetchModBlockedList: don't block ui thread (#7674)
* doFetchModBlockedList: don't block ui thread

doFetchModBlockedList is blocking the ui thread.

Duplicate data in `doFetchModBlockedList::blockListsPerChannel` to about 1000. The tab is dead when function hits, about 4s after reload.

- Yield occasionally using the `setTimeout` method.
- Doing a chunk size of 1 for now so we don't have to yield the inner loop as well (seems good enough). This is just based on a relatively large blocklist size.

- Can't do `await` in a callback, so must change the `forEach` to a `for`.

* yield thread in storeList

Co-authored-by: infinite-persistence <inf.persistence@gmail.com>
2022-08-12 17:23:04 -04:00
jessopb
b9be8d9f3a
small fixes for blocked (#7669) 2022-08-09 13:13:57 -04:00
Franco Montenegro
6b1069f02a
Properly handle blacklisted claims. (#7665)
* Properly handle blacklisted claims.

* Identify blacklist cause and display the proper message.
2022-08-09 11:19:23 -04:00
jessopb
b92fb03856
Remove swap (#7659)
* remove requiresAuth

* remove centralized btcswap code
2022-08-02 17:17:00 -04:00
Franco Montenegro
1a9743e639
Properly handle decimals in supports liquidate component. (#7648) 2022-07-23 18:33:00 -04:00
Byron Eric Perez
2773cbbe6e
changed the color of the editor-toolbar_hover class (#7642)
* changed the color of the editor-toolbar_hover class

* Fixed hover, colors and spacing of editor-toolbar_hover class

* active editor-toolbar class modified

* var --color-editor-button-hover-bg and --color-editor-button-active-bg created

* --color-editor-button-hover-bg and --color-editor-button-active-bg
color corrected in light
2022-07-21 16:58:12 -04:00
zeppi
e11fb5d225 changelog 2022-07-16 18:24:46 -04:00
Franco Montenegro
38200b9912
Use image preview to display the cover image recently uploaded. (#7647) 2022-07-13 20:09:11 -04:00
zeppi
c69826a887 remove old scripts 2022-07-12 15:33:46 -04:00
zeppi
ce4fadbdf9 remove readme 'web' mention 2022-07-12 15:24:31 -04:00
jessopb
2895e93323
Sync pre cleanup (#7635)
* missing yarn lock

* rm modal youtube welcome

* prune some isAuthenticated

* remove invite components

* remove reward/verify components

* more odysee feature cleanup
2022-07-08 14:51:53 -04:00
jessopb
3859124c05
missing yarn lock (#7644) 2022-07-07 18:43:38 -04:00
dependabot[bot]
da5ec6edc1
Bump electron from 15.4.0 to 15.5.5 (#7614)
Bumps [electron](https://github.com/electron/electron) from 15.4.0 to 15.5.5.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/main/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v15.4.0...v15.5.5)

---
updated-dependencies:
- dependency-name: electron
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-07 17:34:07 -04:00
Byron Eric Perez
9825bccf4a
fix hover style for char count field (#7620)
* fix hover style for char count field

* vertically align character counter and emoji button

* add new comment icon class

* Revert "add new comment icon class"

This reverts commit 8a163e0f02.

* created and corrected the icon class

* button--comment-icons-active removed
2022-07-07 16:55:31 -04:00
Franco Montenegro
f065218ff4
Prevent .deb packages from being opened with archive manager. (#7502)
* Prevent .deb packages from being opened with archive manager.

* Allow to properly cancel download upgrade and prevent multiple downloads.

* Fix missing app-update.yml file for .deb builds.

* Small fix for allowPrerelease prop in autoUpdater.

* Use release/tags endpoint to get the release details.

* Handle error case for auto updater.

* Make install now button display the upgrade modal.

* Use GitHub as provider for manual update url.

* Small fixes in updater.

* Fix small lint errors.

* Properly handle auto download on/off.
2022-07-07 16:48:42 -04:00
Byron Eric Perez
f79c622edf
Added checkbox to enable/disable background (#7630)
* Added checkbox to enable/disable background

* bug fix in enable disable button

* small fix in translation

* rename background setting to be disable backgroud; add default value for background setting.
2022-06-28 16:01:19 -04:00
Byron Eric Perez
c7ab47f54d
use default path in windows when choosing a file (#7625)
* use default path in windows when choosing a file

* fix, changed var to let
2022-06-28 15:49:41 -04:00
Franco Montenegro
8c10617259
Use a retry counter/limit to fetch thumbnails. (#7618) 2022-06-28 11:25:20 -04:00
Franco Montenegro
2e565fd95b
Fix splash error message when the app can't initialize. (#7615) 2022-06-20 12:59:56 -04:00
zeppi
68718f32b2 v0.53.4 2022-06-10 13:58:49 -04:00
zeppi
f70bde0639 v0.53.4-alpha.8 2022-06-10 12:51:35 -04:00
jessopb
2be96a25b1
Disk space ipc fixes (#7610)
* delay get-disk-space until daemon ready

* get fresh diskspace when storage viz renders
2022-06-10 12:42:49 -04:00
zeppi
30cbc3f5c5 v0.53.4-alpha.7 2022-06-10 10:46:59 -04:00
zeppi
8d8c1fd58c bump lbrynet to 107.2 2022-06-10 10:44:36 -04:00
zeppi
d8600e286f v0.53.4-alpha.6 2022-06-09 10:47:41 -04:00
zeppi
7d08800836 revert sdk to 107.1 2022-06-09 10:45:50 -04:00
zeppi
27ede86996 v0.53.4-alpha.5 2022-06-08 17:49:17 -04:00
zeppi
60e5471f5e v0.53.4-alpha.4 2022-06-08 17:21:50 -04:00
zeppi
a1e52eea4a changelog 2022-06-08 17:20:46 -04:00
jessopb
5a99d9777f
bump sdk to 0.109.0 (#7607) 2022-06-08 17:11:15 -04:00
Franco Montenegro
fab69450c0
Hide watched progress if claim is being played. (#7606) 2022-06-08 17:11:05 -04:00
zeppi
5609b43fc7 v0.53.4-alpha.3 2022-06-05 15:07:13 -04:00
zeppi
cc9f2e62de v0.53.4-alpha.2 2022-06-05 12:16:53 -04:00
jessopb
dd6a156d7c
fix diskspace windows bytes (#7601) 2022-06-05 12:10:12 -04:00
jessopb
7b0d38eca7
Testing fixes 0.53.4 (#7600)
* view hosting setting backspace, and storage setting scroll to button

* fix duplicate settings_get call

* avoid unneccessary setDaemonSetting unlimited
2022-06-03 16:09:34 -04:00
jessopb
168ae17eb6
fix dragndrop publish (#7599) 2022-06-02 16:42:27 -04:00
zeppi
0067d5a411 v.53.4-alpha.1 2022-06-02 15:50:25 -04:00
jessopb
99ceaadf8b
add hosting to first run (#7598)
* add hosting to first run, enable auto hosting

* take welcomeVersion out of sync

* app strings fix

* recommended view hosting limit

* small changes

* fixes

* appstrings

* small fix
2022-06-02 15:24:11 -04:00
zeppi
743c75df16 changelog 2022-06-02 15:22:47 -04:00
Franco Montenegro
c5b018afc3 Reconnect to default server if custom server fails. 2022-06-01 17:39:46 -04:00
Franco Montenegro
c7511fc803 Add language category. 2022-06-01 17:06:00 -04:00
zeppi
17bd0eec30 fix status bar colors 2022-05-23 17:36:47 -04:00
zeppi
5c6f7a391b fix price key size 2022-05-23 17:21:27 -04:00
zeppi
d841835c9d fix disappearing checkbox on hover 2022-05-23 16:45:18 -04:00
Franco Montenegro
3c3635977e Implement makeSelectPrevPlayableUrlFromCollectionAndUrl and makeSelectNextPlayableUrlFromCollectionAndUrl 2022-05-21 16:41:52 -04:00
Franco Montenegro
d69eeaa589 Do not allow to add non playable items in playlists yet. 2022-05-21 16:41:52 -04:00
Franco Montenegro
8a9af7d354 Handle non playable items in playlists. 2022-05-21 16:41:52 -04:00
Franco Montenegro
6108860063 Do not show shuffle option for empty collections. 2022-05-06 12:43:29 -04:00
Franco Montenegro
63ce691b90 Disable play/suffle buttons from empty collections. 2022-05-06 12:43:29 -04:00
Franco Montenegro
de825fd4dc Do not throw error when trying to play empty collections. 2022-05-06 12:43:29 -04:00
Franco Montenegro
3671e855cb Add Intl.NumberFormat cache. 2022-05-06 11:24:26 -04:00
Franco Montenegro
efa682ef02 Use language stored in localStorage for formatting numbers. 2022-05-06 11:24:26 -04:00
Franco Montenegro
5319232918 Format numbers internationally. 2022-05-06 11:24:26 -04:00
zeppi
c5b7cc5ac4 fix bid reset 2022-05-02 16:14:21 -04:00
Franco Montenegro
02e4b651af Properly handle thumbnail field in publish/edit upload/collection. 2022-05-02 16:01:42 -04:00
Franco Montenegro
34ea712874 Do not reset description field while uploading thumbnail in playlist edit/publish form; use same upload thumbnail layout as file upload for playlist edit/publish. 2022-04-28 10:49:39 -04:00
zeppi
562e154675 v0.53.3 2022-04-27 18:32:11 -04:00
zeppi
5b4948891e changelog 2022-04-27 18:30:51 -04:00
jessopb
5ed13de5d6 Revert "more lbrytv removal"
This reverts commit 6acdfc9623.
2022-04-27 18:28:33 -04:00
jessopb
9e48d22d70 Revert "strip lbrytv"
This reverts commit befcf9fd55.
2022-04-27 18:27:56 -04:00
Franco Montenegro
9f40680b64 Add max length to fields in channel creation. 2022-04-26 16:30:53 -04:00
zeppi
addcd63794 v0.53.2 2022-04-26 15:59:37 -04:00
zeppi
c11235c70e v0.53.2-alpha.1 2022-04-26 15:13:49 -04:00
zeppi
d8bedba43d changelog 2022-04-26 15:02:37 -04:00
zeppi
befcf9fd55 strip lbrytv 2022-04-26 14:31:42 -04:00
jessopb
feb37a17a6 Revert "Update LBRY.tv to just LBRY."
This reverts commit 43c45c1f62.
2022-04-26 10:23:49 -04:00
jessopb
fcff90e78c Revert "some more lbry.tv to lbry changes"
This reverts commit 3980d0f51e.
2022-04-26 10:23:49 -04:00
zeppi
6acdfc9623 more lbrytv removal 2022-04-25 22:05:43 -04:00
zeppi
15ad30d509 fix 0.53.1 style issues 2022-04-25 21:13:07 -04:00
Kenneth C
3980d0f51e some more lbry.tv to lbry changes
Have changed some more lbry.tv instances into lbry.com so now the desktop app should no longer show the old LBRY.tv messages.
2022-04-25 20:50:36 -04:00
Kenneth C
43c45c1f62 Update LBRY.tv to just LBRY.
Noticed that quite a few files still reference the defunct LBRY.tv, so now they should be simply "LBRY" or a similar relevant string.
2022-04-25 20:50:36 -04:00
Franco Montenegro
673ab85bea Fix thumbnails missing while searching in side bar. 2022-04-25 12:38:19 -04:00
zeppi
3932ecf7c0 restore tags link 2022-04-25 10:39:12 -04:00
zeppi
9386cc678f fix collection link 2022-04-25 09:24:49 -04:00
zeppi
fe2af64b90 fix changelog 2022-04-24 10:35:14 -04:00
zeppi
7c2e4eb3e3 wip 2022-04-24 09:57:28 -04:00
zeppi
0c990ba276 fix ci
yarn lock

fix yarn3 warnings

node 16 on deploy

try deploy again

check in yarn/releases

rm lbry-format from lockfile

remove lbry-format yet again

fix flow
2022-04-24 09:57:28 -04:00
zeppi
f6fd061dd6 yarn lock 2022-04-24 09:57:28 -04:00
Daniele Basso
150f280c33 Update README.md 2022-04-24 09:57:28 -04:00
tiziodcaio
3bd97984c0 Update documentation 2022-04-24 09:57:28 -04:00
tiziodcaio
c31e40089c Enabling corepack 2022-04-24 09:57:28 -04:00
tiziodcaio
465d204e69 Update yarn to Berry
Adding changelog
2022-04-24 09:57:28 -04:00
tiziodcaio
6742bc373c Upgrade to yarn v3 2022-04-24 09:57:28 -04:00
jessopb
75d2464443
remove old lbrytv players (#7552) 2022-04-23 17:33:53 -04:00
zeppi
6a26771339 v0.53.1 2022-04-22 12:21:57 -04:00
zeppi
5a2e4ae49a changelog 2022-04-22 12:21:23 -04:00
zeppi
0d44213f78 v0.53.0 2022-04-22 11:45:37 -04:00
zeppi
0bb13331d5 changelog edit 2022-04-22 11:45:13 -04:00
zeppi
6bffc8a993 v0.53.1 2022-04-22 11:40:50 -04:00
zeppi
811bb0cf30 changelog 2022-04-22 11:38:23 -04:00
zeppi
d64da2a8b2 fix viewedBar bug 2022-04-22 11:34:55 -04:00
zeppi
a99f6d4bf2 v0.53.0 2022-04-22 10:25:46 -04:00
zeppi
0101bc0533 v0.53.0-alpha.6 2022-04-22 10:25:29 -04:00
zeppi
83faa7bba0 button tweaks 2022-04-22 10:21:15 -04:00
zeppi
a18aceed1f v0.53.0 2022-04-22 09:46:38 -04:00
zeppi
2eb0219ad1 v0.53.0-alpha.4 2022-04-22 09:46:27 -04:00
zeppi
c58b3c752e changelog 2022-04-22 09:44:57 -04:00
jessopb
ee98531c00
fix repost ribbon (#7549) 2022-04-21 23:02:26 -04:00
Franco Montenegro
ee754f0085
Add persistent watch time setting. (#7547)
* Add persistent watch time setting.

* floating bugfix --jessopb

* Improve how the persist watch time is being stored; add clear cache button.

* Add makeSelectContentWatchedPercentageForUri selector and give feedback when clearing cache.

* tweaks --jessopb

Co-authored-by: zeppi <jessopb@gmail.com>
2022-04-21 23:00:57 -04:00
zeppi
3854bf6fd4 v0.53.0 2022-04-21 11:38:49 -04:00
zeppi
3ca62704d5 v0.53.0-alpha.3 2022-04-21 11:38:03 -04:00
zeppi
34d9b05de0 changelog typo 2022-04-21 11:33:49 -04:00
zeppi
87835451f3 v0.53.0 2022-04-21 11:17:49 -04:00
zeppi
3b7b9e69c7 changelog 2022-04-21 11:12:59 -04:00
zeppi
febbb4f82e changelog 2022-04-21 11:12:26 -04:00
zeppi
e29e982ffb temp following style fix 2022-04-21 11:05:42 -04:00
zeppi
d84746d395 v0.53.0-alpha.1 2022-04-20 17:18:20 -04:00
jessopb
c133d5b53a
style fixes (#7548) 2022-04-20 17:17:47 -04:00
zeppi
845f33b4f2 v0.53.0-alpha.0 2022-04-18 08:55:19 -04:00
zeppi
9b26a65be4 changelog 2022-04-18 08:54:59 -04:00
zeppi
2193c61628 changelog 2022-04-18 08:53:57 -04:00
zeppi
aef3eccfbd changelog 2022-04-17 13:27:02 -04:00
jessopb
3034f4ce6c
bring in styles (#7542)
* bring in ody styles; modify; cleanup

* workflow

* workflow

* v0.52.6-alpha.teststyles.1

* fix hook

* v0.52.6-alpha.teststyles.2

* style fixes

* fix pagination styling

* v0.52.6-alpha.teststyles.3

* wallet icon was bad

* restore deploy script

* fixes

* fix player close button

* modal inputs

* cleanup

* cleanup

* fix staked indicator

* fix profile menu button skel delay

* fix view-all-playlists hover

* fix overlay buttons on collection page

* fix header buttons
2022-04-17 13:04:56 -04:00
Franco Montenegro
50ae6e2869
Add ability to search through publishes. (#7535)
* Add ability to search through publishes.

* Small fix in allClaimListMine type.

* Small fix for search claims in uploads page.

* Add search term in uri when filtering uploads.

* ui/ux touchup

* no appstrings for you

* resolve conflicts

Co-authored-by: jessopb <36554050+jessopb@users.noreply.github.com>
2022-04-14 23:05:59 -04:00
infinite-persistence
21204321c0
Remove abandoned claim from Uploads Page (#7534)
## Issue
In Uploads Page, Claim doesn't go away immediately when deleted, only after a refresh.

## Approach
- Also update `myClaimsPageResults` when abandoning.
- `abandonedUris` is an array because the uris come in various form, so had to check all.

(Cherry-pick of Odysee PR_1276)
2022-04-13 12:22:50 -04:00
infinite-persistence
daab8a28ed
Fix post-editor preview mode (#7532)
## Cause
It broke because lack of awareness that we can't use our components in preview mode. For some reason, we don't have redux access in SimpleMDE's preview mode.

## Change
- Restore the stub for iframes
- Fix preview for images, and apply a similar styling as in Posts.

Co-authored-by: jessopb <36554050+jessopb@users.noreply.github.com>
2022-04-13 12:22:05 -04:00
infinite-persistence
79f05a831f Uploads: show placeholder when loading 2022-04-13 12:08:04 -04:00
dependabot[bot]
243cd0dffd Bump plist from 3.0.4 to 3.0.5
Bumps [plist](https://github.com/TooTallNate/node-plist) from 3.0.4 to 3.0.5.
- [Release notes](https://github.com/TooTallNate/node-plist/releases)
- [Changelog](https://github.com/TooTallNate/plist.js/blob/master/History.md)
- [Commits](https://github.com/TooTallNate/node-plist/commits)

---
updated-dependencies:
- dependency-name: plist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-13 12:04:30 -04:00
dependabot[bot]
8e536e7020 Bump lodash-es from 4.17.15 to 4.17.21
Bumps [lodash-es](https://github.com/lodash/lodash) from 4.17.15 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.21)

---
updated-dependencies:
- dependency-name: lodash-es
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-13 12:04:11 -04:00
dependabot[bot]
b0ab2daf39 Bump moment from 2.24.0 to 2.29.2
Bumps [moment](https://github.com/moment/moment) from 2.24.0 to 2.29.2.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.24.0...2.29.2)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-13 11:46:18 -04:00
Franco Montenegro
3fd3a548ec Add viewed bar in thumbnails. 2022-04-13 11:40:06 -04:00
zeppi
d1c82c9af0 fix send tip default 2022-04-05 16:47:21 -04:00
zeppi
5ef1baff3b v0.52.6 2022-04-04 17:35:27 -04:00
zeppi
da564452f7 fix duplicate plist key 2022-04-04 16:58:46 -04:00
zeppi
c3d836bca7 update mac plist 2022-04-04 16:41:27 -04:00
zeppi
745a3ca889 v0.52.6-alpha.8 2022-04-04 16:39:55 -04:00
zeppi
f5564086c4 v0.52.6 2022-04-04 06:27:05 -04:00
zeppi
0e6b2eae8b changelog 2022-04-04 06:16:08 -04:00
zeppi
23d61df410 v0.52.6-alpha.7 2022-04-03 11:02:05 -04:00
zeppi
c28c5219c1 do not increment welcome version 2022-04-03 11:01:40 -04:00
zeppi
1db943518d v0.52.6-alpha.6 2022-04-03 10:20:11 -04:00
zeppi
9f4ba9041b changelog 2022-04-03 10:19:54 -04:00
zeppi
b47bd7e8b6 cleaner 2022-04-03 10:17:54 -04:00
zeppi
ec600bb8c8 graphic redesign 2022-04-03 10:17:54 -04:00
zeppi
f055198b29 wip 2022-04-02 09:27:07 -04:00
zeppi
e1a66d389f prevent crash when deleting last reply (still needs work) 2022-04-02 09:27:07 -04:00
zeppi
1891107a80 v0.52.6-alpha.5 2022-04-01 10:20:40 -04:00
zeppi
cff40b338c changelog 2022-03-31 14:03:15 -04:00
zeppi
945b4b3992 changelog 2022-03-31 14:02:04 -04:00
zeppi
085929a92e v0.52.6-alpha.4 2022-03-31 12:48:18 -04:00
zeppi
7f83c68d82 bump lbrynet 2022-03-31 12:46:56 -04:00
zeppi
e0c2f03c16 edit input tweak height 2022-03-29 18:06:55 -04:00
zeppi
12b15a2549 edit input field background unset 2022-03-29 18:06:55 -04:00
zeppi
4d75922c8b edittext button style fix 2022-03-29 18:06:55 -04:00
zeppi
0de96358bd restyle collection rename 2022-03-29 18:06:55 -04:00
Franco Montenegro
5a24d6c570 Allow renaming collection in view playlist page. 2022-03-29 18:06:55 -04:00
Franco Montenegro
1369fbb064 Allow users to rename private/unpublished lists. 2022-03-29 18:06:55 -04:00
zeppi
2aeb419969 new token 2022-03-27 23:15:43 -04:00
zeppi
474115b398 v0.52.6-alpha.3 2022-03-27 21:57:24 -04:00
zeppi
d09e294797 v0.52.7-alpha.2 2022-03-27 10:48:41 -04:00
zeppi
1bfb843606 v0.52.7-alpha.1 2022-03-26 19:57:37 -04:00
zeppi
d302fbae09 v0.52.6-alpha.7 2022-03-26 17:45:10 -04:00
zeppi
52e15bbc96 try gh upload-artifact 2.2.4 2022-03-26 17:44:46 -04:00
zeppi
e0dc359241 v0.52.6-alpha.6 2022-03-26 17:20:40 -04:00
zeppi
8275ff1228 try upload-artifacts@v3 2022-03-26 17:20:08 -04:00
zeppi
31d896fb8d v0.52.6-alpha.5 2022-03-26 16:52:49 -04:00
zeppi
0c467ddc8d changelog 2022-03-26 16:52:27 -04:00
zeppi
37dbfcb40a v0.52.6-alpha.4 2022-03-26 15:12:46 -04:00
zeppi
f5b4aba9da v0.52.6-alpha.3 2022-03-26 13:59:02 -04:00
Tobias Speicher
21af8f4f28 refactor: replace deprecated String.prototype.substr()
.substr() is deprecated so we replace it with .slice() which works similarily but isn't deprecated

Signed-off-by: Tobias Speicher <rootcommander@gmail.com>
2022-03-23 12:12:44 -04:00
zeppi
cde52f4d35 fix mac builds 2022-03-22 16:14:15 -04:00
zeppi
7da8be67fe v0.52.6-alpha.2 2022-03-12 22:10:47 -05:00
zeppi
538aa3b42f workflow try continue-on-error 2022-03-12 22:06:57 -05:00
zeppi
fd02bb00b3 increase yarn timeout 2022-03-12 22:06:57 -05:00
zeppi
d5c79495ab v0.52.6-alpha.1 2022-03-12 15:55:47 -05:00
zeppi
702a3f8eb8 changelog 2022-03-11 12:57:29 -05:00
infinite-persistence
35276d5879
Fix comment count not incremented when it was previously 0 (#7510)
It was causing the nudge to add a comment to still appear after one has just entered a comment.

Ticket: Odysee 928
2022-03-11 01:07:41 -05:00
zeppi
a7e70e4d21 bump electron to 15.4.0 2022-03-08 22:09:27 -05:00
zeppi
6560ab6c7b bump electron to 15.3.7 2022-03-08 22:09:27 -05:00
Franco Montenegro
66bdd3fc87 Small refactor to get the last used collection. 2022-03-08 12:30:39 -05:00
Franco Montenegro
c843991378 Update last used collection when a collection is pending or published. 2022-03-08 12:30:39 -05:00
Franco Montenegro
aa008d8a61 Small fix for last used collection when it's a published collection. 2022-03-08 12:30:39 -05:00
Franco Montenegro
ca1d0e71b7 Add last used collection to right click menu. 2022-03-08 12:30:39 -05:00
zeppi
2ddf0a2cbd add medium duration video filter 2022-03-07 18:46:28 -05:00
zeppi
64e48c1eef update flow 2022-03-07 17:07:42 -05:00
zeppi
10381ef06a Revert "Bump shelljs from 0.8.3 to 0.8.5"
This reverts commit 33e5318a29.
2022-03-07 16:43:12 -05:00
infinite-persistence
cef9ade10e Render whole app on language change
## Issues
1. We were manually adding `selectLanguage(state)` as a prop to components used in Settings Page to trigger a render. Flaws:
    - Unclear that the unused prop is just to trigger a render.
    - Manually adding on a case-by-case basis will break over time (missed component).

2. The translation file fetching is delayed (at least in Odysee) and also takes time, so the GUI will end up having mixed strings on F5, depending on when the fetch completed.

## Approach
Make the app wrapper have a key that's tied to the language and translation data, so the entire app renders when language changes. Seems like a common design in most apps.

## Ticket
odysee 921
2022-03-07 09:40:09 -05:00
dependabot[bot]
33e5318a29 Bump shelljs from 0.8.3 to 0.8.5
Bumps [shelljs](https://github.com/shelljs/shelljs) from 0.8.3 to 0.8.5.
- [Release notes](https://github.com/shelljs/shelljs/releases)
- [Changelog](https://github.com/shelljs/shelljs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/shelljs/shelljs/compare/v0.8.3...v0.8.5)

---
updated-dependencies:
- dependency-name: shelljs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 09:37:47 -05:00
dependabot[bot]
8ecdaab6d4 Bump url-parse from 1.5.3 to 1.5.10
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.10.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.10)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 09:37:35 -05:00
dependabot[bot]
9de2465e21 Bump follow-redirects from 1.13.0 to 1.14.8
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.13.0 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.13.0...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 09:36:36 -05:00
zeppi
bef46257bc depbump 2022-03-07 09:30:30 -05:00
Franco Montenegro
d410664d9a Fix small typo in actions/app.js 2022-03-04 10:58:19 -05:00
Franco Montenegro
1f8c9fd24d Display release notes and version for Linux installations using .deb packages. 2022-03-04 10:58:19 -05:00
Franco Montenegro
64a2e908ae Prevent multiple downloads when auto updater isn't supported. Hide upgrade nag when on progress modal is displayed. 2022-03-04 10:58:19 -05:00
Franco Montenegro
40e20dfc1b Small eslint warning fix. 2022-03-01 11:09:50 -05:00
Franco Montenegro
53425d8fe2 Add disk space functions for windows and mac. 2022-03-01 11:09:50 -05:00
zeppi
ca748fd16a fix random mac build failures 2022-02-27 09:07:20 -05:00
zeppi
ea7ed53bfe v0.52.5 2022-02-25 17:57:19 -05:00
zeppi
29c605de86 changelog 2022-02-25 17:56:59 -05:00
zeppi
b56746475b cleanup 2022-02-25 17:52:35 -05:00
zeppi
94f64f8d25 comment on mac disk space 2022-02-25 17:52:35 -05:00
zeppi
04a6c735ac finish view data hosting 2022-02-25 17:52:35 -05:00
zeppi
e9502410de refactor data hosting 2022-02-25 17:52:35 -05:00
zeppi
bf87ac08db reverts electron updates testing 2022-02-23 12:36:55 -05:00
zeppi
72310710af v0.52.5-alpha.2 2022-02-22 14:35:26 -05:00
zeppi
cce7cd43d8 v0.52.5-alpha.1 2022-02-22 13:14:59 -05:00
Franco Montenegro
080eee7d92 Display release changes from release notes instead of using GitHub's API. 2022-02-22 13:14:17 -05:00
Franco Montenegro
3058dbb4a6 Fix typos. 2022-02-22 13:14:17 -05:00
Franco Montenegro
b7d685b4ec Remove trailing spaces from comments. 2022-02-22 13:14:17 -05:00
Franco Montenegro
e1ecf87df7 Better way of handling autoUpdate and listen for update available event to display update nag. 2022-02-22 13:14:17 -05:00
Franco Montenegro
48c5f58a8e Multiple fixes in auto updates.
- Add "disable auto updates" setting (prevents downloading updates in the background but will still notify if there are newer versions)
- Prevent downloading multiple times the same update
- Hide nag when auto update modal is displayed
2022-02-22 13:14:17 -05:00
Franco Montenegro
aa40a44ce3 Only allow to window.open http and https protocols. 2022-02-17 15:09:43 -05:00
Franco Montenegro
8fb67d5980 Fix markdown guide button. 2022-02-17 15:09:43 -05:00
zeppi
67608dfc9c v0.52.4 2022-02-15 22:06:04 -05:00
zeppi
9fc600397c changelog 2022-02-15 22:05:39 -05:00
zeppi
3d85cff0ef Revert "v0.52.4"
This reverts commit 97fbc5e598.
2022-02-15 22:04:40 -05:00
zeppi
97fbc5e598 v0.52.4 2022-02-15 21:56:05 -05:00
zeppi
9375ada72a remove duplicate header search on mobile 2022-02-15 21:48:43 -05:00
zeppi
49c5180820 fix active channel for commenting etc 2022-02-15 20:58:13 -05:00
433 changed files with 33483 additions and 22229 deletions

View file

@ -16,7 +16,7 @@ COMMENT_SERVER_NAME=Odysee
SEARCH_SERVER_API=https://lighthouse.odysee.com/search SEARCH_SERVER_API=https://lighthouse.odysee.com/search
SOCKETY_SERVER_API=wss://sockety.odysee.com/ws SOCKETY_SERVER_API=wss://sockety.odysee.com/ws
THUMBNAIL_CDN_URL=https://image-processor.vanwanet.com/optimize/ THUMBNAIL_CDN_URL=https://image-processor.vanwanet.com/optimize/
WELCOME_VERSION=1.0 WELCOME_VERSION=1.2
# STRIPE # STRIPE
# STRIPE_PUBLIC_KEY='pk_test_NoL1JWL7i1ipfhVId5KfDZgo' # STRIPE_PUBLIC_KEY='pk_test_NoL1JWL7i1ipfhVId5KfDZgo'
@ -45,16 +45,9 @@ CLOUD_CONNECT_SITE_NAME=Odysee
TWITTER_ACCOUNT=LBRYcom TWITTER_ACCOUNT=LBRYcom
BRANDED_SITE=odysee BRANDED_SITE=odysee
## IMAGE ASSETS ## OLD IMAGE ASSETS
YRBL_HAPPY_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a #YRBL_HAPPY_IMG_URL=https://player.odysee.com/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a
YRBL_SAD_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd #YRBL_SAD_IMG_URL=https://player.odysee.com/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
#LOGIN_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/login/b671946e911c66c5fa7233afb35de2badd9eceb8/0e1d81
#LOGO=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
#LOGO_TEXT_LIGHT=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
#LOGO_TEXT_DARK=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
#AVATAR_DEFAULT=
#MISSING_THUMB_DEFAULT=
#FAVICON=
# LOCALE # LOCALE
DEFAULT_LANGUAGE=en DEFAULT_LANGUAGE=en

View file

@ -1,92 +0,0 @@
# Copy this file to .env to make modifications
# Base config
WEBPACK_WEB_PORT=9090
WEBPACK_ELECTRON_PORT=9091
WEB_SERVER_PORT=1337
WELCOME_VERSION=1.0
# Custom Site info
DOMAIN=lbry.tv
URL=https://lbry.tv
# UI
SITE_TITLE=lbry.tv
SITE_NAME=local.lbry.tv
SITE_DESCRIPTION=Meet LBRY, an open, free, and community-controlled content wonderland.
LOGO_TITLE=local.lbry.tv
##### ODYSEE SETTINGS #######
MATOMO_URL=https://analytics.lbry.com/
MATOMO_ID=4
# Base config
WEBPACK_WEB_PORT=9090
WEBPACK_ELECTRON_PORT=9091
WEB_SERVER_PORT=1337
## APIS
LBRY_API_URL=https://api.odysee.com
#LBRY_WEB_API=https://api.na-backend.odysee.com
#LBRY_WEB_STREAMING_API=https://cdn.lbryplayer.xyz
# deprecated:
#LBRY_WEB_BUFFER_API=https://collector-service.api.lbry.tv/api/v1/events/video
#COMMENT_SERVER_API=https://comments.lbry.com/api/v2
WELCOME_VERSION=1.0
# STRIPE
STRIPE_PUBLIC_KEY='pk_live_e8M4dRNnCCbmpZzduEUZBgJO'
## UI
LOADING_BAR_COLOR=#e50054
# IMAGE ASSETS
YRBL_HAPPY_IMG_URL=https://spee.ch/spaceman-happy:a.png
YRBL_SAD_IMG_URL=https://spee.ch/spaceman-sad:d.png
LOGIN_IMG_URL=https://spee.ch/login:b.png
LOGO=https://spee.ch/odysee-logo-png:3.png
LOGO_TEXT_LIGHT=https://spee.ch/odysee-white-png:f.png
LOGO_TEXT_DARK=https://spee.ch/odysee-png:2.png
AVATAR_DEFAULT=https://spee.ch/spaceman-png:2.png
FAVICON=https://spee.ch/favicon-png:c.png
# LOCALE
DEFAULT_LANGUAGE=en
## LINKED CONTENT WHITELIST
KNOWN_APP_DOMAINS=open.lbry.com,lbry.tv,lbry.lat,odysee.com
## CUSTOM CONTENT
# If the following is true, copy custom/homepage.example.js to custom/homepage.js and modify
CUSTOM_HOMEPAGE=true
# Add channels to auto-follow on firstrun (space delimited)
AUTO_FOLLOW_CHANNELS=lbry://@Odysee#80d2590ad04e36fb1d077a9b9e3a8bba76defdf8 lbry://@OdyseeHelp#b58dfaeab6c70754d792cdd9b56ff59b90aea334
## FEATURES AND LIMITS
SIMPLE_SITE=true
BRANDED_SITE=odysee
# SIMPLE_SITE REPLACEMENTS
ENABLE_MATURE=false
ENABLE_UI_NOTIFICATIONS=true
ENABLE_WILD_WEST=true
SHOW_TAGS_INTRO=false
# CENTRALIZED FEATURES
ENABLE_COMMENT_REACTIONS=true
ENABLE_FILE_REACTIONS=true
ENABLE_CREATOR_REACTIONS=true
ENABLE_NO_SOURCE_CLAIMS=true
ENABLE_PREROLL_ADS=false
SHOW_ADS=true
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS=4
CHANNEL_STAKED_LEVEL_LIVESTREAM=3
WEB_PUBLISH_SIZE_LIMIT_GB=4
#SEARCH TYPES - comma-delimited
LIGHTHOUSE_DEFAULT_TYPES=audio,video

View file

@ -4,6 +4,7 @@
.*/node_modules/react-plastic/.* .*/node_modules/react-plastic/.*
.*/node_modules/raf-schd/.* .*/node_modules/raf-schd/.*
.*/node_modules/react-beautiful-dnd/.* .*/node_modules/react-beautiful-dnd/.*
.*/node_modules/resolve/test/.*
[include] [include]

View file

@ -11,8 +11,9 @@ jobs:
name: lint name: lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: Borales/actions-yarn@v2.3.0 - run: corepack enable
- run: yarn
- run: yarn lint - run: yarn lint
build: build:
@ -20,23 +21,39 @@ jobs:
name: 'build' name: 'build'
strategy: strategy:
matrix: matrix:
node-version: [14.x] node-version: [16.x]
os: os:
- ubuntu-latest - ubuntu-latest
- macos-latest - macos-latest
- windows-latest - windows-latest
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
continue-on-error: true
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions/setup-node@v2-beta - uses: actions/setup-node@v3
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- run: corepack enable
- uses: maxim-lobanov/setup-xcode@v1 - uses: maxim-lobanov/setup-xcode@v1
if: startsWith(runner.os, 'mac') if: startsWith(runner.os, 'mac')
with: with:
xcode-version: '12.4.0' xcode-version: '13.1.0'
# This is gonna be hacky.
# Github made us upgrade xcode, which would force an upgrade of electron-builder to fix mac.
# But there were bugs with copyfiles / extraFiles that kept seeing duplicates erroring on ln.
# A flag USE_HARD_LINKS=false in electron-builder.json was suggested in comments, but that broke windows builds.
# So for now we'll install python2 on mac and make sure it can find it.
# Remove this after successfully upgrading electron-builder.
# HACK part 1
- uses: Homebrew/actions/setup-homebrew@master
if: startsWith(runner.os, 'mac')
# HACK part 2
- name: Install Python2
if: startsWith(runner.os, 'mac')
run: |
/bin/bash -c "$(curl -fsSL https://github.com/alfredapp/dependency-scripts/raw/main/scripts/install-python2.sh)"
echo "PYTHON_PATH=/usr/local/bin/python" >> $GITHUB_ENV
- name: Download blockchain headers - name: Download blockchain headers
run: | run: |
@ -46,17 +63,17 @@ jobs:
- name: Build - name: Build
run: | run: |
yarn global add cross-env yarn dlx cross-env
yarn yarn --network-timeout 600000
yarn build yarn build
env: env:
GH_TOKEN: ${{ secrets.GH_TOKEN }} GH_TOKEN: ${{ secrets.GH_TOKEN_NEW }}
NOTARIZATION_USERNAME: ${{ secrets.NOTARIZATION_USERNAME }} NOTARIZATION_USERNAME: ${{ secrets.NOTARIZATION_USERNAME }}
NOTARIZATION_PASSWORD: ${{ secrets.NOTARIZATION_PASSWORD }} NOTARIZATION_PASSWORD: ${{ secrets.NOTARIZATION_PASSWORD }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }} WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
WIN_CSC_LINK: https://raw.githubusercontent.com/lbryio/lbry-desktop/master/build/cert-2021-2022.pfx WIN_CSC_LINK: https://raw.githubusercontent.com/lbryio/lbry-desktop/master/build/cert2023.pfx
CSC_LINK: https://s3.amazonaws.com/files.lbry.io/cert/osx-csc-2021-2022.p12 CSC_LINK: https://s3.amazonaws.com/files.lbry.io/cert/osx-csc-2021-2022.p12
# UI # UI
@ -69,8 +86,6 @@ jobs:
SITE_TITLE: lbry.tv SITE_TITLE: lbry.tv
SITE_NAME: lbry.tv SITE_NAME: lbry.tv
SHOW_ADS: false SHOW_ADS: false
YRBL_HAPPY_IMG_URL: https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a
YRBL_SAD_IMG_URL: https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
ENABLE_COMMENT_REACTIONS: true ENABLE_COMMENT_REACTIONS: true
ENABLE_NO_SOURCE_CLAIMS: false ENABLE_NO_SOURCE_CLAIMS: false
@ -78,21 +93,21 @@ jobs:
KNOWN_APP_DOMAINS: lbry.tv,lbry.lat,odysee.com KNOWN_APP_DOMAINS: lbry.tv,lbry.lat,odysee.com
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS: 0 CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS: 0
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2.2.4
if: | if: |
startsWith(runner.os, 'linux') startsWith(runner.os, 'linux')
with: with:
name: Linux name: Linux
path: ./dist/electron/*.* path: ./dist/electron/*.*
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2.2.4
if: | if: |
startsWith(runner.os, 'mac') startsWith(runner.os, 'mac')
with: with:
name: macOS name: macOS
path: ./dist/electron/*.* path: ./dist/electron/*.*
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2.2.4
if: | if: |
startsWith(runner.os, 'windows') startsWith(runner.os, 'windows')
with: with:

6
.gitignore vendored
View file

@ -36,3 +36,9 @@ package-lock.json
!.env.ody !.env.ody
.env.desktop .env.desktop
.env.lbrytv .env.lbrytv
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
!.yarn/releases

File diff suppressed because one or more lines are too long

785
.yarn/releases/yarn-3.2.0.cjs vendored Executable file

File diff suppressed because one or more lines are too long

0
.yarn/versions/17d7e90d.yml vendored Normal file
View file

0
.yarn/versions/33178102.yml vendored Normal file
View file

0
.yarn/versions/35f2125e.yml vendored Normal file
View file

0
.yarn/versions/4f9fb046.yml vendored Normal file
View file

0
.yarn/versions/5bc94294.yml vendored Normal file
View file

0
.yarn/versions/5f1212ad.yml vendored Normal file
View file

0
.yarn/versions/5f4cac99.yml vendored Normal file
View file

0
.yarn/versions/6b35c994.yml vendored Normal file
View file

0
.yarn/versions/6be5ab70.yml vendored Normal file
View file

0
.yarn/versions/86ac1afd.yml vendored Normal file
View file

0
.yarn/versions/8e384637.yml vendored Normal file
View file

0
.yarn/versions/909c3734.yml vendored Normal file
View file

0
.yarn/versions/951a8d12.yml vendored Normal file
View file

0
.yarn/versions/97e7141a.yml vendored Normal file
View file

0
.yarn/versions/ac69bc5f.yml vendored Normal file
View file

0
.yarn/versions/c6e2b914.yml vendored Normal file
View file

0
.yarn/versions/d1a18cef.yml vendored Normal file
View file

0
.yarn/versions/ec3a9ddf.yml vendored Normal file
View file

0
.yarn/versions/fc1fde84.yml vendored Normal file
View file

0
.yarn/versions/fc597c00.yml vendored Normal file
View file

7
.yarnrc.yml Normal file
View file

@ -0,0 +1,7 @@
nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
spec: "@yarnpkg/plugin-version"
yarnPath: .yarn/releases/yarn-3.2.0.cjs

View file

@ -1,9 +1,162 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased for Desktop] ## [0.53.9] - [2023-2-8]
### Changed
- Updated lbrynet to [0.113.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.113.0)
## [0.53.8] - [2022-11-17]
### Fixed
- Selecting a large file in publish no longer crashes ([#7736](https://github.com/lbryio/lbry-desktop/pull/7736))
- Unfollowing unpublished channels ([#7737](https://github.com/lbryio/lbry-desktop/pull/7737))
### Changed
- Updated xcode to 13.1 and hacked a fix for release ([#7736](https://github.com/lbryio/lbry-desktop/pull/7736))
## [0.53.7] - [2022-11-10]
### Added
- 'Collections' to txo filter _community pr!_ ([#7711](https://github.com/lbryio/lbry-desktop/pull/7711))
- Swap comment servers _community pr!_ ([#7670](https://github.com/lbryio/lbry-desktop/pull/7670))
### Fixed
- Thumbnails no longer disable publish ([#7714](https://github.com/lbryio/lbry-desktop/pull/7714))
- Publishing posts were empty ([#7715](https://github.com/lbryio/lbry-desktop/pull/7715))
- Minor layout fixes _community pr!_ ([#7709](https://github.com/lbryio/lbry-desktop/pull/7709))
- Comment section buttons layout ([#7716](https://github.com/lbryio/lbry-desktop/pull/7716))
### Changed
- Removed watchman and its errors ([#7710](https://github.com/lbryio/lbry-desktop/pull/7710))
- Updated lbrynet to [0.112.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.112.0)
## [0.53.6] - [2022-10-21]
### Fixed
- Make thumbnails optional ([#7690](https://github.com/lbryio/lbry-desktop/pull/7690))
- Show downloads newest first ([#7684](https://github.com/lbryio/lbry-desktop/pull/7684))
- Only allow images in image uploader ([#7672](https://github.com/lbryio/lbry-desktop/pull/7672))
- Fixed bug with csv exports ([#7697](https://github.com/lbryio/lbry-desktop/pull/7697))
- Fixed various upload bugs including transcoding ([#7688](https://github.com/lbryio/lbry-desktop/pull/7688))
- Fallback for files with no extension ([#7704](https://github.com/lbryio/lbry-desktop/pull/7704))
### Changed
- Upgraded Electron to v17.2.0 ([#7703](https://github.com/lbryio/lbry-desktop/pull/7703))
- Upgraded Electron to v17.0.0 ([#7691](https://github.com/lbryio/lbry-desktop/pull/7691))
- Updated lbrynet to [0.111.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.111.0)
## [0.53.5] - [2022-08-26]
### Added
- Checkbox to disable background wallpaper ([#7630](https://github.com/lbryio/lbry-desktop/pull/7630))
- Handle content blocking from hub ([#7665](https://github.com/lbryio/lbry-desktop/pull/7665))
### Fixed
- Better handle decimals liquidating supports ([#7648](https://github.com/lbryio/lbry-desktop/pull/7648))
- Better handle cover uploads ([#7647](https://github.com/lbryio/lbry-desktop/pull/7647))
- Use default path when first choosing file on windows ([#7625](https://github.com/lbryio/lbry-desktop/pull/7625))
- Emoji button hover ([#7620](https://github.com/lbryio/lbry-desktop/pull/7620))
- Prevent infinite retries on thumbs ([#7618](https://github.com/lbryio/lbry-desktop/pull/7618))
- Double splash/error on app startup ([#7615](https://github.com/lbryio/lbry-desktop/pull/7615))
- App updates are now more coherent, also debs work. ([#7502](https://github.com/lbryio/lbry-desktop/pull/7502))
- Better handle many channels moderation calls at startup ([#7674](https://github.com/lbryio/lbry-desktop/pull/7674))
- Fix mobile floating viewer position ([#7677](https://github.com/lbryio/lbry-desktop/pull/7677))
### Changed
- Upgraded Electron to v15.5.5 ([#7614](https://github.com/lbryio/lbry-desktop/pull/7614))
- Upgraded to lbrynet v0.110.0 ([#7680](https://github.com/lbryio/lbry-desktop/pull/7680))
## [0.53.4] - [2022-06-10]
### Added
- Add top in language category for non-english on homepage ([#7585](https://github.com/lbryio/lbry-desktop/pull/7585))
- Auto hosting in settings and hosting first run page ([#7598](https://github.com/lbryio/lbry-desktop/pull/7598))
### Changed
- Updated lbry-sdk to [0.107.2](https://github.com/lbryio/lbry-sdk/releases/tag/v0.107.2)
### Fixed
- Better handle empty collections ([#7571](https://github.com/lbryio/lbry-desktop/pull/7571))
- Better handle thumbnails in uploads/collections ([#7574](https://github.com/lbryio/lbry-desktop/pull/7574))
- Work towards supporting collections of any claim type ([#7578](https://github.com/lbryio/lbry-desktop/pull/7578))
- Improve handling of downed custom servers on startup ([#7593](https://github.com/lbryio/lbry-desktop/pull/7593))
- Hide watch progress in related if being played ([#7606](https://github.com/lbryio/lbry-desktop/pull/7606))
- IPC disk space calls wait for daemon ready; refresh on vis. component load ([#7610](https://github.com/lbryio/lbry-desktop/pull/7610))
## [0.53.3] - [2022-04-27]
### Fixed
- Reverted lbry.tv changes that broke production login ([#7569](https://github.com/lbryio/lbry-desktop/pull/7569))
- Reverted lbry.tv changes that broke login ([#7570](https://github.com/lbryio/lbry-desktop/pull/7570))
## [0.53.2] - [2022-04-26]
### Changed
- Upgraded Yarn to Berry branch ([#7530](https://github.com/lbryio/lbry-desktop/pull/7530))
- Removed some lbrytv references ([#7560](https://github.com/lbryio/lbry-desktop/pull/7560))
- Removed some lbrytv player references ([#7552](https://github.com/lbryio/lbry-desktop/pull/7552))
### Fixed
- Repost style issues ([#7559](https://github.com/lbryio/lbry-desktop/pull/7559))
- Disappearing sidebar thumbs ([#7556](https://github.com/lbryio/lbry-desktop/pull/7556))
- Restore tags sidebar link ([#7555](https://github.com/lbryio/lbry-desktop/pull/7555))
- Playlist view link no longer crashes ([#7552](https://github.com/lbryio/lbry-desktop/pull/7552))
## [0.53.1] - [2022-04-22]
### Added
- Uploads: show placeholder when loading page _community pr!_ ([#7531](https://github.com/lbryio/lbry-desktop/pull/7531))
- Sidebar channel search _styles pr_ ([#7542](https://github.com/lbryio/lbry-desktop/pull/7542))
- Viewed content progress indicator on thumbnail part 1 ([#7541](https://github.com/lbryio/lbry-desktop/pull/7541))
- Viewed content progress indicator on thumbnail part 2 ([#7547](https://github.com/lbryio/lbry-desktop/pull/7547))
- Ability to search through publishes ([#7535](https://github.com/lbryio/lbry-desktop/pull/7535))
### Changed
- Large styles revamp following odysee _styles pr_ ([#7542](https://github.com/lbryio/lbry-desktop/pull/7542))
### Fixed
- Fix bad rerender on homepage _styles pr_ ([#7542](https://github.com/lbryio/lbry-desktop/pull/7542))
- Fix post-editor preview mode _community pr!_ ([#7532](https://github.com/lbryio/lbry-desktop/pull/7532))
- Fix send-tip default tab ([#7533](https://github.com/lbryio/lbry-desktop/pull/7533))
## [0.52.6] - [2022-04-04]
### Added
- Discover page medium duration filter ([#7506](https://github.com/lbryio/lbry-desktop/pull/7506))
- Keep last used collection for Add To ([#7491](https://github.com/lbryio/lbry-desktop/pull/7491))
- Disk space functionality on mac / windows ([#7500](https://github.com/lbryio/lbry-desktop/pull/7500))
- Enable renaming private collections ([#7519](https://github.com/lbryio/lbry-desktop/pull/7519))
### Changed
- Some upgrade modal improvements ([#7488](https://github.com/lbryio/lbry-desktop/pull/7488))
- Updated lbry-sdk to [0.107.1](https://github.com/lbryio/lbry-sdk/releases/tag/v0.107.1)
- New YRBL!; facelift for first run ([#7527](https://github.com/lbryio/lbry-desktop/pull/7527))
### Fixed
- Failed comment count increment ([#7510](https://github.com/lbryio/lbry-desktop/pull/7510))
- App crash playing media on older windows versions by updating electron ([#7509](https://github.com/lbryio/lbry-desktop/pull/7509))
- Local build failures on mac ([#7497](https://github.com/lbryio/lbry-desktop/pull/7497))
- Language change now rerenders whole app ([#7504](https://github.com/lbryio/lbry-desktop/pull/7504))
- Mac notarization ([#7518](https://github.com/lbryio/lbry-desktop/pull/7518))
- Prevent crash when deleting last comment reply ([#7526](https://github.com/lbryio/lbry-desktop/pull/7526))
## [0.52.5] - [2022-02-25]
### Fixed
- New data hosting ux ([#7493](https://github.com/lbryio/lbry-desktop/pull/7493))
- Fix markdown guide button ([#7485](https://github.com/lbryio/lbry-desktop/pull/7485))
## [0.52.4] - [2022-02-15]
### Fixed
- Fixed active channel ([#7481](https://github.com/lbryio/lbry-desktop/pull/7481))
- Remove extra search button in header ([#7482](https://github.com/lbryio/lbry-desktop/pull/7482))
## [0.52.3] - [2022-02-15] ## [0.52.3] - [2022-02-15]

View file

@ -65,26 +65,26 @@ _Note: If coming from a deb install, the directory structure is different and yo
| | Flatpak | Arch | Nixpkgs | ARM/ARM64 | | | Flatpak | Arch | Nixpkgs | ARM/ARM64 |
| -------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------- | | -------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------- |
| Latest Release | [FlatHub Page](https://flathub.org/apps/details/io.lbry.lbry-app) | [AUR Package](https://aur.archlinux.org/packages/lbry-app-bin/) | [Nixpkgs](https://search.nixos.org/packages?channel=unstable&show=lbry&query=lbry) | [Build Guide](https://lbry.tv/@LBRYarm:5) | | Latest Release | [FlatHub Page](https://flathub.org/apps/details/io.lbry.lbry-app) | [AUR Package](https://aur.archlinux.org/packages/lbry-desktop-bin/) | [Nixpkgs](https://search.nixos.org/packages?channel=unstable&show=lbry&query=lbry) | [Build Guide](https://lbry.tv/@LBRYarm:5) |
| Maintainers | [@kcSeb](https://keybase.io/kcseb) | [@kcSeb](https://keybase.io/kcseb) | [@Enderger](https://github.com/enderger) | [@Madiator2011](https://github.com/kodxana) | | Maintainers | N/A | [@RubenKelevra](https://github.com/RubenKelevra) | [@Enderger](https://github.com/enderger) | [@Madiator2011](https://github.com/kodxana) |
## Usage ## Usage
Double click the installed application to interact with the LBRY network. Start the installed application to interact with the LBRY network.
## Running from Source ## Running from Source
You can run the web version (lbry.tv), the electron app, or both at the same time.
#### Prerequisites #### Prerequisites
- [Git](https://git-scm.com/downloads) - [Git](https://git-scm.com/downloads)
- [Node.js](https://nodejs.org/en/download/) (v14 required) - [Node.js](https://nodejs.org/en/download/) (v16 required)
- [Corepack](https://nodejs.org/dist/latest-v17.x/docs/api/corepack.html) `npm i -g corepack` (Included in nodejs 14 LTS, 16 LTS and 17)
- [Yarn](https://yarnpkg.com/en/docs/install) - [Yarn](https://yarnpkg.com/en/docs/install)
1. Clone (or [fork](https://help.github.com/articles/fork-a-repo/)) this repository: `git clone https://github.com/lbryio/lbry-desktop` 1. Clone (or [fork](https://help.github.com/articles/fork-a-repo/)) this repository: `git clone https://github.com/lbryio/lbry-desktop`
2. Change directory into the cloned repository: `cd lbry-desktop` 2. Change directory into the cloned repository: `cd lbry-desktop`
3. Install the dependencies: `yarn` 3. If corepack is not enabled, run `sudo corepack enable` (the sudo is necessary for system-wide installation, if you use container, nvm etc... you might not be forced to use it)
4. Install the dependencies: `yarn`
#### Run the electron app #### Run the electron app

View file

@ -7,6 +7,8 @@ module.exports = api => {
'import-glob', 'import-glob',
'@babel/plugin-transform-runtime', '@babel/plugin-transform-runtime',
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }], ['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }],
['@babel/plugin-proposal-private-methods', { 'loose': false }],
['@babel/plugin-proposal-private-property-in-object', { 'loose': false }],
'@babel/plugin-transform-flow-strip-types', '@babel/plugin-transform-flow-strip-types',
'@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-class-properties',
'react-hot-loader/babel', 'react-hot-loader/babel',

BIN
build/cert2023.pfx Normal file

Binary file not shown.

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>

View file

@ -11,7 +11,7 @@ const config = {
LBRY_WEB_API: process.env.LBRY_WEB_API, //api.na-backend.odysee.com', LBRY_WEB_API: process.env.LBRY_WEB_API, //api.na-backend.odysee.com',
LBRY_WEB_PUBLISH_API: process.env.LBRY_WEB_PUBLISH_API, LBRY_WEB_PUBLISH_API: process.env.LBRY_WEB_PUBLISH_API,
LBRY_API_URL: process.env.LBRY_API_URL, //api.lbry.com', LBRY_API_URL: process.env.LBRY_API_URL, //api.lbry.com',
LBRY_WEB_STREAMING_API: process.env.LBRY_WEB_STREAMING_API, //cdn.lbryplayer.xyz', LBRY_WEB_STREAMING_API: process.env.LBRY_WEB_STREAMING_API, //player.odysee.com
LBRY_WEB_BUFFER_API: process.env.LBRY_WEB_BUFFER_API, LBRY_WEB_BUFFER_API: process.env.LBRY_WEB_BUFFER_API,
SEARCH_SERVER_API: process.env.SEARCH_SERVER_API, SEARCH_SERVER_API: process.env.SEARCH_SERVER_API,
CLOUD_CONNECT_SITE_NAME: process.env.CLOUD_CONNECT_SITE_NAME, CLOUD_CONNECT_SITE_NAME: process.env.CLOUD_CONNECT_SITE_NAME,

View file

@ -29,6 +29,10 @@
"from": "./static/font", "from": "./static/font",
"to": "static/font", "to": "static/font",
"filter": ["**/*"] "filter": ["**/*"]
},
{
"from": "./static/app-update.yml",
"to": "app-update.yml"
} }
], ],
"publish": [ "publish": [
@ -37,7 +41,11 @@
} }
], ],
"mac": { "mac": {
"category": "public.app-category.entertainment" "category": "public.app-category.entertainment",
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist",
"hardenedRuntime" : true,
"gatekeeperAssess": false
}, },
"dmg": { "dmg": {
"iconSize": 128, "iconSize": 128,

View file

@ -10,6 +10,7 @@ import { TO_TRAY_WHEN_CLOSED } from 'constants/settings';
import setupBarMenu from './menu/setupBarMenu'; import setupBarMenu from './menu/setupBarMenu';
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
const remote = require('@electron/remote/main'); const remote = require('@electron/remote/main');
const shell = require('electron').shell;
function GetAppLangCode() { function GetAppLangCode() {
// https://www.electronjs.org/docs/api/locales // https://www.electronjs.org/docs/api/locales
// 1. Gets the user locale. // 1. Gets the user locale.
@ -94,7 +95,7 @@ export default appState => {
// is it a lbry://? pointing to an app page // is it a lbry://? pointing to an app page
if (deepLinkingURI.includes(lbryProtoQ)) { if (deepLinkingURI.includes(lbryProtoQ)) {
let path = deepLinkingURI.substr(lbryProtoQ.length); let path = deepLinkingURI.slice(lbryProtoQ.length);
let page = path.indexOf('?') >= 0 ? path.substring(0, path.indexOf('?')) : path; let page = path.indexOf('?') >= 0 ? path.substring(0, path.indexOf('?')) : path;
if (Object.values(PAGES).includes(page)) { if (Object.values(PAGES).includes(page)) {
deepLinkingURI = deepLinkingURI.replace(lbryProtoQ, '#/$/'); deepLinkingURI = deepLinkingURI.replace(lbryProtoQ, '#/$/');
@ -190,6 +191,11 @@ export default appState => {
}); });
window.webContents.setWindowOpenHandler((details) => { window.webContents.setWindowOpenHandler((details) => {
// Only open http and https links to prevent
// security issues.
if (['https:', 'http:'].includes(new URL(details.url).protocol)) {
shell.openExternal(details.url);
}
return { action: 'deny' }; return { action: 'deny' };
}); });

View file

@ -17,8 +17,16 @@ import startSandbox from './startSandbox';
import installDevtools from './installDevtools'; import installDevtools from './installDevtools';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { diskSpaceLinux, diskSpaceWindows, diskSpaceMac } from '../ui/util/diskspace';
const { download } = require('electron-dl'); const { download } = require('electron-dl');
const mime = require('mime');
const remote = require('@electron/remote/main'); const remote = require('@electron/remote/main');
const os = require('os');
const sudo = require('sudo-prompt');
const probe = require('ffmpeg-probe');
const MAX_IPC_SEND_BUFFER_SIZE = 500000000; // large files crash when serialized for ipc message
remote.initialize(); remote.initialize();
const filePath = path.join(process.resourcesPath, 'static', 'upgradeDisabled'); const filePath = path.join(process.resourcesPath, 'static', 'upgradeDisabled');
let upgradeDisabled; let upgradeDisabled;
@ -29,11 +37,18 @@ try {
upgradeDisabled = false; upgradeDisabled = false;
} }
autoUpdater.autoDownload = !upgradeDisabled; autoUpdater.autoDownload = !upgradeDisabled;
autoUpdater.allowPrerelease = false;
// This is set to true if an auto update has been downloaded through the Electron const UPDATE_STATE_INIT = 0;
// auto-update system and is ready to install. If the user declined an update earlier, const UPDATE_STATE_CHECKING = 1;
// it will still install on shutdown. const UPDATE_STATE_UPDATES_FOUND = 2;
let autoUpdateDownloaded = false; const UPDATE_STATE_NO_UPDATES_FOUND = 3;
const UPDATE_STATE_DOWNLOADING = 4;
const UPDATE_STATE_DOWNLOADED = 5;
let updateState = UPDATE_STATE_INIT;
let updateDownloadItem;
const isAutoUpdateSupported = ['win32', 'darwin'].includes(process.platform) || !!process.env.APPIMAGE;
// This is used to keep track of whether we are showing the special dialog // This is used to keep track of whether we are showing the special dialog
// that we show on Windows after you decline an upgrade and close the app later. // that we show on Windows after you decline an upgrade and close the app later.
@ -226,7 +241,8 @@ app.on('activate', () => {
app.on('will-quit', event => { app.on('will-quit', event => {
if ( if (
process.platform === 'win32' && process.platform === 'win32' &&
autoUpdateDownloaded && updateState === UPDATE_STATE_DOWNLOADED &&
isAutoUpdateSupported &&
!appState.autoUpdateAccepted && !appState.autoUpdateAccepted &&
!showingAutoUpdateCloseAlert !showingAutoUpdateCloseAlert
) { ) {
@ -286,45 +302,118 @@ app.on('before-quit', () => {
appState.isQuitting = true; appState.isQuitting = true;
}); });
ipcMain.on('download-upgrade', async (event, params) => { // Get the content of a file as a raw buffer of bytes.
const { url, options } = params; // Useful to convert a file path to a File instance.
const dir = fs.mkdtempSync(app.getPath('temp') + path.sep); // Example:
options.onProgress = function(p) { // const result = await ipcMain.invoke('get-file-from-path', 'path/to/file');
rendererWindow.webContents.send('download-progress-update', p); // const file = new File([result.buffer], result.name);
// NOTE: if path points to a folder, an empty
// file will be given.
ipcMain.handle('get-file-from-path', (event, path, readContents = true) => {
return new Promise((resolve, reject) => {
fs.stat(path, (error, stats) => {
if (error) {
reject(error);
return;
}
// Separate folders considering "\" and "/"
// as separators (cross platform)
const folders = path.split(/[\\/]/);
const name = folders[folders.length - 1];
if (stats.isDirectory()) {
resolve({
name,
mime: undefined,
path,
buffer: new ArrayBuffer(0),
});
return;
}
if (!readContents) {
resolve({
name,
mime: mime.getType(name) || undefined,
path,
buffer: new ArrayBuffer(0),
});
return;
}
// Encoding null ensures data results in a Buffer.
fs.readFile(path, { encoding: null }, (err, data) => {
if (err) {
reject(err);
return;
}
resolve({
name,
mime: mime.getType(name) || undefined,
path,
buffer: data,
});
});
});
});
});
ipcMain.handle('get-file-details-from-path', async (event, path) => {
const isFfMp4 = (ffprobeResults) => {
return ffprobeResults &&
ffprobeResults.format &&
ffprobeResults.format.format_name &&
ffprobeResults.format.format_name.includes('mp4');
}; };
options.directory = dir; const folders = path.split(/[\\/]/);
options.onCompleted = function(c) { const name = folders[folders.length - 1];
rendererWindow.webContents.send('download-update-complete', c); let duration = 0, size = 0, mimeType;
}; try {
const win = BrowserWindow.getFocusedWindow(); await fs.promises.stat(path);
await download(win, url, options).catch(e => console.log('e', e)); let ffprobeResults;
try {
ffprobeResults = await probe(path);
duration = ffprobeResults.format.duration;
size = ffprobeResults.format.size;
} catch (e) {
}
let fileReadResult;
if (size < MAX_IPC_SEND_BUFFER_SIZE) {
try {
fileReadResult = await fs.promises.readFile(path);
} catch (e) {
}
}
// TODO: use mmmagic to inspect file and get mime type
mimeType = isFfMp4(ffprobeResults) ? 'video/mp4' : mime.getType(name);
const fileData = {name, mime: mimeType || undefined, path, duration: duration, size, buffer: fileReadResult };
return fileData;
} catch (e) {
// no stat
return { error: 'no file' };
}
}); });
ipcMain.on('upgrade', (event, installerPath) => { ipcMain.on('get-disk-space', async (event) => {
app.on('quit', () => { try {
console.log('Launching upgrade installer at', installerPath); const { data_dir } = await Lbry.settings_get();
// This gets triggered called after *all* other quit-related events, so let diskSpace;
// we'll only get here if we're fully prepared and quitting for real. switch (os.platform()) {
shell.openPath(installerPath); case 'linux':
}); diskSpace = await diskSpaceLinux(data_dir);
// what to do if no shutdown in a long time? break;
console.log('Update downloaded to', installerPath); case 'darwin':
console.log('The app will close and you will be prompted to install the latest version of LBRY.'); diskSpace = await diskSpaceMac(data_dir);
console.log('After the install is complete, please reopen the app.'); break;
app.quit(); case 'win32':
}); diskSpace = await diskSpaceWindows(data_dir);
break;
ipcMain.on('check-for-updates', () => { default:
autoUpdater.checkForUpdates(); throw new Error('unknown platform');
}); }
rendererWindow.webContents.send('send-disk-space', { diskSpace });
autoUpdater.on('update-downloaded', () => { } catch (e) {
autoUpdateDownloaded = true; rendererWindow.webContents.send('send-disk-space', { error: e.message || e });
}); console.log('Failed to get disk space', e);
}
ipcMain.on('autoUpdateAccepted', () => {
appState.autoUpdateAccepted = true;
autoUpdater.quitAndInstall();
}); });
ipcMain.on('version-info-requested', () => { ipcMain.on('version-info-requested', () => {
@ -419,3 +508,162 @@ process.on('uncaughtException', error => {
if (daemon) daemon.quit(); if (daemon) daemon.quit();
app.exit(1); app.exit(1);
}); });
// Auto updater
autoUpdater.on('download-progress', () => {
updateState = UPDATE_STATE_DOWNLOADING;
});
autoUpdater.on('update-downloaded', () => {
updateState = UPDATE_STATE_DOWNLOADED;
// If this download was trigger by
// autoUpdateAccepted it means, the user
// wants to install the new update but
// needed to downloaded the files first.
if (appState.autoUpdateAccepted) {
autoUpdater.quitAndInstall();
}
});
autoUpdater.on('update-available', () => {
if (updateState === UPDATE_STATE_DOWNLOADING) {
return;
}
updateState = UPDATE_STATE_UPDATES_FOUND;
});
autoUpdater.on('update-not-available', () => {
updateState = UPDATE_STATE_NO_UPDATES_FOUND;
});
autoUpdater.on('error', () => {
if (updateState === UPDATE_STATE_DOWNLOADING) {
updateState = UPDATE_STATE_UPDATES_FOUND;
return;
}
updateState = UPDATE_STATE_INIT;
});
// Manual (.deb) update
ipcMain.on('cancel-download-upgrade', () => {
if (updateDownloadItem) {
// Cancel the download and execute the onCancel
// callback set in the options.
updateDownloadItem.cancel();
}
});
ipcMain.on('download-upgrade', (event, params) => {
if (updateState !== UPDATE_STATE_UPDATES_FOUND) {
return;
}
if (isAutoUpdateSupported) {
updateState = UPDATE_STATE_DOWNLOADING;
autoUpdater.downloadUpdate();
return;
}
const { url, options } = params;
const dir = fs.mkdtempSync(app.getPath('temp') + path.sep);
updateState = UPDATE_STATE_DOWNLOADING;
// Grab the download item's handler to allow
// cancelling the operation if required.
options.onStarted = function(downloadItem) {
updateDownloadItem = downloadItem;
};
options.onCancel = function() {
updateState = UPDATE_STATE_UPDATES_FOUND;
updateDownloadItem = undefined;
};
options.onProgress = function(p) {
rendererWindow.webContents.send('download-progress-update', p);
};
options.onCompleted = function(c) {
updateState = UPDATE_STATE_DOWNLOADED;
updateDownloadItem = undefined;
rendererWindow.webContents.send('download-update-complete', c);
};
options.directory = dir;
const win = BrowserWindow.getFocusedWindow();
download(win, url, options).catch(e => {
updateState = UPDATE_STATE_UPDATES_FOUND;
console.log('e', e);
});
});
// Update behavior
ipcMain.on('autoUpdateAccepted', () => {
appState.autoUpdateAccepted = true;
// quitAndInstall can only be called if the
// update has been downloaded. Since the user
// can disable auto updates, we have to make
// sure it has been downloaded first.
if (updateState === UPDATE_STATE_DOWNLOADED) {
autoUpdater.quitAndInstall();
return;
}
if (updateState !== UPDATE_STATE_UPDATES_FOUND) {
return;
}
// If the update hasn't been downloaded,
// start downloading it. After it's done, the
// event 'update-downloaded' will be triggered,
// where we will be able to resume the
// update installation.
updateState = UPDATE_STATE_DOWNLOADING;
autoUpdater.downloadUpdate();
});
ipcMain.on('check-for-updates', (event, autoDownload) => {
if (![UPDATE_STATE_INIT, UPDATE_STATE_NO_UPDATES_FOUND].includes(updateState)) {
return;
}
updateState = UPDATE_STATE_CHECKING;
// If autoDownload is true, checkForUpdates will begin the
// download automatically.
if (autoDownload) {
updateState = UPDATE_STATE_DOWNLOADING;
}
autoUpdater.autoDownload = autoDownload;
autoUpdater.checkForUpdates();
});
ipcMain.on('upgrade', (event, installerPath) => {
// what to do if no shutdown in a long time?
console.log('Update downloaded to', installerPath);
console.log('The app will close and you will be prompted to install the latest version of LBRY.');
console.log('After the install is complete, please reopen the app.');
// Prevent .deb package from opening with archive manager (Ubuntu >= 20)
if (process.platform === 'linux' && !process.env.APPIMAGE) {
sudo.exec(`dpkg -i ${installerPath}`, { name: app.name }, (err, stdout, stderr) => {
if (err || stderr) {
rendererWindow.webContents.send('upgrade-installing-error');
return;
}
// Re-launch the application when the installation finishes.
app.relaunch();
app.quit();
});
return;
}
app.on('quit', () => {
console.log('Launching upgrade installer at', installerPath);
// This gets triggered called after *all* other quit-related events, so
// we'll only get here if we're fully prepared and quitting for real.
shell.openPath(installerPath);
});
app.quit();
});

View file

@ -1,5 +1,4 @@
import express from 'express'; // import express from 'express';
import unpackByOutpoint from './unpackByOutpoint';
// Polyfills and `lbry-redux` // Polyfills and `lbry-redux`
global.fetch = require('node-fetch'); global.fetch = require('node-fetch');
@ -8,31 +7,31 @@ if (typeof global.fetch === 'object') {
global.fetch = global.fetch.default; global.fetch = global.fetch.default;
} }
const Lbry = require('lbry'); // const Lbry = require('lbry');
delete global.window; delete global.window;
export default async function startSandbox() { export default async function startSandbox() {
const port = 5278; // const port = 5278;
const sandbox = express(); // const sandbox = express();
sandbox.get('/set/:outpoint', async (req, res) => { // sandbox.get('/set/:outpoint', async (req, res) => {
const { outpoint } = req.params; // const { outpoint } = req.params;
//
const resolvedPath = await unpackByOutpoint(Lbry, outpoint); // const resolvedPath = await unpackByOutpoint(Lbry, outpoint);
//
sandbox.use(`/sandbox/${outpoint}/`, express.static(resolvedPath)); // sandbox.use(`/sandbox/${outpoint}/`, express.static(resolvedPath));
//
res.send(`/sandbox/${outpoint}/`); // res.send(`/sandbox/${outpoint}/`);
}); // });
//
sandbox // sandbox
.listen(port, 'localhost', () => console.log(`Sandbox listening on port ${port}.`)) // .listen(port, 'localhost', () => console.log(`Sandbox listening on port ${port}.`))
.on('error', err => { // .on('error', err => {
if (err.code === 'EADDRINUSE') { // if (err.code === 'EADDRINUSE') {
console.log( // console.log(
`Server already listening at localhost:${port}. This is probably another LBRY app running. If not, games in the app will not work.` // `Server already listening at localhost:${port}. This is probably another LBRY app running. If not, games in the app will not work.`
); // );
} // }
}); // });
} }

View file

@ -1,23 +0,0 @@
import fs from 'fs';
import path from 'path';
import { unpackDirectory } from 'lbry-format';
async function unpackByOutpoint(lbry, outpoint) {
const { items: claimFiles } = await lbry.file_list({ outpoint, full_status: true, page: 1, page_size: 1 });
if (claimFiles && claimFiles.length) {
const claimFileInfo = claimFiles[0];
const packFilePath = path.resolve(claimFileInfo.download_path);
const unpackPath = path.normalize(path.join(claimFileInfo.download_directory, claimFileInfo.claim_name));
if (!fs.existsSync(unpackPath)) {
await unpackDirectory(unpackPath, {
fileName: packFilePath,
});
}
return unpackPath;
}
}
export default unpackByOutpoint;

View file

@ -5,7 +5,7 @@
// involve moving it from 'extras' to 'ui' (big change). // involve moving it from 'extras' to 'ui' (big change).
import { createCachedSelector } from 're-reselect'; import { createCachedSelector } from 're-reselect';
import { selectClaimForUri } from 'redux/selectors/claims'; import { selectClaimForUri, makeSelectIsBlacklisted } from 'redux/selectors/claims';
import { selectMutedChannels } from 'redux/selectors/blocked'; import { selectMutedChannels } from 'redux/selectors/blocked';
import { selectModerationBlockList } from 'redux/selectors/comments'; import { selectModerationBlockList } from 'redux/selectors/comments';
import { selectBlacklistedOutpointMap, selectFilteredOutpointMap } from 'lbryinc'; import { selectBlacklistedOutpointMap, selectFilteredOutpointMap } from 'lbryinc';
@ -18,7 +18,8 @@ export const selectBanStateForUri = createCachedSelector(
selectFilteredOutpointMap, selectFilteredOutpointMap,
selectMutedChannels, selectMutedChannels,
selectModerationBlockList, selectModerationBlockList,
(claim, blackListedOutpointMap, filteredOutpointMap, mutedChannelUris, personalBlocklist) => { (state, uri) => makeSelectIsBlacklisted(uri)(state),
(claim, blackListedOutpointMap, filteredOutpointMap, mutedChannelUris, personalBlocklist, isBlacklisted) => {
const banState = {}; const banState = {};
if (!claim) { if (!claim) {
@ -27,6 +28,10 @@ export const selectBanStateForUri = createCachedSelector(
const channelClaim = getChannelFromClaim(claim); const channelClaim = getChannelFromClaim(claim);
if (isBlacklisted) {
banState['blacklisted'] = true;
}
// This will be replaced once blocking is done at the wallet server level. // This will be replaced once blocking is done at the wallet server level.
if (blackListedOutpointMap) { if (blackListedOutpointMap) {
if ( if (

37
flow-typed/Claim.js vendored
View file

@ -145,12 +145,49 @@ declare type PurchaseReceipt = {
type: 'purchase', type: 'purchase',
}; };
declare type ClaimErrorCensor = {
address: string,
amount: string,
canonical_url: string,
claim_id: string,
claim_op: string,
confirmations: number,
has_signing_key: boolean,
height: number,
meta: {
activation_height: number,
claims_in_channel: number,
creation_height: number,
creation_timestamp: number,
effective_amount: string,
expiration_height: number,
is_controlling: boolean,
reposted: number,
support_amount: string,
take_over_height: number,
},
name: string,
normalized_name: string,
nout: number,
permanent_url: string,
short_url: string,
timestamp: number,
txid: string,
type: string,
value: {
public_key: string,
public_key_id: string,
},
value_type: string,
}
declare type ClaimActionResolveInfo = { declare type ClaimActionResolveInfo = {
[string]: { [string]: {
stream: ?StreamClaim, stream: ?StreamClaim,
channel: ?ChannelClaim, channel: ?ChannelClaim,
claimsInChannel: ?number, claimsInChannel: ?number,
collection: ?CollectionClaim, collection: ?CollectionClaim,
errorCensor: ?ClaimErrorCensor,
}, },
} }

View file

@ -6,3 +6,8 @@ declare type CommentServerDetails = {
declare type WalletServerDetails = { declare type WalletServerDetails = {
}; };
declare type DiskSpace = {
total: number,
free: number,
};

10
flow-typed/file-data.js vendored Normal file
View file

@ -0,0 +1,10 @@
// @flow
declare type FileData = {
file?: Blob,
path: string,
duration?: number,
size?: number,
mimeType: string,
error?: string,
}

9
flow-typed/file-with-path.js vendored Normal file
View file

@ -0,0 +1,9 @@
// @flow
declare type FileWithPath = {
file: File,
// The full path will only be available in
// the application. For browser, the name
// of the file will be used.
path: string,
}

View file

@ -22,6 +22,7 @@ declare type RowDataItem = {
channelIds?: Array<string>, channelIds?: Array<string>,
limitClaimsPerChannel?: number, limitClaimsPerChannel?: number,
pageSize?: number, pageSize?: number,
languages?: Array<string>,
}, },
route?: string, route?: string,
hideForUnauth?: boolean, hideForUnauth?: boolean,

View file

@ -1,6 +0,0 @@
// @flow
declare type WebFile = File & {
path?: string,
title?: string,
}

View file

@ -1,6 +1,6 @@
{ {
"name": "lbry", "name": "lbry",
"version": "0.52.3", "version": "0.53.9",
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
"keywords": [ "keywords": [
"lbry" "lbry"
@ -23,52 +23,47 @@
"analyze": "source-map-explorer --only-mapped dist/electron/webpack/ui*.js --html dist/sourceMap.html", "analyze": "source-map-explorer --only-mapped dist/electron/webpack/ui*.js --html dist/sourceMap.html",
"compile:electron": "node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js --config webpack.electron.config.js", "compile:electron": "node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js --config webpack.electron.config.js",
"compile": "cross-env NODE_ENV=production yarn compile:electron", "compile": "cross-env NODE_ENV=production yarn compile:electron",
"copyenv": "copyfiles ./.env* web/",
"dev": "yarn dev:electron", "dev": "yarn dev:electron",
"dev:electron": "cross-env NODE_ENV=development node ./electron/devServer.js", "dev:electron": "cross-env NODE_ENV=development node ./electron/devServer.js",
"dev:internal-apis": "LBRY_API_URL='http://localhost:8080' yarn dev:electron",
"dev:iatv": "LBRY_API_URL='http://localhost:15400' SDK_API_URL='http://localhost:15100' yarn dev:web",
"pack": "electron-builder --dir", "pack": "electron-builder --dir",
"dist": "electron-builder", "dist": "electron-builder",
"build": "cross-env NODE_ENV=production yarn compile:electron && electron-builder build", "build": "cross-env NODE_ENV=production yarn compile:electron && electron-builder build",
"build:dir": "yarn build -- --dir -c.compression=store -c.mac.identity=null", "build:dir": "yarn build -- --dir -c.compression=store -c.mac.identity=null",
"crossenv": "./node_modules/cross-env/dist/bin/cross-env", "crossenv": "cross-env",
"flow": "flow", "flow": "flow",
"lint": "eslint 'ui/**/*.{js,jsx}' && eslint 'electron/**/*.js' && flow", "lint": "eslint 'ui/**/*.{js,jsx}' && eslint 'electron/**/*.js' && flow",
"lint-fix": "eslint --fix --quiet 'ui/**/*.{js,jsx}' && eslint --fix --quiet 'electron/**/*.js'", "lint-fix": "eslint --fix --quiet 'ui/**/*.{js,jsx}' && eslint --fix --quiet 'electron/**/*.js'",
"format": "prettier 'src/**/*.{js,jsx,scss,json}' --write", "format": "prettier 'src/**/*.{js,jsx,scss,json}' --write",
"flow-defs": "flow-typed install", "flow-defs": "flow-typed install",
"precommit": "lint-staged", "precommit": "lint-staged",
"preinstall": "yarn cache clean lbry-redux && yarn cache clean lbryinc",
"postinstall": "electron-builder install-app-deps && node ./build/downloadDaemon.js", "postinstall": "electron-builder install-app-deps && node ./build/downloadDaemon.js",
"postinstall:warning": "echo '\n\nWARNING\n\nNot all node modules were installed because NODE_ENV is set to \"production\".\nThis should only be set after installing dependencies with \"yarn\". The app will not work.\n\n'" "postinstall:warning": "echo '\n\nWARNING\n\nNot all node modules were installed because NODE_ENV is set to \"production\".\nThis should only be set after installing dependencies with \"yarn\". The app will not work.\n\n'"
}, },
"dependencies": { "dependencies": {
"@electron/remote": "^2.0.1", "@electron/remote": "^2.0.1",
"@emotion/react": "^11.6.0", "@emotion/react": "^11.10.4",
"@emotion/styled": "^11.6.0", "@emotion/styled": "^11.10.4",
"@mui/material": "^5.2.1", "@mui/material": "^5.2.1",
"@ungap/from-entries": "^0.2.1", "@ungap/from-entries": "^0.2.1",
"auto-launch": "^5.0.5", "auto-launch": "^5.0.5",
"electron-dl": "^3.2.0", "electron-dl": "^3.2.0",
"electron-log": "^2.2.12", "electron-log": "^4.4.8",
"electron-notarize": "^1.0.0", "electron-notarize": "^1.0.0",
"electron-updater": "^4.2.4", "electron-updater": "^4.2.4",
"express": "^4.17.1", "express": "^4.17.1",
"ffmpeg-probe": "^1.0.6",
"humanize-duration": "^3.27.0", "humanize-duration": "^3.27.0",
"if-env": "^1.0.4",
"match-sorter": "^6.3.0", "match-sorter": "^6.3.0",
"mime": "^3.0.0",
"node-html-parser": "^5.1.0", "node-html-parser": "^5.1.0",
"parse-duration": "^1.0.0", "parse-duration": "^1.0.0",
"proxy-polyfill": "0.1.6", "proxy-polyfill": "0.1.6",
"re-reselect": "^4.0.0", "re-reselect": "^4.0.0",
"react-beautiful-dnd": "^13.1.0", "react-beautiful-dnd": "^13.1.0",
"react-datetime-picker": "^3.4.3", "react-datetime-picker": "^3.4.3",
"remove-markdown": "^0.3.0",
"rss": "^1.2.2",
"source-map-explorer": "^2.5.2", "source-map-explorer": "^2.5.2",
"tempy": "^0.6.0", "sudo-prompt": "^9.2.1",
"videojs-logo": "^2.1.4" "tempy": "^0.6.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.0.0", "@babel/core": "^7.0.0",
@ -79,7 +74,7 @@
"@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-transform-flow-strip-types": "^7.2.3", "@babel/plugin-transform-flow-strip-types": "^7.2.3",
"@babel/plugin-transform-runtime": "^7.4.3", "@babel/plugin-transform-runtime": "^7.4.3",
"@babel/polyfill": "^7.2.5", "@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.12.11", "@babel/preset-env": "^7.12.11",
"@babel/preset-flow": "^7.12.1", "@babel/preset-flow": "^7.12.1",
"@babel/preset-react": "^7.0.0", "@babel/preset-react": "^7.0.0",
@ -87,9 +82,8 @@
"@datapunt/matomo-tracker-js": "^0.1.4", "@datapunt/matomo-tracker-js": "^0.1.4",
"@hot-loader/react-dom": "^16.13", "@hot-loader/react-dom": "^16.13",
"@meetfranz/electron-cookies": "^3.0.2", "@meetfranz/electron-cookies": "^3.0.2",
"@reach/auto-id": "^0.13.0",
"@reach/combobox": "^0.12.1", "@reach/combobox": "^0.12.1",
"@reach/menu-button": "0.7.4", "@reach/menu-button": "0.8.6",
"@reach/rect": "^0.16.0", "@reach/rect": "^0.16.0",
"@reach/tabs": "^0.1.5", "@reach/tabs": "^0.1.5",
"@reach/tooltip": "^0.12.1", "@reach/tooltip": "^0.12.1",
@ -98,21 +92,17 @@
"@sentry/webpack-plugin": "^1.10.0", "@sentry/webpack-plugin": "^1.10.0",
"@types/three": "^0.103.2", "@types/three": "^0.103.2",
"adm-zip": "^0.4.13", "adm-zip": "^0.4.13",
"async-exit-hook": "^2.0.1",
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.1",
"babel-loader": "^8.0.5", "babel-loader": "^8.0.5",
"babel-plugin-add-module-exports": "^1.0.4", "babel-plugin-add-module-exports": "^1.0.4",
"babel-plugin-import-glob": "^2.0.0", "babel-plugin-import-glob": "^2.0.0",
"babel-plugin-transform-imports": "^1.5.1", "babel-plugin-transform-imports": "^1.5.1",
"babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-plugin-transform-object-rest-spread": "^6.26.0",
"bluebird": "^3.5.1",
"chalk": "^4.1.0", "chalk": "^4.1.0",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"codemirror": "^5.39.2", "codemirror": "^5.39.2",
"concurrently": "^4.1.2",
"connected-react-router": "^6.8.0", "connected-react-router": "^6.8.0",
"copy-webpack-plugin": "^6.4.1", "copy-webpack-plugin": "^6.4.1",
"copyfiles": "^2.4.1",
"country-data": "^0.0.31", "country-data": "^0.0.31",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"crypto-js": "^4.0.0", "crypto-js": "^4.0.0",
@ -123,11 +113,10 @@
"decompress": "^4.2.1", "decompress": "^4.2.1",
"del": "^3.0.0", "del": "^3.0.0",
"devtron": "^1.4.0", "devtron": "^1.4.0",
"dom-scroll-into-view": "^1.2.1",
"dotenv-defaults": "^2.0.1", "dotenv-defaults": "^2.0.1",
"dotenv-webpack": "^1.8.0", "dotenv-webpack": "^1.8.0",
"electron": "15.3.2", "electron": "17.2.0",
"electron-builder": "^22.9.1", "electron-builder": "^22.10.5",
"electron-devtools-installer": "^3.1.1", "electron-devtools-installer": "^3.1.1",
"electron-is-dev": "^0.3.0", "electron-is-dev": "^0.3.0",
"electron-webpack": "^2.8.2", "electron-webpack": "^2.8.2",
@ -149,23 +138,19 @@
"eslint-plugin-standard": "^4.0.1", "eslint-plugin-standard": "^4.0.1",
"file-loader": "^4.2.0", "file-loader": "^4.2.0",
"flow-bin": "^0.97.0", "flow-bin": "^0.97.0",
"flow-typed": "^2.3.0", "flow-typed": "^3.7.0",
"formik": "^0.10.4", "formik": "^0.10.4",
"hast-util-sanitize": "^3.0.2", "hast-util-sanitize": "^3.0.2",
"history": "^4.9.0", "history": "^4.9.0",
"husky": "^3.1.0", "husky": "^3.1.0",
"imagesloaded": "^4.1.4", "imagesloaded": "^4.1.4",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git",
"lint-staged": "^7.0.2", "lint-staged": "^7.0.2",
"localforage": "^1.7.1", "localforage": "^1.7.1",
"lodash-es": "^4.17.14", "lodash-es": "^4.17.21",
"mammoth": "^1.4.16", "mammoth": "^1.4.16",
"moment": "^2.22.0", "moment": "^2.29.2",
"node-abi": "^2.5.1", "node-fetch": "^2.6.7",
"node-fetch": "^2.6.1",
"node-html-parser": "^5.1.0",
"node-libs-browser": "^2.1.0",
"node-loader": "^0.6.0", "node-loader": "^0.6.0",
"node-wget": "^0.4.3", "node-wget": "^0.4.3",
"nodemon": "^1.19.1", "nodemon": "^1.19.1",
@ -180,7 +165,6 @@
"rc-progress": "^2.0.6", "rc-progress": "^2.0.6",
"react": "^16.8.2", "react": "^16.8.2",
"react-awesome-lightbox": "^1.7.3", "react-awesome-lightbox": "^1.7.3",
"react-confetti": "^4.0.1",
"react-dom": "^16.8.2", "react-dom": "^16.8.2",
"react-draggable": "^3.3.0", "react-draggable": "^3.3.0",
"react-google-recaptcha": "^2.0.1", "react-google-recaptcha": "^2.0.1",
@ -191,7 +175,6 @@
"react-router": "^5.1.0", "react-router": "^5.1.0",
"react-router-dom": "^5.1.0", "react-router-dom": "^5.1.0",
"react-simplemde-editor": "^4.1.3", "react-simplemde-editor": "^4.1.3",
"react-spring": "^8.0.20",
"reakit": "^1.0.0-beta.13", "reakit": "^1.0.0-beta.13",
"redux": "^3.6.0", "redux": "^3.6.0",
"redux-persist": "^5.10.0", "redux-persist": "^5.10.0",
@ -208,20 +191,16 @@
"sass": "^1.29.0", "sass": "^1.29.0",
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"semver": "^5.3.0", "semver": "^5.3.0",
"stream-to-blob-url": "^2.1.1",
"strip-markdown": "^3.0.3", "strip-markdown": "^3.0.3",
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"terser-webpack-plugin": "^4.2.3", "terser-webpack-plugin": "^4.2.3",
"three-full": "^28.0.1", "three-full": "^28.0.2",
"tiny-relative-date": "^1.3.0",
"tree-kill": "^1.1.0",
"unist-util-visit": "^2.0.3", "unist-util-visit": "^2.0.3",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"video.js": "^7.14.3", "video.js": "^7.14.3",
"videojs-contrib-quality-levels": "^2.0.9", "videojs-contrib-quality-levels": "^2.0.9",
"videojs-event-tracking": "^1.0.1", "videojs-event-tracking": "^1.0.1",
"villain-react": "^1.0.9", "villain-react": "^1.0.9",
"wavesurfer.js": "^2.2.1",
"webpack": "^4.44.2", "webpack": "^4.44.2",
"webpack-bundle-analyzer": "^3.1.0", "webpack-bundle-analyzer": "^3.1.0",
"webpack-cli": "^3.3.10", "webpack-cli": "^3.3.10",
@ -231,17 +210,17 @@
"webpack-hot-middleware": "^2.24.3", "webpack-hot-middleware": "^2.24.3",
"webpack-merge": "^4.2.1", "webpack-merge": "^4.2.1",
"webpack-node-externals": "^1.7.2", "webpack-node-externals": "^1.7.2",
"y18n": "^4.0.1",
"yarnhook": "^0.2.0" "yarnhook": "^0.2.0"
}, },
"engines": { "engines": {
"node": ">=7", "node": ">=16.13",
"yarn": "^1.3" "yarn": "^1.3"
}, },
"lbrySettings": { "lbrySettings": {
"lbrynetDaemonVersion": "0.106.0", "lbrynetDaemonVersion": "0.113.0",
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip", "lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip",
"lbrynetDaemonDir": "static/daemon", "lbrynetDaemonDir": "static/daemon",
"lbrynetDaemonFileName": "lbrynet" "lbrynetDaemonFileName": "lbrynet"
} },
"packageManager": "yarn@3.2.0"
} }

View file

@ -2206,13 +2206,6 @@
"Enabling a minimum amount to comment will force all comments to have tips associated with them. This can help prevent spam.": "Enabling a minimum amount to comment will force all comments to have tips associated with them. This can help prevent spam.", "Enabling a minimum amount to comment will force all comments to have tips associated with them. This can help prevent spam.": "Enabling a minimum amount to comment will force all comments to have tips associated with them. This can help prevent spam.",
"Comments containing these words will be blocked.": "Comments containing these words will be blocked.", "Comments containing these words will be blocked.": "Comments containing these words will be blocked.",
"Enter the full channel name or URL to search.\n\nExamples:\n - @channel\n - @channel#3\n - https://odysee.com/@Odysee:8\n - lbry://@Odysee#8": "Enter the full channel name or URL to search.\n\nExamples:\n - @channel\n - @channel#3\n - https://odysee.com/@Odysee:8\n - lbry://@Odysee#8", "Enter the full channel name or URL to search.\n\nExamples:\n - @channel\n - @channel#3\n - https://odysee.com/@Odysee:8\n - lbry://@Odysee#8": "Enter the full channel name or URL to search.\n\nExamples:\n - @channel\n - @channel#3\n - https://odysee.com/@Odysee:8\n - lbry://@Odysee#8",
"Disk Space": "Disk Space",
"Data Hosting": "Data Hosting",
"Limit": "Limit",
"Limit Space Used": "Limit Space Used",
"Apply": "Apply",
"Limit in GB": "Limit in GB",
"If you set a limit, playing videos may exceed your limit until cleanup runs every 30 minutes.": "If you set a limit, playing videos may exceed your limit until cleanup runs every 30 minutes.",
"Enable Data Hosting": "Enable Data Hosting", "Enable Data Hosting": "Enable Data Hosting",
"Data over the limit will be deleted within 30 minutes. This will make the Yrbl cry a little bit.": "Data over the limit will be deleted within 30 minutes. This will make the Yrbl cry a little bit.", "Data over the limit will be deleted within 30 minutes. This will make the Yrbl cry a little bit.": "Data over the limit will be deleted within 30 minutes. This will make the Yrbl cry a little bit.",
"Choose %asset%": "Choose %asset%", "Choose %asset%": "Choose %asset%",
@ -2228,13 +2221,6 @@
"Enable Prerelease Updates": "Enable Prerelease Updates", "Enable Prerelease Updates": "Enable Prerelease Updates",
"Enable Upgrade to Test Builds": "Enable Upgrade to Test Builds", "Enable Upgrade to Test Builds": "Enable Upgrade to Test Builds",
"Prereleases may break things and we may not be able to fix them for you.": "Prereleases may break things and we may not be able to fix them for you.", "Prereleases may break things and we may not be able to fix them for you.": "Prereleases may break things and we may not be able to fix them for you.",
"Limit (GB)": "Limit (GB)",
"Limit Hosting for Content you Use": "Limit Hosting for Content you Use",
"Allow (GB)": "Allow (GB)",
"Content Data Hosting helps to seed things that you watch and download.": "Content Data Hosting helps to seed things that you watch and download.",
"Network Data Hosting allows the p2p network to store blobs unrelated to your browsing.": "Network Data Hosting allows the p2p network to store blobs unrelated to your browsing.",
"Content: Limit (GB)": "Content: Limit (GB)",
"Network: Allow (GB)": "Network: Allow (GB)",
"A channel is required to repost on LBRY": "A channel is required to repost on LBRY", "A channel is required to repost on LBRY": "A channel is required to repost on LBRY",
"Admin": "Admin", "Admin": "Admin",
"Stickers": "Stickers", "Stickers": "Stickers",
@ -2256,19 +2242,6 @@
"Move Up": "Move Up", "Move Up": "Move Up",
"Move Down": "Move Down", "Move Down": "Move Down",
"Trending for #Game": "Trending for #Game", "Trending for #Game": "Trending for #Game",
"Help the P2P data network by hosting data.": "Help the P2P data network by hosting data.",
"History hosting lets you choose how much storage to use helping content you've consumed.": "History hosting lets you choose how much storage to use helping content you've consumed.",
"Automatic hosting lets you delegate some amount of storage for the network to automatically download ad host.": "Automatic hosting lets you delegate some amount of storage for the network to automatically download ad host.",
"Playing videos may exceed your history hosting limit until cleanup runs every 30 minutes.": "Playing videos may exceed your history hosting limit until cleanup runs every 30 minutes.",
"History: Limit (GB)": "History: Limit (GB)",
"Automatic: Allow (GB)": "Automatic: Allow (GB)",
"Automatic hosting lets you delegate some amount of storage for the network to automatically download and host.": "Automatic hosting lets you delegate some amount of storage for the network to automatically download and host.",
"History Hosting": "History Hosting",
"Automatic Hosting": "Automatic Hosting",
"History Hosting lets you choose how much storage to use helping content you've consumed.": "History Hosting lets you choose how much storage to use helping content you've consumed.",
"Automatic Hosting lets you delegate some amount of storage for the network to automatically download and host.": "Automatic Hosting lets you delegate some amount of storage for the network to automatically download and host.",
"Help improve the P2P data network (and make LBRY happy) by hosting data.": "Help improve the P2P data network (and make LBRY happy) by hosting data.",
"Limit Hosting of Content History": "Limit Hosting of Content History",
"Remove custom comment server": "Remove custom comment server", "Remove custom comment server": "Remove custom comment server",
"Use Https": "Use Https", "Use Https": "Use Https",
"Server URL": "Server URL", "Server URL": "Server URL",
@ -2285,5 +2258,69 @@
"Enable Automatic Hosting": "Enable Automatic Hosting", "Enable Automatic Hosting": "Enable Automatic Hosting",
"Download and serve arbitrary data on the network.": "Download and serve arbitrary data on the network.", "Download and serve arbitrary data on the network.": "Download and serve arbitrary data on the network.",
"View History Hosting": "View History Hosting", "View History Hosting": "View History Hosting",
"Disable automatic updates": "Disable automatic updates",
"Preven't new updates to be downloaded automatically in the background (we will keep notifying you if there is an update)": "Preven't new updates to be downloaded automatically in the background (we will keep notifying you if there is an update)",
"Unlimited View Hosting": "Unlimited View Hosting",
"Choose View Hosting Limit": "Choose View Hosting Limit",
"View Hosting Limit (GB)": "View Hosting Limit (GB)",
"%free% of %total% available": "%free% of %total% available",
"Short (< 4 min)": "Short (< 4 min)",
"Medium (4 - 20 min)": "Medium (4 - 20 min)",
"Rename List": "Rename List",
"New Name": "New Name",
"Rename": "Rename",
"New Collection Name": "New Collection Name",
"In %collection%": "In %collection%",
"Add to %collection%": "Add to %collection%",
"Show this channel your appreciation by sending a donation of Credits. ": "Show this channel your appreciation by sending a donation of Credits. ",
"You've entered the land of content freedom! Let's make sure everything is ship shape.": "You've entered the land of content freedom! Let's make sure everything is ship shape.",
"By continuing, you agree to the %terms%": "By continuing, you agree to the %terms%",
"Privacy": "Privacy",
"LBRY takes privacy and choice seriously. Is it ok if we monitor performance and help creators track their views?": "LBRY takes privacy and choice seriously. Is it ok if we monitor performance and help creators track their views?",
"Yes, share with LBRY": "Yes, share with LBRY",
"Search Uploads": "Search Uploads",
"This refundable boost will improve the discoverability of this %claimTypeText% while active. ": "This refundable boost will improve the discoverability of this %claimTypeText% while active. ",
"Show less": "Show less",
"Elements": "Elements",
"Icons": "Icons",
"Go to": "Go to",
"Clearing...": "Clearing...",
"Clear Views": "Clear Views",
"Show Video View Progress": "Show Video View Progress",
"Display view progress on thumbnail. This setting will not hide any blockchain activity or downloads.": "Display view progress on thumbnail. This setting will not hide any blockchain activity or downloads.",
"Content Hosting": "Content Hosting",
"Hosting": "Hosting",
"Viewed Hosting": "Viewed Hosting",
"Auto Hosting": "Auto Hosting",
"Help creators and improve the P2P data network by hosting content.": "Help creators and improve the P2P data network by hosting content.",
"I'm happy with my settings": "I'm happy with my settings",
"We've noticed you already have some settings.": "We've noticed you already have some settings.",
"You choose how much data to host.": "You choose how much data to host.",
"Go back": "Go back",
"Custom Hosting": "Custom Hosting",
"Automatic Hosting (GB)": "Automatic Hosting (GB)",
"* Note that as peer-to-peer software, your IP address and potentially other system information can be sent to other users, though this information is not stored permanently.": "* Note that as peer-to-peer software, your IP address and potentially other system information can be sent to other users, though this information is not stored permanently.",
"Help improve the P2P data network (and make LBRY users happy) by hosting data.": "Help improve the P2P data network (and make LBRY users happy) by hosting data.",
"View History Hosting lets you choose how much storage to use hosting content you've consumed.": "View History Hosting lets you choose how much storage to use hosting content you've consumed.",
"Automatic Hosting downloads a small portion of content active on the network.": "Automatic Hosting downloads a small portion of content active on the network.",
"Publishes --[legend, storage category]--": "Publishes",
"Auto Hosting --[legend, storage category]--": "Auto Hosting",
"View Hosting --[legend, storage category]--": "View Hosting",
"%spaceUsed% of %limit% GB": "%spaceUsed% of %limit% GB",
"%spaceUsed% of %limit% Free GB": "%spaceUsed% of %limit% Free GB",
"Disabled": "Disabled",
"Free --[legend, unused disk space]--": "Free",
"Top content in %language%": "Top content in %language%",
"Apply": "Apply",
"Disable background": "Disable background",
"Installing, please wait...": "Installing, please wait...",
"There was an error during installation. Please, try again.": "There was an error during installation. Please, try again.",
"Odysee Connect --[Section in Help Page]--": "Odysee Connect",
"Your hub has blocked this content because it subscribes to the following blocking channel:": "Your hub has blocked this content because it subscribes to the following blocking channel:",
"Your hub has blocked access to this content do to a complaint received under the US Digital Millennium Copyright Act.": "Your hub has blocked access to this content do to a complaint received under the US Digital Millennium Copyright Act.",
"Autoplay Next is on.": "Autoplay Next is on.",
"This will be visible in a few minutes after you submit this form.": "This will be visible in a few minutes after you submit this form.",
"Anon --[used in <%anonymous% Reposted>]--": "Anon",
"Your update is now pending. It will take a few minutes to appear for other users.": "Your update is now pending. It will take a few minutes to appear for other users.",
"--end--": "--end--" "--end--": "--end--"
} }

3
static/app-update.yml Normal file
View file

@ -0,0 +1,3 @@
owner: lbryio
repo: lbry-desktop
provider: github

BIN
static/img/freespch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

102
static/img/yrblhappy.svg Normal file
View file

@ -0,0 +1,102 @@
<svg width="2859" height="3858" viewBox="0 0 2859 3858" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.997" d="M229.331 2573.92C227.658 2571.29 287.004 2544.38 324.218 2448.2C337.11 2414.69 347.357 2369.08 337.943 2323.16C334.776 2307.96 329.583 2292.41 320.457 2279.96C313.372 2270.39 303.743 2262.04 292.932 2259.23C281.648 2255.61 267.954 2257.93 254.626 2263.16C231.995 2270.93 211.286 2285.24 190.078 2302.35C167.021 2283.54 134.978 2268.82 104.768 2273.7C81.902 2276.54 60.511 2295.24 49.4462 2318.86C3.74465 2410.06 71.315 2519.88 150.29 2625.09C150.29 2625.09 150.29 2625.09 150.29 2625.09C230.276 2725.89 340.979 2812.76 472.956 2860.92C580.106 2900.19 698.127 2914.49 816.398 2905.34C858.558 2901.63 900.297 2891.12 931.227 2867C941.601 2859.12 950.867 2849.65 958.548 2839.11C967.767 2826.46 974.702 2812.27 978.534 2797.4C985.145 2772.44 984.014 2745.1 975.509 2720.73V2720.73C967.343 2698.01 953.089 2677.33 934.061 2665.58C910.149 2650.23 881.933 2641.07 853.199 2637.76C819.885 2634.11 785.627 2639.42 757.021 2654.45C719.662 2673.22 691.325 2709.24 671.796 2748.4C639.342 2814.04 629.429 2890.35 625.585 2963.42C620.787 3054.16 660.729 3141.58 719.642 3201.36C770.676 3252.96 831.322 3289.74 893.723 3308.69C908.697 3313.56 926.857 3313.53 945.412 3314.04C973.343 3314.51 1002.22 3313.39 1029.19 3312.46C1112.71 3309.54 1178.34 3307.56 1247.24 3311.4C1252.48 3312.55 1259.26 3308.03 1265.44 3302.94C1274.49 3294.73 1281.43 3283.17 1287.71 3271.73C1306.29 3237.38 1318.13 3197.66 1326.75 3167.88C1349.83 3064.98 1363.32 3012.13 1366.36 3012.73C1369.41 3013.33 1361.94 3067.36 1344.36 3171.88C1344.36 3171.88 1344.36 3171.88 1344.36 3171.88C1337.33 3202.62 1327.04 3243.92 1308.44 3282.33C1302.39 3294.99 1294.5 3308.84 1282.76 3320.8C1274.53 3329.67 1261.97 3337.01 1246.23 3337.34C1178.13 3335.81 1114.64 3339.62 1030.69 3344.52C1003.79 3346.11 974.453 3347.89 945.212 3348.03C926.769 3348.32 905.587 3348.33 883.825 3342.43C815.106 3322.91 748.321 3284.25 692.192 3228.84C625.184 3162.88 579.614 3066.05 583.303 2961.59C585.929 2885.84 596.46 2803.96 631.931 2729.13C653.524 2683.25 688.026 2640.3 736.117 2614.43C773.614 2594.93 816.524 2587.77 858.202 2592.39C893.307 2596.11 928.083 2607.44 958.736 2626.81C987.785 2645.66 1008.37 2674.19 1019.07 2705.51V2705.51C1030.67 2738.69 1032.2 2775.02 1023.26 2809.17C1017.73 2829.86 1008.36 2849.2 995.965 2866.3C985.637 2880.55 973.211 2893.24 959.166 2903.86C917.766 2934.55 867.899 2948.06 819.932 2951.28C695.515 2960.79 571.075 2945 457.507 2902.73C317.198 2850.29 201.177 2757.52 118.223 2650.2V2650.2C32.6442 2545.24 -32.8981 2417.48 17.6801 2303.93C33.4423 2270.48 64.451 2246.14 100.199 2240.83C136.634 2236.45 169.491 2255.33 190.178 2280.49C205.009 2262.04 222.599 2245.98 243.989 2236.31C261.83 2229.19 281.993 2227.28 301.035 2233.04C318.973 2239.12 332.793 2251.36 341.852 2265.2C353.144 2282.35 358.941 2301.28 361.69 2318.87C370.075 2371.61 356.822 2420.33 340.993 2455.25C291.994 2563.91 225.032 2567.17 229.331 2573.92V2573.92Z" fill="black"/>
<path d="M1160.62 2299.49C1160.62 2299.49 1166.66 2341.8 1118.3 2468.75C1069.94 2595.69 1066.92 2885.85 1042.74 2949.32C1018.56 3012.79 885.57 3224.37 915.795 3411.76C946.02 3599.15 1094.12 3865.13 1275.47 3798.64C1456.82 3732.14 1420.55 3744.23 1420.55 3744.23C1420.55 3744.23 1946.46 3859.09 2294.05 3659.6C2372.63 3695.87 2420.99 3726.1 2538.87 3656.58C2656.74 3587.06 2717.19 3396.65 2714.17 3266.68C2711.15 3136.71 2523.75 2852.6 2502.6 2792.15C2481.44 2731.7 2402.85 2435.5 2363.56 2311.58C2324.27 2187.66 2354.5 2166.5 2354.5 2166.5L1160.62 2299.49Z" fill="#DE5700" stroke="black" stroke-width="46.0804"/>
<path d="M2798.72 15.367C2698.4 16.4866 2391.12 184.492 2306.37 277.783C2219.35 373.579 2165.64 521.033 2148.97 571.513C2050.88 508.595 1907.17 507.155 1907.17 507.155C1907.17 507.155 1991.8 479.955 2082.48 455.775C1925.31 401.371 1722.8 449.727 1722.8 449.727C1722.8 449.727 1813.47 349.989 1895.08 277.45C1768.13 310.697 1620.04 383.233 1529.36 437.638C1553.54 401.368 1595.86 362.076 1680.49 244.199C1447.75 301.626 1160.61 528.318 1060.87 612.947C1072.96 537.385 1103.19 489.025 1139.46 404.395C1002.07 499.513 937.628 607.905 907.715 681.853C876.541 624.261 794.11 483.695 690.543 400.173C558.035 293.312 45.0981 126.611 113.489 254.844C181.88 383.077 164.781 558.322 207.525 827.611C250.27 1096.9 634.972 1250.78 634.972 1250.78C637.191 1249.99 639.395 1249.09 641.592 1248.17C619.011 1319.85 598.866 1424.54 583.679 1597.01C511.014 1706.01 478.959 1727.38 470.41 1767.99C540.938 1733.8 575.13 1708.15 626.423 1695.32C581.542 1770.13 579.407 1872.71 598.642 2035.14C634.974 1943.24 632.832 1945.37 671.302 1917.59C681.988 2026.59 705.503 2086.43 733.287 2120.63C743.973 2060.78 776.031 2037.28 776.031 2037.28C776.031 2037.28 797.404 2167.65 859.383 2257.41C872.206 2178.34 887.165 2165.51 887.165 2165.51C887.165 2165.51 1135.08 2490.37 1767.7 2456.17C2400.31 2421.98 2579.84 1985.98 2579.84 1985.98C2579.84 1985.98 2592.66 2041.56 2592.66 2062.93C2639.68 1994.54 2669.6 1853.48 2669.6 1853.48C2669.6 1853.48 2703.8 1934.69 2695.25 1985.98C2733.72 1921.86 2742.26 1763.72 2725.17 1691.05C2785.01 1755.17 2836.31 1776.54 2836.31 1776.54C2836.31 1776.54 2703.79 1545.72 2699.52 1507.25C2695.25 1468.78 2793.56 1562.81 2793.56 1562.81C2793.56 1562.81 2731.97 1460.26 2716.62 1432.45C2659.41 1328.78 2605.12 1139.43 2528.87 1011.72C2592.86 970.123 2850.88 788.773 2843.33 573.68C2834.72 328.21 2786.46 176.103 2827.99 51.0384C2836.43 25.6346 2824.3 15.0816 2798.72 15.367V15.367Z" fill="#DE5700"/>
<path d="M1160.62 2299.49C1160.62 2299.49 1166.66 2341.8 1118.3 2468.75C1069.94 2595.69 1066.92 2885.85 1042.74 2949.32C1018.56 3012.79 885.57 3224.37 915.795 3411.76C946.02 3599.15 1094.12 3865.13 1275.47 3798.64C1456.82 3732.14 1420.55 3744.23 1420.55 3744.23C1420.55 3744.23 1946.46 3859.09 2294.05 3659.6C2372.63 3695.87 2420.99 3726.1 2538.87 3656.58C2656.74 3587.06 2717.19 3396.65 2714.17 3266.68C2711.15 3136.71 2523.75 2852.6 2502.6 2792.15C2481.44 2731.7 2402.85 2435.5 2363.56 2311.58C2324.27 2187.66 2354.5 2166.5 2354.5 2166.5L1160.62 2299.49Z" fill="#DE5700"/>
<path d="M1940.31 2212.63L1557.07 2255.32C1406.21 2289.92 1288.96 2332.21 1288.96 2332.21C1288.96 2332.21 1220.57 2746.83 1233.39 2862.24C1246.22 2977.65 1173.55 3152.9 1212.02 3328.15C1245.61 3481.2 1311.83 3644.02 1558.64 3765.38C1710.04 3782.34 1960.24 3792 2176.82 3713.48C2280.67 3629.51 2354.73 3520.47 2383.21 3435.02C2447.33 3242.67 2370.39 2909.27 2340.47 2840.87C2310.55 2772.48 2344.75 2558.76 2178.04 2315.11C2132.1 2247.96 2043.91 2219.17 1940.31 2212.63Z" fill="#F7EDE9"/>
<path opacity="0.6" d="M2798.72 15.367C2698.4 16.4866 2391.12 184.492 2306.37 277.783C2219.35 373.579 2165.64 521.033 2148.97 571.513C2050.88 508.595 1907.17 507.155 1907.17 507.155C1907.17 507.155 1991.8 479.955 2082.48 455.775C1925.31 401.371 1722.8 449.727 1722.8 449.727C1722.8 449.727 1813.47 349.989 1895.08 277.45C1768.13 310.697 1620.04 383.233 1529.36 437.638C1553.54 401.368 1595.86 362.076 1680.49 244.199C1447.75 301.626 1160.61 528.318 1060.87 612.947C1072.96 537.385 1103.19 489.025 1139.46 404.395C1002.07 499.513 937.628 607.905 907.715 681.853C876.541 624.261 794.11 483.695 690.543 400.173C558.035 293.312 45.0981 126.611 113.489 254.844C181.88 383.077 164.781 558.322 207.525 827.611C250.27 1096.9 634.972 1250.78 634.972 1250.78C637.191 1249.99 639.395 1249.09 641.592 1248.17C619.011 1319.85 598.866 1424.54 583.679 1597.01C511.014 1706.01 478.959 1727.38 470.41 1767.99C540.938 1733.8 575.13 1708.15 626.423 1695.32C581.542 1770.13 579.407 1872.71 598.642 2035.14C634.974 1943.24 632.832 1945.37 671.302 1917.59C681.988 2026.59 705.503 2086.43 733.287 2120.63C743.973 2060.78 776.031 2037.28 776.031 2037.28C776.031 2037.28 797.404 2167.65 859.383 2257.41C872.206 2178.34 887.165 2165.51 887.165 2165.51C887.165 2165.51 1135.08 2490.37 1767.7 2456.17C2400.31 2421.98 2579.84 1985.98 2579.84 1985.98C2579.84 1985.98 2592.66 2041.56 2592.66 2062.93C2639.68 1994.54 2669.6 1853.48 2669.6 1853.48C2669.6 1853.48 2703.8 1934.69 2695.25 1985.98C2733.72 1921.86 2742.26 1763.72 2725.17 1691.05C2785.01 1755.17 2836.31 1776.54 2836.31 1776.54C2836.31 1776.54 2703.79 1545.72 2699.52 1507.25C2695.25 1468.78 2793.56 1562.81 2793.56 1562.81C2793.56 1562.81 2731.97 1460.26 2716.62 1432.45C2659.41 1328.78 2605.12 1139.43 2528.87 1011.72C2592.86 970.123 2850.88 788.773 2843.33 573.68C2834.72 328.21 2786.46 176.103 2827.99 51.0384C2836.43 25.6346 2824.3 15.0816 2798.72 15.367V15.367Z" fill="url(#paint0_radial_2_3)"/>
<path d="M1785.69 1777.75C1684.07 1778.04 1631.38 1822.48 1594.58 1842.79C1435.61 2029.15 1115.77 1926.47 942.736 2050.1C912.815 2071.47 871.139 2186.88 871.139 2186.88L873.322 2195.17C881.063 2170.83 887.165 2165.51 887.165 2165.51C887.165 2165.51 1135.08 2490.37 1767.7 2456.17C2277.77 2428.6 2493.17 2139.93 2557.52 2029.09C2551.52 1973.12 2534.07 1898.88 2483.67 1896.22C2402.45 1891.95 2066.9 1864.16 1964.32 1808.59C1922.64 1786.02 1855.22 1777.56 1785.69 1777.75V1777.75Z" fill="#F7EDE9"/>
<path opacity="0.993" d="M1961.57 1985.15C1963.63 1987.09 1933.18 2033.96 1856.33 2063.83V2063.83C1839.85 2070.21 1822.61 2075.45 1804.72 2079.62C1766.98 2088.41 1729.87 2091.61 1698.49 2092.27C1674.97 2092.78 1655.68 2091.74 1642.07 2090.22C1634.99 2089.43 1629.58 2088.53 1625.85 2087.62C1623.95 2087.15 1622.51 2086.68 1621.54 2086.24C1621.04 2086.01 1620.67 2085.78 1620.42 2085.57C1620.15 2085.33 1620.02 2085.11 1620.03 2084.89C1620.05 2084.67 1620.2 2084.47 1620.49 2084.27C1620.76 2084.08 1621.15 2083.91 1621.67 2083.73C1622.67 2083.4 1624.14 2083.08 1626.06 2082.78C1629.77 2082.2 1635.24 2081.66 1642.21 2081.09C1655.61 2079.99 1674.74 2078.77 1697.58 2076.59C1728.3 2073.63 1764.16 2069.35 1800.38 2060.94C1817.57 2056.95 1834.05 2052.22 1849.95 2046.59C1918.62 2022.43 1958.6 1982.34 1961.57 1985.15V1985.15Z" fill="black"/>
<path d="M1934.67 1959.27C1935.77 1956.91 1954.37 1960.97 1967.17 1981.57C1979.98 2002.16 1975.41 2020.64 1972.82 2020.59C1970 2020.53 1967.84 2002.79 1958.14 1987.19C1948.44 1971.58 1933.47 1961.83 1934.67 1959.27V1959.27Z" fill="black"/>
<path d="M1263.38 1639.08C1266.22 1756.73 1183.41 1844.17 1098.66 1852.16C951.388 1866.04 891.515 1767.76 901.935 1653.12C912.302 1539.07 1011.03 1433.96 1109.23 1430.52C1193.46 1427.58 1260.47 1518.48 1263.38 1639.08Z" fill="black"/>
<g filter="url(#filter0_f_2_3)">
<path d="M1109.1 1636.63C1138.87 1598.95 1137.08 1543.74 1105.1 1513.3C1073.11 1482.87 1023.06 1488.73 993.289 1526.41C963.521 1564.08 965.315 1619.29 997.297 1649.73C1029.28 1680.17 1079.34 1674.3 1109.1 1636.63Z" fill="#BEBEBE"/>
</g>
<path d="M1109.1 1636.63C1138.87 1598.95 1137.08 1543.74 1105.1 1513.3C1073.11 1482.87 1023.06 1488.73 993.289 1526.41C963.521 1564.08 965.315 1619.29 997.297 1649.73C1029.28 1680.17 1079.34 1674.3 1109.1 1636.63Z" fill="#DEDEDE"/>
<g filter="url(#filter1_f_2_3)">
<path d="M1220.38 1725.27C1218.97 1703.96 1200.95 1686.44 1180.12 1686.13C1159.3 1685.82 1143.56 1702.84 1144.97 1724.14C1146.37 1745.45 1164.4 1762.98 1185.22 1763.29C1206.05 1763.6 1221.79 1746.58 1220.38 1725.27Z" fill="#BEBEBE"/>
</g>
<path d="M1217.34 1725.22C1216.05 1705.95 1199.48 1690.11 1180.33 1689.83C1161.18 1689.54 1146.71 1704.93 1148.01 1724.2C1149.3 1743.46 1165.87 1759.31 1185.02 1759.59C1204.17 1759.87 1218.64 1744.48 1217.34 1725.22Z" fill="#DEDEDE"/>
<path d="M2111.74 1483.68C2108.91 1601.33 2191.71 1688.77 2276.47 1696.76C2423.74 1710.64 2483.61 1612.36 2473.19 1497.72C2462.82 1383.67 2364.09 1278.56 2265.89 1275.13C2181.66 1272.18 2114.65 1363.09 2111.74 1483.68Z" fill="black"/>
<g filter="url(#filter2_f_2_3)">
<path d="M2266.02 1481.23C2236.25 1443.55 2238.05 1388.34 2270.03 1357.9C2302.01 1327.47 2352.07 1333.34 2381.83 1371.01C2411.6 1408.68 2409.81 1463.9 2377.83 1494.33C2345.85 1524.77 2295.79 1518.9 2266.02 1481.23Z" fill="#BEBEBE"/>
</g>
<path d="M2266.02 1481.23C2236.25 1443.55 2238.05 1388.34 2270.03 1357.9C2302.01 1327.47 2352.07 1333.34 2381.83 1371.01C2411.6 1408.68 2409.81 1463.9 2377.83 1494.33C2345.85 1524.77 2295.79 1518.9 2266.02 1481.23Z" fill="#DEDEDE"/>
<g filter="url(#filter3_f_2_3)">
<path d="M2154.74 1569.87C2156.15 1548.56 2174.17 1531.04 2195 1530.73C2215.82 1530.42 2231.57 1547.44 2230.16 1568.75C2228.75 1590.05 2210.72 1607.58 2189.9 1607.89C2169.07 1608.2 2153.33 1591.18 2154.74 1569.87Z" fill="#BEBEBE"/>
</g>
<path d="M2157.78 1569.82C2159.08 1550.55 2175.65 1534.71 2194.79 1534.43C2213.94 1534.15 2228.41 1549.53 2227.12 1568.8C2225.82 1588.06 2209.25 1603.91 2190.1 1604.19C2170.96 1604.47 2156.49 1589.08 2157.78 1569.82Z" fill="#DEDEDE"/>
<path d="M1662.35 1829.49C1645.46 1787.85 1850.52 1752.32 1854.28 1791.71C1858.37 1834.59 1804.4 1912.61 1777.2 1917.14C1750 1921.68 1680.39 1873.96 1662.35 1829.49V1829.49Z" fill="black"/>
<g opacity="0.8">
<g filter="url(#filter4_f_2_3)">
<path d="M1786.9 1793.91C1788.82 1786.22 1801.15 1781.29 1814.44 1782.91C1827.74 1784.53 1836.97 1792.08 1835.05 1799.77C1833.13 1807.46 1820.8 1812.39 1807.51 1810.77C1794.21 1809.15 1784.99 1801.61 1786.9 1793.91Z" fill="#BEBEBE"/>
</g>
<path d="M1788.84 1794.15C1790.59 1787.19 1801.91 1782.76 1814.14 1784.25C1826.36 1785.74 1834.85 1792.58 1833.11 1799.54C1831.36 1806.49 1820.04 1810.92 1807.81 1809.43C1795.59 1807.94 1787.1 1801.1 1788.84 1794.15Z" fill="#DEDEDE"/>
</g>
<path d="M2741.41 163.935C2735.43 163.644 2728.58 173.489 2718.76 194.994C2673.88 293.306 2462.29 385.213 2381.08 483.525C2299.87 581.837 2284.9 697.243 2374.67 851.122C2421.52 931.442 2482.9 980.277 2532.12 1009.56C2600.59 964.628 2850.77 785.686 2843.33 573.68C2841.17 511.985 2836.51 456.205 2831.39 405.253C2769.94 259.579 2759.63 164.818 2741.41 163.935V163.935Z" fill="url(#paint1_radial_2_3)"/>
<path d="M181.665 291.229C163.173 289.362 174.995 366.697 171.814 505.727C180.547 595.591 187.448 701.123 207.525 827.611C246.788 1074.97 573.781 1224.58 626.915 1247.37C670.403 1199.53 739.457 1106.83 766.704 960.629C806.777 745.606 754.64 615.556 641.83 530.754C529.019 445.951 288.043 418.155 211.526 319.567C197.179 301.081 187.769 291.846 181.665 291.229V291.229Z" fill="url(#paint2_radial_2_3)"/>
<path d="M2798.72 15.367C2698.4 16.4866 2391.12 184.492 2306.37 277.783C2219.35 373.579 2165.64 521.033 2148.97 571.513C2050.88 508.595 1907.17 507.155 1907.17 507.155C1907.17 507.155 1991.8 479.955 2082.48 455.775C1925.31 401.371 1722.8 449.727 1722.8 449.727C1722.8 449.727 1813.47 349.989 1895.08 277.45C1768.13 310.697 1620.04 383.233 1529.36 437.638C1553.54 401.368 1595.86 362.076 1680.49 244.199C1447.75 301.626 1160.61 528.318 1060.87 612.947C1072.96 537.385 1103.19 489.025 1139.46 404.395C1002.07 499.513 937.628 607.905 907.715 681.853C876.541 624.261 794.11 483.695 690.543 400.173C558.035 293.312 45.0981 126.611 113.489 254.844C181.88 383.077 164.781 558.322 207.525 827.611C250.27 1096.9 634.972 1250.78 634.972 1250.78C637.191 1249.99 639.395 1249.09 641.592 1248.17C619.011 1319.85 598.866 1424.54 583.679 1597.01C511.014 1706.01 478.959 1727.38 470.41 1767.99C540.938 1733.8 575.13 1708.15 626.423 1695.32C581.542 1770.13 579.407 1872.71 598.642 2035.14C634.974 1943.24 632.832 1945.37 671.302 1917.59C681.988 2026.59 705.503 2086.43 733.287 2120.63C743.973 2060.78 776.031 2037.28 776.031 2037.28C776.031 2037.28 797.404 2167.65 859.383 2257.41C872.206 2178.34 887.165 2165.51 887.165 2165.51C887.165 2165.51 1135.08 2490.37 1767.7 2456.17C2400.31 2421.98 2579.84 1985.98 2579.84 1985.98C2579.84 1985.98 2592.66 2041.56 2592.66 2062.93C2639.68 1994.54 2669.6 1853.48 2669.6 1853.48C2669.6 1853.48 2703.8 1934.69 2695.25 1985.98C2733.72 1921.86 2742.26 1763.72 2725.17 1691.05C2785.01 1755.17 2836.31 1776.54 2836.31 1776.54C2836.31 1776.54 2703.79 1545.72 2699.52 1507.25C2695.25 1468.78 2793.56 1562.81 2793.56 1562.81C2793.56 1562.81 2731.97 1460.26 2716.62 1432.45C2659.41 1328.78 2605.12 1139.43 2528.87 1011.72C2592.86 970.123 2850.88 788.773 2843.33 573.68C2834.72 328.21 2786.46 176.103 2827.99 51.0384C2836.43 25.6346 2824.3 15.0816 2798.72 15.367V15.367Z" stroke="black" stroke-width="30.7203" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1166.07 3775.9C1091.27 3651.94 1054.81 3567.11 1049.59 3511.42C1044.78 3460.13 1038.37 3398.15 1075.24 3428.61C1085.92 3383.72 1083.79 3358.08 1111.57 3370.9C1139.36 3383.72 1158.59 3411.51 1158.59 3411.51C1158.59 3411.51 1154.32 3347.39 1182.1 3368.76C1233.19 3399.52 1324.44 3688.35 1313.81 3770.16C1302.14 3860.06 1231.96 3879.6 1166.07 3775.9V3775.9Z" fill="url(#paint3_linear_2_3)" stroke="black" stroke-width="23.0402"/>
<path d="M2556.53 3668.47C2609.53 3533.74 2631.28 3444 2627.1 3388.22C2623.26 3336.85 2619.21 3274.67 2587.96 3310.87C2569.91 3268.41 2567.73 3242.76 2542.48 3260.06C2517.23 3277.35 2502.92 3307.96 2502.92 3307.96C2502.92 3307.96 2496.4 3244.03 2472.59 3269.75C2427.37 3308.62 2385.74 3608.66 2409.91 3687.53C2436.47 3774.21 2508.93 3781.73 2556.53 3668.47V3668.47Z" fill="url(#paint4_linear_2_3)" stroke="black" stroke-width="23.0402"/>
<path d="M1562.1 3063.57C1524.1 3059.67 1486.65 3074.05 1455.28 3094.55C1440.72 3104.25 1426.76 3115.03 1414.48 3127.52C1438.67 3156.34 1465.72 3183.02 1496.29 3205.05C1502.66 3208.89 1510.78 3214.39 1518.34 3210.58C1525.16 3205.3 1523.61 3195.64 1524.22 3188.07C1530.46 3197.06 1541.83 3202.2 1552.66 3201.65C1562.44 3199.92 1561.73 3187.56 1560.44 3180.1C1559.69 3173.07 1556.6 3166.42 1556.17 3159.41C1562.43 3160.56 1568.02 3169.72 1575.98 3167.49C1584.76 3164.88 1580.38 3153.58 1580.28 3146.94C1575.9 3118.83 1568.65 3091.24 1562.1 3063.57V3063.57Z" fill="url(#paint5_linear_2_3)"/>
<path d="M2302.03 3008.83C2271.36 3023.52 2235.53 3023.15 2203.06 3015.16C2175.5 3008.19 2149 2996.64 2125.3 2980.94C2128.65 3015.23 2131.75 3049.73 2139.6 3083.34C2140.74 3090.5 2145.31 3102 2154.43 3096.05C2163.06 3091.33 2167.94 3082.23 2175.33 3076.17C2175.86 3081.7 2172.59 3088.04 2172.97 3094.1C2172.43 3103.97 2175.25 3117.51 2186.59 3119.85C2200.16 3121.29 2212.08 3112.19 2221.11 3103.04C2227.36 3097.53 2223.84 3112.39 2227.54 3115.27C2229.88 3123.69 2240.07 3132.21 2248.05 3124.67C2257.97 3116 2262.87 3103.26 2269.34 3092.1C2283.08 3065.57 2293.72 3037.5 2302.03 3008.83V3008.83Z" fill="url(#paint6_linear_2_3)"/>
<path d="M1517.64 2663.48C1517.64 2663.48 1517.64 2663.48 1517.67 2663.48C1520.97 2664.02 1526.42 2740.85 1532.65 2874.63C1534.91 2900.48 1540.5 2925.66 1547.39 2954.9C1554.58 2985.32 1562.49 3014.75 1571.38 3047.9C1578.08 3072.85 1585.59 3099.84 1591.55 3126.74C1593.42 3135.07 1595.31 3143.95 1596.25 3153.37C1596.57 3156.1 1596.76 3159.46 1596.39 3163.39C1597.28 3165.14 1595.58 3169.34 1590.43 3175.07V3175.07C1580.39 3180.9 1569.4 3179.92 1561.47 3173.37V3173.37C1559.01 3171.29 1557.89 3169.89 1557.57 3169.88C1559.13 3171.17 1561.37 3170.83 1565.41 3169.42H1565.41C1567.06 3167.09 1567.82 3166.38 1567.48 3165.67C1567.51 3167 1568.74 3169.46 1569.97 3173.33V3173.33C1574.02 3183.37 1572.31 3196.44 1561.97 3206.72V3206.72C1550.18 3212.97 1538.44 3211.07 1531.04 3204.36V3204.36C1528.22 3202.07 1526.49 3200.26 1525.34 3199.66H1525.34C1524.94 3200.04 1525.8 3199.59 1528.79 3199.47V3199.47C1531.49 3196.56 1532.68 3197.17 1530.81 3199.19C1530.12 3201.61 1529.26 3205.67 1526.9 3210.83C1526.22 3212.23 1525.38 3213.53 1524.39 3214.71C1520.87 3218.89 1515.47 3221.56 1508.72 3222C1497.43 3220.63 1489.74 3215.57 1485.08 3211.33C1426.38 3166.73 1381.27 3109.36 1347.87 3050.36C1312.57 2987.93 1289.97 2924.54 1275.1 2870.05C1253.47 2738.94 1243.01 2664.06 1246.21 2663.48C1249.41 2662.9 1265.97 2736.63 1291.73 2866.13V2866.13C1308.09 2918.97 1331.53 2980.15 1366.49 3039.63C1399.64 3096.09 1443.21 3150.79 1498.89 3192.79C1504.65 3196.18 1508.06 3199.72 1509.67 3198.89C1507.79 3199.52 1506.9 3199.67 1506.47 3200.08C1506.35 3200.2 1506.26 3200.33 1506.2 3200.5C1506.94 3199.44 1507.34 3196.53 1508.73 3192.3C1508.67 3188.65 1512.14 3183.04 1520.37 3177.93V3177.93C1527.93 3176.03 1533.99 3177.15 1537.72 3180.15H1537.72C1541.56 3182.71 1544.07 3185.1 1545.79 3186.59V3186.59C1547.9 3187.76 1550.06 3189.47 1548.1 3188.32H1548.1C1549.88 3189.46 1549.02 3184.96 1548.23 3180.69C1547.29 3178.15 1545.76 3174.34 1544.81 3168.99C1543.68 3162.9 1546.08 3156.29 1552.14 3150.81V3150.81C1559.11 3147.32 1565.42 3147.49 1569.99 3150.72V3150.72C1573.53 3153.21 1575.53 3155.29 1576.51 3156.24C1576.77 3156.9 1578.18 3157.59 1576.82 3156.92C1573.94 3160.94 1572.68 3161.93 1573.89 3160.86C1574.1 3159.67 1573.92 3157.84 1573.76 3155.45C1573.11 3147.76 1571.43 3139.75 1569.7 3131.46C1564.19 3105.34 1557.05 3078.42 1550.71 3053.27C1542.36 3020.15 1534.87 2989.98 1528.34 2959.17C1522.03 2929.53 1516.99 2902.93 1515.44 2875.5C1513.55 2741.07 1514.34 2664.11 1517.6 2663.48C1517.63 2663.47 1517.63 2663.48 1517.63 2663.48L1517.64 2663.48Z" fill="black"/>
<path d="M2054.36 2616.63C2054.36 2616.63 2054.36 2616.63 2054.39 2616.62C2056.19 2615.89 2070.04 2637.19 2094.89 2678.94C2109.22 2707.44 2132.01 2758.35 2129.26 2813.73C2126.35 2866.49 2129.91 2919.11 2136.27 2983.73C2138.7 3008.27 2141.56 3033.66 2145.95 3058.66C2147.37 3066.7 2148.83 3074.55 2150.94 3081.92C2153.48 3086.92 2152.68 3089.64 2151.85 3087.1V3087.1C2150.35 3086.42 2149.64 3086.43 2147.76 3086.96C2148.59 3086.81 2149.83 3084.69 2152.36 3081.82C2154.18 3079.26 2156.95 3075.55 2161.56 3071.71V3071.71C2167.24 3067.27 2175.05 3066.8 2183.03 3071.14V3071.14C2189.11 3077.02 2191.46 3083.31 2190.86 3088.36C2190.8 3093.49 2190.09 3097.39 2189.91 3100.1C2189.14 3103.56 2191.72 3107.99 2194.93 3108.22C2193.44 3110.41 2195.34 3107.08 2199.65 3103.9C2200.36 3103.37 2201.14 3102.85 2201.98 3102.36C2204.18 3100.03 2207.36 3096.8 2212.18 3093.66V3093.66C2217.35 3090.16 2224.54 3089.74 2232.22 3093.32V3093.32C2239.64 3099.62 2242.27 3105.64 2242.32 3108.84V3108.84C2243.94 3113.56 2244.7 3117.24 2245.92 3119.33H2245.92C2246.6 3118.44 2244.84 3119 2239.24 3117.9C2240.48 3118.95 2242.2 3113.83 2247.17 3108.21C2313.25 3000.93 2319.46 2871.49 2314.9 2781.07C2297.57 2668.78 2289.5 2605.08 2292.54 2604.55C2295.58 2604.02 2309.48 2666.75 2331.2 2779.09C2339.6 2871.29 2335.62 3005.12 2266.47 3120.62C2263.84 3126.17 2258.15 3134.43 2246.52 3139.76V3139.76C2235.07 3140.6 2227.55 3136.27 2225.41 3129.88C2222.7 3124.33 2221.47 3119.55 2220.39 3116.09C2218.14 3112.39 2218.74 3110.5 2219.99 3112.94V3112.94C2222.91 3113.55 2223.8 3114.03 2224.18 3113.43C2222.87 3114.01 2221.12 3116.14 2218.22 3118.84C2217.57 3119.81 2216.8 3120.78 2215.9 3121.71C2210.47 3127.42 2200.54 3132.07 2187.13 3129.99C2174.17 3124.43 2166.53 3112.21 2166.89 3098.57C2167.2 3093.95 2167.9 3090.58 2167.82 3088.37C2167.22 3087.43 2167.96 3087.26 2169.25 3089.56L2169.25 3089.56C2172.81 3090.59 2174.25 3090.97 2175.57 3089.9C2174.45 3090.47 2173.01 3092.84 2170.38 3095.95C2168.41 3098.82 2165.16 3102.7 2159.8 3106.38C2152.56 3110.22 2144.7 3109.78 2138.18 3105.33L2138.18 3105.33C2130.69 3097.78 2128.79 3091.01 2129.09 3088.03V3088.03C2126.7 3079.31 2125.14 3070.69 2123.79 3062.43C2119.5 3036.46 2116.88 3010.52 2114.8 2985.7C2109.33 2920.88 2107.01 2866.34 2111.71 2812.49C2116.41 2763.32 2096.79 2712.68 2084.96 2683.93C2063.44 2641.21 2052.84 2617.95 2054.33 2616.66V2616.66C2054.36 2616.65 2054.36 2616.65 2054.36 2616.65L2054.36 2616.63Z" fill="black"/>
<path d="M1565.2 3063.14C1564.91 3065.73 1555.96 3066.2 1541.37 3069.17C1525.48 3072.41 1508.74 3077.63 1488.07 3087.53C1480.4 3091.19 1473 3095.12 1465.92 3099.1C1438.07 3119.19 1417.43 3130.85 1415.06 3127.79C1412.69 3124.73 1429.23 3107.59 1456.24 3085.16C1463.45 3080.3 1471.31 3075.72 1479.69 3071.69C1501.77 3061.09 1522.77 3056.66 1540.11 3056.79C1556.81 3056.91 1565.43 3061.05 1565.2 3063.14V3063.14Z" fill="black"/>
<path d="M2297.82 3016.57C2298.41 3019.14 2289.95 3024.6 2272.7 3028.14C2254.99 3031.77 2231.89 3032.36 2206.84 3026.95C2194.91 3024.37 2183.64 3020.67 2173.35 3016.16C2144.06 2998.71 2126.51 2984.91 2128.57 2981.06C2130.62 2977.21 2151.75 2984.02 2181.57 2998.09C2191.34 3001.25 2201.5 3004.04 2212.24 3006.34C2255.38 3015.56 2296.57 3011.08 2297.82 3016.57V3016.57Z" fill="black"/>
<defs>
<filter id="filter0_f_2_3" x="951.462" y="1473.2" width="199.468" height="216.64" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="10.3119" result="effect1_foregroundBlur_2_3"/>
</filter>
<filter id="filter1_f_2_3" x="1135.42" y="1676.67" width="94.502" height="96.079" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="4.72782" result="effect1_foregroundBlur_2_3"/>
</filter>
<filter id="filter2_f_2_3" x="2224.19" y="1317.8" width="199.468" height="216.64" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="10.3119" result="effect1_foregroundBlur_2_3"/>
</filter>
<filter id="filter3_f_2_3" x="2145.2" y="1521.27" width="94.5021" height="96.079" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="4.72782" result="effect1_foregroundBlur_2_3"/>
</filter>
<filter id="filter4_f_2_3" x="1781.61" y="1777.56" width="58.7359" height="38.5579" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="2.52106" result="effect1_foregroundBlur_2_3"/>
</filter>
<radialGradient id="paint0_radial_2_3" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(1760.99 1829.81) rotate(-0.182296) scale(306.481 287.176)">
<stop stop-color="#CC3100"/>
<stop offset="1" stop-color="#DE6B00"/>
</radialGradient>
<radialGradient id="paint1_radial_2_3" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2373.33 907.327) rotate(63.7909) scale(608.272 241.85)">
<stop stop-color="#FF927A"/>
<stop offset="1" stop-color="#F7C199"/>
</radialGradient>
<radialGradient id="paint2_radial_2_3" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(785.008 1066.98) rotate(-157.738) scale(359.552 439.05)">
<stop stop-color="#FF927A"/>
<stop offset="1" stop-color="#F7C199"/>
</radialGradient>
<linearGradient id="paint3_linear_2_3" x1="1257.34" y1="3813.75" x2="1136.44" y2="3481.28" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<linearGradient id="paint4_linear_2_3" x1="2481.02" y1="3700.43" x2="2528.01" y2="3388.4" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<linearGradient id="paint5_linear_2_3" x1="1465.89" y1="3071.73" x2="1527.85" y2="3160.89" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<linearGradient id="paint6_linear_2_3" x1="2205.57" y1="3007.9" x2="2200.48" y2="3085.58" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 27 KiB

73
static/img/yrblsad.svg Normal file
View file

@ -0,0 +1,73 @@
<svg width="2959" height="3706" viewBox="0 0 2959 3706" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.997" d="M316.789 2931.12C315.488 2929.29 342.101 2913.78 372.838 2868.23C384.205 2851.41 395.682 2829.37 402.48 2802.88C407.785 2782.32 410.27 2759.1 408.909 2733.66C407.69 2710.88 403.393 2686.99 395.976 2661.83V2661.83C382.3 2615.37 359.257 2568.62 326.569 2519.31C298.838 2477.58 265.182 2435.96 225.052 2395.73C208.608 2379.25 191.087 2363.05 172.444 2347.71C157.209 2335.18 141.225 2323.1 124.379 2312.5C111.765 2304.63 99.0872 2297.4 86.1465 2292.93C81.4965 2291.35 77.2099 2290.09 73.3454 2289.68C70.3614 2289.5 68.2282 2289.3 67.36 2289.79C67.103 2290.02 66.986 2289.93 67.7268 2289.46C67.8742 2288.79 67.916 2289.67 67.402 2291.25V2291.25C66.8491 2293.83 67.2734 2297.48 67.8385 2301.99C68.763 2308.14 70.6571 2314.59 72.9592 2321.43V2321.43C79.957 2342.07 90.3586 2362.14 101.941 2382.98C118.976 2413.51 138.274 2443.25 159.063 2473.54C239.086 2574.41 349.687 2660.96 481.224 2708.82C588.471 2748.15 706.505 2762.42 824.643 2753.29C866.817 2749.58 908.547 2739.08 939.471 2714.96C946.162 2709.88 952.392 2704.14 958.034 2697.88C971.642 2682.77 981.817 2664.63 986.785 2645.36C993.4 2620.4 992.269 2593.07 983.767 2568.69C975.601 2545.97 961.347 2525.28 942.318 2513.53C918.401 2498.17 890.181 2489.01 861.448 2485.7C828.124 2482.05 793.861 2487.36 765.252 2502.39C748.435 2511.06 733.146 2523.06 719.946 2537.05C703.762 2554.16 690.691 2574.62 680.006 2596.35C647.54 2662.01 637.627 2738.34 633.783 2811.39C631.492 2858.76 639.748 2905.63 657.74 2947.16C674.348 2985.79 699.212 3020.25 727.85 3049.36C755.245 3077.18 786.301 3100.41 818.625 3119.3C845.995 3135.23 873.674 3148.13 901.953 3156.71C916.938 3161.58 935.105 3161.55 953.657 3162.06C981.591 3162.53 1010.48 3161.41 1037.44 3160.48C1120.97 3157.55 1186.59 3155.58 1255.49 3159.41C1258.01 3159.67 1260.93 3159.01 1263.71 3157.85C1267.08 3156.47 1270.42 3153.91 1273.73 3150.93C1282.8 3142.7 1289.74 3131.12 1296.02 3119.67C1304.49 3103.94 1311.23 3087.27 1316.96 3071.71C1324.16 3052.16 1330.13 3032.79 1335.12 3015.45C1347.23 2973.37 1356.5 2932.2 1361.78 2909.03C1368.62 2876.64 1372.92 2860.42 1374.61 2860.7C1376.3 2860.97 1375.37 2877.73 1371.82 2910.71V2910.71C1368.73 2935.64 1362.81 2975.3 1352.55 3019.95C1348.43 3037.86 1343.3 3057.89 1336.77 3078.48C1331.6 3094.81 1325.21 3112.65 1316.67 3130.22C1310.63 3142.89 1302.73 3156.75 1290.99 3168.72C1286.56 3173.24 1281.1 3177.52 1274.47 3180.82C1268.55 3183.74 1261.74 3185.39 1254.47 3185.26C1186.38 3183.73 1122.9 3187.53 1038.93 3192.43C1012.03 3194.02 982.698 3195.8 953.459 3195.94C935.016 3196.23 913.838 3196.25 892.086 3190.34C860.467 3181.34 829.909 3167.88 800.35 3151.26C765.137 3131.53 731.042 3106.84 700.477 3076.77C668.369 3045.23 640.218 3007.16 620.629 2963.48C599.562 2916.19 589.495 2863.25 591.598 2809.55C594.222 2733.83 604.742 2651.95 640.214 2577.11C652.15 2552.07 667.567 2527.86 687.265 2506.54C703.474 2489.04 722.685 2473.88 744.379 2462.43C781.862 2442.93 824.765 2435.76 866.445 2440.38C901.541 2444.1 936.315 2455.43 966.972 2474.79C996.013 2493.63 1016.6 2522.16 1027.31 2553.48V2553.48C1038.91 2586.65 1040.44 2622.98 1031.5 2657.13C1024.34 2683.95 1010.73 2708.48 992.439 2728.83C984.857 2737.27 976.473 2744.98 967.414 2751.83C926.027 2782.52 876.166 2796.04 828.18 2799.26C703.899 2808.78 579.433 2793.06 465.731 2750.76C325.525 2698.22 209.253 2605.43 125.942 2497.69C104.813 2466.19 84.9637 2434.73 67.2313 2402.07C55.3916 2380.34 44.3348 2357.9 36.3566 2333.64V2333.64C33.6731 2325.54 31.3734 2316.86 30.0211 2307.57C28.9492 2300.97 28.6637 2293.32 29.9722 2284.91C30.8048 2278.53 33.7282 2271.54 39.1215 2264.8C44.6302 2258.8 51.1436 2255 57.9177 2253.4C65.6381 2251.65 72.5521 2251.65 78.3106 2252.64C85.8795 2253.76 92.7209 2255.75 98.8267 2258.08C115.658 2264.44 130.588 2273.11 144.014 2282.01C162.336 2294.05 179.275 2307.32 195.03 2320.84C214.373 2337.42 232.368 2354.74 249.101 2372.26C289.906 2414.94 323.84 2459.09 351.487 2503.24C384.143 2555.26 406.809 2605.59 419.621 2655.32C426.578 2682.37 430.13 2708.29 430.416 2732.98C430.737 2760.6 426.738 2785.78 419.794 2807.86C410.802 2836.34 396.954 2859.18 383.542 2876.09C346.533 2922.69 316.167 2930.24 316.792 2931.12L316.789 2931.12Z" fill="black"/>
<path d="M1168.86 2147.45C1168.86 2147.45 1174.91 2189.77 1126.55 2316.71C1078.19 2443.66 1075.16 2733.81 1050.98 2797.29C1026.8 2860.76 893.814 3072.33 924.039 3259.73C954.264 3447.12 1102.37 3713.1 1283.71 3646.6C1465.06 3580.11 1428.79 3592.2 1428.79 3592.2C1428.79 3592.2 1954.71 3707.05 2302.29 3507.57C2380.88 3543.84 2429.23 3574.06 2547.11 3504.55C2664.99 3435.03 2725.44 3244.61 2722.41 3114.65C2719.39 2984.68 2532 2700.57 2510.84 2640.12C2489.68 2579.67 2411.1 2283.46 2371.81 2159.54C2332.51 2035.62 2362.74 2014.46 2362.74 2014.46L1168.86 2147.45Z" fill="#DE5700" stroke="black" stroke-width="46.0804"/>
<path d="M2910.99 15.367C2810.67 16.4868 2399.36 32.4575 2314.62 125.748C2227.59 221.545 2173.88 368.999 2157.21 419.478C2059.12 356.561 1915.41 355.12 1915.41 355.12C1915.41 355.12 2000.05 327.92 2090.72 303.741C1933.55 249.336 1731.05 297.692 1731.05 297.692C1731.05 297.692 1816.06 254.536 1897.66 181.997C1770.72 215.244 1628.28 231.198 1537.61 285.603C1534.34 256.983 1479.51 292.115 1564.25 174.208C1331.52 231.635 1168.86 376.283 1069.11 460.912C1081.2 385.351 1085.97 396.401 1122.24 311.772C984.85 406.889 945.872 455.871 915.959 529.819C884.785 472.227 802.353 331.66 698.786 248.138C566.279 141.277 -48.0541 314.703 20.3368 442.936C88.7277 571.169 253.044 550.321 295.788 819.61C338.532 1088.9 643.216 1098.74 643.216 1098.74C645.435 1097.95 647.639 1097.05 649.836 1096.13C627.255 1167.82 607.109 1272.5 591.923 1444.97C519.258 1553.97 513.208 1597.36 504.66 1637.96C575.188 1603.77 583.374 1556.11 634.667 1543.29C589.785 1618.09 587.651 1720.68 606.886 1883.1C643.218 1791.2 641.076 1793.34 679.546 1765.56C690.232 1874.55 713.747 1934.4 741.53 1968.59C752.217 1908.75 784.275 1885.25 784.275 1885.25C784.275 1885.25 805.648 2015.62 867.627 2105.38C880.451 2026.3 895.409 2013.48 895.409 2013.48C895.409 2013.48 1143.32 2338.33 1775.94 2304.14C2408.55 2269.94 2588.08 1833.95 2588.08 1833.95C2588.08 1833.95 2600.91 1889.52 2600.91 1910.89C2647.93 1842.5 2677.85 1701.44 2677.85 1701.44C2677.85 1701.44 2712.04 1782.65 2703.49 1833.95C2741.96 1769.83 2750.51 1611.68 2733.41 1539.02C2793.25 1603.13 2844.55 1624.51 2844.55 1624.51C2844.55 1624.51 2712.04 1393.69 2707.76 1355.22C2703.49 1316.75 2801.81 1410.78 2801.81 1410.78C2801.81 1410.78 2740.21 1308.23 2724.86 1280.41C2667.66 1176.75 2613.36 987.392 2537.11 859.689C2601.1 818.088 2795.1 718.757 2787.56 503.664C2778.95 258.194 2898.72 176.103 2940.26 51.0386C2948.69 25.6348 2936.56 15.0816 2910.99 15.367V15.367Z" fill="#DE5700"/>
<path d="M1168.86 2147.45C1168.86 2147.45 1174.91 2189.77 1126.55 2316.71C1078.19 2443.66 1075.16 2733.81 1050.98 2797.29C1026.8 2860.76 893.814 3072.33 924.039 3259.73C954.264 3447.12 1102.37 3713.1 1283.71 3646.6C1465.06 3580.11 1428.79 3592.2 1428.79 3592.2C1428.79 3592.2 1954.71 3707.05 2302.29 3507.57C2380.88 3543.84 2429.23 3574.06 2547.11 3504.55C2664.99 3435.03 2725.44 3244.61 2722.41 3114.65C2719.39 2984.68 2532 2700.57 2510.84 2640.12C2489.68 2579.67 2411.1 2283.46 2371.81 2159.54C2332.51 2035.62 2362.74 2014.46 2362.74 2014.46L1168.86 2147.45Z" fill="#DE5700"/>
<path d="M1948.55 2060.6L1565.32 2103.28C1414.45 2137.89 1297.2 2180.18 1297.2 2180.18C1297.2 2180.18 1228.81 2594.8 1241.64 2710.21C1254.46 2825.62 1181.79 3000.87 1220.26 3176.12C1253.86 3329.16 1320.07 3491.98 1566.89 3613.34C1718.29 3630.31 1968.48 3639.97 2185.07 3561.45C2288.91 3477.48 2362.98 3368.43 2391.46 3282.98C2455.58 3090.63 2378.64 2757.23 2348.72 2688.84C2318.79 2620.45 2352.99 2406.72 2186.29 2163.08C2140.34 2095.93 2052.15 2067.14 1948.55 2060.6V2060.6Z" fill="#F7EDE9"/>
<path opacity="0.6" d="M2910.99 15.367C2810.67 16.4868 2399.36 32.4575 2314.62 125.748C2227.59 221.545 2173.88 368.999 2157.21 419.478C2059.12 356.561 1915.41 355.12 1915.41 355.12C1915.41 355.12 2000.05 327.92 2090.72 303.741C1933.55 249.336 1731.05 297.692 1731.05 297.692C1731.05 297.692 1816.06 254.536 1897.66 181.997C1770.72 215.244 1628.28 231.198 1537.61 285.603C1538.99 259.97 1477.23 293.202 1564.25 174.208C1331.52 231.635 1168.86 376.283 1069.11 460.912C1081.2 385.351 1085.97 396.401 1122.24 311.772C984.85 406.889 945.872 455.871 915.959 529.819C884.785 472.227 802.353 331.66 698.786 248.138C566.279 141.277 -48.0541 314.703 20.3368 442.936C88.7277 571.169 253.044 550.321 295.788 819.61C338.532 1088.9 643.216 1098.74 643.216 1098.74C645.435 1097.95 647.639 1097.05 649.836 1096.13C627.255 1167.82 607.109 1272.5 591.923 1444.97C519.258 1553.97 514.209 1598.36 505.661 1638.96C576.188 1604.77 583.374 1556.11 634.667 1543.29C589.785 1618.09 587.651 1720.68 606.886 1883.1C643.218 1791.2 641.076 1793.34 679.546 1765.56C690.232 1874.55 713.747 1934.4 741.53 1968.59C752.217 1908.75 784.275 1885.25 784.275 1885.25C784.275 1885.25 805.648 2015.62 867.627 2105.38C880.451 2026.3 895.409 2013.48 895.409 2013.48C895.409 2013.48 1143.32 2338.33 1775.94 2304.14C2408.55 2269.94 2588.08 1833.95 2588.08 1833.95C2588.08 1833.95 2600.91 1889.52 2600.91 1910.89C2647.93 1842.5 2677.85 1701.44 2677.85 1701.44C2677.85 1701.44 2712.04 1782.65 2703.49 1833.95C2741.96 1769.83 2750.51 1611.68 2733.41 1539.02C2793.25 1603.13 2844.55 1624.51 2844.55 1624.51C2844.55 1624.51 2712.04 1393.69 2707.76 1355.22C2703.49 1316.75 2801.81 1410.78 2801.81 1410.78C2801.81 1410.78 2740.21 1308.23 2724.86 1280.41C2667.66 1176.75 2613.36 987.392 2537.11 859.689C2601.1 818.088 2801.11 718.757 2793.56 503.664C2784.96 258.194 2898.72 176.103 2940.26 51.0386C2948.69 25.6348 2936.56 15.0816 2910.99 15.367V15.367Z" fill="url(#paint0_radial_28_46)"/>
<path d="M1793.93 1625.72C1692.31 1626.01 1639.62 1670.45 1602.82 1690.75C1443.85 1877.11 1124.01 1774.44 950.98 1898.07C921.059 1919.44 879.383 2034.85 879.383 2034.85L881.565 2043.13C889.307 2018.8 895.409 2013.48 895.409 2013.48C895.409 2013.48 1143.32 2338.33 1775.94 2304.14C2286.01 2276.56 2501.41 1987.9 2565.77 1877.06C2559.76 1821.08 2542.31 1746.84 2491.91 1744.19C2410.7 1739.91 2075.15 1712.12 1972.56 1656.56C1930.89 1633.98 1863.46 1625.52 1793.93 1625.72V1625.72Z" fill="#F7EDE9"/>
<path d="M1670.59 1677.46C1653.7 1635.82 1858.76 1600.28 1862.52 1639.68C1866.61 1682.55 1812.65 1760.58 1785.45 1765.11C1758.24 1769.64 1688.63 1721.93 1670.59 1677.46V1677.46Z" fill="black"/>
<g opacity="0.8" filter="url(#filter0_f_28_46)">
<path d="M1795.15 1641.88C1797.06 1634.19 1809.39 1629.26 1822.69 1630.88C1835.98 1632.49 1845.21 1640.04 1843.29 1647.73C1841.38 1655.43 1829.05 1660.35 1815.75 1658.74C1802.45 1657.12 1793.23 1649.57 1795.15 1641.88Z" fill="#BEBEBE"/>
</g>
<path opacity="0.8" d="M1797.09 1642.11C1798.83 1635.16 1810.16 1630.73 1822.38 1632.22C1834.6 1633.7 1843.1 1640.55 1841.35 1647.5C1839.61 1654.46 1828.28 1658.89 1816.06 1657.4C1803.83 1655.91 1795.34 1649.07 1797.09 1642.11Z" fill="#DEDEDE"/>
<path d="M2839.03 126.979C2750.83 205.43 2490.04 199.914 2389.32 331.49C2311.81 432.749 2293.15 545.208 2382.91 699.087C2429.76 779.407 2491.15 828.243 2540.37 857.529C2656.85 814.594 2791.93 737.805 2791.56 525.669C2791.4 431.967 2868.09 265.271 2862.97 214.318C2865.39 180.456 2897.45 75.0209 2839.03 126.979V126.979Z" fill="url(#paint1_radial_28_46)"/>
<path d="M135.341 546.877C204.087 610.736 275.71 693.122 295.788 819.61C335.05 1066.97 582.025 1072.54 635.159 1095.33C678.647 1047.5 747.7 954.793 774.947 808.594C815.021 593.571 743.572 440.231 630.27 356.086C544.242 292.197 465.345 399.217 373.009 410.597C226.391 428.666 137.346 442.883 104.936 460.272C73.1798 477.31 100.208 513.662 135.341 546.877V546.877Z" fill="url(#paint2_radial_28_46)"/>
<path d="M2910.99 15.367C2810.67 16.4868 2399.36 32.4575 2314.62 125.748C2227.59 221.545 2173.88 368.999 2157.21 419.478C2059.12 356.561 1915.41 355.12 1915.41 355.12C1915.41 355.12 2000.05 327.92 2090.72 303.741C1933.55 249.336 1731.05 297.692 1731.05 297.692C1731.05 297.692 1816.06 254.536 1897.66 181.997C1770.72 215.244 1628.28 231.198 1537.61 285.603C1544.1 286.111 1479.62 292.085 1564.25 174.208C1331.52 231.635 1168.86 376.283 1069.11 460.912C1081.2 385.351 1085.97 396.401 1122.24 311.772C984.85 406.889 945.872 455.871 915.959 529.819C884.785 472.227 802.353 331.66 698.786 248.138C566.279 141.277 -48.0541 314.703 20.3368 442.936C88.7277 571.169 253.044 550.321 295.788 819.61C338.532 1088.9 643.216 1098.74 643.216 1098.74C645.435 1097.95 647.639 1097.05 649.836 1096.13C627.255 1167.82 607.109 1272.5 591.923 1444.97C519.258 1553.97 513.208 1598.36 504.66 1638.96C575.188 1604.77 583.374 1556.11 634.667 1543.29C589.785 1618.09 587.651 1720.68 606.886 1883.1C643.218 1791.2 641.076 1793.34 679.546 1765.56C690.232 1874.55 713.747 1934.4 741.53 1968.59C752.217 1908.75 784.275 1885.25 784.275 1885.25C784.275 1885.25 805.648 2015.62 867.627 2105.38C880.451 2026.3 895.409 2013.48 895.409 2013.48C895.409 2013.48 1143.32 2338.33 1775.94 2304.14C2408.55 2269.94 2588.08 1833.95 2588.08 1833.95C2588.08 1833.95 2600.91 1889.52 2600.91 1910.89C2647.93 1842.5 2677.85 1701.44 2677.85 1701.44C2677.85 1701.44 2712.04 1782.65 2703.49 1833.95C2741.96 1769.83 2750.51 1611.68 2733.41 1539.02C2793.25 1603.13 2844.55 1624.51 2844.55 1624.51C2844.55 1624.51 2712.04 1393.69 2707.76 1355.22C2703.49 1316.75 2801.81 1410.78 2801.81 1410.78C2801.81 1410.78 2740.21 1308.23 2724.86 1280.41C2667.66 1176.75 2613.36 987.392 2537.11 859.689C2601.1 818.088 2797.11 782.772 2789.56 567.679C2780.95 322.209 2898.72 176.103 2940.26 51.0386C2948.69 25.6348 2936.56 15.0816 2910.99 15.367V15.367Z" stroke="black" stroke-width="30.7203" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1174.32 3623.87C1099.51 3499.91 1063.06 3415.08 1057.84 3359.39C1053.03 3308.09 1046.62 3246.12 1083.48 3276.57C1094.17 3231.69 1092.03 3206.04 1119.82 3218.87C1147.6 3231.69 1166.83 3259.47 1166.83 3259.47C1166.83 3259.47 1162.56 3195.36 1190.34 3216.73C1241.43 3247.48 1332.69 3536.32 1322.06 3618.13C1310.38 3708.02 1240.21 3727.57 1174.32 3623.87V3623.87Z" fill="url(#paint3_linear_28_46)" stroke="black" stroke-width="23.0402"/>
<path d="M2564.78 3516.43C2617.78 3381.7 2639.52 3291.97 2635.35 3236.19C2631.5 3184.81 2627.45 3122.63 2596.2 3158.83C2578.16 3116.37 2575.97 3090.73 2550.72 3108.02C2525.48 3125.31 2511.17 3155.92 2511.17 3155.92C2511.17 3155.92 2504.65 3092 2480.83 3117.72C2435.61 3156.59 2393.99 3456.62 2418.16 3535.5C2444.71 3622.17 2517.17 3629.7 2564.78 3516.43V3516.43Z" fill="url(#paint4_linear_28_46)" stroke="black" stroke-width="23.0402"/>
<path d="M1547.64 2230.3C1547.64 2230.3 1409.61 2394.34 1345.59 2428.35C1281.58 2462.36 1537.64 2590.38 1537.64 2590.38C1537.64 2590.38 1687.67 2386.34 1693.67 2308.32L1699.68 2230.3H1547.64Z" fill="#F7EDE9"/>
<path d="M1552.45 2225.31C1571.48 2258.43 1605.03 2280.42 1639.99 2293.91C1656.36 2300.07 1673.27 2305.1 1690.57 2307.77C1699.84 2271.3 1705.7 2233.76 1705.72 2196.08C1705.12 2188.67 1704.84 2178.86 1697.33 2174.95C1689.06 2172.5 1682.13 2179.41 1675.63 2183.33C1679.28 2173.01 1676.81 2160.78 1670.04 2152.31C1662.92 2145.38 1653.3 2153.18 1648.01 2158.59C1642.73 2163.3 1639.14 2169.69 1633.7 2174.14C1630.98 2168.39 1635.15 2158.49 1628.69 2153.34C1621.45 2147.74 1614.83 2157.89 1609.5 2161.85C1589.24 2181.83 1571.08 2203.83 1552.45 2225.31V2225.31Z" fill="url(#paint5_linear_28_46)"/>
<path d="M1253.67 2495.08C1253.67 2495.08 1253.7 2495.06 1253.71 2494.98C1253.73 2494.91 1253.75 2494.77 1253.73 2494.55C1253.85 2494.31 1254.06 2494 1254.36 2493.63C1254.95 2492.9 1255.9 2491.91 1257.19 2490.66C1259.68 2488.27 1263.48 2484.94 1268.52 2480.67C1277.89 2472.76 1291.17 2462 1308.59 2447.97C1332.04 2429.09 1377.21 2393.23 1416.14 2359.67C1435.84 2342.71 1453.06 2323.43 1472.83 2300.71C1493.32 2277.11 1512.59 2253.5 1534.3 2226.92C1550.64 2206.9 1568.16 2185.04 1586.51 2164.5C1592.19 2158.11 1598.29 2151.39 1605.38 2145.13C1607.41 2143.27 1610.03 2141.16 1613.44 2139.16C1614.53 2138.47 1616.19 2137.74 1618.44 2137.08C1620 2136.39 1622.68 2136.37 1626.4 2137.18C1631.32 2138.25 1636.42 2142 1640.22 2148.66C1642.23 2154.09 1642.53 2158.57 1641.93 2161.68C1641.68 2164.89 1641.2 2166.62 1641.38 2166.88C1641.51 2164.86 1639.93 2163.24 1636.43 2160.78C1633.57 2160.8 1632.55 2160.6 1632.18 2161.3C1633.23 2160.49 1634.51 2158.06 1636.94 2154.8C1639.08 2151.42 1642.54 2147.44 1647.9 2143.9C1654.96 2140.17 1662.36 2139.65 1668.71 2141.79C1674.35 2143.23 1679.64 2147.46 1683.14 2154.38C1685.12 2160.15 1685.36 2164.93 1684.86 2168.28C1684.65 2171.9 1684.19 2174.36 1684.38 2175.65C1684.92 2175.76 1684.05 2175.31 1682.21 2172.96C1680.34 2172.13 1679.39 2171.73 1679.02 2171.98C1678.97 2172.08 1679.56 2171.81 1680.8 2171.48C1683.17 2170.62 1686.96 2168.95 1692.53 2167.86C1693.69 2167.59 1695.01 2167.47 1696.48 2167.52C1698.3 2167.58 1700.34 2167.9 1702.57 2168.52C1707.01 2170.25 1710.27 2172.9 1712.21 2176.09C1717.7 2186.05 1718.08 2195.25 1717.36 2201.51C1715.45 2275.24 1695.21 2345.41 1666.81 2407C1636.86 2472 1598.69 2527.26 1563.18 2571.11C1524.08 2619.42 1486.97 2655.52 1460.54 2678.9C1446.05 2691.72 1434.5 2700.95 1426.26 2707C1421.97 2710.14 1418.65 2712.38 1416.29 2713.78C1415.08 2714.49 1414.14 2714.98 1413.46 2715.25C1413.12 2715.38 1412.84 2715.46 1412.63 2715.49C1412.53 2715.5 1412.44 2715.5 1412.37 2715.49C1412.3 2715.47 1412.24 2715.44 1412.21 2715.4C1412.17 2715.35 1412.14 2715.31 1412.16 2715.22C1412.16 2715.15 1412.17 2715.06 1412.21 2714.96C1412.28 2714.77 1412.41 2714.51 1412.62 2714.21C1413.02 2713.6 1413.68 2712.78 1414.6 2711.74C1416.38 2709.72 1419.19 2706.81 1422.87 2703.08C1430.3 2695.57 1440.14 2685.87 1453.75 2671.8C1477.95 2646.79 1512.96 2609.16 1549.7 2560.56C1583.1 2516.35 1619.21 2461.46 1647.22 2398.15C1673.71 2338.25 1692.69 2270.9 1694.25 2201.13C1693.64 2194.48 1694.52 2189.65 1692.9 2188.82C1693.08 2189.33 1693.81 2189.75 1695.21 2190.46C1695.85 2190.55 1696.22 2190.64 1696.36 2190.69C1696.47 2190.73 1696.44 2190.74 1696.24 2190.7C1694.94 2190.72 1692.35 2192.09 1688.11 2193.43C1686.33 2194.1 1683.84 2194.74 1680.61 2195.05C1677.54 2195.49 1673.78 2194.67 1669.64 2192.37C1663.69 2187.36 1661.05 2181.78 1661.31 2177V2177C1661.15 2172.39 1661.62 2168.95 1661.82 2166.69C1661.73 2164.15 1662.06 2162.83 1661.8 2163.16C1662.81 2164.08 1662.41 2164.31 1661.87 2163.8C1660.62 2163.58 1659.43 2163.35 1659.67 2163.67C1658.82 2163.83 1657.66 2165.67 1655.61 2168.16V2168.16C1654.1 2170.4 1651.9 2173.87 1648.11 2177.76C1643.82 2182.24 1637.07 2184.15 1629.07 2182.43C1622.17 2178.82 1618.62 2173.59 1618.58 2168V2168C1618.53 2163.66 1619.06 2160.83 1619.25 2159.47C1619.14 2157.69 1619.49 2157.05 1619.48 2158C1620.8 2159.19 1620.41 2159.57 1619.62 2158.83C1622.22 2159.29 1623.69 2159.41 1624.13 2159.02C1624.75 2158.78 1624.9 2158.78 1624.53 2158.91C1623.44 2159.44 1622.06 2160.64 1620.22 2162.16C1614.36 2167.19 1608.83 2173.23 1603.11 2179.48C1585.13 2199.21 1567.45 2220.73 1550.73 2240.56C1528.73 2266.69 1508.62 2290.39 1487.43 2313.69C1467.11 2336.07 1448.51 2355.66 1427.18 2372.92C1384.59 2407.27 1342.02 2437.75 1315.01 2456.55C1296.77 2469.25 1282.19 2478.95 1271.97 2485.38C1266.36 2488.91 1262.02 2491.49 1258.97 2493.12C1257.38 2493.97 1256.14 2494.55 1255.26 2494.88C1254.81 2495.05 1254.45 2495.15 1254.19 2495.19C1253.98 2495.1 1253.85 2495.08 1253.77 2495.07C1253.7 2495.07 1253.67 2495.08 1253.67 2495.08L1253.67 2495.08Z" fill="black"/>
<path d="M1550.29 2223.04C1552.02 2222.06 1555.96 2226.15 1563.08 2233.04C1570.64 2240.36 1579.91 2248.83 1593.5 2258.19C1600.35 2262.92 1607.58 2267.34 1615.33 2271.58C1622.75 2275.64 1630.22 2279.3 1637.63 2282.7C1670.11 2293.53 1691.56 2303.44 1690.46 2307.15C1689.37 2310.85 1665.88 2307.47 1631.98 2298.68C1623.76 2295.61 1615.41 2291.88 1607.22 2287.42C1598.68 2282.76 1590.69 2277.53 1583.42 2271.78C1569.42 2260.68 1560.14 2248.95 1554.8 2239.31C1549.55 2229.84 1548.78 2223.89 1550.29 2223.04V2223.04Z" fill="black"/>
<path d="M2182.1 2821.65C2148.09 2821.91 2115.82 2806.33 2089.83 2785.3C2067.85 2767.28 2048.77 2745.55 2034 2721.26C2022.45 2753.72 2010.59 2786.27 2003.4 2820.03C2001.39 2826.99 2000.64 2839.35 2011.42 2837.84C2021.24 2837.24 2029.53 2831.07 2038.79 2828.73C2036.92 2833.96 2031.26 2838.31 2029.04 2843.95C2024.34 2852.66 2021.14 2866.11 2030.41 2873.05C2042.08 2880.13 2056.74 2876.96 2068.8 2872.51C2076.8 2870.19 2067.29 2882.14 2069.42 2886.32C2067.95 2894.94 2073.56 2906.98 2083.99 2903.55C2096.65 2899.92 2106.5 2890.47 2117.11 2883.12C2140.83 2864.95 2162.39 2844.07 2182.1 2821.65V2821.65Z" fill="url(#paint6_linear_28_46)"/>
<path d="M2124.7 2361.37C2124.7 2361.37 2124.69 2361.37 2124.7 2361.37C2126.63 2361.25 2130.12 2386.35 2134.88 2434.81C2135.35 2453.78 2134.73 2477.74 2130.57 2503.41C2127.18 2524.43 2120.99 2548.65 2108.67 2571.61C2096.65 2593.93 2086.27 2617.36 2075.16 2644.03C2064.04 2670.75 2053.24 2698.81 2042.73 2728.46C2034.5 2751.7 2026.3 2775.9 2019.64 2800.39C2017.5 2808.27 2015.49 2816 2014.27 2823.56C2013.89 2825.98 2013.58 2828.06 2013.57 2829.79C2014.02 2831.42 2013.52 2831.12 2012.88 2828.64C2013.06 2828.52 2012.5 2828.22 2011.21 2827.25C2009.87 2826.84 2009.31 2826.6 2009.25 2826.77C2010.06 2826.98 2012.08 2825.6 2015.59 2824.07C2018.33 2822.53 2022.41 2820.34 2028.22 2818.83C2030.63 2818.04 2034.14 2818.05 2038.54 2819.25C2043.23 2821.27 2046.38 2824.16 2047.89 2827.45C2050.9 2835.35 2050.35 2842.05 2047.66 2846.36C2045.41 2850.98 2043.12 2854.21 2041.81 2856.58C2040.65 2859.24 2039.62 2860.95 2040.01 2861.51C2039.43 2861.99 2041.07 2863.68 2042.89 2866.07C2042.2 2865.98 2042.89 2865.88 2043.64 2865.99C2044.95 2866.01 2046.72 2865.44 2049 2864.68C2049.85 2864.39 2050.77 2864.08 2051.77 2863.76C2054.75 2862.59 2059 2861.02 2064.7 2860.23C2070.87 2859.25 2077.55 2861.93 2082.98 2868.44L2082.98 2868.44C2085.37 2872.89 2086.2 2876.48 2085.97 2878.82V2878.82C2086.05 2881.94 2085.82 2884.6 2085.52 2886.78C2084.98 2891.73 2084.11 2895.39 2084.32 2897.81C2084.65 2898.69 2084.3 2898.52 2083.76 2896.92C2082.02 2894.82 2080.59 2893.78 2078.89 2893.67C2078.04 2893.95 2078.68 2893.42 2080.68 2893.01V2893.01C2083.59 2892.01 2086.71 2890.26 2090.18 2888.27L2090.18 2888.27C2140.92 2854.85 2181.84 2810.27 2213.89 2764.4C2248.17 2715.46 2272.77 2664.59 2290.65 2620.8C2322.67 2511.91 2342.43 2450.89 2345.4 2451.7C2348.38 2452.52 2334.32 2515.13 2306.25 2625.93C2289.7 2671.41 2265.85 2724.43 2231.15 2776.22C2198.69 2824.56 2156.17 2871.74 2102.37 2907.71C2098.38 2910.13 2093.86 2912.59 2088.63 2914.6C2086.06 2915.87 2081.86 2916.84 2076.18 2916.55C2071.56 2916.09 2067.33 2913.5 2064.07 2908.9C2061.84 2904.53 2061.06 2900.99 2061.27 2898.63C2061.18 2892.46 2062.1 2887.6 2062.59 2884.02C2062.78 2882.14 2062.96 2880.71 2062.88 2879.75C2062.52 2878.92 2062.91 2879.21 2063.57 2880.99L2063.57 2880.99C2065.95 2882.79 2066.56 2883.6 2067.15 2883.22C2065.73 2883.19 2063.23 2884.37 2059.46 2885.58C2058.49 2885.95 2057.43 2886.34 2056.29 2886.71C2053.25 2887.71 2049.62 2888.62 2045.35 2889.06C2039.02 2889.69 2032.31 2887.55 2026.58 2882.45C2021.64 2878.11 2017.75 2871.14 2016.92 2862.1C2017.1 2855.05 2019.1 2849.42 2021.62 2845.41C2023.87 2841.36 2025.93 2838.6 2026.8 2836.58C2026.66 2835.47 2027.4 2835.63 2027.59 2838.26C2027.8 2839.09 2028.89 2839.83 2030.96 2840.94C2032.77 2841.23 2033.43 2841.45 2033.17 2841.25C2031.91 2841.29 2029.6 2842.82 2025.89 2844.53C2022.89 2846.28 2018.3 2848.41 2011.88 2849.46C2008.88 2849.97 2005.24 2849.48 2001.23 2847.77C1996.95 2845.35 1994.14 2842.37 1992.76 2839.32C1990.7 2834.14 1990.32 2830.66 1990.83 2829.24C1990.95 2825.7 1991.39 2822.55 1991.89 2819.79C1993.44 2810.89 1995.69 2802.43 1997.98 2794.38C2005.13 2769.04 2013.8 2744.45 2022.47 2721.1C2033.56 2691.25 2045.05 2663 2056.94 2636.2C2056.94 2636.2 2056.94 2636.2 2056.94 2636.2C2068.74 2609.56 2080.15 2585.7 2093.32 2563.01C2105.09 2542.96 2111.7 2520.53 2115.92 2500.68C2121.01 2476.68 2122.93 2453.52 2123.78 2435.1C2122.46 2387.18 2122.76 2361.68 2124.68 2361.37L2124.7 2361.37Z" fill="black"/>
<path d="M2175 2826.87C2174.44 2829.44 2164.46 2830.8 2147.34 2826.66C2129.78 2822.41 2108.61 2813.13 2088.24 2797.58C2078.48 2790.13 2069.81 2781.92 2062.37 2773.42C2043.37 2745.24 2033.41 2725.37 2036.91 2722.76C2040.4 2720.15 2056.55 2735.24 2077.5 2760.58C2085.04 2767.64 2093.09 2774.53 2101.89 2781.22C2120.61 2795.44 2137.36 2804.74 2152.67 2812.56C2166.96 2819.86 2175.65 2823.9 2175 2826.87V2826.87Z" fill="black"/>
<path opacity="0.969" d="M2271.02 1481.65C2270.98 1481.7 2270.96 1481.76 2270.93 1481.82C2270.3 1482.5 2269.52 1483.07 2268.45 1483.4C2266.31 1484.06 2263.43 1484.13 2259.51 1483.48C2251.72 1482.17 2240.55 1478.45 2225.78 1472.61C2195.05 1460.45 2150 1440.05 2094.71 1417.03C2083.82 1413.11 2066.88 1406.63 2047.14 1395.61C2042.15 1394.09 2032.43 1386.77 2019.12 1373.26C2005.68 1360.16 2000.71 1338.54 2004.65 1309.48V1309.48C2015.17 1285.72 2024.38 1273.62 2031.14 1272.29C2040.81 1265.93 2048.46 1262.35 2053.94 1260.86C2072.42 1254.93 2088.82 1252.2 2103.52 1250.56C2122.55 1247.86 2141.12 1246.81 2159.25 1246.97C2184.24 1247.19 2208.15 1249.72 2230.89 1253.25C2276.78 1260.23 2318.45 1271.46 2353.6 1283.35C2444.6 1317.86 2493.15 1346 2484.81 1358.31C2477.63 1368.89 2429.3 1366.68 2351.7 1352.28C2319.35 1347.49 2279.06 1341.07 2239.34 1336.79C2204.14 1333.35 2168.81 1329.86 2134.1 1332.29C2133.42 1332.34 2132.74 1332.39 2132.06 1332.44C2117.45 1333.99 2104.62 1334.71 2092.5 1336.9C2088.86 1337.69 2086.18 1337.74 2084.54 1337.85C2083.85 1338.92 2083.97 1336.16 2085.92 1331.01C2085.96 1323.35 2084.56 1319.35 2081.58 1317.6C2079.4 1317.18 2079.97 1318.08 2081.88 1320.29C2089.26 1327.57 2100.53 1333.47 2111.5 1339.38C2169.79 1370.45 2212.91 1401.57 2241.33 1428.53C2254.76 1441.26 2263.67 1452.08 2268.92 1460.88C2271.53 1465.26 2272.96 1468.94 2273.54 1472.03C2273.83 1473.57 2273.79 1474.92 2273.58 1476.1C2273.39 1476.64 2273.09 1477.16 2272.82 1477.63V1477.63C2283.36 1455.58 2295.93 1429.3 2306.47 1407.26C2306.56 1407.07 2306.56 1407.08 2306.47 1407.26C2329.9 1358.27 2248.02 1529.51 2271.45 1480.52C2271.32 1480.9 2271.19 1481.31 2271.02 1481.65L2271.02 1481.65Z" fill="black"/>
<path opacity="0.997" d="M2062.08 1928.03C2066.08 1963.78 2031.67 1988.95 1996.69 1993.07C1952.17 1998.32 1895.66 1971.73 1812.67 1981.01C1754.15 1987.55 1699.65 2020.18 1652.86 2030.03C1581.12 2045.14 1530.79 2037.18 1525.3 1988C1516.22 1906.75 1629.02 1827.46 1777.25 1810.9C1925.48 1794.33 2053 1846.78 2062.08 1928.03V1928.03Z" fill="black"/>
<path opacity="0.969" d="M928.618 1507.23C938.738 1515.86 985.438 1505.63 1058.08 1479.04C1088.78 1468.85 1127.78 1455.32 1166.09 1444.19C1201.06 1434.49 1236.16 1424.44 1272.09 1420.85C1274.07 1420.72 1276.03 1420.58 1277.96 1420.44C1290.49 1419.5 1301.76 1418.33 1312.8 1418.39C1316.66 1418.53 1319.6 1418.1 1321.7 1417.99C1322.82 1418.82 1322.93 1416.45 1321.25 1412.65C1320.85 1406.53 1321.81 1403.64 1324 1402.45C1325.64 1402.66 1324.84 1404.21 1323.13 1406.79C1316.37 1415.86 1305.6 1423.98 1295.62 1431.73C1242.64 1472.89 1205.17 1511.48 1181.64 1543.57C1170.52 1558.73 1163.7 1571.17 1160.11 1581.02C1158.32 1585.91 1157.66 1589.9 1157.68 1593.16C1157.68 1594.78 1158.04 1596.16 1158.48 1597.34C1158.81 1597.86 1159.26 1598.34 1159.64 1598.77C1143.14 1572.13 1123.51 1540.47 1107.01 1513.83C1106.88 1513.63 1106.88 1513.63 1107.01 1513.83C1067.71 1450.43 1200.7 1665.03 1161.4 1601.63C1161.56 1602.08 1161.71 1602.62 1161.9 1603C1162.06 1603.17 1162.23 1603.33 1162.41 1603.48C1162.93 1603.91 1163.53 1604.25 1164.29 1604.43C1166.32 1604.89 1168.93 1604.66 1172.5 1603.49C1179.61 1601.16 1189.55 1595.86 1202.88 1587.73C1230.59 1570.82 1271.17 1543.07 1322 1510.73C1332.09 1505.08 1348.78 1495.65 1367.94 1481.3C1372.95 1479.1 1382.55 1469.79 1395.45 1453.3H1395.45C1408.68 1437.14 1411.42 1412.6 1403.47 1380.91V1380.91C1388.85 1356.01 1377.31 1343.97 1369.85 1343.56C1358.65 1338.09 1350.13 1335.4 1344.28 1334.74C1324.43 1331.51 1307.46 1331.4 1292.46 1332.26C1269.62 1332.69 1247.91 1335.32 1227.11 1339.44C1205.39 1343.75 1184.84 1349.64 1165.34 1356.17C1120.73 1370.95 1081.19 1389.4 1048.22 1407.42C960.49 1459.08 916.235 1496.67 928.618 1507.23V1507.23Z" fill="black"/>
<path d="M2570.51 1270.25C2570.51 1270.25 2611.95 1201.33 2707.84 1167.02C2803.74 1132.7 2924.6 1340.93 2570.51 1270.25Z" fill="#71E0E0"/>
<path opacity="0.997" d="M2773.75 1203.7C2773.35 1218.61 2757.87 1223.28 2737.72 1222.74C2717.56 1222.2 2700.36 1216.65 2700.76 1201.74C2701.16 1186.83 2717.82 1175.18 2737.98 1175.72C2758.13 1176.26 2774.15 1188.79 2773.75 1203.7V1203.7Z" fill="white"/>
<path d="M2715.89 1392.5C2715.89 1392.5 2772.4 1373.32 2843.17 1399.83C2913.95 1426.34 2882.64 1602.24 2715.89 1392.5Z" fill="#71E0E0"/>
<path opacity="0.997" d="M2862.94 1452.19C2855.56 1460.45 2844.55 1455.68 2833.39 1445.72C2822.23 1435.75 2815.15 1424.36 2822.52 1416.1C2829.89 1407.85 2844.91 1409.23 2856.08 1419.2C2867.24 1429.16 2870.31 1443.94 2862.94 1452.19V1452.19Z" fill="white"/>
<path d="M841.958 1500.18C841.958 1500.18 771.339 1461.71 671.266 1480.64C571.194 1499.57 572.326 1740.33 841.958 1500.18Z" fill="#71E0E0"/>
<path opacity="0.997" d="M632.987 1545.62C640.877 1558.28 656.592 1554.48 673.702 1543.82C690.813 1533.15 702.84 1519.65 694.949 1507C687.059 1494.34 666.792 1492.73 649.681 1503.39C632.57 1514.06 625.096 1532.97 632.987 1545.62V1545.62Z" fill="white"/>
<path d="M778.439 1679.19C778.439 1679.19 719.99 1691.24 672.36 1749.92C624.73 1808.6 740.752 1944.48 778.439 1679.19Z" fill="#71E0E0"/>
<path opacity="0.997" d="M681.813 1805.09C692.35 1808.48 699.433 1798.79 704.016 1784.55C708.599 1770.31 708.946 1756.9 698.41 1753.51C687.874 1750.12 675.617 1758.91 671.033 1773.16C666.45 1787.4 671.277 1801.7 681.813 1805.09V1805.09Z" fill="white"/>
<path d="M1833.6 1920.21C1830.99 1920.21 1828.37 1920.21 1825.74 1920.25C1816.01 1920.32 1806.14 1921.2 1796.18 1922.94C1702.44 1939.32 1636.6 1955.14 1607.38 2036.68C1621.25 2035.85 1636.48 2033.62 1652.86 2030.17C1699.65 2020.32 1754.15 1987.69 1812.67 1981.15C1895.67 1971.87 1952.17 1998.46 1996.69 1993.21C2001.8 1992.61 2006.89 1991.55 2011.86 1990.08C1974.97 1931.79 1909.4 1920.36 1833.6 1920.22V1920.21Z" fill="#DF6747"/>
<defs>
<filter id="filter0_f_28_46" x="1790.28" y="1625.95" width="57.8831" height="37.7055" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="2.30794" result="effect1_foregroundBlur_28_46"/>
</filter>
<radialGradient id="paint0_radial_28_46" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(1769.23 1677.78) rotate(-0.182296) scale(306.481 287.176)">
<stop stop-color="#CC3100"/>
<stop offset="1" stop-color="#DE6B00"/>
</radialGradient>
<radialGradient id="paint1_radial_28_46" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2381.57 755.292) rotate(63.7909) scale(608.272 241.85)">
<stop stop-color="#FF927A"/>
<stop offset="1" stop-color="#F7C199"/>
</radialGradient>
<radialGradient id="paint2_radial_28_46" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(793.252 914.947) rotate(-157.738) scale(359.552 439.05)">
<stop stop-color="#FF927A"/>
<stop offset="1" stop-color="#F7C199"/>
</radialGradient>
<linearGradient id="paint3_linear_28_46" x1="1265.58" y1="3661.71" x2="1144.68" y2="3329.24" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<linearGradient id="paint4_linear_28_46" x1="2489.26" y1="3548.4" x2="2536.25" y2="3236.36" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<linearGradient id="paint5_linear_28_46" x1="1615.27" y1="2298.63" x2="1651.45" y2="2196.26" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<linearGradient id="paint6_linear_28_46" x1="2095.19" y1="2779.79" x2="2057.55" y2="2847.94" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 32 KiB

109
static/img/yrblsec.svg Normal file
View file

@ -0,0 +1,109 @@
<svg width="2859" height="3858" viewBox="0 0 2859 3858" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_35_87)">
<path opacity="0.997" d="M229.331 2573.92C227.658 2571.29 287.004 2544.38 324.218 2448.2C337.11 2414.69 347.357 2369.08 337.943 2323.16C334.776 2307.96 329.583 2292.41 320.457 2279.96C313.372 2270.39 303.743 2262.04 292.932 2259.23C281.648 2255.61 267.954 2257.93 254.626 2263.16C231.995 2270.93 211.286 2285.24 190.078 2302.35C167.021 2283.54 134.978 2268.82 104.768 2273.7C81.902 2276.54 60.511 2295.24 49.4462 2318.86C3.74465 2410.06 71.315 2519.88 150.29 2625.09C150.29 2625.09 150.29 2625.09 150.29 2625.09C230.276 2725.89 340.979 2812.76 472.956 2860.92C580.106 2900.19 698.127 2914.49 816.398 2905.34C858.558 2901.63 900.297 2891.12 931.227 2867C941.601 2859.12 950.867 2849.65 958.548 2839.11C967.767 2826.46 974.702 2812.27 978.534 2797.4C985.145 2772.44 984.014 2745.1 975.509 2720.73V2720.73C967.343 2698.01 953.089 2677.33 934.061 2665.58C910.149 2650.23 881.933 2641.07 853.199 2637.76C819.885 2634.11 785.627 2639.42 757.021 2654.45C719.662 2673.22 691.325 2709.24 671.796 2748.4C639.342 2814.04 629.429 2890.35 625.585 2963.42C620.787 3054.16 660.729 3141.58 719.642 3201.36C770.676 3252.96 831.322 3289.74 893.723 3308.69C908.697 3313.56 926.857 3313.53 945.412 3314.04C973.343 3314.51 1002.22 3313.39 1029.19 3312.46C1112.71 3309.54 1178.34 3307.56 1247.24 3311.4C1252.48 3312.55 1259.26 3308.03 1265.44 3302.94C1274.49 3294.73 1281.43 3283.17 1287.71 3271.73C1306.29 3237.38 1318.13 3197.66 1326.75 3167.88C1349.83 3064.98 1363.32 3012.13 1366.36 3012.73C1369.41 3013.33 1361.94 3067.36 1344.36 3171.88C1344.36 3171.88 1344.36 3171.88 1344.36 3171.88C1337.33 3202.62 1327.04 3243.92 1308.44 3282.33C1302.39 3294.99 1294.5 3308.84 1282.76 3320.8C1274.53 3329.67 1261.97 3337.01 1246.23 3337.34C1178.13 3335.81 1114.64 3339.62 1030.69 3344.52C1003.79 3346.11 974.453 3347.89 945.212 3348.03C926.769 3348.32 905.587 3348.33 883.825 3342.43C815.106 3322.91 748.321 3284.25 692.192 3228.84C625.184 3162.88 579.614 3066.05 583.303 2961.59C585.929 2885.84 596.46 2803.96 631.931 2729.13C653.524 2683.25 688.026 2640.3 736.117 2614.43C773.614 2594.93 816.524 2587.77 858.202 2592.39C893.307 2596.11 928.083 2607.44 958.736 2626.81C987.785 2645.66 1008.37 2674.19 1019.07 2705.51V2705.51C1030.67 2738.69 1032.2 2775.02 1023.26 2809.17C1017.73 2829.86 1008.36 2849.2 995.965 2866.3C985.637 2880.55 973.211 2893.24 959.166 2903.86C917.766 2934.55 867.899 2948.06 819.932 2951.28C695.515 2960.79 571.075 2945 457.507 2902.73C317.198 2850.29 201.177 2757.52 118.223 2650.2V2650.2C32.6442 2545.24 -32.8981 2417.48 17.6801 2303.93C33.4423 2270.48 64.451 2246.14 100.199 2240.83C136.634 2236.45 169.491 2255.33 190.178 2280.49C205.009 2262.04 222.599 2245.98 243.989 2236.31C261.83 2229.19 281.993 2227.28 301.035 2233.04C318.973 2239.12 332.793 2251.36 341.852 2265.2C353.144 2282.35 358.941 2301.28 361.69 2318.87C370.075 2371.61 356.822 2420.33 340.993 2455.25C291.994 2563.91 225.032 2567.17 229.331 2573.92V2573.92Z" fill="black"/>
<path d="M1160.62 2299.49C1160.62 2299.49 1166.66 2341.8 1118.3 2468.75C1069.94 2595.69 1066.92 2885.85 1042.74 2949.32C1018.56 3012.79 885.57 3224.37 915.795 3411.76C946.02 3599.15 1094.12 3865.13 1275.47 3798.64C1456.82 3732.14 1420.55 3744.23 1420.55 3744.23C1420.55 3744.23 1946.46 3859.09 2294.05 3659.6C2372.63 3695.87 2420.99 3726.1 2538.87 3656.58C2656.74 3587.06 2717.19 3396.65 2714.17 3266.68C2711.15 3136.71 2523.75 2852.6 2502.6 2792.15C2481.44 2731.7 2402.86 2435.5 2363.56 2311.58C2324.27 2187.66 2354.5 2166.5 2354.5 2166.5L1160.62 2299.49Z" fill="#DE5700" stroke="black" stroke-width="46.0804"/>
<path d="M2798.72 15.367C2698.4 16.4866 2391.12 184.492 2306.37 277.783C2219.35 373.579 2165.64 521.033 2148.97 571.513C2050.88 508.595 1907.17 507.155 1907.17 507.155C1907.17 507.155 1991.8 479.955 2082.48 455.775C1925.31 401.371 1722.8 449.727 1722.8 449.727C1722.8 449.727 1813.47 349.989 1895.08 277.45C1768.13 310.697 1620.04 383.233 1529.36 437.638C1553.54 401.368 1595.86 362.076 1680.49 244.199C1447.75 301.626 1160.61 528.318 1060.87 612.947C1072.96 537.385 1103.19 489.025 1139.46 404.395C1002.07 499.513 937.628 607.905 907.715 681.853C876.542 624.261 794.11 483.695 690.543 400.173C558.035 293.312 45.0983 126.611 113.489 254.844C181.88 383.077 164.781 558.322 207.526 827.611C250.27 1096.9 634.972 1250.78 634.972 1250.78C637.192 1249.99 639.395 1249.09 641.592 1248.17C619.011 1319.85 598.866 1424.54 583.679 1597.01C511.014 1706.01 478.959 1727.38 470.41 1767.99C540.938 1733.8 575.13 1708.15 626.423 1695.32C581.542 1770.13 579.407 1872.71 598.642 2035.14C634.975 1943.24 632.833 1945.37 671.303 1917.59C681.988 2026.59 705.503 2086.43 733.287 2120.63C743.973 2060.78 776.031 2037.28 776.031 2037.28C776.031 2037.28 797.404 2167.65 859.383 2257.41C872.207 2178.34 887.165 2165.51 887.165 2165.51C887.165 2165.51 1135.08 2490.37 1767.7 2456.17C2400.31 2421.98 2579.84 1985.98 2579.84 1985.98C2579.84 1985.98 2592.66 2041.56 2592.66 2062.93C2639.68 1994.54 2669.6 1853.48 2669.6 1853.48C2669.6 1853.48 2703.8 1934.69 2695.25 1985.98C2733.72 1921.86 2742.26 1763.72 2725.17 1691.05C2785.01 1755.17 2836.31 1776.54 2836.31 1776.54C2836.31 1776.54 2703.79 1545.72 2699.52 1507.25C2695.25 1468.78 2793.56 1562.81 2793.56 1562.81C2793.56 1562.81 2731.97 1460.26 2716.62 1432.45C2659.41 1328.78 2605.12 1139.43 2528.87 1011.72C2592.86 970.123 2850.88 788.773 2843.33 573.68C2834.72 328.21 2786.46 176.103 2827.99 51.0384C2836.43 25.6346 2824.3 15.0816 2798.72 15.367V15.367Z" fill="#DE5700"/>
<path d="M1160.62 2299.49C1160.62 2299.49 1166.66 2341.8 1118.3 2468.75C1069.94 2595.69 1066.92 2885.85 1042.74 2949.32C1018.56 3012.79 885.57 3224.37 915.795 3411.76C946.02 3599.15 1094.12 3865.13 1275.47 3798.64C1456.82 3732.14 1420.55 3744.23 1420.55 3744.23C1420.55 3744.23 1946.46 3859.09 2294.05 3659.6C2372.63 3695.87 2420.99 3726.1 2538.87 3656.58C2656.74 3587.06 2717.19 3396.65 2714.17 3266.68C2711.15 3136.71 2523.75 2852.6 2502.6 2792.15C2481.44 2731.7 2402.86 2435.5 2363.56 2311.58C2324.27 2187.66 2354.5 2166.5 2354.5 2166.5L1160.62 2299.49Z" fill="#DE5700"/>
<path d="M1940.31 2212.63L1557.07 2255.32C1406.21 2289.92 1288.96 2332.21 1288.96 2332.21C1288.96 2332.21 1220.57 2746.83 1233.39 2862.24C1246.22 2977.65 1173.55 3152.9 1212.02 3328.15C1245.61 3481.2 1311.83 3644.02 1558.64 3765.38C1710.04 3782.34 1960.24 3792 2176.82 3713.48C2280.67 3629.51 2354.73 3520.47 2383.22 3435.02C2447.33 3242.67 2370.39 2909.27 2340.47 2840.87C2310.55 2772.48 2344.75 2558.76 2178.04 2315.11C2132.1 2247.96 2043.91 2219.17 1940.31 2212.63Z" fill="#F7EDE9"/>
<path opacity="0.6" d="M2798.72 15.367C2698.4 16.4866 2391.12 184.492 2306.37 277.783C2219.35 373.579 2165.64 521.033 2148.97 571.513C2050.88 508.595 1907.17 507.155 1907.17 507.155C1907.17 507.155 1991.8 479.955 2082.48 455.775C1925.31 401.371 1722.8 449.727 1722.8 449.727C1722.8 449.727 1813.47 349.989 1895.08 277.45C1768.13 310.697 1620.04 383.233 1529.36 437.638C1553.54 401.368 1595.86 362.076 1680.49 244.199C1447.75 301.626 1160.61 528.318 1060.87 612.947C1072.96 537.385 1103.19 489.025 1139.46 404.395C1002.07 499.513 937.628 607.905 907.715 681.853C876.542 624.261 794.11 483.695 690.543 400.173C558.035 293.312 45.0983 126.611 113.489 254.844C181.88 383.077 164.781 558.322 207.526 827.611C250.27 1096.9 634.972 1250.78 634.972 1250.78C637.192 1249.99 639.395 1249.09 641.592 1248.17C619.011 1319.85 598.866 1424.54 583.679 1597.01C511.014 1706.01 478.959 1727.38 470.41 1767.99C540.938 1733.8 575.13 1708.15 626.423 1695.32C581.542 1770.13 579.407 1872.71 598.642 2035.14C634.975 1943.24 632.833 1945.37 671.303 1917.59C681.988 2026.59 705.503 2086.43 733.287 2120.63C743.973 2060.78 776.031 2037.28 776.031 2037.28C776.031 2037.28 797.404 2167.65 859.383 2257.41C872.207 2178.34 887.165 2165.51 887.165 2165.51C887.165 2165.51 1135.08 2490.37 1767.7 2456.17C2400.31 2421.98 2579.84 1985.98 2579.84 1985.98C2579.84 1985.98 2592.66 2041.56 2592.66 2062.93C2639.68 1994.54 2669.6 1853.48 2669.6 1853.48C2669.6 1853.48 2703.8 1934.69 2695.25 1985.98C2733.72 1921.86 2742.26 1763.72 2725.17 1691.05C2785.01 1755.17 2836.31 1776.54 2836.31 1776.54C2836.31 1776.54 2703.79 1545.72 2699.52 1507.25C2695.25 1468.78 2793.56 1562.81 2793.56 1562.81C2793.56 1562.81 2731.97 1460.26 2716.62 1432.45C2659.41 1328.78 2605.12 1139.43 2528.87 1011.72C2592.86 970.123 2850.88 788.773 2843.33 573.68C2834.72 328.21 2786.46 176.103 2827.99 51.0384C2836.43 25.6346 2824.3 15.0816 2798.72 15.367V15.367Z" fill="url(#paint0_radial_35_87)"/>
<path d="M1785.69 1777.75C1684.07 1778.04 1631.38 1822.48 1594.58 1842.79C1435.61 2029.15 1115.77 1926.47 942.736 2050.1C912.815 2071.47 871.139 2186.88 871.139 2186.88L873.322 2195.17C881.064 2170.83 887.165 2165.51 887.165 2165.51C887.165 2165.51 1135.08 2490.37 1767.7 2456.17C2277.77 2428.6 2493.17 2139.93 2557.52 2029.09C2551.52 1973.12 2534.07 1898.88 2483.67 1896.22C2402.45 1891.95 2066.9 1864.16 1964.32 1808.59C1922.64 1786.02 1855.22 1777.56 1785.69 1777.75V1777.75Z" fill="#F7EDE9"/>
<path opacity="0.993" d="M1961.57 1985.15C1963.63 1987.09 1933.18 2033.96 1856.33 2063.83V2063.83C1839.85 2070.21 1822.61 2075.45 1804.72 2079.62C1766.98 2088.41 1729.87 2091.61 1698.49 2092.27C1674.97 2092.78 1655.68 2091.74 1642.07 2090.22C1635 2089.43 1629.58 2088.53 1625.85 2087.62C1623.95 2087.15 1622.51 2086.68 1621.54 2086.24C1621.04 2086.01 1620.67 2085.78 1620.42 2085.57C1620.15 2085.33 1620.02 2085.11 1620.03 2084.89C1620.05 2084.67 1620.2 2084.47 1620.49 2084.27C1620.76 2084.08 1621.15 2083.91 1621.67 2083.73C1622.67 2083.4 1624.14 2083.08 1626.06 2082.78C1629.77 2082.2 1635.24 2081.66 1642.21 2081.09C1655.61 2079.99 1674.75 2078.77 1697.58 2076.59C1728.3 2073.63 1764.16 2069.35 1800.38 2060.94C1817.58 2056.95 1834.05 2052.22 1849.95 2046.59C1918.62 2022.43 1958.6 1982.34 1961.57 1985.15V1985.15Z" fill="black"/>
<path d="M1934.67 1959.27C1935.77 1956.91 1954.37 1960.97 1967.17 1981.57C1979.98 2002.16 1975.41 2020.64 1972.82 2020.59C1970 2020.53 1967.84 2002.79 1958.14 1987.19C1948.44 1971.58 1933.47 1961.83 1934.67 1959.27V1959.27Z" fill="black"/>
<path d="M1263.38 1639.08C1266.22 1756.73 1183.41 1844.17 1098.66 1852.16C951.388 1866.04 891.515 1767.76 901.936 1653.12C912.303 1539.07 1011.03 1433.96 1109.23 1430.52C1193.46 1427.58 1260.47 1518.48 1263.38 1639.08Z" fill="black"/>
<g filter="url(#filter0_f_35_87)">
<path d="M1109.1 1636.63C1138.87 1598.95 1137.08 1543.74 1105.1 1513.3C1073.11 1482.87 1023.06 1488.73 993.29 1526.41C963.522 1564.08 965.316 1619.29 997.297 1649.73C1029.28 1680.17 1079.34 1674.3 1109.1 1636.63Z" fill="#BEBEBE"/>
</g>
<path d="M1109.1 1636.63C1138.87 1598.95 1137.08 1543.74 1105.1 1513.3C1073.11 1482.87 1023.06 1488.73 993.29 1526.41C963.522 1564.08 965.316 1619.29 997.297 1649.73C1029.28 1680.17 1079.34 1674.3 1109.1 1636.63Z" fill="#DEDEDE"/>
<g filter="url(#filter1_f_35_87)">
<path d="M1220.38 1725.27C1218.97 1703.96 1200.95 1686.44 1180.12 1686.13C1159.3 1685.82 1143.56 1702.84 1144.97 1724.14C1146.38 1745.45 1164.4 1762.98 1185.22 1763.29C1206.05 1763.6 1221.79 1746.58 1220.38 1725.27Z" fill="#BEBEBE"/>
</g>
<path d="M1217.34 1725.22C1216.05 1705.95 1199.48 1690.11 1180.33 1689.83C1161.18 1689.54 1146.71 1704.93 1148.01 1724.2C1149.3 1743.46 1165.87 1759.31 1185.02 1759.59C1204.17 1759.87 1218.64 1744.48 1217.34 1725.22Z" fill="#DEDEDE"/>
<path d="M2111.74 1483.68C2108.91 1601.33 2191.71 1688.77 2276.47 1696.76C2423.74 1710.64 2483.61 1612.36 2473.19 1497.72C2462.82 1383.67 2364.09 1278.56 2265.89 1275.13C2181.66 1272.18 2114.65 1363.09 2111.74 1483.68Z" fill="black"/>
<g filter="url(#filter2_f_35_87)">
<path d="M2266.02 1481.23C2236.25 1443.55 2238.05 1388.34 2270.03 1357.9C2302.01 1327.47 2352.07 1333.34 2381.83 1371.01C2411.6 1408.68 2409.81 1463.9 2377.83 1494.33C2345.85 1524.77 2295.79 1518.9 2266.02 1481.23Z" fill="#BEBEBE"/>
</g>
<path d="M2266.02 1481.23C2236.25 1443.55 2238.05 1388.34 2270.03 1357.9C2302.01 1327.47 2352.07 1333.34 2381.83 1371.01C2411.6 1408.68 2409.81 1463.9 2377.83 1494.33C2345.85 1524.77 2295.79 1518.9 2266.02 1481.23Z" fill="#DEDEDE"/>
<g filter="url(#filter3_f_35_87)">
<path d="M2154.74 1569.87C2156.15 1548.56 2174.17 1531.04 2195 1530.73C2215.83 1530.42 2231.57 1547.44 2230.16 1568.75C2228.75 1590.05 2210.72 1607.58 2189.9 1607.89C2169.07 1608.2 2153.33 1591.18 2154.74 1569.87Z" fill="#BEBEBE"/>
</g>
<path d="M2157.78 1569.82C2159.08 1550.55 2175.65 1534.71 2194.79 1534.43C2213.94 1534.15 2228.41 1549.53 2227.12 1568.8C2225.82 1588.06 2209.25 1603.91 2190.1 1604.19C2170.96 1604.47 2156.49 1589.08 2157.78 1569.82Z" fill="#DEDEDE"/>
<path d="M1662.35 1829.49C1645.46 1787.85 1850.52 1752.32 1854.28 1791.71C1858.37 1834.59 1804.4 1912.61 1777.2 1917.14C1750 1921.68 1680.39 1873.96 1662.35 1829.49V1829.49Z" fill="black"/>
<g opacity="0.8">
<g filter="url(#filter4_f_35_87)">
<path d="M1786.9 1793.91C1788.82 1786.22 1801.15 1781.29 1814.45 1782.91C1827.74 1784.53 1836.97 1792.08 1835.05 1799.77C1833.13 1807.46 1820.8 1812.39 1807.51 1810.77C1794.21 1809.15 1784.99 1801.61 1786.9 1793.91Z" fill="#BEBEBE"/>
</g>
<path d="M1788.84 1794.15C1790.59 1787.19 1801.91 1782.76 1814.14 1784.25C1826.36 1785.74 1834.85 1792.58 1833.11 1799.54C1831.36 1806.49 1820.04 1810.92 1807.81 1809.43C1795.59 1807.94 1787.1 1801.1 1788.84 1794.15Z" fill="#DEDEDE"/>
</g>
<path d="M2741.41 163.935C2735.43 163.645 2728.58 173.489 2718.76 194.994C2673.88 293.306 2462.29 385.213 2381.08 483.525C2299.87 581.837 2284.9 697.243 2374.67 851.122C2421.52 931.442 2482.9 980.277 2532.12 1009.56C2600.59 964.628 2850.77 785.686 2843.33 573.68C2841.17 511.985 2836.51 456.206 2831.39 405.253C2769.94 259.579 2759.63 164.818 2741.41 163.935V163.935Z" fill="url(#paint1_radial_35_87)"/>
<path d="M181.665 291.229C163.173 289.362 174.995 366.697 171.814 505.727C180.547 595.591 187.448 701.123 207.526 827.611C246.789 1074.97 573.781 1224.58 626.915 1247.37C670.403 1199.53 739.457 1106.83 766.704 960.629C806.777 745.606 754.64 615.556 641.83 530.754C529.02 445.951 288.043 418.155 211.526 319.567C197.179 301.081 187.769 291.846 181.665 291.229V291.229Z" fill="url(#paint2_radial_35_87)"/>
<path d="M2798.72 15.367C2698.4 16.4866 2391.12 184.492 2306.37 277.783C2219.35 373.579 2165.64 521.033 2148.97 571.513C2050.88 508.595 1907.17 507.155 1907.17 507.155C1907.17 507.155 1991.8 479.955 2082.48 455.775C1925.31 401.371 1722.8 449.727 1722.8 449.727C1722.8 449.727 1813.47 349.989 1895.08 277.45C1768.13 310.697 1620.04 383.233 1529.36 437.638C1553.54 401.368 1595.86 362.076 1680.49 244.199C1447.75 301.626 1160.61 528.318 1060.87 612.947C1072.96 537.385 1103.19 489.025 1139.46 404.395C1002.07 499.513 937.628 607.905 907.715 681.853C876.542 624.261 794.11 483.695 690.543 400.173C558.035 293.312 45.0983 126.611 113.489 254.844C181.88 383.077 164.781 558.322 207.526 827.611C250.27 1096.9 634.972 1250.78 634.972 1250.78C637.192 1249.99 639.395 1249.09 641.592 1248.17C619.011 1319.85 598.866 1424.54 583.679 1597.01C511.014 1706.01 478.959 1727.38 470.41 1767.99C540.938 1733.8 575.13 1708.15 626.423 1695.32C581.542 1770.13 579.407 1872.71 598.642 2035.14C634.975 1943.24 632.833 1945.37 671.303 1917.59C681.988 2026.59 705.503 2086.43 733.287 2120.63C743.973 2060.78 776.031 2037.28 776.031 2037.28C776.031 2037.28 797.404 2167.65 859.383 2257.41C872.207 2178.34 887.165 2165.51 887.165 2165.51C887.165 2165.51 1135.08 2490.37 1767.7 2456.17C2400.31 2421.98 2579.84 1985.98 2579.84 1985.98C2579.84 1985.98 2592.66 2041.56 2592.66 2062.93C2639.68 1994.54 2669.6 1853.48 2669.6 1853.48C2669.6 1853.48 2703.8 1934.69 2695.25 1985.98C2733.72 1921.86 2742.26 1763.72 2725.17 1691.05C2785.01 1755.17 2836.31 1776.54 2836.31 1776.54C2836.31 1776.54 2703.79 1545.72 2699.52 1507.25C2695.25 1468.78 2793.56 1562.81 2793.56 1562.81C2793.56 1562.81 2731.97 1460.26 2716.62 1432.45C2659.41 1328.78 2605.12 1139.43 2528.87 1011.72C2592.86 970.123 2850.88 788.773 2843.33 573.68C2834.72 328.21 2786.46 176.103 2827.99 51.0384C2836.43 25.6346 2824.3 15.0816 2798.72 15.367V15.367Z" stroke="black" stroke-width="30.7203" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1166.07 3775.9C1091.27 3651.94 1054.81 3567.11 1049.59 3511.42C1044.78 3460.13 1038.37 3398.15 1075.24 3428.61C1085.93 3383.72 1083.79 3358.08 1111.57 3370.9C1139.36 3383.72 1158.59 3411.51 1158.59 3411.51C1158.59 3411.51 1154.32 3347.39 1182.1 3368.76C1233.19 3399.52 1324.44 3688.35 1313.81 3770.16C1302.14 3860.06 1231.96 3879.6 1166.07 3775.9V3775.9Z" fill="url(#paint3_linear_35_87)" stroke="black" stroke-width="23.0402"/>
<path d="M2556.53 3668.47C2609.53 3533.74 2631.28 3444 2627.1 3388.22C2623.26 3336.85 2619.21 3274.67 2587.96 3310.87C2569.91 3268.41 2567.73 3242.76 2542.48 3260.06C2517.23 3277.35 2502.92 3307.96 2502.92 3307.96C2502.92 3307.96 2496.4 3244.03 2472.59 3269.75C2427.37 3308.62 2385.74 3608.66 2409.91 3687.53C2436.47 3774.21 2508.93 3781.73 2556.53 3668.47V3668.47Z" fill="url(#paint4_linear_35_87)" stroke="black" stroke-width="23.0402"/>
<path d="M1562.1 3063.57C1524.1 3059.67 1486.65 3074.05 1455.28 3094.55C1440.72 3104.25 1426.76 3115.03 1414.48 3127.52C1438.67 3156.34 1465.72 3183.02 1496.29 3205.05C1502.66 3208.89 1510.79 3214.39 1518.35 3210.58C1525.16 3205.3 1523.61 3195.64 1524.22 3188.07C1530.46 3197.06 1541.84 3202.2 1552.66 3201.65C1562.44 3199.92 1561.73 3187.56 1560.44 3180.1C1559.69 3173.07 1556.6 3166.42 1556.17 3159.41C1562.43 3160.56 1568.02 3169.72 1575.98 3167.49C1584.76 3164.88 1580.38 3153.58 1580.28 3146.94C1575.9 3118.83 1568.65 3091.24 1562.1 3063.57V3063.57Z" fill="url(#paint5_linear_35_87)"/>
<path d="M1517.64 2663.48C1517.64 2663.48 1517.64 2663.48 1517.67 2663.48C1520.97 2664.02 1526.42 2740.85 1532.65 2874.63C1534.91 2900.48 1540.5 2925.66 1547.39 2954.9C1554.58 2985.32 1562.49 3014.75 1571.38 3047.9C1578.08 3072.85 1585.59 3099.84 1591.55 3126.74C1593.42 3135.07 1595.31 3143.95 1596.25 3153.37C1596.57 3156.1 1596.76 3159.46 1596.39 3163.39C1597.28 3165.14 1595.58 3169.34 1590.43 3175.07V3175.07C1580.39 3180.9 1569.4 3179.92 1561.47 3173.37V3173.37C1559.01 3171.29 1557.89 3169.89 1557.57 3169.88C1559.13 3171.17 1561.37 3170.83 1565.41 3169.42H1565.41C1567.07 3167.09 1567.82 3166.38 1567.48 3165.67C1567.51 3167 1568.74 3169.46 1569.97 3173.33V3173.33C1574.02 3183.37 1572.31 3196.44 1561.97 3206.72V3206.72C1550.18 3212.97 1538.44 3211.07 1531.04 3204.36V3204.36C1528.22 3202.07 1526.49 3200.26 1525.34 3199.66H1525.34C1524.94 3200.04 1525.8 3199.59 1528.79 3199.47V3199.47C1531.49 3196.56 1532.68 3197.17 1530.81 3199.19C1530.12 3201.61 1529.26 3205.67 1526.9 3210.83C1526.22 3212.23 1525.38 3213.53 1524.39 3214.71C1520.87 3218.89 1515.47 3221.56 1508.72 3222C1497.43 3220.63 1489.74 3215.57 1485.08 3211.33C1426.38 3166.73 1381.27 3109.36 1347.87 3050.36C1312.57 2987.93 1289.98 2924.54 1275.1 2870.05C1253.47 2738.94 1243.01 2664.06 1246.21 2663.48C1249.41 2662.9 1265.97 2736.63 1291.73 2866.13V2866.13C1308.09 2918.97 1331.53 2980.15 1366.49 3039.63C1399.64 3096.09 1443.21 3150.79 1498.89 3192.79C1504.65 3196.18 1508.06 3199.72 1509.67 3198.89C1507.79 3199.52 1506.9 3199.67 1506.47 3200.08C1506.35 3200.2 1506.26 3200.33 1506.2 3200.5C1506.94 3199.44 1507.34 3196.53 1508.73 3192.3C1508.67 3188.65 1512.14 3183.04 1520.37 3177.93V3177.93C1527.93 3176.03 1533.99 3177.15 1537.72 3180.15H1537.72C1541.56 3182.71 1544.07 3185.1 1545.79 3186.59V3186.59C1547.9 3187.76 1550.06 3189.47 1548.1 3188.32H1548.1C1549.89 3189.46 1549.02 3184.96 1548.23 3180.69C1547.29 3178.15 1545.76 3174.34 1544.81 3168.99C1543.68 3162.9 1546.08 3156.29 1552.14 3150.81V3150.81C1559.11 3147.32 1565.42 3147.49 1569.99 3150.72V3150.72C1573.53 3153.21 1575.53 3155.29 1576.51 3156.24C1576.77 3156.9 1578.18 3157.59 1576.82 3156.92C1573.94 3160.94 1572.68 3161.93 1573.89 3160.86C1574.1 3159.67 1573.92 3157.84 1573.76 3155.45C1573.11 3147.76 1571.43 3139.75 1569.7 3131.46C1564.19 3105.34 1557.05 3078.42 1550.71 3053.27C1542.36 3020.15 1534.87 2989.98 1528.34 2959.17C1522.03 2929.53 1516.99 2902.93 1515.44 2875.5C1513.55 2741.07 1514.34 2664.11 1517.6 2663.48C1517.63 2663.47 1517.63 2663.48 1517.63 2663.48L1517.64 2663.48Z" fill="black"/>
<path d="M1565.2 3063.14C1564.91 3065.73 1555.96 3066.2 1541.37 3069.17C1525.48 3072.41 1508.74 3077.63 1488.07 3087.53C1480.4 3091.19 1473 3095.12 1465.92 3099.1C1438.07 3119.19 1417.43 3130.85 1415.06 3127.79C1412.69 3124.73 1429.23 3107.59 1456.25 3085.16C1463.45 3080.3 1471.31 3075.72 1479.69 3071.69C1501.77 3061.09 1522.77 3056.66 1540.11 3056.79C1556.81 3056.91 1565.43 3061.05 1565.2 3063.14V3063.14Z" fill="black"/>
<path d="M2047.1 3038.3C2015.08 3027.25 1989.62 3002.03 1971.75 2973.82C1956.72 2949.74 1945.57 2923.17 1939.25 2895.65C1918.3 2922.05 1897.04 2948.41 1879.78 2977.47C1875.73 2983.29 1871.18 2994.54 1881.77 2996.72C1891.18 2999.42 1900.88 2996.43 1910.31 2997.32C1906.93 3001.57 1900.26 3003.74 1896.41 3008.26C1889.29 3014.81 1882.1 3026.28 1888.65 3035.81C1897.4 3046.28 1912.16 3048.19 1924.86 3048.06C1933.1 3048.55 1920.45 3056.52 1921.15 3061.12C1917.09 3068.66 1918.61 3081.73 1929.47 3082C1942.49 3082.82 1954.68 3077.29 1966.93 3073.96C1994.86 3064.92 2021.6 3052.63 2047.1 3038.3V3038.3Z" fill="url(#paint6_linear_35_87)"/>
<path d="M2136.43 2590.6C2136.43 2590.6 2136.43 2590.6 2136.46 2590.61C2138.25 2591.35 2133.68 2615.94 2123.09 2662.55C2113.97 2692.52 2095.65 2744.12 2055.96 2781.07C2017.94 2816.07 1984.67 2855.47 1945.22 2905.25C1930.26 2924.17 1915.03 2943.97 1901.15 2964.57C1896.69 2971.21 1892.4 2977.73 1888.9 2984.37C1887.31 2989.65 1884.88 2991 1886.02 2988.64C1885.41 2987.11 1884.89 2986.63 1883.18 2985.7C1883.88 2986.16 1886.21 2985.54 1889.98 2985.28C1893.03 2984.76 1897.54 2984.08 1903.47 2984.6C1910.57 2985.44 1916.49 2990.55 1919.26 2999.16C1919.62 3007.51 1917.02 3013.57 1913.15 3016.69C1909.61 3020.25 1906.45 3022.49 1904.48 3024.27C1901.57 3026.15 1900.4 3031.06 1902.55 3033.46C1899.98 3033.96 1903.61 3032.95 1908.88 3033.72C1909.75 3033.84 1910.66 3034.02 1911.6 3034.26C1914.77 3034.15 1919.24 3034.1 1924.84 3035.26C1930.94 3036.4 1936.38 3041.11 1939.46 3048.98C1940.49 3058.56 1938.28 3064.62 1936.14 3066.9C1934.09 3071.33 1932.13 3074.45 1931.58 3076.77C1932.68 3076.62 1931.02 3075.79 1927.76 3071.11C1927.93 3072.71 1932.65 3070.31 1940.05 3069.84C2060.52 3040.57 2153.12 2954.06 2211.42 2887.43C2275.45 2796.57 2313.04 2746.24 2315.58 2747.99C2318.13 2749.74 2285.39 2803.44 2224.48 2897.39C2167.72 2967.95 2073.72 3059.09 1945.44 3091.98C1939.78 3094.05 1930.07 3095.88 1918.09 3091.52C1909.3 3084.14 1906.86 3075.86 1909.67 3069.89C1911.51 3064.11 1913.88 3059.89 1915.46 3056.71C1916.37 3052.55 1918.09 3051.64 1917.32 3054.22C1919 3056.69 1919.32 3057.64 1919.99 3057.49C1918.66 3056.99 1915.95 3057.25 1912.03 3057.13C1910.91 3057.36 1909.69 3057.5 1908.41 3057.54C1900.62 3057.76 1890.34 3054.11 1882.13 3043.31C1876.61 3030.37 1879.45 3016.48 1889 3007.16C1892.37 3004.14 1895.17 3002.25 1896.61 3000.66C1896.82 2999.58 1897.47 2999.97 1896.83 3002.48C1898.68 3005.68 1899.46 3006.96 1901.14 3007.12C1899.94 3006.74 1897.3 3007.4 1893.29 3007.76C1889.92 3008.39 1884.94 3008.85 1878.59 3007.7C1870.78 3005.36 1865.44 2999.58 1863.79 2991.91C1863.56 2981.4 1866.8 2975.32 1869.05 2973.44C1873.27 2965.66 1878.02 2958.53 1882.67 2951.79C1897.28 2930.57 1913.07 2910.54 1928.48 2891.68C1968.69 2842.39 2004.17 2802.5 2044.22 2767.98C2081.07 2736.75 2101.47 2687.54 2112.56 2659.14C2126.21 2614.17 2134.44 2590.46 2136.39 2590.6C2136.42 2590.61 2136.42 2590.61 2136.42 2590.61L2136.43 2590.6Z" fill="black"/>
<path d="M2038.8 3040.8C2037.48 3043.01 2027.68 3040.96 2012.89 3031.42C1997.72 3021.64 1980.73 3005.97 1966.44 2984.73C1959.64 2974.61 1954.07 2964.16 1949.75 2953.83C1940.62 2921.19 1937.42 2899.28 1941.52 2898.01C1945.61 2896.74 1956.14 2916.23 1967.96 2946.88C1972.82 2955.89 1978.21 2964.93 1984.35 2974.02C2009.03 3010.53 2041.64 3036.08 2038.8 3040.8V3040.8Z" fill="black"/>
<path d="M1643 3039.5V3096H1697.5V3039.5C1697.5 3039.5 1697.5 2974.5 1764.5 2974.5C1831.5 2974.5 1823.5 3039.5 1823.5 3039.5V3096H1874V3039.5C1869.33 3003.67 1850 2922 1764.5 2922C1678.44 2922 1643.67 3001 1643 3039.5Z" fill="#C4C4C4" stroke="black" stroke-width="14"/>
<rect x="1604.5" y="3089.5" width="333" height="269" fill="#F7CF45" stroke="black" stroke-width="15"/>
</g>
<defs>
<filter id="filter0_f_35_87" x="951.462" y="1473.2" width="199.468" height="216.64" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="10.3119" result="effect1_foregroundBlur_35_87"/>
</filter>
<filter id="filter1_f_35_87" x="1135.42" y="1676.67" width="94.5019" height="96.079" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="4.72782" result="effect1_foregroundBlur_35_87"/>
</filter>
<filter id="filter2_f_35_87" x="2224.19" y="1317.8" width="199.468" height="216.64" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="10.3119" result="effect1_foregroundBlur_35_87"/>
</filter>
<filter id="filter3_f_35_87" x="2145.2" y="1521.27" width="94.5019" height="96.079" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="4.72782" result="effect1_foregroundBlur_35_87"/>
</filter>
<filter id="filter4_f_35_87" x="1781.61" y="1777.56" width="58.7359" height="38.5579" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="2.52106" result="effect1_foregroundBlur_35_87"/>
</filter>
<radialGradient id="paint0_radial_35_87" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(1760.99 1829.81) rotate(-0.182296) scale(306.481 287.176)">
<stop stop-color="#CC3100"/>
<stop offset="1" stop-color="#DE6B00"/>
</radialGradient>
<radialGradient id="paint1_radial_35_87" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2373.33 907.327) rotate(63.7909) scale(608.272 241.85)">
<stop stop-color="#FF927A"/>
<stop offset="1" stop-color="#F7C199"/>
</radialGradient>
<radialGradient id="paint2_radial_35_87" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(785.008 1066.98) rotate(-157.738) scale(359.552 439.05)">
<stop stop-color="#FF927A"/>
<stop offset="1" stop-color="#F7C199"/>
</radialGradient>
<linearGradient id="paint3_linear_35_87" x1="1257.34" y1="3813.75" x2="1136.44" y2="3481.28" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<linearGradient id="paint4_linear_35_87" x1="2481.02" y1="3700.43" x2="2528.01" y2="3388.4" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<linearGradient id="paint5_linear_35_87" x1="1465.89" y1="3071.73" x2="1527.85" y2="3160.89" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<linearGradient id="paint6_linear_35_87" x1="1978.5" y1="2970.47" x2="1922.1" y2="3021.61" gradientUnits="userSpaceOnUse">
<stop stop-color="#F79041"/>
<stop offset="1" stop-color="#F7C199"/>
</linearGradient>
<clipPath id="clip0_35_87">
<rect width="2858.86" height="3857.48" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -1,4 +1,11 @@
// @flow // @flow
/*
Removed Watchman (internal view tracking) code.
This file may eventually implement cantina
Refer to 0cc0e213a5c5bf9e2a76316df5d9da4b250a13c3 for initial integration commit
refer to ___ for removal commit.
*/
import { Lbryio } from 'lbryinc'; import { Lbryio } from 'lbryinc';
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import MatomoTracker from '@datapunt/matomo-tracker-js'; import MatomoTracker from '@datapunt/matomo-tracker-js';
@ -14,9 +21,6 @@ const devInternalApis = process.env.LBRY_API_URL && process.env.LBRY_API_URL.inc
export const SHARE_INTERNAL = 'shareInternal'; export const SHARE_INTERNAL = 'shareInternal';
const SHARE_THIRD_PARTY = 'shareThirdParty'; const SHARE_THIRD_PARTY = 'shareThirdParty';
const WATCHMAN_BACKEND_ENDPOINT = 'https://watchman.na-backend.odysee.com/reports/playback';
// const SEND_DATA_TO_WATCHMAN_INTERVAL = 10; // in seconds
if (isProduction) { if (isProduction) {
ElectronCookies.enable({ ElectronCookies.enable({
origin: 'https://lbry.tv', origin: 'https://lbry.tv',
@ -68,114 +72,10 @@ type LogPublishParams = {
let internalAnalyticsEnabled: boolean = false; let internalAnalyticsEnabled: boolean = false;
if (window.localStorage.getItem(SHARE_INTERNAL) === 'true') internalAnalyticsEnabled = true; if (window.localStorage.getItem(SHARE_INTERNAL) === 'true') internalAnalyticsEnabled = true;
/**
* Determine the mobile device type viewing the data
* This function returns one of 'and' (Android), 'ios', or 'web'.
*
* @returns {String}
*/
function getDeviceType() {
return 'dsk';
}
// variables initialized for watchman
let amountOfBufferEvents = 0;
let amountOfBufferTimeInMS = 0;
let videoType, userId, claimUrl, playerPoweredBy, videoPlayer, bitrateAsBitsPerSecond;
let lastSentTime;
// calculate data for backend, send them, and reset buffer data for next interval
async function sendAndResetWatchmanData() {
if (!userId) {
return 'Can only be used with a user id';
}
if (!videoPlayer) {
return 'Video player not initialized';
}
let timeSinceLastIntervalSend = new Date() - lastSentTime;
lastSentTime = new Date();
let protocol;
if (videoType === 'application/x-mpegURL') {
protocol = 'hls';
// get bandwidth if it exists from the texttrack (so it's accurate if user changes quality)
// $FlowFixMe
bitrateAsBitsPerSecond = videoPlayer.textTracks?.().tracks_[0]?.activeCues[0]?.value?.bandwidth;
} else {
protocol = 'stb';
}
// current position in video in MS
const positionInVideo = Math.round(videoPlayer.currentTime()) * 1000;
// get the duration marking the time in the video for relative position calculation
const totalDurationInSeconds = Math.round(videoPlayer.duration());
// build object for watchman backend
const objectToSend = {
rebuf_count: amountOfBufferEvents,
rebuf_duration: amountOfBufferTimeInMS,
url: claimUrl.replace('lbry://', ''),
device: getDeviceType(),
duration: timeSinceLastIntervalSend,
protocol,
player: playerPoweredBy,
user_id: userId.toString(),
position: Math.round(positionInVideo),
rel_position: Math.round((positionInVideo / (totalDurationInSeconds * 1000)) * 100),
bitrate: bitrateAsBitsPerSecond,
bandwidth: undefined,
// ...(userDownloadBandwidthInBitsPerSecond && {bandwidth: userDownloadBandwidthInBitsPerSecond}), // add bandwidth if populated
};
// post to watchman
await sendWatchmanData(objectToSend);
// reset buffer data
amountOfBufferEvents = 0;
amountOfBufferTimeInMS = 0;
}
let watchmanInterval;
// clear watchman interval and mark it as null (when video paused)
function stopWatchmanInterval() {
clearInterval(watchmanInterval);
watchmanInterval = null;
}
// creates the setInterval that will run send to watchman on recurring basis
function startWatchmanIntervalIfNotRunning() {
if (!watchmanInterval) {
// instantiate the first time to calculate duration from
lastSentTime = new Date();
}
}
// post data to the backend
async function sendWatchmanData(body) {
try {
const response = await fetch(WATCHMAN_BACKEND_ENDPOINT, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
return response;
} catch (err) {}
}
const analytics: Analytics = { const analytics: Analytics = {
// receive buffer events from tracking plugin and save buffer amounts and times for backend call // receive buffer events from tracking plugin and save buffer amounts and times for backend call
videoBufferEvent: async (claim, data) => { videoBufferEvent: async (claim, data) => {
amountOfBufferEvents = amountOfBufferEvents + 1; // stub
amountOfBufferTimeInMS = amountOfBufferTimeInMS + data.bufferDuration;
},
onDispose: () => {
stopWatchmanInterval();
}, },
/** /**
* Is told whether video is being started or paused, and adjusts interval accordingly * Is told whether video is being started or paused, and adjusts interval accordingly
@ -183,40 +83,9 @@ const analytics: Analytics = {
* @param {object} passedPlayer - VideoJS Player object * @param {object} passedPlayer - VideoJS Player object
*/ */
videoIsPlaying: (isPlaying, passedPlayer) => { videoIsPlaying: (isPlaying, passedPlayer) => {
let playerIsSeeking = false; // stub
// have to use this because videojs pauses/unpauses during seek
// sometimes the seeking function isn't populated yet so check for it as well
if (passedPlayer && passedPlayer.seeking) {
playerIsSeeking = passedPlayer.seeking();
}
// if being paused, and not seeking, send existing data and stop interval
if (!isPlaying && !playerIsSeeking) {
sendAndResetWatchmanData();
stopWatchmanInterval();
// if being told to pause, and seeking, send and restart interval
} else if (!isPlaying && playerIsSeeking) {
sendAndResetWatchmanData();
stopWatchmanInterval();
startWatchmanIntervalIfNotRunning();
// is being told to play, and seeking, don't do anything,
// assume it's been started already from pause
} else if (isPlaying && playerIsSeeking) {
// start but not a seek, assuming a start from paused content
} else if (isPlaying && !playerIsSeeking) {
startWatchmanIntervalIfNotRunning();
}
}, },
videoStartEvent: (claimId, timeToStartVideo, poweredBy, passedUserId, canonicalUrl, passedPlayer, videoBitrate) => { videoStartEvent: (claimId, timeToStartVideo, poweredBy, passedUserId, canonicalUrl, passedPlayer, videoBitrate) => {
// populate values for watchman when video starts
userId = passedUserId;
claimUrl = canonicalUrl;
playerPoweredBy = poweredBy;
videoType = passedPlayer.currentSource().type;
videoPlayer = passedPlayer;
bitrateAsBitsPerSecond = videoBitrate;
// sendPromMetric('time_to_start', duration); // sendPromMetric('time_to_start', duration);
sendMatomoEvent('Media', 'TimeToStart', claimId, timeToStartVideo); sendMatomoEvent('Media', 'TimeToStart', claimId, timeToStartVideo);
}, },
@ -382,24 +251,9 @@ function sendMatomoEvent(category, action, name, value) {
} }
} }
// Prometheus
// function sendPromMetric(name: string, value?: number) {
// if (IS_WEB) {
// let url = new URL(SDK_API_PATH + '/metric/ui');
// const params = { name: name, value: value ? value.toString() : '' };
// url.search = new URLSearchParams(params).toString();
// return fetch(url, { method: 'post' });
// }
// }
const MatomoInstance = new MatomoTracker({ const MatomoInstance = new MatomoTracker({
urlBase: MATOMO_URL, urlBase: MATOMO_URL,
siteId: MATOMO_ID, // optional, default value: `1` siteId: MATOMO_ID, // optional, default value: `1`
// heartBeat: { // optional, enabled by default
// active: true, // optional, default value: true
// seconds: 10 // optional, default value: `15
// },
// linkTracking: false // optional, default value: true
}); });
analytics.pageView(generateInitialUrl(window.location.hash)); analytics.pageView(generateInitialUrl(window.location.hash));

View file

@ -5,7 +5,7 @@ import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user';
import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectUnclaimedRewards } from 'redux/selectors/rewards'; import { selectUnclaimedRewards } from 'redux/selectors/rewards';
import { doFetchChannelListMine, doFetchCollectionListMine, doResolveUris } from 'redux/actions/claims'; import { doFetchChannelListMine, doFetchCollectionListMine, doResolveUris } from 'redux/actions/claims';
import { selectMyChannelUrls } from 'redux/selectors/claims'; import { selectMyChannelUrls, selectMyChannelClaimIds } from 'redux/selectors/claims';
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import { import {
@ -19,6 +19,7 @@ import {
selectAutoUpdateDownloaded, selectAutoUpdateDownloaded,
selectModal, selectModal,
selectActiveChannelClaim, selectActiveChannelClaim,
selectIsUpdateModalDisplayed,
} from 'redux/selectors/app'; } from 'redux/selectors/app';
import { doGetWalletSyncPreference, doSetLanguage } from 'redux/actions/settings'; import { doGetWalletSyncPreference, doSetLanguage } from 'redux/actions/settings';
import { doSyncLoop } from 'redux/actions/sync'; import { doSyncLoop } from 'redux/actions/sync';
@ -48,7 +49,9 @@ const select = (state) => ({
syncFatalError: selectSyncFatalError(state), syncFatalError: selectSyncFatalError(state),
activeChannelClaim: selectActiveChannelClaim(state), activeChannelClaim: selectActiveChannelClaim(state),
myChannelUrls: selectMyChannelUrls(state), myChannelUrls: selectMyChannelUrls(state),
myChannelClaimIds: selectMyChannelClaimIds(state),
subscriptions: selectSubscriptions(state), subscriptions: selectSubscriptions(state),
isUpdateModalDisplayed: selectIsUpdateModalDisplayed(state),
}); });
const perform = (dispatch) => ({ const perform = (dispatch) => ({

View file

@ -76,6 +76,7 @@ type Props = {
fetchModBlockedList: () => void, fetchModBlockedList: () => void,
resolveUris: (Array<string>) => void, resolveUris: (Array<string>) => void,
fetchModAmIList: () => void, fetchModAmIList: () => void,
isUpdateModalDisplayed: boolean,
}; };
function App(props: Props) { function App(props: Props) {
@ -111,6 +112,7 @@ function App(props: Props) {
resolveUris, resolveUris,
subscriptions, subscriptions,
fetchModAmIList, fetchModAmIList,
isUpdateModalDisplayed,
} = props; } = props;
const appRef = useRef(); const appRef = useRef();
@ -126,9 +128,9 @@ function App(props: Props) {
const [upgradeNagClosed, setUpgradeNagClosed] = useState(false); const [upgradeNagClosed, setUpgradeNagClosed] = useState(false);
const [resolvedSubscriptions, setResolvedSubscriptions] = useState(false); const [resolvedSubscriptions, setResolvedSubscriptions] = useState(false);
// const [retryingSync, setRetryingSync] = useState(false); // const [retryingSync, setRetryingSync] = useState(false);
const [langRenderKey, setLangRenderKey] = useState(0);
const [sidebarOpen] = usePersistedState('sidebar', true); const [sidebarOpen] = usePersistedState('sidebar', true);
const showUpgradeButton = const showUpgradeButton = (autoUpdateDownloaded || isUpgradeAvailable) && !upgradeNagClosed;
(autoUpdateDownloaded || (process.platform === 'linux' && isUpgradeAvailable)) && !upgradeNagClosed;
// referral claiming // referral claiming
const referredRewardAvailable = rewards && rewards.some((reward) => reward.reward_type === REWARDS.TYPE_REFEREE); const referredRewardAvailable = rewards && rewards.some((reward) => reward.reward_type === REWARDS.TYPE_REFEREE);
const urlParams = new URLSearchParams(search); const urlParams = new URLSearchParams(search);
@ -141,7 +143,6 @@ function App(props: Props) {
const shouldMigrateLanguage = LANGUAGE_MIGRATIONS[language]; const shouldMigrateLanguage = LANGUAGE_MIGRATIONS[language];
const hasActiveChannelClaim = activeChannelId !== undefined; const hasActiveChannelClaim = activeChannelId !== undefined;
const isPersonalized = hasVerifiedEmail; const isPersonalized = hasVerifiedEmail;
const renderFiledrop = isAuthenticated;
useEffect(() => { useEffect(() => {
if (userId) { if (userId) {
@ -326,6 +327,11 @@ function App(props: Props) {
} }
}, [sidebarOpen, isPersonalized, resolvedSubscriptions, subscriptions, resolveUris, setResolvedSubscriptions]); }, [sidebarOpen, isPersonalized, resolvedSubscriptions, subscriptions, resolveUris, setResolvedSubscriptions]);
useEffect(() => {
// When language is changed or translations are fetched, we render.
setLangRenderKey(Date.now());
}, [language, languages]);
if (syncFatalError) { if (syncFatalError) {
return <SyncFatalError />; return <SyncFatalError />;
} }
@ -337,15 +343,16 @@ function App(props: Props) {
[`${MAIN_WRAPPER_CLASS}--scrollbar`]: useCustomScrollbar, [`${MAIN_WRAPPER_CLASS}--scrollbar`]: useCustomScrollbar,
})} })}
ref={appRef} ref={appRef}
key={langRenderKey}
onContextMenu={(e) => openContextMenu(e)} onContextMenu={(e) => openContextMenu(e)}
> >
<Router /> <Router />
<ModalRouter /> <ModalRouter />
{renderFiledrop && <FileDrop />} <FileDrop />
<FileRenderFloating /> <FileRenderFloating />
{isEnhancedLayout && <Yrbl className="yrbl--enhanced" />} {isEnhancedLayout && <Yrbl className="yrbl--enhanced" />}
{showUpgradeButton && ( {showUpgradeButton && !isUpdateModalDisplayed && (
<Nag <Nag
message={__('An upgrade is available.')} message={__('An upgrade is available.')}
actionText={__('Install Now')} actionText={__('Install Now')}

View file

@ -0,0 +1,21 @@
import { connect } from 'react-redux';
import StorageViz from './view';
import {
selectViewBlobSpace,
selectViewHostingLimit,
selectAutoBlobSpace,
selectPrivateBlobSpace,
selectAutoHostingLimit,
} from 'redux/selectors/settings';
import { selectDiskSpace } from 'redux/selectors/app';
const select = (state) => ({
diskSpace: selectDiskSpace(state),
viewHostingLimit: selectViewHostingLimit(state),
autoHostingLimit: selectAutoHostingLimit(state),
viewBlobSpace: selectViewBlobSpace(state),
autoBlobSpace: selectAutoBlobSpace(state),
privateBlobSpace: selectPrivateBlobSpace(state),
});
export default connect(select)(StorageViz);

View file

@ -0,0 +1,130 @@
// @flow
import * as React from 'react';
import I18nMessage from 'component/i18nMessage';
import { ipcRenderer } from 'electron';
type Props = {
// --- select ---
diskSpace: DiskSpace, // KB
viewHostingLimit: number, // MB
autoHostingLimit: number,
viewBlobSpace: number,
autoBlobSpace: number,
privateBlobSpace: number,
};
function StorageViz(props: Props) {
const { diskSpace, viewHostingLimit, autoHostingLimit, viewBlobSpace, autoBlobSpace, privateBlobSpace } = props;
React.useEffect(() => {
ipcRenderer.send('get-disk-space');
}, []);
if (!diskSpace || !diskSpace.total) {
return (
<div className={'storage__wrapper'}>
<div className={'storage__bar'}>
<div className="help">{__('Cannot get disk space information.')}</div>
</div>
</div>
);
}
const totalMB = diskSpace && Math.floor(diskSpace.total / 1024);
const freeMB = diskSpace && Math.floor(diskSpace.free / 1024);
const otherMB = totalMB - (freeMB + viewBlobSpace + autoBlobSpace + privateBlobSpace);
const autoFree = autoHostingLimit - autoBlobSpace;
const viewFree = viewHostingLimit > 0 ? viewHostingLimit - viewBlobSpace : freeMB - autoFree;
const unallocFree = freeMB - viewFree - autoFree;
const viewLimit =
viewHostingLimit === 0
? freeMB - (autoHostingLimit - autoBlobSpace) + viewBlobSpace
: viewHostingLimit + viewBlobSpace;
const getPercent = (val, lim = totalMB) => (val / lim) * 100;
const getGB = (val) => (Number(val) / 1024).toFixed(2);
const otherPercent = getPercent(otherMB);
const privatePercent = getPercent(privateBlobSpace);
const autoLimitPercent = getPercent(autoHostingLimit);
const viewLimitPercent = getPercent(viewLimit);
const viewUsedPercentOfLimit = getPercent(viewBlobSpace, viewLimit);
const autoUsedPercentOfLimit = getPercent(autoBlobSpace, autoHostingLimit);
return (
<div className={'storage__wrapper'}>
<div className={'storage__bar'}>
<div className={'storage__other'} style={{ width: `${otherPercent}%` }} />
<div className={'storage__private'} style={{ width: `${privatePercent}%` }} />
<div className={'storage__auto'} style={{ width: `${autoLimitPercent}%` }}>
<div className={'storage__auto--used'} style={{ width: `${autoUsedPercentOfLimit}%` }} />
<div className={'storage__auto--free'} />
</div>
<div className={'storage__viewed'} style={{ width: `${viewLimitPercent}%` }}>
<div className={'storage__viewed--used'} style={{ width: `${viewUsedPercentOfLimit}%` }} />
<div className={'storage__viewed--free'} />
</div>
{viewHostingLimit !== 0 && <div style={{ 'background-color': 'unset' }} />}
</div>
<div className={'storage__legend-wrapper'}>
<div className={'storage__legend-item'}>
<div className={'storage__legend-item-swatch storage__legend-item-swatch--private'} />
<div className={'storage__legend-item-label'}>
<label>{__('Publishes --[legend, storage category]--')}</label>
<div className={'help'}>{`${getGB(privateBlobSpace)} GB`}</div>
</div>
</div>
<div className={'storage__legend-item'}>
<div className={'storage__legend-item-swatch storage__legend-item-swatch--auto'} />
<div className={'storage__legend-item-label'}>
<label>{__('Auto Hosting --[legend, storage category]--')}</label>
<div className={'help'}>
{autoHostingLimit === 0 ? (
__('Disabled')
) : (
<I18nMessage
tokens={{
spaceUsed: getGB(autoBlobSpace),
limit: getGB(autoHostingLimit),
}}
>
%spaceUsed% of %limit% GB
</I18nMessage>
)}
</div>
</div>
</div>
<div className={'storage__legend-item'}>
<div className={'storage__legend-item-swatch storage__legend-item-swatch--viewed'} />
<div className={'storage__legend-item-label'}>
<label>{__('View Hosting --[legend, storage category]--')}</label>
<div className={'help'}>
{viewHostingLimit === 1 ? (
__('Disabled')
) : (
<I18nMessage
tokens={{
spaceUsed: getGB(viewBlobSpace),
limit: viewHostingLimit !== 0 ? getGB(viewHostingLimit) : getGB(viewFree),
}}
>
%spaceUsed% of %limit% Free GB
</I18nMessage>
)}
</div>
</div>
</div>
{viewHostingLimit !== 0 && (
<div className={'storage__legend-item'}>
<div className={'storage__legend-item-swatch storage__legend-item-swatch--free'} />
<div className={'storage__legend-item-label'}>
<label>{__('Free --[legend, unused disk space]--')}</label>
<div className={'help'}>{`${getGB(unallocFree)} GB`}</div>
</div>
</div>
)}
</div>
</div>
);
}
export default StorageViz;

View file

@ -1,6 +1,5 @@
// @flow // @flow
import { Combobox, ComboboxInput, ComboboxPopover, ComboboxList, ComboboxOption } from '@reach/combobox'; import { Combobox, ComboboxInput, ComboboxPopover, ComboboxList, ComboboxOption } from '@reach/combobox';
// import '@reach/combobox/styles.css'; --> 'scss/third-party.scss'
import { matchSorter } from 'match-sorter'; import { matchSorter } from 'match-sorter';
import React from 'react'; import React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
@ -118,7 +117,7 @@ export default function BlockList(props: Props) {
return ( return (
<> <>
<div className="help--notice">{help}</div> <div className="help--notice">{help}</div>
<div className="section"> <div className="section" style={{ zIndex: '4' }}>
<SearchList <SearchList
list={localList} list={localList}
placeholder={__('e.g. odysee')} placeholder={__('e.g. odysee')}

View file

@ -5,7 +5,6 @@ import Icon from 'component/common/icon';
import classnames from 'classnames'; import classnames from 'classnames';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { formatLbryUrlForWeb } from 'util/url'; import { formatLbryUrlForWeb } from 'util/url';
import * as PAGES from 'constants/pages';
import useCombinedRefs from 'effects/use-combined-refs'; import useCombinedRefs from 'effects/use-combined-refs';
type Props = { type Props = {
@ -34,7 +33,6 @@ type Props = {
onMouseLeave: ?(any) => any, onMouseLeave: ?(any) => any,
pathname: string, pathname: string,
emailVerified: boolean, emailVerified: boolean,
requiresAuth: ?boolean,
myref: any, myref: any,
dispatch: any, dispatch: any,
'aria-label'?: string, 'aria-label'?: string,
@ -66,7 +64,6 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
iconColor, iconColor,
activeClass, activeClass,
emailVerified, emailVerified,
requiresAuth,
myref, myref,
dispatch, // <button> doesn't know what to do with dispatch dispatch, // <button> doesn't know what to do with dispatch
pathname, pathname,
@ -75,7 +72,7 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
...otherProps ...otherProps
} = props; } = props;
const disable = disabled || (user === null && requiresAuth); const disable = disabled;
const combinedClassName = classnames( const combinedClassName = classnames(
'button', 'button',
@ -183,31 +180,6 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
} }
} }
if (requiresAuth && !emailVerified) {
let redirectUrl = `/$/${PAGES.AUTH}?redirect=${pathname}`;
if (authSrc) {
redirectUrl += `&src=${authSrc}`;
}
return (
<NavLink
exact
onClick={(e) => {
e.stopPropagation();
}}
to={redirectUrl}
title={title || defaultTooltip}
disabled={disable}
className={combinedClassName}
activeClassName={activeClass}
aria-label={ariaLabel}
>
{content}
</NavLink>
);
}
return path ? ( return path ? (
<NavLink <NavLink
exact exact

View file

@ -6,6 +6,7 @@ import CreditAmount from 'component/common/credit-amount';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import YoutubeBadge from 'component/youtubeBadge'; import YoutubeBadge from 'component/youtubeBadge';
import SUPPORTED_LANGUAGES from 'constants/supported_languages'; import SUPPORTED_LANGUAGES from 'constants/supported_languages';
import { formatNumber } from 'util/number';
type Props = { type Props = {
claim: ChannelClaim, claim: ChannelClaim,
@ -74,7 +75,7 @@ function ChannelAbout(props: Props) {
</div> </div>
<label>{__('Total Uploads')}</label> <label>{__('Total Uploads')}</label>
<div className="media__info-text">{claim.meta.claims_in_channel}</div> <div className="media__info-text">{formatNumber(claim.meta.claims_in_channel || 0, 2, true)}</div>
<label>{__('Last Updated')}</label> <label>{__('Last Updated')}</label>
<div className="media__info-text"> <div className="media__info-text">

View file

@ -3,10 +3,9 @@ import * as MODALS from 'constants/modal_types';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import React from 'react'; import React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import { FormField } from 'component/common/form'; import { FormField, FormFieldAreaAdvanced } from 'component/common/form';
import Button from 'component/button'; import Button from 'component/button';
import TagsSearch from 'component/tagsSearch'; import TagsSearch from 'component/tagsSearch';
import { FF_MAX_CHARS_IN_DESCRIPTION } from 'constants/form-field';
import ErrorText from 'component/common/error-text'; import ErrorText from 'component/common/error-text';
import ChannelThumbnail from 'component/channelThumbnail'; import ChannelThumbnail from 'component/channelThumbnail';
import { isNameValid, parseURI } from 'util/lbryURI'; import { isNameValid, parseURI } from 'util/lbryURI';
@ -27,6 +26,9 @@ import Gerbil from 'component/channelThumbnail/gerbil.png';
const LANG_NONE = 'none'; const LANG_NONE = 'none';
const MAX_TAG_SELECT = 5; const MAX_TAG_SELECT = 5;
const MAX_NAME_LEN = 128;
const MAX_TITLE_LEN = 255;
const MAX_DESCRIPTION_LEN = 2056;
type Props = { type Props = {
claim: ChannelClaim, claim: ChannelClaim,
@ -92,10 +94,11 @@ function ChannelForm(props: Props) {
const [nameError, setNameError] = React.useState(undefined); const [nameError, setNameError] = React.useState(undefined);
const [bidError, setBidError] = React.useState(''); const [bidError, setBidError] = React.useState('');
const [isUpload, setIsUpload] = React.useState({ cover: false, thumbnail: false }); const [isUpload, setIsUpload] = React.useState({ cover: false, thumbnail: false });
const [coverError, setCoverError] = React.useState(false);
const [thumbError, setThumbError] = React.useState(false); const [thumbError, setThumbError] = React.useState(false);
const { claim_id: claimId } = claim || {}; const { claim_id: claimId } = claim || {};
const [params, setParams]: [any, (any) => void] = React.useState(getChannelParams()); const [params, setParams]: [any, (any) => void] = React.useState(getChannelParams());
const [coverError, setCoverError] = React.useState(false);
const [coverPreview, setCoverPreview] = React.useState(params.coverUrl);
const { channelName } = parseURI(uri); const { channelName } = parseURI(uri);
const name = params.name; const name = params.name;
const isNewChannel = !uri; const isNewChannel = !uri;
@ -204,7 +207,8 @@ function ChannelForm(props: Props) {
setThumbError(false); setThumbError(false);
} }
function handleCoverChange(coverUrl: string, uploadSelected: boolean) { function handleCoverChange(coverUrl: string, uploadSelected: boolean, preview: ?string) {
setCoverPreview(preview || '');
setParams({ ...params, coverUrl }); setParams({ ...params, coverUrl });
setIsUpload({ ...isUpload, cover: uploadSelected }); setIsUpload({ ...isUpload, cover: uploadSelected });
setCoverError(false); setCoverError(false);
@ -257,7 +261,7 @@ function ChannelForm(props: Props) {
} }
}, [hasClaimedInitialRewards, claimInitialRewards]); }, [hasClaimedInitialRewards, claimInitialRewards]);
const coverSrc = coverError ? ThumbnailBrokenImage : params.coverUrl; const coverSrc = coverError ? ThumbnailBrokenImage : coverPreview;
let thumbnailPreview; let thumbnailPreview;
if (!params.thumbnailUrl) { if (!params.thumbnailUrl) {
@ -271,7 +275,7 @@ function ChannelForm(props: Props) {
// TODO clear and bail after submit // TODO clear and bail after submit
return ( return (
<> <>
<div className={classnames('main--contained', { 'card--disabled': disabled })}> <div className={classnames({ 'card--disabled': disabled })}>
<header className="channel-cover"> <header className="channel-cover">
<div className="channel__quick-actions"> <div className="channel__quick-actions">
<Button <Button
@ -279,7 +283,7 @@ function ChannelForm(props: Props) {
title={__('Cover')} title={__('Cover')}
onClick={() => onClick={() =>
openModal(MODALS.IMAGE_UPLOAD, { openModal(MODALS.IMAGE_UPLOAD, {
onUpdate: (coverUrl, isUpload) => handleCoverChange(coverUrl, isUpload), onUpdate: (coverUrl, isUpload, preview) => handleCoverChange(coverUrl, isUpload, preview),
title: __('Edit Cover Image'), title: __('Edit Cover Image'),
helpText: __('(6.25:1)'), helpText: __('(6.25:1)'),
assetName: __('Cover Image'), assetName: __('Cover Image'),
@ -321,7 +325,6 @@ function ChannelForm(props: Props) {
uri={uri} uri={uri}
thumbnailPreview={thumbnailPreview} thumbnailPreview={thumbnailPreview}
allowGifs allowGifs
showDelayedMessage={isUpload.thumbnail}
setThumbUploadError={setThumbError} setThumbUploadError={setThumbError}
thumbUploadError={thumbError} thumbUploadError={thumbError}
/> />
@ -332,7 +335,7 @@ function ChannelForm(props: Props) {
<div className="channel-cover__gradient" /> <div className="channel-cover__gradient" />
</header> </header>
<Tabs> <Tabs className="channelPage-wrapper">
<TabList className="tabs__list--channel-page"> <TabList className="tabs__list--channel-page">
<Tab>{__('General')}</Tab> <Tab>{__('General')}</Tab>
<Tab>{__('Credit Details')}</Tab> <Tab>{__('Credit Details')}</Tab>
@ -359,6 +362,7 @@ function ChannelForm(props: Props) {
error={nameError} error={nameError}
disabled={!isNewChannel} disabled={!isNewChannel}
onChange={(e) => setParams({ ...params, name: e.target.value })} onChange={(e) => setParams({ ...params, name: e.target.value })}
maxLength={MAX_NAME_LEN}
/> />
</fieldset-group> </fieldset-group>
{!isNewChannel && <span className="form-field__help">{__('This field cannot be changed.')}</span>} {!isNewChannel && <span className="form-field__help">{__('This field cannot be changed.')}</span>}
@ -370,15 +374,16 @@ function ChannelForm(props: Props) {
placeholder={__('My Awesome Channel')} placeholder={__('My Awesome Channel')}
value={params.title} value={params.title}
onChange={(e) => setParams({ ...params, title: e.target.value })} onChange={(e) => setParams({ ...params, title: e.target.value })}
maxLength={MAX_TITLE_LEN}
/> />
<FormField <FormFieldAreaAdvanced
type="markdown" type="markdown"
name="content_description2" name="content_description2"
label={__('Description')} label={__('Description')}
placeholder={__('Description of your content')} placeholder={__('Description of your content')}
value={params.description} value={params.description}
onChange={(text) => setParams({ ...params, description: text })} onChange={(text) => setParams({ ...params, description: text })}
textAreaMaxLength={FF_MAX_CHARS_IN_DESCRIPTION} textAreaMaxLength={MAX_DESCRIPTION_LEN}
/> />
</> </>
} }

View file

@ -13,6 +13,7 @@ type Props = {
level: number, level: number,
large?: boolean, large?: boolean,
inline?: boolean, inline?: boolean,
hideTooltip?: Boolean,
}; };
function getChannelIcon(level: number): string { function getChannelIcon(level: number): string {
@ -28,7 +29,7 @@ function getChannelIcon(level: number): string {
} }
function ChannelStakedIndicator(props: Props) { function ChannelStakedIndicator(props: Props) {
const { channelClaim, amount, level, large = false, inline = false } = props; const { channelClaim, amount, level, large = false, inline = false, hideTooltip } = props;
if (!channelClaim || !channelClaim.meta) { if (!channelClaim || !channelClaim.meta) {
return null; return null;
@ -37,6 +38,7 @@ function ChannelStakedIndicator(props: Props) {
const isControlling = channelClaim && channelClaim.meta.is_controlling; const isControlling = channelClaim && channelClaim.meta.is_controlling;
const icon = getChannelIcon(level); const icon = getChannelIcon(level);
if (!hideTooltip) {
return ( return (
<Tooltip <Tooltip
title={ title={
@ -64,6 +66,18 @@ function ChannelStakedIndicator(props: Props) {
</div> </div>
</Tooltip> </Tooltip>
); );
} else {
return (
<div
className={classnames('channel-staked__wrapper', {
'channel-staked__wrapper--large': large,
'channel-staked__wrapper--inline': inline,
})}
>
<LevelIcon icon={icon} large={large} isControlling={isControlling} />
</div>
);
}
} }
type LevelIconProps = { type LevelIconProps = {

View file

@ -23,6 +23,7 @@ type Props = {
showDelayedMessage?: boolean, showDelayedMessage?: boolean,
noLazyLoad?: boolean, noLazyLoad?: boolean,
hideStakedIndicator?: boolean, hideStakedIndicator?: boolean,
hideTooltip?: boolean,
xsmall?: boolean, xsmall?: boolean,
noOptimization?: boolean, noOptimization?: boolean,
setThumbUploadError: (boolean) => void, setThumbUploadError: (boolean) => void,
@ -45,17 +46,28 @@ function ChannelThumbnail(props: Props) {
showDelayedMessage = false, showDelayedMessage = false,
noLazyLoad, noLazyLoad,
hideStakedIndicator = false, hideStakedIndicator = false,
hideTooltip,
setThumbUploadError, setThumbUploadError,
ThumbUploadError, ThumbUploadError,
} = props; } = props;
const [retries, setRetries] = React.useState(3);
const [thumbLoadError, setThumbLoadError] = React.useState(ThumbUploadError); const [thumbLoadError, setThumbLoadError] = React.useState(ThumbUploadError);
const shouldResolve = claim === undefined; const shouldResolve = !isResolving && claim === undefined;
const thumbnail = rawThumbnail && rawThumbnail.trim().replace(/^http:\/\//i, 'https://'); const thumbnail = rawThumbnail && rawThumbnail.trim().replace(/^http:\/\//i, 'https://');
const thumbnailPreview = rawThumbnailPreview && rawThumbnailPreview.trim().replace(/^http:\/\//i, 'https://'); const thumbnailPreview = rawThumbnailPreview && rawThumbnailPreview.trim().replace(/^http:\/\//i, 'https://');
const defaultAvatar = AVATAR_DEFAULT || Gerbil; const defaultAvatar = AVATAR_DEFAULT || Gerbil;
const channelThumbnail = thumbnailPreview || thumbnail || defaultAvatar; const channelThumbnail = thumbnailPreview || thumbnail || defaultAvatar;
const isGif = channelThumbnail && channelThumbnail.endsWith('gif'); const isGif = channelThumbnail && channelThumbnail.endsWith('gif');
const showThumb = (!obscure && !!thumbnail) || thumbnailPreview; const showThumb = (!obscure && !!thumbnail) || thumbnailPreview;
const avatarSrc = React.useMemo(() => {
if (retries <= 0) {
return defaultAvatar;
}
if (!thumbLoadError) {
return channelThumbnail;
}
return defaultAvatar;
}, [retries, thumbLoadError, channelThumbnail, defaultAvatar]);
// Generate a random color class based on the first letter of the channel name // Generate a random color class based on the first letter of the channel name
const { channelName } = parseURI(uri); const { channelName } = parseURI(uri);
@ -77,7 +89,7 @@ function ChannelThumbnail(props: Props) {
if (isGif && !allowGifs) { if (isGif && !allowGifs) {
return ( return (
<FreezeframeWrapper src={channelThumbnail} className={classnames('channel-thumbnail', className)}> <FreezeframeWrapper src={channelThumbnail} className={classnames('channel-thumbnail', className)}>
{!hideStakedIndicator && <ChannelStakedIndicator uri={uri} claim={claim} />} {!hideStakedIndicator && <ChannelStakedIndicator uri={uri} claim={claim} hideTooltip={hideTooltip} />}
</FreezeframeWrapper> </FreezeframeWrapper>
); );
} }
@ -91,21 +103,30 @@ function ChannelThumbnail(props: Props) {
'channel-thumbnail--resolving': isResolving, 'channel-thumbnail--resolving': isResolving,
})} })}
> >
{/* show delay necessary? */}
{showDelayedMessage ? ( {showDelayedMessage ? (
<div className="channel-thumbnail--waiting">{__('This will be visible in a few minutes.')}</div> <div className="channel-thumbnail--waiting">{__('This will be visible in a few minutes.')}</div>
) : ( ) : (
<OptimizedImage <OptimizedImage
alt={__('Channel profile picture')} alt={__('Channel profile picture')}
className={!channelThumbnail ? 'channel-thumbnail__default' : 'channel-thumbnail__custom'} className={!channelThumbnail ? 'channel-thumbnail__default' : 'channel-thumbnail__custom'}
src={(!thumbLoadError && channelThumbnail) || defaultAvatar} src={avatarSrc}
loading={noLazyLoad ? undefined : 'lazy'} loading={noLazyLoad ? undefined : 'lazy'}
onError={() => { onError={() => {
setRetries((retries) => retries - 1);
if (setThumbUploadError) { if (setThumbUploadError) {
setThumbUploadError(true); setThumbUploadError(true);
} else { } else {
setThumbLoadError(true); setThumbLoadError(true);
} }
}} }}
onLoad={() => {
if (setThumbUploadError) {
setThumbUploadError(false);
} else {
setThumbLoadError(false);
}
}}
/> />
)} )}
{!hideStakedIndicator && <ChannelStakedIndicator uri={uri} claim={claim} />} {!hideStakedIndicator && <ChannelStakedIndicator uri={uri} claim={claim} />}

View file

@ -115,19 +115,13 @@ const ClaimCollectionAdd = (props: Props) => {
inputButton={ inputButton={
<> <>
<Button <Button
button={'alt'}
icon={ICONS.ADD} icon={ICONS.ADD}
className={'button-toggle'} className={'button-toggle'}
disabled={!newCollectionName.length} disabled={!newCollectionName.length}
onClick={() => handleAddCollection()} onClick={() => handleAddCollection()}
ref={buttonref} ref={buttonref}
/> />
<Button <Button className={'button-toggle'} icon={ICONS.REMOVE} onClick={() => handleClearNew()} />
button={'alt'}
className={'button-toggle'}
icon={ICONS.REMOVE}
onClick={() => handleClearNew()}
/>
</> </>
} }
onChange={handleNameInput} onChange={handleNameInput}

View file

@ -102,6 +102,7 @@ export default function ClaimList(props: Props) {
let tileUris = (prefixUris || []).concat(uris || []); let tileUris = (prefixUris || []).concat(uris || []);
tileUris = tileUris.filter((uri) => !excludeUris.includes(uri)); tileUris = tileUris.filter((uri) => !excludeUris.includes(uri));
if (prefixUris && prefixUris.length) tileUris.splice(prefixUris.length * -1, prefixUris.length);
const totalLength = tileUris.length; const totalLength = tileUris.length;
@ -143,7 +144,7 @@ export default function ClaimList(props: Props) {
const mainEl = document.querySelector(`.${MAIN_CLASS}`); const mainEl = document.querySelector(`.${MAIN_CLASS}`);
if (mainEl && !loading && urisLength >= pageSize) { if (mainEl && !loading && urisLength >= pageSize) {
const contentWrapperAtBottomOfPage = mainEl.getBoundingClientRect().bottom - 0.5 <= window.innerHeight; const contentWrapperAtBottomOfPage = mainEl.getBoundingClientRect().bottom - 1.5 <= window.innerHeight;
if (contentWrapperAtBottomOfPage) { if (contentWrapperAtBottomOfPage) {
onScrollBottom(); onScrollBottom();

View file

@ -253,7 +253,7 @@ function ClaimListDiscover(props: Props) {
release_time?: string, release_time?: string,
claim_type?: string | Array<string>, claim_type?: string | Array<string>,
name?: string, name?: string,
duration?: string, duration?: string | Array<string>,
reposted_claim_id?: string, reposted_claim_id?: string,
stream_types?: any, stream_types?: any,
fee_amount?: string, fee_amount?: string,
@ -345,6 +345,8 @@ function ClaimListDiscover(props: Props) {
options.duration = '<=240'; options.duration = '<=240';
} else if (durationParam === CS.DURATION_LONG) { } else if (durationParam === CS.DURATION_LONG) {
options.duration = '>=1200'; options.duration = '>=1200';
} else if (durationParam === CS.DURATION_MEDIUM) {
options.duration = ['<=1200', '>=240'];
} }
} }

View file

@ -230,7 +230,6 @@ function ClaimListHeader(props: Props) {
{CS.ORDER_BY_TYPES.map((type) => ( {CS.ORDER_BY_TYPES.map((type) => (
<Button <Button
key={type} key={type}
button="alt"
onClick={(e) => onClick={(e) =>
handleChange({ handleChange({
key: CS.ORDER_BY_KEY, key: CS.ORDER_BY_KEY,
@ -251,7 +250,6 @@ function ClaimListHeader(props: Props) {
<div className="claim-search__menu-group"> <div className="claim-search__menu-group">
{!hideAdvancedFilter && ( {!hideAdvancedFilter && (
<Button <Button
button="alt"
aria-label={__('More')} aria-label={__('More')}
className={classnames(`button-toggle button-toggle--top button-toggle--more`, { className={classnames(`button-toggle button-toggle--top button-toggle--more`, {
'button-toggle--custom': isFiltered(), 'button-toggle--custom': isFiltered(),
@ -261,7 +259,8 @@ function ClaimListHeader(props: Props) {
onClick={() => setExpanded(!expanded)} onClick={() => setExpanded(!expanded)}
/> />
)} )}
</div>
<div className="claim-search__menu-group">
{tileLayout !== undefined && ( {tileLayout !== undefined && (
<Button <Button
onClick={() => { onClick={() => {
@ -424,7 +423,8 @@ function ClaimListHeader(props: Props) {
{CS.DURATION_TYPES.map((dur) => ( {CS.DURATION_TYPES.map((dur) => (
<option key={dur} value={dur}> <option key={dur} value={dur}>
{/* i18fixme */} {/* i18fixme */}
{dur === CS.DURATION_SHORT && __('Short (< 4 minutes)')} {dur === CS.DURATION_SHORT && __('Short (< 4 min)')}
{dur === CS.DURATION_MEDIUM && __('Medium (4 - 20 min)')}
{dur === CS.DURATION_LONG && __('Long (> 20 min)')} {dur === CS.DURATION_LONG && __('Long (> 20 min)')}
{dur === CS.DURATION_ALL && __('Any')} {dur === CS.DURATION_ALL && __('Any')}
</option> </option>

View file

@ -3,10 +3,12 @@ import { selectClaimForUri, selectClaimIsMine } from 'redux/selectors/claims';
import { doCollectionEdit, doFetchItemsInCollection } from 'redux/actions/collections'; import { doCollectionEdit, doFetchItemsInCollection } from 'redux/actions/collections';
import { doPrepareEdit } from 'redux/actions/publish'; import { doPrepareEdit } from 'redux/actions/publish';
import { import {
makeSelectCollectionForId,
makeSelectCollectionForIdHasClaimUrl, makeSelectCollectionForIdHasClaimUrl,
makeSelectCollectionIsMine, makeSelectCollectionIsMine,
makeSelectEditedCollectionForId, makeSelectEditedCollectionForId,
makeSelectUrlsForCollectionId, makeSelectUrlsForCollectionId,
selectLastUsedCollection,
} from 'redux/selectors/collections'; } from 'redux/selectors/collections';
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
import * as COLLECTIONS_CONSTS from 'constants/collections'; import * as COLLECTIONS_CONSTS from 'constants/collections';
@ -43,6 +45,8 @@ const select = (state, props) => {
const shuffleList = selectListShuffle(state); const shuffleList = selectListShuffle(state);
const shuffle = shuffleList && shuffleList.collectionId === collectionId && shuffleList.newUrls; const shuffle = shuffleList && shuffleList.collectionId === collectionId && shuffleList.newUrls;
const playNextUri = shuffle && shuffle[0]; const playNextUri = shuffle && shuffle[0];
const lastUsedCollectionId = selectLastUsedCollection(state);
const lastUsedCollection = makeSelectCollectionForId(lastUsedCollectionId)(state);
return { return {
claim, claim,
@ -70,6 +74,14 @@ const select = (state, props) => {
editedCollection: makeSelectEditedCollectionForId(collectionId)(state), editedCollection: makeSelectEditedCollectionForId(collectionId)(state),
resolvedList: makeSelectUrlsForCollectionId(collectionId)(state), resolvedList: makeSelectUrlsForCollectionId(collectionId)(state),
playNextUri, playNextUri,
lastUsedCollection,
hasClaimInLastUsedCollection: makeSelectCollectionForIdHasClaimUrl(
lastUsedCollectionId,
contentPermanentUri
)(state),
lastUsedCollectionIsNotBuiltin:
lastUsedCollectionId !== COLLECTIONS_CONSTS.WATCH_LATER_ID &&
lastUsedCollectionId !== COLLECTIONS_CONSTS.FAVORITES_ID,
}; };
}; };

View file

@ -39,7 +39,7 @@ type Props = {
doChannelUnmute: (string) => void, doChannelUnmute: (string) => void,
doCommentModBlock: (string) => void, doCommentModBlock: (string) => void,
doCommentModUnBlock: (string) => void, doCommentModUnBlock: (string) => void,
doCommentModBlockAsAdmin: (string, string) => void, doCommentModBlockAsAdmin: (string, ?string, ?string) => void,
doCommentModUnBlockAsAdmin: (string, string) => void, doCommentModUnBlockAsAdmin: (string, string) => void,
doCollectionEdit: (string, any) => void, doCollectionEdit: (string, any) => void,
hasClaimInWatchLater: boolean, hasClaimInWatchLater: boolean,
@ -60,6 +60,9 @@ type Props = {
resolvedList: boolean, resolvedList: boolean,
fetchCollectionItems: (string) => void, fetchCollectionItems: (string) => void,
doToggleShuffleList: (string) => void, doToggleShuffleList: (string) => void,
lastUsedCollection: ?Collection,
hasClaimInLastUsedCollection: boolean,
lastUsedCollectionIsNotBuiltin: boolean,
}; };
function ClaimMenuList(props: Props) { function ClaimMenuList(props: Props) {
@ -100,10 +103,18 @@ function ClaimMenuList(props: Props) {
resolvedList, resolvedList,
fetchCollectionItems, fetchCollectionItems,
doToggleShuffleList, doToggleShuffleList,
lastUsedCollection,
hasClaimInLastUsedCollection,
lastUsedCollectionIsNotBuiltin,
} = props; } = props;
const [doShuffle, setDoShuffle] = React.useState(false); const [doShuffle, setDoShuffle] = React.useState(false);
const incognitoClaim = contentChannelUri && !contentChannelUri.includes('@'); const incognitoClaim = contentChannelUri && !contentChannelUri.includes('@');
const isChannel = !incognitoClaim && !contentSigningChannel; const isChannel = !incognitoClaim && !contentSigningChannel;
// $FlowFixMe
const claimLength = claim && claim.value && claim.value.claims && claim.value.claims.length;
// $FlowFixMe
const claimCount = editedCollection ? editedCollection.items.length : claimLength;
const isEmptyCollection = (Number(claimCount) || 0) <= 0;
const { channelName } = parseURI(contentChannelUri); const { channelName } = parseURI(contentChannelUri);
const showDelete = claimIsMine || (fileInfo && (fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0)); const showDelete = claimIsMine || (fileInfo && (fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0));
const subscriptionLabel = repostedClaim const subscriptionLabel = repostedClaim
@ -226,7 +237,7 @@ function ClaimMenuList(props: Props) {
if (channelIsAdminBlocked) { if (channelIsAdminBlocked) {
doCommentModUnBlockAsAdmin(contentChannelUri, ''); doCommentModUnBlockAsAdmin(contentChannelUri, '');
} else { } else {
doCommentModBlockAsAdmin(contentChannelUri, ''); doCommentModBlockAsAdmin(contentChannelUri, undefined, undefined);
} }
} }
@ -291,6 +302,7 @@ function ClaimMenuList(props: Props) {
{__('View List')} {__('View List')}
</a> </a>
</MenuItem> </MenuItem>
{!isEmptyCollection && (
<MenuItem <MenuItem
className="comment__menu-option" className="comment__menu-option"
onSelect={() => { onSelect={() => {
@ -303,6 +315,7 @@ function ClaimMenuList(props: Props) {
{__('Shuffle Play')} {__('Shuffle Play')}
</div> </div>
</MenuItem> </MenuItem>
)}
{isMyCollection && ( {isMyCollection && (
<> <>
<MenuItem <MenuItem
@ -359,6 +372,22 @@ function ClaimMenuList(props: Props) {
{__('Add to Lists')} {__('Add to Lists')}
</div> </div>
</MenuItem> </MenuItem>
{lastUsedCollection && lastUsedCollectionIsNotBuiltin && (
<MenuItem
className="comment__menu-option"
onSelect={() =>
handleAdd(hasClaimInLastUsedCollection, lastUsedCollection.name, lastUsedCollection.id)
}
>
<div className="menu__link">
{!hasClaimInLastUsedCollection && <Icon aria-hidden icon={ICONS.ADD} />}
{hasClaimInLastUsedCollection && <Icon aria-hidden icon={ICONS.DELETE} />}
{!hasClaimInLastUsedCollection &&
__('Add to %collection%', { collection: lastUsedCollection.name })}
{hasClaimInLastUsedCollection && __('In %collection%', { collection: lastUsedCollection.name })}
</div>
</MenuItem>
)}
<hr className="menu__separator" /> <hr className="menu__separator" />
</> </>
) )

View file

@ -11,17 +11,24 @@ function ClaimPreviewLoading(props: Props) {
const { isChannel, type } = props; const { isChannel, type } = props;
return ( return (
<li <li
className={classnames('claim-preview__wrapper', { className={classnames('placeholder claim-preview__wrapper', {
'claim-preview__wrapper--channel': isChannel && type !== 'inline', 'claim-preview__wrapper--channel': isChannel && type !== 'inline',
'claim-preview__wrapper--inline': type === 'inline', 'claim-preview__wrapper--inline': type === 'inline',
'claim-preview__wrapper--small': type === 'small', 'claim-preview__wrapper--small': type === 'small',
})} })}
> >
<div className={classnames('claim-preview', { 'claim-preview--large': type === 'large' })}> <div className={classnames('claim-preview', { 'claim-preview--large': type === 'large' })}>
<div className="placeholder media__thumb" /> <div className="media__thumb" />
<div className="placeholder__wrapper"> <div className="placeholder__wrapper">
<div className="placeholder claim-preview__title" /> <div className="claim-preview__title" />
<div className="placeholder media__subtitle" /> <div className="claim-preview__title_b" />
<div className="claim-tile__info">
<div className="channel-thumbnail" />
<div className="claim-tile__about">
<div className="media__subtitle" />
<div className="media__subtitle_b" />
</div>
</div>
</div> </div>
</div> </div>
</li> </li>

View file

@ -9,7 +9,7 @@ import * as COLLECTIONS_CONSTS from 'constants/collections';
import { isChannelClaim } from 'util/claim'; import { isChannelClaim } from 'util/claim';
import { formatLbryUrlForWeb } from 'util/url'; import { formatLbryUrlForWeb } from 'util/url';
import { formatClaimPreviewTitle } from 'util/formatAriaLabel'; import { formatClaimPreviewTitle } from 'util/formatAriaLabel';
import { toCompactNotation } from 'util/string'; import { formatNumber } from 'util/number';
import Tooltip from 'component/common/tooltip'; import Tooltip from 'component/common/tooltip';
import FileThumbnail from 'component/fileThumbnail'; import FileThumbnail from 'component/fileThumbnail';
import UriIndicator from 'component/uriIndicator'; import UriIndicator from 'component/uriIndicator';
@ -30,6 +30,7 @@ import ClaimPreviewLoading from './claim-preview-loading';
import ClaimPreviewHidden from './claim-preview-no-mature'; import ClaimPreviewHidden from './claim-preview-no-mature';
import ClaimPreviewNoContent from './claim-preview-no-content'; import ClaimPreviewNoContent from './claim-preview-no-content';
import CollectionEditButtons from 'component/collectionEditButtons'; import CollectionEditButtons from 'component/collectionEditButtons';
import { useIsMobile } from 'effects/use-screensize';
import AbandonedChannelPreview from 'component/abandonedChannelPreview'; import AbandonedChannelPreview from 'component/abandonedChannelPreview';
// preview images used on the landing page and on the channel page // preview images used on the landing page and on the channel page
@ -137,12 +138,13 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
indexInContainer, indexInContainer,
channelSubCount, channelSubCount,
swipeLayout = false, swipeLayout = false,
lang,
showEdit, showEdit,
dragHandleProps, dragHandleProps,
unavailableUris, unavailableUris,
} = props; } = props;
const isMobile = useIsMobile();
const isCollection = claim && claim.value_type === 'collection'; const isCollection = claim && claim.value_type === 'collection';
const collectionClaimId = isCollection && claim && claim.claim_id; const collectionClaimId = isCollection && claim && claim.claim_id;
const listId = collectionId || collectionClaimId; const listId = collectionId || collectionClaimId;
@ -159,16 +161,19 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
if (channelSubCount === undefined) { if (channelSubCount === undefined) {
return <span />; return <span />;
} }
const formattedSubCount = toCompactNotation(channelSubCount, lang, 10000); const formattedSubCount = formatNumber(channelSubCount, 2, true);
const formattedSubCountLocale = formatNumber(channelSubCount, 2, false);
return ( return (
<Tooltip title={channelSubCount} followCursor placement="top"> <div className="media__subtitle">
<Tooltip title={formattedSubCountLocale} followCursor placement="top">
<span className="claim-preview__channel-sub-count"> <span className="claim-preview__channel-sub-count">
{channelSubCount === 1 ? __('1 Follower') : __('%formattedSubCount% Followers', { formattedSubCount })} {channelSubCount === 1 ? __('1 Follower') : __('%formattedSubCount% Followers', { formattedSubCount })}
</span> </span>
</Tooltip> </Tooltip>
</div>
); );
}, [channelSubCount]); }, [channelSubCount]);
const isValid = uri && isURIValid(uri); const isValid = uri && isURIValid(uri, false);
// $FlowFixMe // $FlowFixMe
const isPlayable = const isPlayable =
@ -347,7 +352,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
<> <>
{!pending ? ( {!pending ? (
<NavLink aria-hidden tabIndex={-1} {...navLinkProps}> <NavLink aria-hidden tabIndex={-1} {...navLinkProps}>
<FileThumbnail thumbnail={thumbnailUrl}> <FileThumbnail uri={uri} thumbnail={thumbnailUrl}>
<div className="claim-preview__hover-actions"> <div className="claim-preview__hover-actions">
{isPlayable && <FileWatchLaterLink focusable={false} uri={repostedContentUri} />} {isPlayable && <FileWatchLaterLink focusable={false} uri={repostedContentUri} />}
</div> </div>
@ -359,12 +364,12 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
</div> </div>
{/* @endif */} {/* @endif */}
<div className="claim-preview__file-property-overlay"> <div className="claim-preview__file-property-overlay">
<PreviewOverlayProperties uri={uri} /> <PreviewOverlayProperties uri={uri} small={type === 'small'} />
</div> </div>
</FileThumbnail> </FileThumbnail>
</NavLink> </NavLink>
) : ( ) : (
<FileThumbnail thumbnail={thumbnailUrl} /> <FileThumbnail uri={uri} thumbnail={thumbnailUrl} />
)} )}
</> </>
)} )}
@ -380,10 +385,19 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
</NavLink> </NavLink>
)} )}
</div> </div>
<div className="claim-tile__info" uri={uri}>
{!isChannelUri && signingChannel && (
<div className="claim-preview__channel-staked">
<UriIndicator focusable={false} uri={uri} link hideAnonymous>
<ChannelThumbnail uri={signingChannel.permanent_url} xsmall />
</UriIndicator>
</div>
)}
<ClaimPreviewSubtitle uri={uri} type={type} /> <ClaimPreviewSubtitle uri={uri} type={type} />
{(pending || !!reflectingProgress) && <PublishPending uri={uri} />} {(pending || !!reflectingProgress) && <PublishPending uri={uri} />}
{channelSubscribers} {channelSubscribers}
</div> </div>
</div>
{type !== 'small' && ( {type !== 'small' && (
<div className="claim-preview__actions"> <div className="claim-preview__actions">
{!pending && ( {!pending && (
@ -393,11 +407,6 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
actions actions
) : ( ) : (
<div className="claim-preview__primary-actions"> <div className="claim-preview__primary-actions">
{!isChannelUri && signingChannel && (
<div className="claim-preview__channel-staked">
<ChannelThumbnail uri={signingChannel.permanent_url} xsmall />
</div>
)}
{isChannelUri && !banState.muted && !claimIsMine && ( {isChannelUri && !banState.muted && !claimIsMine && (
<SubscribeButton <SubscribeButton
uri={repostedChannelUri || (uri.startsWith('lbry://') ? uri : `lbry://${uri}`)} uri={repostedChannelUri || (uri.startsWith('lbry://') ? uri : `lbry://${uri}`)}
@ -411,13 +420,11 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
)} )}
{claim && ( {claim && (
<React.Fragment> <React.Fragment>
{typeof properties === 'function' ? ( {typeof properties === 'function'
properties(claim) ? properties(claim)
) : properties !== undefined ? ( : properties !== undefined
properties ? properties
) : ( : !isMobile && <ClaimTags uri={uri} type={type} />}
<ClaimTags uri={uri} type={type} />
)}
</React.Fragment> </React.Fragment>
)} )}
</div> </div>

View file

@ -5,6 +5,7 @@ import DateTime from 'component/dateTime';
import Button from 'component/button'; import Button from 'component/button';
import FileViewCountInline from 'component/fileViewCountInline'; import FileViewCountInline from 'component/fileViewCountInline';
import { parseURI } from 'util/lbryURI'; import { parseURI } from 'util/lbryURI';
import { formatNumber } from 'util/number';
type Props = { type Props = {
uri: string, uri: string,
@ -34,7 +35,7 @@ function ClaimPreviewSubtitle(props: Props) {
<> <>
{isChannel && {isChannel &&
type !== 'inline' && type !== 'inline' &&
`${claimsInChannel} ${claimsInChannel === 1 ? __('upload') : __('uploads')}`} `${formatNumber(claimsInChannel, 2, true)} ${claimsInChannel === 1 ? __('upload') : __('uploads')}`}
{!isChannel && ( {!isChannel && (
<> <>

View file

@ -8,7 +8,6 @@ import TruncatedText from 'component/common/truncated-text';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import ChannelThumbnail from 'component/channelThumbnail'; import ChannelThumbnail from 'component/channelThumbnail';
import FileViewCountInline from 'component/fileViewCountInline'; import FileViewCountInline from 'component/fileViewCountInline';
import SubscribeButton from 'component/subscribeButton';
import useGetThumbnail from 'effects/use-get-thumbnail'; import useGetThumbnail from 'effects/use-get-thumbnail';
import { formatLbryUrlForWeb, generateListSearchUrlParams } from 'util/url'; import { formatLbryUrlForWeb, generateListSearchUrlParams } from 'util/url';
import { formatClaimPreviewTitle } from 'util/formatAriaLabel'; import { formatClaimPreviewTitle } from 'util/formatAriaLabel';
@ -85,7 +84,6 @@ function ClaimPreviewTile(props: Props) {
const shouldFetch = claim === undefined; const shouldFetch = claim === undefined;
const thumbnailUrl = useGetThumbnail(uri, claim, streamingUrl, getFile, placeholder) || thumbnail; const thumbnailUrl = useGetThumbnail(uri, claim, streamingUrl, getFile, placeholder) || thumbnail;
const canonicalUrl = claim && claim.canonical_url; const canonicalUrl = claim && claim.canonical_url;
const permanentUrl = claim && claim.permanent_url;
const repostedContentUri = claim && (claim.reposted_claim ? claim.reposted_claim.permanent_url : claim.permanent_url); const repostedContentUri = claim && (claim.reposted_claim ? claim.reposted_claim.permanent_url : claim.permanent_url);
const listId = collectionId || collectionClaimId; const listId = collectionId || collectionClaimId;
const navigateUrl = const navigateUrl =
@ -110,7 +108,6 @@ function ClaimPreviewTile(props: Props) {
const isChannel = claim && claim.value_type === 'channel'; const isChannel = claim && claim.value_type === 'channel';
const channelUri = !isChannel ? signingChannel && signingChannel.permanent_url : claim && claim.permanent_url; const channelUri = !isChannel ? signingChannel && signingChannel.permanent_url : claim && claim.permanent_url;
const channelTitle = signingChannel && ((signingChannel.value && signingChannel.value.title) || signingChannel.name); const channelTitle = signingChannel && ((signingChannel.value && signingChannel.value.title) || signingChannel.name);
const repostedChannelUri = isRepost && isChannel ? permanentUrl || canonicalUrl : undefined;
// Aria-label value for claim preview // Aria-label value for claim preview
let ariaLabelData = isChannel ? title : formatClaimPreviewTitle(title, channelTitle, date, mediaDuration); let ariaLabelData = isChannel ? title : formatClaimPreviewTitle(title, channelTitle, date, mediaDuration);
@ -148,17 +145,24 @@ function ClaimPreviewTile(props: Props) {
if (placeholder || (!claim && isResolvingUri)) { if (placeholder || (!claim && isResolvingUri)) {
return ( return (
<li className={classnames('claim-preview--tile', {})}> <li className={classnames('placeholder claim-preview--tile', {})}>
<div className="placeholder media__thumb"> <div className="media__thumb">
<img src={PlaceholderTx} alt="Placeholder" /> <img src={PlaceholderTx} alt="Placeholder" />
</div> </div>
<div className="placeholder__wrapper"> <div className="placeholder__wrapper">
<div className="placeholder claim-tile__title" /> <div className="claim-tile__title" />
<div className="claim-tile__title_b" />
<div <div
className={classnames('claim-tile__info placeholder', { className={classnames('claim-tile__info', {
contains_view_count: shouldShowViewCount, contains_view_count: shouldShowViewCount,
})} })}
/> >
<div className="channel-thumbnail" />
<div className="claim-tile__about">
<div className="button__content" />
<div className="claim-tile__about--counts" />
</div>
</div>
</div> </div>
</li> </li>
); );
@ -175,7 +179,7 @@ function ClaimPreviewTile(props: Props) {
})} })}
> >
<NavLink {...navLinkProps} role="none" tabIndex={-1} aria-hidden> <NavLink {...navLinkProps} role="none" tabIndex={-1} aria-hidden>
<FileThumbnail thumbnail={thumbnailUrl} allowGifs> <FileThumbnail uri={uri} thumbnail={thumbnailUrl} allowGifs>
{!isChannel && ( {!isChannel && (
<React.Fragment> <React.Fragment>
<div className="claim-preview__hover-actions"> <div className="claim-preview__hover-actions">
@ -220,11 +224,7 @@ function ClaimPreviewTile(props: Props) {
contains_view_count: shouldShowViewCount, contains_view_count: shouldShowViewCount,
})} })}
> >
{isChannel ? ( {!isChannel && (
<div className="claim-tile__about--channel">
<SubscribeButton uri={repostedChannelUri || uri} />
</div>
) : (
<React.Fragment> <React.Fragment>
<UriIndicator focusable={false} uri={uri} link hideAnonymous> <UriIndicator focusable={false} uri={uri} link hideAnonymous>
<ChannelThumbnail uri={channelUri} xsmall /> <ChannelThumbnail uri={channelUri} xsmall />

View file

@ -19,8 +19,11 @@ function ClaimRepostAuthor(props: Props) {
if (short && repostUrl) { if (short && repostUrl) {
return ( return (
<span className="claim-preview__repost-author"> <span className="claim-preview__repost-author">
<div className="claim-preview__repost-ribbon">
<Icon icon={ICONS.REPOST} size={12} /> <Icon icon={ICONS.REPOST} size={12} />
<br />
<span>{repostUrl}</span> <span>{repostUrl}</span>
</div>
</span> </span>
); );
} }
@ -28,17 +31,19 @@ function ClaimRepostAuthor(props: Props) {
if (repostUrl && !repostChannelUrl) { if (repostUrl && !repostChannelUrl) {
return ( return (
<div className="claim-preview__repost-author"> <div className="claim-preview__repost-author">
<div className="claim-preview__repost-ribbon claim-preview__repost-ribbon--anon">
<Icon icon={ICONS.REPOST} size={10} /> <Icon icon={ICONS.REPOST} size={10} />
<span> <span>
<I18nMessage <I18nMessage
tokens={{ tokens={{
anonymous: <strong>{__('Anonymous --[used in <%anonymous% Reposted>]--')}</strong>, anonymous: <strong>{__('Anon --[used in <%anonymous% Reposted>]--')}</strong>,
}} }}
> >
%anonymous% Reposted %anonymous%
</I18nMessage> </I18nMessage>
</span> </span>
</div> </div>
</div>
); );
} }
if (!repostUrl) { if (!repostUrl) {
@ -47,10 +52,11 @@ function ClaimRepostAuthor(props: Props) {
return ( return (
<div className="claim-preview__repost-author"> <div className="claim-preview__repost-author">
<div className="claim-preview__repost-ribbon">
<Icon icon={ICONS.REPOST} size={10} className="claim-preview__repost-icon" /> <Icon icon={ICONS.REPOST} size={10} className="claim-preview__repost-icon" />
<I18nMessage tokens={{ repost_channel_link: <UriIndicator link uri={repostChannelUrl} /> }}> <br />
%repost_channel_link% reposted <UriIndicator link uri={repostChannelUrl} />
</I18nMessage> </div>
</div> </div>
); );
} }

View file

@ -23,7 +23,7 @@ export default function ClaimSupportButton(props: Props) {
return ( return (
<Button <Button
button={fileAction ? undefined : 'alt'} button={fileAction ? undefined : 'secondary'}
className={classnames({ 'button--file-action': fileAction })} className={classnames({ 'button--file-action': fileAction })}
icon={ICONS.LBC} icon={ICONS.LBC}
iconSize={fileAction ? 22 : undefined} iconSize={fileAction ? 22 : undefined}

View file

@ -9,6 +9,7 @@ import { doToggleTagFollowDesktop } from 'redux/actions/tags';
import { makeSelectClientSetting, selectShowMatureContent } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectShowMatureContent } from 'redux/selectors/settings';
import { selectMutedAndBlockedChannelIds } from 'redux/selectors/blocked'; import { selectMutedAndBlockedChannelIds } from 'redux/selectors/blocked';
import { ENABLE_NO_SOURCE_CLAIMS } from 'config'; import { ENABLE_NO_SOURCE_CLAIMS } from 'config';
import { createNormalizedClaimSearchKey } from 'util/claim';
import ClaimListDiscover from './view'; import ClaimListDiscover from './view';
@ -17,13 +18,22 @@ const select = (state, props) => {
const hideReposts = makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state); const hideReposts = makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state);
const mutedAndBlockedChannelIds = selectMutedAndBlockedChannelIds(state); const mutedAndBlockedChannelIds = selectMutedAndBlockedChannelIds(state);
return { const options = resolveSearchOptions({
claimSearchByQuery: selectClaimSearchByQuery(state),
claimsByUri: selectClaimsByUri(state),
fetchingClaimSearchByQuery: selectFetchingClaimSearchByQuery(state),
showNsfw, showNsfw,
hideReposts, hideReposts,
options: resolveSearchOptions({ showNsfw, hideReposts, mutedAndBlockedChannelIds, pageSize: 8, ...props }), mutedAndBlockedChannelIds,
pageSize: 8,
...props,
});
const searchKey = createNormalizedClaimSearchKey(options);
return {
claimSearchResults: selectClaimSearchByQuery(state)[searchKey],
claimsByUri: selectClaimsByUri(state),
fetchingClaimSearch: selectFetchingClaimSearchByQuery(state)[searchKey],
showNsfw,
hideReposts,
optionsStringified: JSON.stringify(options),
}; };
}; };

View file

@ -1,31 +1,8 @@
// @flow // @flow
import type { Node } from 'react'; import type { Node } from 'react';
import React from 'react'; import React from 'react';
import { createNormalizedClaimSearchKey } from 'util/claim';
import ClaimPreviewTile from 'component/claimPreviewTile'; import ClaimPreviewTile from 'component/claimPreviewTile';
import useFetchViewCount from 'effects/use-fetch-view-count'; import useFetchViewCount from 'effects/use-fetch-view-count';
import usePrevious from 'effects/use-previous';
type SearchOptions = {
page_size: number,
page: number,
no_totals: boolean,
any_tags: Array<string>,
channel_ids: Array<string>,
claim_ids?: Array<string>,
not_channel_ids: Array<string>,
not_tags: Array<string>,
order_by: Array<string>,
languages?: Array<string>,
release_time?: string,
claim_type?: string | Array<string>,
timestamp?: string,
fee_amount?: string,
limit_claims_per_channel?: number,
stream_types?: Array<string>,
has_source?: boolean,
has_no_source?: boolean,
};
function urisEqual(prev: ?Array<string>, next: ?Array<string>) { function urisEqual(prev: ?Array<string>, next: ?Array<string>) {
if (!prev || !next) { if (!prev || !next) {
@ -68,12 +45,12 @@ type Props = {
hasNoSource?: boolean, hasNoSource?: boolean,
// --- select --- // --- select ---
location: { search: string }, location: { search: string },
claimSearchByQuery: { [string]: Array<string> }, claimSearchResults: Array<string>,
claimsByUri: { [string]: any }, claimsByUri: { [string]: any },
fetchingClaimSearchByQuery: { [string]: boolean }, fetchingClaimSearch: boolean,
showNsfw: boolean, showNsfw: boolean,
hideReposts: boolean, hideReposts: boolean,
options: SearchOptions, optionsStringified: string,
// --- perform --- // --- perform ---
doClaimSearch: ({}) => void, doClaimSearch: ({}) => void,
doFetchViewCount: (claimIdCsv: string) => void, doFetchViewCount: (claimIdCsv: string) => void,
@ -82,10 +59,10 @@ type Props = {
function ClaimTilesDiscover(props: Props) { function ClaimTilesDiscover(props: Props) {
const { const {
doClaimSearch, doClaimSearch,
claimSearchByQuery, claimSearchResults,
claimsByUri, claimsByUri,
fetchViewCount, fetchViewCount,
fetchingClaimSearchByQuery, fetchingClaimSearch,
hasNoSource, hasNoSource,
renderProperties, renderProperties,
// pinUrls, // pinUrls,
@ -93,16 +70,15 @@ function ClaimTilesDiscover(props: Props) {
showNoSourceClaims, showNoSourceClaims,
doFetchViewCount, doFetchViewCount,
pageSize = 8, pageSize = 8,
options, optionsStringified,
} = props; } = props;
const searchKey = createNormalizedClaimSearchKey(options); const prevUris = React.useRef();
const fetchingClaimSearch = fetchingClaimSearchByQuery[searchKey]; const claimSearchUris = claimSearchResults || [];
const claimSearchUris = claimSearchByQuery[searchKey] || [];
const isUnfetchedClaimSearch = claimSearchByQuery[searchKey] === undefined; const isUnfetchedClaimSearch = claimSearchResults === undefined;
// Don't use the query from createNormalizedClaimSearchKey for the effect since that doesn't include page & release_time // Don't use the query from createNormalizedClaimSearchKey for the effect since that doesn't include page & release_time
const optionsStringForEffect = JSON.stringify(options);
const shouldPerformSearch = !fetchingClaimSearch && claimSearchUris.length === 0; const shouldPerformSearch = !fetchingClaimSearch && claimSearchUris.length === 0;
const uris = (prefixUris || []).concat(claimSearchUris); const uris = (prefixUris || []).concat(claimSearchUris);
@ -124,21 +100,19 @@ function ClaimTilesDiscover(props: Props) {
uris.push(...Array(pageSize - uris.length).fill('')); uris.push(...Array(pageSize - uris.length).fill(''));
} }
const prevUris = usePrevious(uris);
useFetchViewCount(fetchViewCount, uris, claimsByUri, doFetchViewCount); useFetchViewCount(fetchViewCount, uris, claimsByUri, doFetchViewCount);
const finalUris = isUnfetchedClaimSearch && prevUris.current ? prevUris.current : uris;
prevUris.current = finalUris;
// Run `doClaimSearch` // Run `doClaimSearch`
React.useEffect(() => { React.useEffect(() => {
if (shouldPerformSearch) { if (shouldPerformSearch) {
const searchOptions = JSON.parse(optionsStringForEffect); const searchOptions = JSON.parse(optionsStringified);
doClaimSearch(searchOptions); doClaimSearch(searchOptions);
} }
}, [doClaimSearch, shouldPerformSearch, optionsStringForEffect]); }, [doClaimSearch, shouldPerformSearch, optionsStringified]);
// Show previous results while we fetch to avoid blinkies and poor CLS. // Show previous results while we fetch to avoid blinkies and poor CLS.
const finalUris = isUnfetchedClaimSearch && prevUris ? prevUris : uris;
return ( return (
<ul className="claim-grid"> <ul className="claim-grid">
{finalUris && finalUris.length {finalUris && finalUris.length
@ -167,33 +141,33 @@ function ClaimTilesDiscover(props: Props) {
export default React.memo<Props>(ClaimTilesDiscover, areEqual); export default React.memo<Props>(ClaimTilesDiscover, areEqual);
function debug_trace(val) { // ****************************************************************************
if (process.env.DEBUG_TRACE) console.log(`Render due to: ${val}`); // ****************************************************************************
function trace(key, value) {
// @if process.env.DEBUG_TILE_RENDER
// $FlowFixMe "cannot coerce certain types".
console.log(`[claimTilesDiscover] ${key}: ${value}`); // eslint-disable-line no-console
// @endif
} }
function areEqual(prev: Props, next: Props) { function areEqual(prev: Props, next: Props) {
const prevOptions: SearchOptions = prev.options; // --- Deep-compare ---
const nextOptions: SearchOptions = next.options; // These are props that are hard to memoize from where it is passed.
const prevSearchKey = createNormalizedClaimSearchKey(prevOptions); if (prev.claimType !== next.claimType) {
const nextSearchKey = createNormalizedClaimSearchKey(nextOptions); // Array<string>: confirm the contents are actually different.
if (prev.claimType && next.claimType && JSON.stringify(prev.claimType) !== JSON.stringify(next.claimType)) {
if (prevSearchKey !== nextSearchKey) { trace('claimType', next.claimType);
debug_trace('search key');
return false; return false;
} }
// --- Deep-compare ---
if (!urisEqual(prev.claimSearchByQuery[prevSearchKey], next.claimSearchByQuery[nextSearchKey])) {
debug_trace('claimSearchByQuery');
return false;
} }
const ARRAY_KEYS = ['prefixUris', 'channelIds']; const ARRAY_KEYS = ['prefixUris', 'channelIds'];
for (let i = 0; i < ARRAY_KEYS.length; ++i) { for (let i = 0; i < ARRAY_KEYS.length; ++i) {
const key = ARRAY_KEYS[i]; const key = ARRAY_KEYS[i];
if (!urisEqual(prev[key], next[key])) { if (!urisEqual(prev[key], next[key])) {
debug_trace(`${key}`); trace(key, next[key]);
return false; return false;
} }
} }
@ -203,22 +177,19 @@ function areEqual(prev: Props, next: Props) {
// to update this function. Better to render more than miss an important one. // to update this function. Better to render more than miss an important one.
const KEYS_TO_IGNORE = [ const KEYS_TO_IGNORE = [
...ARRAY_KEYS, ...ARRAY_KEYS,
'claimSearchByQuery', 'claimType', // Handled above.
'fetchingClaimSearchByQuery', // We are showing previous results while fetching. 'claimsByUri', // Used for view-count. Just ignore it for now.
'options', // Covered by search-key comparison.
'location', 'location',
'history', 'history',
'match', 'match',
'claimsByUri',
'doClaimSearch', 'doClaimSearch',
'doToggleTagFollowDesktop',
]; ];
const propKeys = Object.keys(next); const propKeys = Object.keys(next);
for (let i = 0; i < propKeys.length; ++i) { for (let i = 0; i < propKeys.length; ++i) {
const pk = propKeys[i]; const pk = propKeys[i];
if (!KEYS_TO_IGNORE.includes(pk) && prev[pk] !== next[pk]) { if (!KEYS_TO_IGNORE.includes(pk) && prev[pk] !== next[pk]) {
debug_trace(`${pk}`); trace(pk, next[pk]);
return false; return false;
} }
} }

View file

@ -54,9 +54,13 @@ function CollectionActions(props: Props) {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const claimId = claim && claim.claim_id; const claimId = claim && claim.claim_id;
const webShareable = true; // collections have cost? const webShareable = true; // collections have cost?
const isEmptyCollection = !firstItem;
const doPlay = React.useCallback( const doPlay = React.useCallback(
(playUri) => { (playUri) => {
if (!playUri) {
return;
}
const navigateUrl = formatLbryUrlForWeb(playUri); const navigateUrl = formatLbryUrlForWeb(playUri);
push({ push({
pathname: navigateUrl, pathname: navigateUrl,
@ -81,6 +85,7 @@ function CollectionActions(props: Props) {
icon={ICONS.PLAY} icon={ICONS.PLAY}
label={__('Play')} label={__('Play')}
title={__('Play')} title={__('Play')}
disabled={isEmptyCollection}
onClick={() => { onClick={() => {
doToggleShuffleList(collectionId, false); doToggleShuffleList(collectionId, false);
doPlay(firstItem); doPlay(firstItem);
@ -91,6 +96,7 @@ function CollectionActions(props: Props) {
icon={ICONS.SHUFFLE} icon={ICONS.SHUFFLE}
label={__('Shuffle Play')} label={__('Shuffle Play')}
title={__('Shuffle Play')} title={__('Shuffle Play')}
disabled={isEmptyCollection}
onClick={() => { onClick={() => {
doToggleShuffleList(collectionId, true); doToggleShuffleList(collectionId, true);
setDoShuffle(true); setDoShuffle(true);
@ -177,7 +183,7 @@ function CollectionActions(props: Props) {
if (isMobile) { if (isMobile) {
return ( return (
<div className="media__actions"> <div className="media__actions stretch">
{lhsSection} {lhsSection}
{rhsSection} {rhsSection}
{infoButtons} {infoButtons}

View file

@ -10,7 +10,6 @@ import Card from 'component/common/card';
import Button from 'component/button'; import Button from 'component/button';
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
import * as COLLECTIONS_CONSTS from 'constants/collections'; import * as COLLECTIONS_CONSTS from 'constants/collections';
import Icon from 'component/common/icon';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
type Props = { type Props = {
@ -58,21 +57,21 @@ export default function CollectionContent(props: Props) {
return ( return (
<Card <Card
isBodyList isBodyList
className="file-page__recommended-collection" className="file-page__playlist-collection"
title={ title={
<> <>
<span className="file-page__recommended-collection__row"> <Button
<Icon button="link"
className="file-page__playlist-collection__row"
navigate={`/$/${PAGES.LIST}/${id}`}
icon={ icon={
(id === COLLECTIONS_CONSTS.WATCH_LATER_ID && ICONS.TIME) || (id === COLLECTIONS_CONSTS.WATCH_LATER_ID && ICONS.TIME) ||
(id === COLLECTIONS_CONSTS.FAVORITES_ID && ICONS.STAR) || (id === COLLECTIONS_CONSTS.FAVORITES_ID && ICONS.STAR) ||
ICONS.STACK ICONS.STACK
} }
className="icon--margin-right" label={collectionName}
/> />
{collectionName} <span className="file-page__playlist-collection__row">
</span>
<span className="file-page__recommended-collection__row">
<Button <Button
button="alt" button="alt"
title={__('Loop')} title={__('Loop')}
@ -93,21 +92,14 @@ export default function CollectionContent(props: Props) {
</> </>
} }
titleActions={ titleActions={
<> isMyCollection && (
<div className="card__title-actions--link">
{/* TODO: BUTTON TO SAVE COLLECTION - Probably save/copy modal */}
<Button label={__('View List')} button="link" navigate={`/$/${PAGES.LIST}/${id}`} />
</div>
{isMyCollection && (
<Button <Button
title={__('Edit')} title={__('Edit')}
className={classnames('button-toggle', { 'button-toggle--active': showEdit })} className={classnames('button-toggle', { 'button-toggle--active': showEdit })}
icon={ICONS.EDIT} icon={ICONS.EDIT}
onClick={() => setShowEdit(!showEdit)} onClick={() => setShowEdit(!showEdit)}
/> />
)} )
</>
} }
body={ body={
<DragDropContext onDragEnd={handleOnDragEnd}> <DragDropContext onDragEnd={handleOnDragEnd}>

View file

@ -23,6 +23,7 @@ import CollectionForm from './view';
import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app'; import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app';
import { doSetActiveChannel, doSetIncognito } from 'redux/actions/app'; import { doSetActiveChannel, doSetIncognito } from 'redux/actions/app';
import { doCollectionEdit } from 'redux/actions/collections'; import { doCollectionEdit } from 'redux/actions/collections';
import { doResetThumbnailStatus } from 'redux/actions/publish';
const select = (state, props) => ({ const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state), claim: makeSelectClaimForUri(props.uri)(state),
@ -52,6 +53,7 @@ const perform = (dispatch, ownProps) => ({
setActiveChannel: (claimId) => dispatch(doSetActiveChannel(claimId)), setActiveChannel: (claimId) => dispatch(doSetActiveChannel(claimId)),
setIncognito: (incognito) => dispatch(doSetIncognito(incognito)), setIncognito: (incognito) => dispatch(doSetIncognito(incognito)),
doCollectionEdit: (params) => dispatch(doCollectionEdit(ownProps.collectionId, params)), doCollectionEdit: (params) => dispatch(doCollectionEdit(ownProps.collectionId, params)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
}); });
export default connect(select, perform)(CollectionForm); export default connect(select, perform)(CollectionForm);

View file

@ -17,7 +17,7 @@ import { useHistory } from 'react-router-dom';
import { isNameValid, regexInvalidURI } from 'util/lbryURI'; import { isNameValid, regexInvalidURI } from 'util/lbryURI';
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses'; import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'component/common/tabs'; import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'component/common/tabs';
import { FormField } from 'component/common/form'; import { FormField, FormFieldAreaAdvanced } from 'component/common/form';
import { handleBidChange } from 'util/publish'; import { handleBidChange } from 'util/publish';
import { FF_MAX_CHARS_IN_DESCRIPTION } from 'constants/form-field'; import { FF_MAX_CHARS_IN_DESCRIPTION } from 'constants/form-field';
import { INVALID_NAME_ERROR } from 'constants/claim'; import { INVALID_NAME_ERROR } from 'constants/claim';
@ -58,6 +58,7 @@ type Props = {
setActiveChannel: (string) => void, setActiveChannel: (string) => void,
setIncognito: (boolean) => void, setIncognito: (boolean) => void,
doCollectionEdit: (CollectionEditParams) => void, doCollectionEdit: (CollectionEditParams) => void,
resetThumbnailStatus: () => void,
}; };
function CollectionForm(props: Props) { function CollectionForm(props: Props) {
@ -92,6 +93,7 @@ function CollectionForm(props: Props) {
setIncognito, setIncognito,
onDone, onDone,
doCollectionEdit, doCollectionEdit,
resetThumbnailStatus,
} = props; } = props;
const activeChannelName = activeChannelClaim && activeChannelClaim.name; const activeChannelName = activeChannelClaim && activeChannelClaim.name;
let prefix = 'lbry://'; let prefix = 'lbry://';
@ -158,7 +160,7 @@ function CollectionForm(props: Props) {
} }
function handleUpdateThumbnail(update: { [string]: string }) { function handleUpdateThumbnail(update: { [string]: string }) {
if (update.thumbnail_url) { if (update.thumbnail_url !== undefined) {
setParam(update); setParam(update);
} else if (update.thumbnail_status) { } else if (update.thumbnail_status) {
setThumbStatus(update.thumbnail_status); setThumbStatus(update.thumbnail_status);
@ -309,6 +311,10 @@ function CollectionForm(props: Props) {
} }
}, [uri, hasClaim]); }, [uri, hasClaim]);
React.useEffect(() => {
resetThumbnailStatus();
}, [resetThumbnailStatus]);
return ( return (
<> <>
<div className={classnames('main--contained', { 'card--disabled': disabled })}> <div className={classnames('main--contained', { 'card--disabled': disabled })}>
@ -358,13 +364,14 @@ function CollectionForm(props: Props) {
/> />
<fieldset-section> <fieldset-section>
<SelectThumbnail <SelectThumbnail
thumbnailParam={params.thumbnail_url} thumbnail={params.thumbnail_url}
thumbnailParamError={thumbError} thumbnailError={thumbError}
thumbnailParamStatus={thumbStatus} thumbnailParamStatus={thumbStatus}
updateThumbnailParams={handleUpdateThumbnail} updateThumbnailParams={handleUpdateThumbnail}
usePublishFormMode
/> />
</fieldset-section> </fieldset-section>
<FormField <FormFieldAreaAdvanced
type="markdown" type="markdown"
name="content_description2" name="content_description2"
label={__('Description')} label={__('Description')}

View file

@ -33,7 +33,7 @@ function CollectionPreviewOverlay(props: Props) {
collectionItemUrls.map((item, index) => { collectionItemUrls.map((item, index) => {
if (index < 2) { if (index < 2) {
return ( return (
<div className="collection-preview__overlay-grid-items"> <div key={item} className="collection-preview__overlay-grid-items">
<FileThumbnail uri={item} key={item} /> <FileThumbnail uri={item} key={item} />
</div> </div>
); );

View file

@ -95,7 +95,7 @@ export default function CollectionsListMine(props: Props) {
{builtin.map((list: Collection) => { {builtin.map((list: Collection) => {
const { items: itemUrls } = list; const { items: itemUrls } = list;
return ( return (
<> <React.Fragment key={list.name}>
{Boolean(itemUrls && itemUrls.length) && ( {Boolean(itemUrls && itemUrls.length) && (
<div className="claim-grid__wrapper" key={list.name}> <div className="claim-grid__wrapper" key={list.name}>
<h1 className="claim-grid__header"> <h1 className="claim-grid__header">
@ -124,7 +124,7 @@ export default function CollectionsListMine(props: Props) {
<ClaimList tileLayout key={list.name} uris={itemUrls.slice(0, 6)} collectionId={list.id} /> <ClaimList tileLayout key={list.name} uris={itemUrls.slice(0, 6)} collectionId={list.id} />
</div> </div>
)} )}
</> </React.Fragment>
); );
})} })}
<div className="claim-grid__wrapper"> <div className="claim-grid__wrapper">

View file

@ -8,6 +8,7 @@ import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field';
import { SITE_NAME, ENABLE_COMMENT_REACTIONS } from 'config'; import { SITE_NAME, ENABLE_COMMENT_REACTIONS } from 'config';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { parseURI } from 'util/lbryURI'; import { parseURI } from 'util/lbryURI';
import { formatNumber } from 'util/number';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import Button from 'component/button'; import Button from 'component/button';
import Expandable from 'component/expandable'; import Expandable from 'component/expandable';
@ -16,7 +17,7 @@ import CommentBadge from 'component/common/comment-badge'; // have this?
import ChannelThumbnail from 'component/channelThumbnail'; import ChannelThumbnail from 'component/channelThumbnail';
import { Menu, MenuButton } from '@reach/menu-button'; import { Menu, MenuButton } from '@reach/menu-button';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import { FormField, Form } from 'component/common/form'; import { FormFieldAreaAdvanced, Form } from 'component/common/form';
import classnames from 'classnames'; import classnames from 'classnames';
import usePersistedState from 'effects/use-persisted-state'; import usePersistedState from 'effects/use-persisted-state';
import CommentReactions from 'component/commentReactions'; import CommentReactions from 'component/commentReactions';
@ -318,7 +319,7 @@ function CommentView(props: Props) {
<div> <div>
{isEditing ? ( {isEditing ? (
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<FormField <FormFieldAreaAdvanced
className="comment__edit-input" className="comment__edit-input"
type={advancedEditor ? 'markdown' : 'textarea'} type={advancedEditor ? 'markdown' : 'textarea'}
name="editing_comment" name="editing_comment"
@ -384,7 +385,7 @@ function CommentView(props: Props) {
label={ label={
numDirectReplies < 2 numDirectReplies < 2
? __('Show reply') ? __('Show reply')
: __('Show %count% replies', { count: numDirectReplies }) : __('Show %count% replies', { count: formatNumber(numDirectReplies, 2, true) })
} }
button="link" button="link"
onClick={() => { onClick={() => {

View file

@ -0,0 +1,32 @@
// @flow
import React from 'react';
import SelectChannel from 'component/selectChannel';
import Button from 'component/button';
import * as ICONS from 'constants/icons';
type Props = {
isReply: boolean,
advancedHandler: () => void,
advanced: boolean,
};
export default function CommentCreateHeader(props: Props) {
const { isReply, advancedHandler, advanced } = props;
return (
<div className="comment-create__header">
<div className="comment-create__label-wrapper">
<span className="comment-create__label">{(isReply ? __('Replying as') : __('Comment as')) + ' '}</span>
<SelectChannel tiny />
</div>
<div className="form-field__quick-action">
<Button
button="alt"
icon={advanced ? ICONS.SIMPLE_EDITOR : ICONS.ADVANCED_EDITOR}
onClick={advancedHandler}
aria-label={isReply ? undefined : advanced ? __('Simple Editor') : __('Advanced Editor')}
/>
</div>
</div>
);
}

View file

@ -4,7 +4,7 @@ import 'scss/component/_comment-create.scss';
import { buildValidSticker } from 'util/comments'; import { buildValidSticker } from 'util/comments';
import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field'; import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field';
import { FormField, Form } from 'component/common/form'; import { FormFieldAreaAdvanced, Form } from 'component/common/form';
import { getChannelIdFromClaim } from 'util/claim'; import { getChannelIdFromClaim } from 'util/claim';
import { Lbryio } from 'lbryinc'; import { Lbryio } from 'lbryinc';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
@ -22,13 +22,12 @@ import I18nMessage from 'component/i18nMessage';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import OptimizedImage from 'component/optimizedImage'; import OptimizedImage from 'component/optimizedImage';
import React from 'react'; import React from 'react';
import SelectChannel from 'component/selectChannel';
import StickerSelector from './sticker-selector'; import StickerSelector from './sticker-selector';
import CommentCreateHeader from './comment-create-header';
import type { ElementRef } from 'react'; import type { ElementRef } from 'react';
import UriIndicator from 'component/uriIndicator'; import UriIndicator from 'component/uriIndicator';
import usePersistedState from 'effects/use-persisted-state'; import usePersistedState from 'effects/use-persisted-state';
import WalletTipAmountSelector from 'component/walletTipAmountSelector'; import WalletTipAmountSelector from 'component/walletTipAmountSelector';
import { getStripeEnvironment } from 'util/stripe'; import { getStripeEnvironment } from 'util/stripe';
const stripeEnvironment = getStripeEnvironment(); const stripeEnvironment = getStripeEnvironment();
@ -364,31 +363,6 @@ export function CommentCreate(props: Props) {
.catch(() => {}); .catch(() => {});
}, [canReceiveFiatTip, claim.claim_id, claim.name, claim.signing_channel, stickerSelector]); }, [canReceiveFiatTip, claim.claim_id, claim.name, claim.signing_channel, stickerSelector]);
// LIVESTREAM ONLY - REMOVE
// Handle keyboard shortcut comment creation
// React.useEffect(() => {
// function altEnterListener(e: SyntheticKeyboardEvent<*>) {
// const inputRef = formFieldRef && formFieldRef.current && formFieldRef.current.input;
//
// if (inputRef && inputRef.current === document.activeElement) {
// // $FlowFixMe
// const isTyping = e.target.attributes['term'];
//
// if (((isLivestream && !isTyping) || e.ctrlKey || e.metaKey) && e.keyCode === KEYCODES.ENTER) {
// e.preventDefault();
// buttonRef.current.click();
// }
// }
// }
//
// window.addEventListener('keydown', altEnterListener);
//
// // removes the listener so it doesn't cause problems elsewhere in the app
// return () => {
// window.removeEventListener('keydown', altEnterListener);
// };
// }, [isLivestream]);
// ************************************************************************** // **************************************************************************
// Render // Render
// ************************************************************************** // **************************************************************************
@ -410,7 +384,11 @@ export function CommentCreate(props: Props) {
push(pathPlusRedirect); push(pathPlusRedirect);
}} }}
> >
<FormField type="textarea" name={'comment_signup_prompt'} placeholder={__('Say something about this...')} /> <FormFieldAreaAdvanced
type="textarea"
name={'comment_signup_prompt'}
placeholder={__('Say something about this...')}
/>
<div className="section__actions--no-margin"> <div className="section__actions--no-margin">
<Button disabled button="primary" label={__('Post --[button to submit something]--')} /> <Button disabled button="primary" label={__('Post --[button to submit something]--')} />
</div> </div>
@ -421,22 +399,22 @@ export function CommentCreate(props: Props) {
return ( return (
<Form <Form
onSubmit={() => {}} onSubmit={() => {}}
className={classnames('commentCreate', { className={classnames('comment-create', {
'commentCreate--reply': isReply, 'comment-create--reply': isReply,
'commentCreate--nestedReply': isNested, 'comment-create--nestedReply': isNested,
'commentCreate--bottom': bottom, 'comment-create--bottom': bottom,
})} })}
> >
{/* Input Box/Preview Box */} {/* Input Box/Preview Box */}
{stickerSelector ? ( {stickerSelector ? (
<StickerSelector onSelect={(sticker) => handleSelectSticker(sticker)} claimIsMine={claimIsMine} /> <StickerSelector onSelect={(sticker) => handleSelectSticker(sticker)} claimIsMine={claimIsMine} />
) : isReviewingStickerComment && activeChannelClaim && selectedSticker ? ( ) : isReviewingStickerComment && activeChannelClaim && selectedSticker ? (
<div className="commentCreate__stickerPreview"> <div className="comment-create__stickerPreview">
<div className="commentCreate__stickerPreviewInfo"> <div className="comment-create__stickerPreviewInfo">
<ChannelThumbnail xsmall uri={activeChannelClaim.canonical_url} /> <ChannelThumbnail xsmall uri={activeChannelClaim.canonical_url} />
<UriIndicator uri={activeChannelClaim.canonical_url} link /> <UriIndicator uri={activeChannelClaim.canonical_url} link />
</div> </div>
<div className="commentCreate__stickerPreviewImage"> <div className="comment-create__stickerPreviewImage">
<OptimizedImage src={selectedSticker && selectedSticker.url} waitLoad loading="lazy" /> <OptimizedImage src={selectedSticker && selectedSticker.url} waitLoad loading="lazy" />
</div> </div>
{/* figure out lbc sticker prices */} {/* figure out lbc sticker prices */}
@ -448,15 +426,15 @@ export function CommentCreate(props: Props) {
)} )}
</div> </div>
) : isReviewingSupportComment && activeChannelClaim ? ( ) : isReviewingSupportComment && activeChannelClaim ? (
<div className="commentCreate__supportCommentPreview"> <div className="comment-create__supportCommentPreview">
<CreditAmount <CreditAmount
amount={tipAmount} amount={tipAmount}
className="commentCreate__supportCommentPreviewAmount" className="comment-create__supportCommentPreviewAmount"
isFiat={activeTab === TAB_FIAT} isFiat={activeTab === TAB_FIAT}
size={activeTab === TAB_LBC ? 18 : 2} size={activeTab === TAB_LBC ? 18 : 2}
/> />
<ChannelThumbnail xsmall uri={activeChannelClaim.canonical_url} /> <ChannelThumbnail xsmall uri={activeChannelClaim.canonical_url} />
<div className="commentCreate__supportCommentBody"> <div className="comment-create__supportCommentBody">
<UriIndicator uri={activeChannelClaim.canonical_url} link /> <UriIndicator uri={activeChannelClaim.canonical_url} link />
<div>{commentValue}</div> <div>{commentValue}</div>
</div> </div>
@ -471,23 +449,22 @@ export function CommentCreate(props: Props) {
/> />
)} )}
<FormField <FormFieldAreaAdvanced
autoFocus={isReply} autoFocus={isReply}
charCount={charCount} charCount={charCount}
className={isReply ? 'content_reply' : 'content_comment'} className={isReply ? 'content_reply' : 'content_comment'}
disabled={isFetchingChannels} disabled={isFetchingChannels}
label={ header={
<div className="commentCreate__labelWrapper"> <CommentCreateHeader
<span className="commentCreate__label">{(isReply ? __('Replying as') : __('Comment as')) + ' '}</span> isReply={isReply}
<SelectChannel tiny /> advanced={advancedEditor}
</div> advancedHandler={() => setAdvancedEditor(!advancedEditor)}
/>
} }
name={isReply ? 'content_reply' : 'content_description'} name={isReply ? 'content_reply' : 'content_description'}
quickActionLabel={isReply ? undefined : advancedEditor ? __('Simple Editor') : __('Advanced Editor')}
ref={formFieldRef} ref={formFieldRef}
onChange={handleCommentChange} onChange={handleCommentChange}
openEmoteMenu={() => setShowEmotes(!showEmotes)} openEmoteMenu={() => setShowEmotes(!showEmotes)}
quickActionHandler={() => setAdvancedEditor(!advancedEditor)}
onFocus={onTextareaFocus} onFocus={onTextareaFocus}
onBlur={onTextareaBlur} onBlur={onTextareaBlur}
placeholder={__('Say something about this...')} placeholder={__('Say something about this...')}
@ -655,7 +632,7 @@ export function CommentCreate(props: Props) {
{/* Help Text */} {/* Help Text */}
{deletedComment && <div className="error__text">{__('This comment has been deleted.')}</div>} {deletedComment && <div className="error__text">{__('This comment has been deleted.')}</div>}
{!!minAmount && ( {!!minAmount && (
<div className="help--notice commentCreate__minAmountNotice"> <div className="help--notice comment-create__minAmountNotice">
<I18nMessage tokens={{ lbc: <CreditAmount noFormat amount={minAmount} /> }}> <I18nMessage tokens={{ lbc: <CreditAmount noFormat amount={minAmount} /> }}>
{minTip ? 'Comment min: %lbc%' : minSuper ? 'HyperChat min: %lbc%' : ''} {minTip ? 'Comment min: %lbc%' : minSuper ? 'HyperChat min: %lbc%' : ''}
</I18nMessage> </I18nMessage>

View file

@ -8,6 +8,8 @@ import classnames from 'classnames';
import Button from 'component/button'; import Button from 'component/button';
import ChannelThumbnail from 'component/channelThumbnail'; import ChannelThumbnail from 'component/channelThumbnail';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { useIsMobile } from 'effects/use-screensize';
import { formatNumber } from 'util/number';
type Props = { type Props = {
myReacts: Array<string>, myReacts: Array<string>,
@ -43,6 +45,8 @@ export default function CommentReactions(props: Props) {
location: { pathname }, location: { pathname },
} = useHistory(); } = useHistory();
const isMobile = useIsMobile();
React.useEffect(() => { React.useEffect(() => {
if (!claim) { if (!claim) {
resolve(uri); resolve(uri);
@ -101,20 +105,30 @@ export default function CommentReactions(props: Props) {
<Button <Button
title={__('Upvote')} title={__('Upvote')}
icon={likeIcon} icon={likeIcon}
className={classnames('comment__action', { iconSize={isMobile && 12}
className={classnames('comment__action button-like', {
'comment__action--active': myReacts && myReacts.includes(REACTION_TYPES.LIKE), 'comment__action--active': myReacts && myReacts.includes(REACTION_TYPES.LIKE),
})} })}
onClick={handleCommentLike} onClick={handleCommentLike}
label={<span className="comment__reaction-count">{getCountForReact(REACTION_TYPES.LIKE)}</span>} label={
<span className="comment__reaction-count">
{formatNumber(getCountForReact(REACTION_TYPES.LIKE), 2, true)}
</span>
}
/> />
<Button <Button
title={__('Downvote')} title={__('Downvote')}
icon={dislikeIcon} icon={dislikeIcon}
className={classnames('comment__action', { iconSize={isMobile && 12}
className={classnames('comment__action button-dislike', {
'comment__action--active': myReacts && myReacts.includes(REACTION_TYPES.DISLIKE), 'comment__action--active': myReacts && myReacts.includes(REACTION_TYPES.DISLIKE),
})} })}
onClick={handleCommentDislike} onClick={handleCommentDislike}
label={<span className="comment__reaction-count">{getCountForReact(REACTION_TYPES.DISLIKE)}</span>} label={
<span className="comment__reaction-count">
{formatNumber(getCountForReact(REACTION_TYPES.DISLIKE), 2, true)}
</span>
}
/> />
{!shouldHide && ENABLE_CREATOR_REACTIONS && (canCreatorReact || creatorLiked) && ( {!shouldHide && ENABLE_CREATOR_REACTIONS && (canCreatorReact || creatorLiked) && (

View file

@ -23,6 +23,9 @@ import { doCommentReset, doCommentList, doCommentById, doCommentReactList } from
import { selectActiveChannelClaim } from 'redux/selectors/app'; import { selectActiveChannelClaim } from 'redux/selectors/app';
import { getChannelIdFromClaim } from 'util/claim'; import { getChannelIdFromClaim } from 'util/claim';
import CommentsList from './view'; import CommentsList from './view';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import * as SETTINGS from 'constants/settings';
import { doSetClientSetting } from 'redux/actions/settings';
const select = (state, props) => { const select = (state, props) => {
const { uri } = props; const { uri } = props;
@ -56,15 +59,19 @@ const select = (state, props) => {
myReactsByCommentId: selectMyReacts(state), myReactsByCommentId: selectMyReacts(state),
othersReactsById: selectOthersReacts(state), othersReactsById: selectOthersReacts(state),
activeChannelId: activeChannelClaim && activeChannelClaim.claim_id, activeChannelId: activeChannelClaim && activeChannelClaim.claim_id,
customCommentServers: makeSelectClientSetting(SETTINGS.CUSTOM_COMMENTS_SERVERS)(state),
commentServer: makeSelectClientSetting(SETTINGS.CUSTOM_COMMENTS_SERVER_URL)(state),
}; };
}; };
const perform = { const perform = (dispatch, ownProps) => ({
fetchTopLevelComments: doCommentList, fetchTopLevelComments: (uri, parentId, page, pageSize, sortBy) =>
fetchComment: doCommentById, dispatch(doCommentList(uri, parentId, page, pageSize, sortBy)),
fetchReacts: doCommentReactList, fetchComment: (commentId) => dispatch(doCommentById(commentId)),
resetComments: doCommentReset, fetchReacts: (commentIds) => dispatch(doCommentReactList(commentIds)),
doResolveUris, resetComments: (claimId) => dispatch(doCommentReset(claimId)),
}; doResolveUris: (uris, returnCachedClaims) => dispatch(doResolveUris(uris, returnCachedClaims)),
setCommentServer: (url) => dispatch(doSetClientSetting(SETTINGS.CUSTOM_COMMENTS_SERVER_URL, url, true)),
});
export default connect(select, perform)(CommentsList); export default connect(select, perform)(CommentsList);

View file

@ -1,6 +1,6 @@
// @flow // @flow
import { COMMENT_PAGE_SIZE_TOP_LEVEL, SORT_BY } from 'constants/comment'; import { COMMENT_PAGE_SIZE_TOP_LEVEL, SORT_BY } from 'constants/comment';
import { ENABLE_COMMENT_REACTIONS } from 'config'; import { ENABLE_COMMENT_REACTIONS, COMMENT_SERVER_API, COMMENT_SERVER_NAME } from 'config';
import { useIsMobile, useIsMediumScreen } from 'effects/use-screensize'; import { useIsMobile, useIsMediumScreen } from 'effects/use-screensize';
import { getCommentsListTitle } from 'util/comments'; import { getCommentsListTitle } from 'util/comments';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
@ -15,6 +15,8 @@ import Empty from 'component/common/empty';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import Spinner from 'component/spinner'; import Spinner from 'component/spinner';
import usePersistedState from 'effects/use-persisted-state'; import usePersistedState from 'effects/use-persisted-state';
import { FormField } from 'component/common/form';
import Comments from 'comments';
const DEBOUNCE_SCROLL_HANDLER_MS = 200; const DEBOUNCE_SCROLL_HANDLER_MS = 200;
@ -52,6 +54,9 @@ type Props = {
fetchReacts: (commentIds: Array<string>) => Promise<any>, fetchReacts: (commentIds: Array<string>) => Promise<any>,
resetComments: (claimId: string) => void, resetComments: (claimId: string) => void,
doResolveUris: (uris: Array<string>, returnCachedClaims: boolean) => void, doResolveUris: (uris: Array<string>, returnCachedClaims: boolean) => void,
customCommentServers: Array<CommentServerDetails>,
setCommentServer: (string) => void,
commentServer: string,
}; };
export default function CommentList(props: Props) { export default function CommentList(props: Props) {
@ -80,11 +85,17 @@ export default function CommentList(props: Props) {
fetchReacts, fetchReacts,
resetComments, resetComments,
doResolveUris, doResolveUris,
customCommentServers,
setCommentServer,
commentServer,
} = props; } = props;
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const isMediumScreen = useIsMediumScreen(); const isMediumScreen = useIsMediumScreen();
const defaultServer = { name: COMMENT_SERVER_NAME, url: COMMENT_SERVER_API };
const allServers = [defaultServer, ...(customCommentServers || [])];
const spinnerRef = React.useRef(); const spinnerRef = React.useRef();
const DEFAULT_SORT = ENABLE_COMMENT_REACTIONS ? SORT_BY.POPULARITY : SORT_BY.NEWEST; const DEFAULT_SORT = ENABLE_COMMENT_REACTIONS ? SORT_BY.POPULARITY : SORT_BY.NEWEST;
const [sort, setSort] = usePersistedState('comment-sort-by', DEFAULT_SORT); const [sort, setSort] = usePersistedState('comment-sort-by', DEFAULT_SORT);
@ -255,7 +266,16 @@ export default function CommentList(props: Props) {
}, [alreadyResolved, doResolveUris, topLevelComments]); }, [alreadyResolved, doResolveUris, topLevelComments]);
const commentProps = { isTopLevel: true, threadDepth: 3, uri, claimIsMine, linkedCommentId }; const commentProps = { isTopLevel: true, threadDepth: 3, uri, claimIsMine, linkedCommentId };
const actionButtonsProps = { totalComments, sort, changeSort, setPage }; const actionButtonsProps = {
totalComments,
sort,
changeSort,
setPage,
allServers,
commentServer,
defaultServer,
setCommentServer,
};
return ( return (
<Card <Card
@ -334,17 +354,21 @@ type ActionButtonsProps = {
sort: string, sort: string,
changeSort: (string) => void, changeSort: (string) => void,
setPage: (number) => void, setPage: (number) => void,
allServers: Array<CommentServerDetails>,
commentServer: string,
setCommentServer: (string) => void,
defaultServer: CommentServerDetails,
}; };
const CommentActionButtons = (actionButtonsProps: ActionButtonsProps) => { const CommentActionButtons = (actionButtonsProps: ActionButtonsProps) => {
const { totalComments, sort, changeSort, setPage } = actionButtonsProps; const { totalComments, sort, changeSort, setPage, allServers, commentServer, setCommentServer, defaultServer } =
actionButtonsProps;
const sortButtonProps = { activeSort: sort, changeSort }; const sortButtonProps = { activeSort: sort, changeSort };
return ( return (
<> <div className={'comment__actions-row'}>
{totalComments > 1 && ENABLE_COMMENT_REACTIONS && ( {totalComments > 1 && ENABLE_COMMENT_REACTIONS && (
<span className="comment__sort"> <div className="comment__sort-group">
<SortButton {...sortButtonProps} label={__('Best')} icon={ICONS.BEST} sortOption={SORT_BY.POPULARITY} /> <SortButton {...sortButtonProps} label={__('Best')} icon={ICONS.BEST} sortOption={SORT_BY.POPULARITY} />
<SortButton <SortButton
{...sortButtonProps} {...sortButtonProps}
@ -353,11 +377,39 @@ const CommentActionButtons = (actionButtonsProps: ActionButtonsProps) => {
sortOption={SORT_BY.CONTROVERSY} sortOption={SORT_BY.CONTROVERSY}
/> />
<SortButton {...sortButtonProps} label={__('New')} icon={ICONS.NEW} sortOption={SORT_BY.NEWEST} /> <SortButton {...sortButtonProps} label={__('New')} icon={ICONS.NEW} sortOption={SORT_BY.NEWEST} />
</span> </div>
)} )}
{allServers.length >= 2 && (
<div className="button__selected-server">
<FormField
type="select-tiny"
onChange={function (x) {
const selectedServer = x.target.value;
setPage(0);
setCommentServer(selectedServer);
if (selectedServer === defaultServer.url) {
Comments.setServerUrl(undefined);
} else {
Comments.setServerUrl(selectedServer);
}
}}
value={commentServer}
>
{allServers.map(function (server) {
return (
<option key={server.url} value={server.url}>
{server.name}
</option>
);
})}
</FormField>
</div>
)}
<div className="button_refresh">
<Button button="alt" icon={ICONS.REFRESH} title={__('Refresh')} onClick={() => setPage(0)} /> <Button button="alt" icon={ICONS.REFRESH} title={__('Refresh')} onClick={() => setPage(0)} />
</> </div>
</div>
); );
}; };

View file

@ -44,7 +44,7 @@ function CommentsReplies(props: Props) {
const [commentsToDisplay, setCommentsToDisplay] = React.useState(fetchedReplies); const [commentsToDisplay, setCommentsToDisplay] = React.useState(fetchedReplies);
const isResolvingReplies = fetchedReplies && resolvedReplies.length !== fetchedReplies.length; const isResolvingReplies = fetchedReplies && resolvedReplies.length !== fetchedReplies.length;
const alreadyResolved = !isResolvingReplies && resolvedReplies.length !== 0; const alreadyResolved = !isResolvingReplies && resolvedReplies.length !== 0;
const canDisplayComments = commentsToDisplay && commentsToDisplay.length === fetchedReplies.length; const canDisplayComments = commentsToDisplay && fetchedReplies && commentsToDisplay.length === fetchedReplies.length;
// Batch resolve comment channel urls // Batch resolve comment channel urls
React.useEffect(() => { React.useEffect(() => {

View file

@ -63,7 +63,7 @@ export default function Card(props: Props) {
} }
}} }}
> >
<div> <div className="card__first-pane">
{(title || subtitle) && ( {(title || subtitle) && (
<div <div
className={classnames('card__header--between', { className={classnames('card__header--between', {
@ -73,7 +73,7 @@ export default function Card(props: Props) {
<div <div
className={classnames('card__title-section', { className={classnames('card__title-section', {
'card__title-section--body-list': isBodyList, 'card__title-section--body-list': isBodyList,
'card__title-section--small': smallTitle, 'card__title-section--smallx': smallTitle,
})} })}
> >
{icon && <Icon sectionIcon icon={icon} />} {icon && <Icon sectionIcon icon={icon} />}

View file

@ -0,0 +1,41 @@
// @flow
import React, { useEffect, useState } from 'react';
import { FormField } from 'component/common/form';
import Icon from 'component/common/icon';
import useDebounce from 'effects/use-debounce';
import classnames from 'classnames';
const FILTER_DEBOUNCE_MS = 300;
interface Props {
defaultValue?: string;
icon?: string;
placeholder?: string;
inline?: boolean;
onChange: (newValue: string) => any;
}
export default function DebouncedInput(props: Props) {
const { defaultValue = '', icon, placeholder = '', inline, onChange } = props;
const [rawValue, setRawValue] = useState(defaultValue);
const debouncedValue: string = useDebounce(rawValue, FILTER_DEBOUNCE_MS);
useEffect(() => {
onChange(debouncedValue);
}, [onChange, debouncedValue]);
return (
<div className={classnames({ wunderbar: !inline, 'wunderbar--inline': inline })}>
{icon && <Icon icon={icon} />}
<FormField
className={classnames({ wunderbar__input: !inline, 'wunderbar__input--inline': inline })}
type="text"
name="debounced_search"
spellCheck={false}
placeholder={placeholder}
value={rawValue}
onChange={(e) => setRawValue(e.target.value.trim())}
/>
</div>
);
}

View file

@ -3,8 +3,8 @@ import React from 'react';
import { useRadioState, Radio, RadioGroup } from 'reakit/Radio'; import { useRadioState, Radio, RadioGroup } from 'reakit/Radio';
type Props = { type Props = {
files: Array<WebFile>, files: Array<File>,
onChange: (WebFile | void) => void, onChange: (File | void) => void,
}; };
type RadioProps = { type RadioProps = {
@ -26,16 +26,16 @@ function FileList(props: Props) {
const getFile = (value?: string) => { const getFile = (value?: string) => {
if (files && files.length) { if (files && files.length) {
return files.find((file: WebFile) => file.name === value); return files.find((file: File) => file.name === value);
} }
}; };
React.useEffect(() => { React.useEffect(() => {
if (radio.stops.length) { if (radio.items.length) {
if (!radio.currentId) { if (!radio.currentId) {
radio.first(); radio.first();
} else { } else {
const first = radio.stops[0].ref.current; const first = radio.items[0].ref.current;
// First auto-selection // First auto-selection
if (first && first.id === radio.currentId && !radio.state) { if (first && first.id === radio.currentId && !radio.state) {
const file = getFile(first.value); const file = getFile(first.value);
@ -46,12 +46,12 @@ function FileList(props: Props) {
if (radio.state) { if (radio.state) {
// Find selected element // Find selected element
const stop = radio.stops.find(item => item.id === radio.currentId); const stop = radio.items.find((item) => item.id === radio.currentId);
const element = stop && stop.ref.current; const element = stop && stop.ref.current;
// Only update state if new item is selected // Only update state if new item is selected
if (element && element.value !== radio.state) { if (element && element.value !== radio.state) {
const file = getFile(element.value); const file = getFile(element.value);
// Sselect new file and update state // Select new file and update state
onChange(file); onChange(file);
radio.setState(element.value); radio.setState(element.value);
} }

View file

@ -1,25 +1,29 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import * as remote from '@electron/remote'; import * as remote from '@electron/remote';
import { ipcRenderer } from 'electron';
import Button from 'component/button'; import Button from 'component/button';
import { FormField } from 'component/common/form'; import { FormField } from 'component/common/form';
type Props = { type Props = {
type: string, type: string,
currentPath?: ?string, currentPath?: ?string,
onFileChosen: (WebFile) => void, onFileChosen: (FileWithPath) => void,
label?: string, label?: string,
placeholder?: string, placeholder?: string,
accept?: string, accept?: string,
error?: string, error?: string,
disabled?: boolean, disabled?: boolean,
autoFocus?: boolean, autoFocus?: boolean,
filters?: Array<{ name: string, extension: string[] }>,
readFile?: boolean,
}; };
class FileSelector extends React.PureComponent<Props> { class FileSelector extends React.PureComponent<Props> {
static defaultProps = { static defaultProps = {
autoFocus: false, autoFocus: false,
type: 'file', type: 'file',
readFile: true,
}; };
fileInput: React.ElementRef<any>; fileInput: React.ElementRef<any>;
@ -41,18 +45,49 @@ class FileSelector extends React.PureComponent<Props> {
const file = files[0]; const file = files[0];
if (this.props.onFileChosen) { if (this.props.onFileChosen) {
this.props.onFileChosen(file); this.props.onFileChosen({ file, path: file.path || file.name });
} }
this.fileInput.current.value = null; // clear the file input this.fileInput.current.value = null; // clear the file input
}; };
handleDirectoryInputSelection = () => { handleDirectoryInputSelection = () => {
remote.dialog.showOpenDialog({ properties: ['openDirectory'] }).then((result) => { let defaultPath;
let properties;
let isWin = process.platform === 'win32';
let type = this.props.type;
if (isWin === true) {
defaultPath = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
}
if (type === 'openFile') {
properties = ['openFile'];
}
if (type === 'openDirectory') {
properties = ['openDirectory'];
}
remote.dialog
.showOpenDialog({
properties,
defaultPath,
filters: this.props.filters,
})
.then((result) => {
const path = result && result.filePaths[0]; const path = result && result.filePaths[0];
if (path) { if (path) {
// $FlowFixMe return ipcRenderer.invoke('get-file-from-path', path, this.props.readFile);
this.props.onFileChosen({ path });
} }
})
.then((result) => {
if (!result) {
return;
}
const file = new File([result.buffer], result.name, {
type: result.mime,
});
this.props.onFileChosen({ file, path: result.path });
}); });
}; };
@ -71,7 +106,7 @@ class FileSelector extends React.PureComponent<Props> {
<FormField <FormField
label={label} label={label}
webkitdirectory="true" webkitdirectory="true"
className="form-field--copyable" className="form-field--with-button"
error={error} error={error}
disabled={disabled} disabled={disabled}
type="text" type="text"
@ -80,9 +115,13 @@ class FileSelector extends React.PureComponent<Props> {
inputButton={ inputButton={
<Button <Button
autoFocus={autoFocus} autoFocus={autoFocus}
button="secondary" button="primary"
disabled={disabled} disabled={disabled}
onClick={type === 'openDirectory' ? this.handleDirectoryInputSelection : this.fileInputButton} onClick={
type === 'openDirectory' || type === 'openFile'
? this.handleDirectoryInputSelection
: this.fileInputButton
}
label={__('Browse')} label={__('Browse')}
/> />
} }

View file

@ -0,0 +1,240 @@
// @flow
import 'easymde/dist/easymde.min.css';
import { FF_MAX_CHARS_DEFAULT } from 'constants/form-field';
import { openEditorMenu, stopContextMenu } from 'util/context-menu';
import * as ICONS from 'constants/icons';
import Button from 'component/button';
import MarkdownPreview from 'component/common/markdown-preview';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import SimpleMDE from 'react-simplemde-editor';
import TextareaWithSuggestions from 'component/textareaWithSuggestions';
import type { ElementRef, Node } from 'react';
type Props = {
autoFocus?: boolean,
blockWrap: boolean,
charCount?: number,
children?: React$Node,
disabled?: boolean,
helper?: string | React$Node,
hideSuggestions?: boolean,
isLivestream?: boolean,
label?: string | Node,
labelOnLeft: boolean,
name: string,
noEmojis?: boolean,
placeholder?: string | number,
quickActionLabel?: string,
textAreaMaxLength?: number,
type?: string,
value?: string | number,
onChange?: (any) => any,
openEmoteMenu?: () => void,
quickActionHandler?: (any) => any,
render?: () => React$Node,
header?: React$Node,
};
export class FormFieldAreaAdvanced extends React.PureComponent<Props> {
static defaultProps = { labelOnLeft: false, blockWrap: true };
input: { current: ElementRef<any> };
constructor(props: Props) {
super(props);
this.input = React.createRef();
}
componentDidMount() {
const { autoFocus } = this.props;
const input = this.input.current;
if (input && autoFocus) input.focus();
}
render() {
const {
autoFocus,
blockWrap,
charCount,
children,
helper,
hideSuggestions,
isLivestream,
label,
header,
labelOnLeft,
name,
noEmojis,
quickActionLabel,
textAreaMaxLength,
type,
openEmoteMenu,
quickActionHandler,
render,
...inputProps
} = this.props;
// Ideally, the character count should (and can) be appended to the
// SimpleMDE's "options::status" bar. However, I couldn't figure out how
// to pass the current value to it's callback, nor query the current
// text length from the callback. So, we'll use our own widget.
const hasCharCount = charCount !== undefined && charCount >= 0;
const countInfo = hasCharCount && textAreaMaxLength !== undefined && (
<span className="comment__char-count-mde">{`${charCount || '0'}/${textAreaMaxLength}`}</span>
);
const quickAction =
quickActionLabel && quickActionHandler ? (
<div className="form-field__quick-action">
<Button button="link" onClick={quickActionHandler} label={quickActionLabel} />
</div>
) : null;
const input = () => {
switch (type) {
case 'markdown':
const handleEvents = { contextmenu: openEditorMenu };
const getInstance = (editor) => {
// SimpleMDE max char check
editor.codemirror.on('beforeChange', (instance, changes) => {
if (textAreaMaxLength && changes.update) {
var str = changes.text.join('\n');
var delta = str.length - (instance.indexFromPos(changes.to) - instance.indexFromPos(changes.from));
if (delta <= 0) return;
delta = instance.getValue().length + delta - textAreaMaxLength;
if (delta > 0) {
str = str.substring(0, str.length - delta);
changes.update(changes.from, changes.to, str.split('\n'));
}
}
});
// "Create Link (Ctrl-K)": highlight URL instead of label:
editor.codemirror.on('changes', (instance, changes) => {
try {
// Grab the last change from the buffered list. I assume the
// buffered one ('changes', instead of 'change') is more efficient,
// and that "Create Link" will always end up last in the list.
const lastChange = changes[changes.length - 1];
if (lastChange.origin === '+input') {
// https://github.com/Ionaru/easy-markdown-editor/blob/8fa54c496f98621d5f45f57577ce630bee8c41ee/src/js/easymde.js#L765
const EASYMDE_URL_PLACEHOLDER = '(https://)';
// The URL placeholder is always placed last, so just look at the
// last text in the array to also cover the multi-line case:
const urlLineText = lastChange.text[lastChange.text.length - 1];
if (urlLineText.endsWith(EASYMDE_URL_PLACEHOLDER) && urlLineText !== '[]' + EASYMDE_URL_PLACEHOLDER) {
const from = lastChange.from;
const to = lastChange.to;
const isSelectionMultiline = lastChange.text.length > 1;
const baseIndex = isSelectionMultiline ? 0 : from.ch;
// Everything works fine for the [Ctrl-K] case, but for the
// [Button] case, this handler happens before the original
// code, thus our change got wiped out.
// Add a small delay to handle that case.
setTimeout(() => {
instance.setSelection(
{ line: to.line, ch: baseIndex + urlLineText.lastIndexOf('(') + 1 },
{ line: to.line, ch: baseIndex + urlLineText.lastIndexOf(')') }
);
}, 25);
}
}
} catch (e) {} // Do nothing (revert to original behavior)
});
};
return (
<div className="form-field--SimpleMDE" onContextMenu={stopContextMenu}>
<fieldset-section>
{!header && (
<div className="form-field__two-column">
<div>
<label htmlFor={name}>{label}</label>
</div>
{quickAction}
</div>
)}
{!!header && <div className="form-field__textarea-header">{header}</div>}
<SimpleMDE
{...inputProps}
id={name}
type="textarea"
events={handleEvents}
getMdeInstance={getInstance}
options={{
spellChecker: true,
hideIcons: ['heading', 'image', 'fullscreen', 'side-by-side'],
previewRender(plainText) {
const preview = <MarkdownPreview content={plainText} noDataStore />;
return ReactDOMServer.renderToString(preview);
},
}}
/>
{countInfo}
</fieldset-section>
</div>
);
case 'textarea':
return (
<fieldset-section>
{!header && (label || quickAction) && (
<div className="form-field__two-column">
<label htmlFor={name}>{label}</label>
{quickAction}
</div>
)}
{!!header && <div className="form-field__textarea-header">{header}</div>}
{hideSuggestions ? (
<textarea
type={type}
id={name}
maxLength={textAreaMaxLength || FF_MAX_CHARS_DEFAULT}
ref={this.input}
{...inputProps}
/>
) : (
<TextareaWithSuggestions
type={type}
id={name}
maxLength={textAreaMaxLength || FF_MAX_CHARS_DEFAULT}
inputRef={this.input}
isLivestream={isLivestream}
{...inputProps}
/>
)}
<div className="form-field__textarea-info">
{!noEmojis && openEmoteMenu && (
<Button
type="alt"
className="button--comment-icons"
title="Emotes"
onClick={openEmoteMenu}
icon={ICONS.EMOJI}
iconSize={20}
/>
)}
{countInfo}
</div>
</fieldset-section>
);
}
};
return (
<>
{type && input()}
{helper && <div className="form-field__help">{helper}</div>}
</>
);
}
}
export default FormFieldAreaAdvanced;

View file

@ -1,14 +1,7 @@
// @flow // @flow
import 'easymde/dist/easymde.min.css'; import 'easymde/dist/easymde.min.css';
import { FF_MAX_CHARS_DEFAULT } from 'constants/form-field'; import { FF_MAX_CHARS_DEFAULT } from 'constants/form-field';
import { openEditorMenu, stopContextMenu } from 'util/context-menu';
import * as ICONS from 'constants/icons';
import Button from 'component/button';
import MarkdownPreview from 'component/common/markdown-preview';
import React from 'react'; import React from 'react';
import ReactDOMServer from 'react-dom/server';
import SimpleMDE from 'react-simplemde-editor';
import TextareaWithSuggestions from 'component/textareaWithSuggestions';
import type { ElementRef, Node } from 'react'; import type { ElementRef, Node } from 'react';
type Props = { type Props = {
@ -21,19 +14,15 @@ type Props = {
disabled?: boolean, disabled?: boolean,
error?: string | boolean, error?: string | boolean,
helper?: string | React$Node, helper?: string | React$Node,
hideSuggestions?: boolean,
inputButton?: React$Node, inputButton?: React$Node,
isLivestream?: boolean,
label?: string | Node, label?: string | Node,
labelOnLeft: boolean, labelOnLeft: boolean,
max?: number, max?: number,
min?: number, min?: number,
name: string, name: string,
noEmojis?: boolean,
placeholder?: string | number, placeholder?: string | number,
postfix?: string, postfix?: string,
prefix?: string, prefix?: string,
quickActionLabel?: string,
range?: number, range?: number,
readOnly?: boolean, readOnly?: boolean,
stretch?: boolean, stretch?: boolean,
@ -41,8 +30,6 @@ type Props = {
type?: string, type?: string,
value?: string | number, value?: string | number,
onChange?: (any) => any, onChange?: (any) => any,
openEmoteMenu?: () => void,
quickActionHandler?: (any) => any,
render?: () => React$Node, render?: () => React$Node,
}; };
@ -72,21 +59,15 @@ export class FormField extends React.PureComponent<Props> {
children, children,
error, error,
helper, helper,
hideSuggestions,
inputButton, inputButton,
isLivestream,
label, label,
labelOnLeft, labelOnLeft,
name, name,
noEmojis,
postfix, postfix,
prefix, prefix,
quickActionLabel,
stretch, stretch,
textAreaMaxLength, textAreaMaxLength,
type, type,
openEmoteMenu,
quickActionHandler,
render, render,
...inputProps ...inputProps
} = this.props; } = this.props;
@ -101,18 +82,10 @@ export class FormField extends React.PureComponent<Props> {
const countInfo = hasCharCount && textAreaMaxLength !== undefined && ( const countInfo = hasCharCount && textAreaMaxLength !== undefined && (
<span className="comment__char-count-mde">{`${charCount || '0'}/${textAreaMaxLength}`}</span> <span className="comment__char-count-mde">{`${charCount || '0'}/${textAreaMaxLength}`}</span>
); );
const Wrapper = blockWrap const Wrapper = blockWrap
? ({ children: innerChildren }) => <fieldset-section class="radio">{innerChildren}</fieldset-section> ? ({ children: innerChildren }) => <fieldset-section class="radio">{innerChildren}</fieldset-section>
: ({ children: innerChildren }) => <span className="radio">{innerChildren}</span>; : ({ children: innerChildren }) => <span className="radio">{innerChildren}</span>;
const quickAction =
quickActionLabel && quickActionHandler ? (
<div className="form-field__quick-action">
<Button button="link" onClick={quickActionHandler} label={quickActionLabel} />
</div>
) : null;
const inputSimple = (type: string) => ( const inputSimple = (type: string) => (
<> <>
<input id={name} type={type} {...inputProps} /> <input id={name} type={type} {...inputProps} />
@ -143,102 +116,14 @@ export class FormField extends React.PureComponent<Props> {
return inputSelect(''); return inputSelect('');
case 'select-tiny': case 'select-tiny':
return inputSelect('select--slim'); return inputSelect('select--slim');
case 'markdown':
const handleEvents = { contextmenu: openEditorMenu };
const getInstance = (editor) => {
// SimpleMDE max char check
editor.codemirror.on('beforeChange', (instance, changes) => {
if (textAreaMaxLength && changes.update) {
var str = changes.text.join('\n');
var delta = str.length - (instance.indexFromPos(changes.to) - instance.indexFromPos(changes.from));
if (delta <= 0) return;
delta = instance.getValue().length + delta - textAreaMaxLength;
if (delta > 0) {
str = str.substr(0, str.length - delta);
changes.update(changes.from, changes.to, str.split('\n'));
}
}
});
// "Create Link (Ctrl-K)": highlight URL instead of label:
editor.codemirror.on('changes', (instance, changes) => {
try {
// Grab the last change from the buffered list. I assume the
// buffered one ('changes', instead of 'change') is more efficient,
// and that "Create Link" will always end up last in the list.
const lastChange = changes[changes.length - 1];
if (lastChange.origin === '+input') {
// https://github.com/Ionaru/easy-markdown-editor/blob/8fa54c496f98621d5f45f57577ce630bee8c41ee/src/js/easymde.js#L765
const EASYMDE_URL_PLACEHOLDER = '(https://)';
// The URL placeholder is always placed last, so just look at the
// last text in the array to also cover the multi-line case:
const urlLineText = lastChange.text[lastChange.text.length - 1];
if (urlLineText.endsWith(EASYMDE_URL_PLACEHOLDER) && urlLineText !== '[]' + EASYMDE_URL_PLACEHOLDER) {
const from = lastChange.from;
const to = lastChange.to;
const isSelectionMultiline = lastChange.text.length > 1;
const baseIndex = isSelectionMultiline ? 0 : from.ch;
// Everything works fine for the [Ctrl-K] case, but for the
// [Button] case, this handler happens before the original
// code, thus our change got wiped out.
// Add a small delay to handle that case.
setTimeout(() => {
instance.setSelection(
{ line: to.line, ch: baseIndex + urlLineText.lastIndexOf('(') + 1 },
{ line: to.line, ch: baseIndex + urlLineText.lastIndexOf(')') }
);
}, 25);
}
}
} catch (e) {} // Do nothing (revert to original behavior)
});
};
return (
<div className="form-field--SimpleMDE" onContextMenu={stopContextMenu}>
<fieldset-section>
<div className="form-field__two-column">
<div>
<label htmlFor={name}>{label}</label>
</div>
{quickAction}
</div>
<SimpleMDE
{...inputProps}
id={name}
type="textarea"
events={handleEvents}
getMdeInstance={getInstance}
options={{
spellChecker: true,
hideIcons: ['heading', 'image', 'fullscreen', 'side-by-side', 'guide'], // guide hidden until fixed
previewRender(plainText) {
const preview = <MarkdownPreview content={plainText} noDataStore />;
return ReactDOMServer.renderToString(preview);
},
}}
/>
{countInfo}
</fieldset-section>
</div>
);
case 'textarea': case 'textarea':
return ( return (
<fieldset-section> <fieldset-section>
{(label || quickAction) && ( {label && (
<div className="form-field__two-column"> <div className="form-field__two-column">
<label htmlFor={name}>{label}</label> <label htmlFor={name}>{label}</label>
{quickAction}
</div> </div>
)} )}
{hideSuggestions ? (
<textarea <textarea
type={type} type={type}
id={name} id={name}
@ -246,30 +131,7 @@ export class FormField extends React.PureComponent<Props> {
ref={this.input} ref={this.input}
{...inputProps} {...inputProps}
/> />
) : ( <div className="form-field__textarea-info">{countInfo}</div>
<TextareaWithSuggestions
type={type}
id={name}
maxLength={textAreaMaxLength || FF_MAX_CHARS_DEFAULT}
inputRef={this.input}
isLivestream={isLivestream}
{...inputProps}
/>
)}
<div className="form-field__textarea-info">
{!noEmojis && openEmoteMenu && (
<Button
type="alt"
className="button--file-action"
title="Emotes"
onClick={openEmoteMenu}
icon={ICONS.EMOJI}
iconSize={20}
/>
)}
{countInfo}
</div>
</fieldset-section> </fieldset-section>
); );
default: default:

View file

@ -1,4 +1,5 @@
export { Form } from './form-components/form'; export { Form } from './form-components/form';
export { FormField } from './form-components/form-field'; export { FormField } from './form-components/form-field';
export { FormFieldAreaAdvanced } from './form-components/form-field-area-advanced';
export { FormFieldPrice } from './form-components/form-field-price'; export { FormFieldPrice } from './form-components/form-field-price';
export { Submit } from './form-components/submit'; export { Submit } from './form-components/submit';

View file

@ -67,19 +67,16 @@ export const icons = {
viewBox="0 0 24 24" viewBox="0 0 24 24"
width={size} width={size}
height={size} height={size}
fill="none" fill="black"
stroke={color} stroke={color}
strokeWidth="0" strokeWidth="0"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
{...rest} {...rest}
> >
<path d="M1.03125 14.1562V9.84375L12 0L22.9688 9.84375V14.1562L12 24L1.03125 14.1562Z" fill="black" /> <path d="M1.03125 14.1562V9.84375L12 0L22.9688 9.84375V14.1562L12 24L1.03125 14.1562Z" />
<path d="M8.925 10.3688L3.99375 14.8125L7.70625 18.15L12.6375 13.7063L8.925 10.3688Z" fill="black" /> <path d="M8.925 10.3688L3.99375 14.8125L7.70625 18.15L12.6375 13.7063L8.925 10.3688Z" />
<path <path d="M8.925 10.3688L15.1312 4.80005L12 1.98755L2.60625 10.425V13.575L3.99375 14.8125L8.925 10.3688Z" />
d="M8.925 10.3688L15.1312 4.80005L12 1.98755L2.60625 10.425V13.575L3.99375 14.8125L8.925 10.3688Z"
fill="black"
/>
<path <path
d="M8.925 10.3688L3.99375 14.8125L7.70625 18.15L12.6375 13.7063L8.925 10.3688Z" d="M8.925 10.3688L3.99375 14.8125L7.70625 18.15L12.6375 13.7063L8.925 10.3688Z"
fill={`url(#paint0_linear${randomId})`} fill={`url(#paint0_linear${randomId})`}
@ -172,7 +169,7 @@ export const icons = {
</g> </g>
), ),
[ICONS.HOME]: buildIcon( [ICONS.HOME]: buildIcon(
<g strokeWidth="2" fill="none" fillRule="evenodd" strokeLinecap="round" strokeLinejoin="round"> <g fill="none" fillRule="evenodd" strokeLinecap="round" strokeLinejoin="round">
<path d="M1, 11 L12, 2 C12, 2 22.9999989, 11.0000005 23, 11" /> <path d="M1, 11 L12, 2 C12, 2 22.9999989, 11.0000005 23, 11" />
<path d="M3, 10 C3, 10 3, 10.4453982 3, 10.9968336 L3, 20.0170446 C3, 20.5675806 3.43788135, 21.0138782 4.00292933, 21.0138781 L8.99707067, 21.0138779 C9.55097324, 21.0138779 10, 20.5751284 10, 20.0089602 L10, 15.0049177 C10, 14.449917 10.4433532, 14 11.0093689, 14 L12.9906311, 14 C13.5480902, 14 14, 14.4387495 14, 15.0049177 L14, 20.0089602 C14, 20.5639609 14.4378817, 21.0138779 15.0029302, 21.0138779 L19.9970758, 21.0138781 C20.5509789, 21.0138782 21.000006, 20.56848 21.000006, 20.0170446 L21.0000057, 10" /> <path d="M3, 10 C3, 10 3, 10.4453982 3, 10.9968336 L3, 20.0170446 C3, 20.5675806 3.43788135, 21.0138782 4.00292933, 21.0138781 L8.99707067, 21.0138779 C9.55097324, 21.0138779 10, 20.5751284 10, 20.0089602 L10, 15.0049177 C10, 14.449917 10.4433532, 14 11.0093689, 14 L12.9906311, 14 C13.5480902, 14 14, 14.4387495 14, 15.0049177 L14, 20.0089602 C14, 20.5639609 14.4378817, 21.0138779 15.0029302, 21.0138779 L19.9970758, 21.0138781 C20.5509789, 21.0138782 21.000006, 20.56848 21.000006, 20.0170446 L21.0000057, 10" />
</g> </g>
@ -198,9 +195,25 @@ export const icons = {
<path d="M20.88 18.09A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.29" /> <path d="M20.88 18.09A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.29" />
</g> </g>
), ),
[ICONS.SUBSCRIBE]: buildIcon( [ICONS.SUBSCRIBE]: (props: IconProps) => {
const { size = 24, color = 'currentColor', ...otherProps } = props;
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width={size}
height={size}
fill={color}
stroke={'#FFFFFF'}
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...otherProps}
>
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" /> <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
), </svg>
);
},
[ICONS.SUBSCRIBED]: (props: IconProps) => { [ICONS.SUBSCRIBED]: (props: IconProps) => {
const { size = 24, color = 'currentColor', ...otherProps } = props; const { size = 24, color = 'currentColor', ...otherProps } = props;
return ( return (
@ -210,8 +223,8 @@ export const icons = {
width={size} width={size}
height={size} height={size}
fill={color} fill={color}
stroke={color} stroke={'#FFFFFF'}
strokeWidth="1" strokeWidth="2"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
{...otherProps} {...otherProps}
@ -221,9 +234,25 @@ export const icons = {
); );
}, },
[ICONS.UNSUBSCRIBE]: buildIcon( [ICONS.UNSUBSCRIBE]: (props: IconProps) => {
const { size = 24, color = 'currentColor', ...otherProps } = props;
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width={size}
height={size}
fill={color}
stroke={'#FFFFFF'}
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...otherProps}
>
<path d="M 12,5.67 10.94,4.61 C 5.7533356,-0.57666427 -2.0266644,7.2033357 3.16,12.39 l 1.06,1.06 7.78,7.78 7.78,-7.78 1.06,-1.06 c 2.149101,-2.148092 2.149101,-5.6319078 0,-7.78 -2.148092,-2.1491008 -5.631908,-2.1491008 -7.78,0 L 9.4481298,8.2303201 15.320603,9.2419066 11.772427,13.723825" /> <path d="M 12,5.67 10.94,4.61 C 5.7533356,-0.57666427 -2.0266644,7.2033357 3.16,12.39 l 1.06,1.06 7.78,7.78 7.78,-7.78 1.06,-1.06 c 2.149101,-2.148092 2.149101,-5.6319078 0,-7.78 -2.148092,-2.1491008 -5.631908,-2.1491008 -7.78,0 L 9.4481298,8.2303201 15.320603,9.2419066 11.772427,13.723825" />
), </svg>
);
},
[ICONS.SETTINGS]: buildIcon( [ICONS.SETTINGS]: buildIcon(
<g> <g>
<circle cx="12" cy="12" r="3" /> <circle cx="12" cy="12" r="3" />
@ -586,12 +615,24 @@ export const icons = {
<path d="M21 13v2a4 4 0 0 1-4 4H3" /> <path d="M21 13v2a4 4 0 0 1-4 4H3" />
</g> </g>
), ),
[ICONS.MORE_VERTICAL]: buildIcon( [ICONS.MORE_VERTICAL]: (props: CustomProps) => (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="20"
height="20"
fill="none"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<g> <g>
<circle cx="12" cy="5" r="1" /> <circle cx="12" cy="5" r="1" />
<circle cx="12" cy="12" r="1" /> <circle cx="12" cy="12" r="1" />
<circle cx="12" cy="19" r="1" /> <circle cx="12" cy="19" r="1" />
</g> </g>
</svg>
), ),
[ICONS.MORE]: buildIcon( [ICONS.MORE]: buildIcon(
<g transform="rotate(90 12 12)"> <g transform="rotate(90 12 12)">
@ -974,7 +1015,6 @@ export const icons = {
width={props.size || '16'} width={props.size || '16'}
height={props.size || '18'} height={props.size || '18'}
fill="none" fill="none"
strokeWidth="1.5"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
> >
@ -1124,13 +1164,6 @@ export const icons = {
[ICONS.DOWNVOTE]: buildIcon( [ICONS.DOWNVOTE]: buildIcon(
<path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" /> <path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" />
), ),
[ICONS.FIRE_ACTIVE]: buildIcon(
<path
d="M11.3969 23.04C11.3969 23.04 18.4903 21.8396 18.9753 16.2795C19.3997 9.89148 14.2161 7.86333 13.2915 4.56586C13.1861 4.2261 13.1051 3.88045 13.049 3.53109C12.9174 2.68094 12.8516 1.82342 12.852 0.964865C12.852 0.964865 5.607 0.426785 4.87947 10.6227C4.34858 10.1469 3.92655 9.57999 3.63777 8.9548C3.349 8.32962 3.19921 7.65853 3.19706 6.98033C3.19706 6.98033 -4.32074 18.7767 8.45649 23.04C7.94555 22.1623 7.67841 21.1842 7.67841 20.1909C7.67841 19.1976 7.94555 18.2195 8.45649 17.3418C9.54778 15.0653 9.97218 13.8788 9.97218 13.8788C9.97218 13.8788 15.5044 18.6525 11.3969 23.04Z"
fill="#FF6635"
strokeWidth="0"
/>
),
[ICONS.SLIME_ACTIVE]: buildIcon( [ICONS.SLIME_ACTIVE]: buildIcon(
<path <path
d="M13.065 4.18508C12.5638 4.47334 11.9699 4.5547 11.4096 4.41183C10.8494 4.26896 10.367 3.91315 10.065 3.42008C9.70126 2.96799 9.52899 2.39146 9.58506 1.81392C9.64113 1.23639 9.92109 0.703759 10.365 0.330081C10.8662 0.0418164 11.4601 -0.0395341 12.0204 0.103332C12.5806 0.246199 13.063 0.602008 13.365 1.09508C13.7287 1.54717 13.901 2.12371 13.8449 2.70124C13.7889 3.27877 13.5089 3.8114 13.065 4.18508ZM2.565 6.76508C1.98518 6.6732 1.39241 6.81157 0.913189 7.15066C0.433971 7.48976 0.106262 8.00272 0 8.58008C0.0118186 9.17159 0.256137 9.73464 0.680058 10.1473C1.10398 10.56 1.67339 10.7891 2.265 10.7851C2.84509 10.8863 3.44175 10.7561 3.92691 10.4224C4.41207 10.0886 4.74707 9.57801 4.86 9.00008C4.85804 8.7046 4.79789 8.41241 4.683 8.14018C4.56811 7.86794 4.40072 7.62101 4.1904 7.41347C3.98007 7.20593 3.73093 7.04185 3.45719 6.9306C3.18345 6.81935 2.89048 6.7631 2.595 6.76508H2.565ZM22.2 15.1951C21.9286 15.0703 21.635 15.0008 21.3364 14.9907C21.0379 14.9806 20.7403 15.0301 20.461 15.1362C20.1818 15.2423 19.9264 15.403 19.7099 15.6088C19.4934 15.8146 19.3201 16.0615 19.2 16.3351C19.1369 16.6299 19.1337 16.9345 19.1906 17.2306C19.2475 17.5267 19.3634 17.8084 19.5313 18.0588C19.6992 18.3093 19.9157 18.5235 20.168 18.6886C20.4203 18.8537 20.7033 18.9665 21 19.0201C21.2714 19.1449 21.565 19.2143 21.8636 19.2244C22.1621 19.2346 22.4597 19.1851 22.739 19.079C23.0182 18.9729 23.2736 18.8122 23.4901 18.6064C23.7066 18.4005 23.8799 18.1536 24 17.8801C24.0634 17.5873 24.0677 17.2849 24.0127 16.9904C23.9577 16.696 23.8444 16.4155 23.6795 16.1654C23.5147 15.9153 23.3015 15.7007 23.0526 15.5341C22.8037 15.3674 22.524 15.2522 22.23 15.1951H22.2ZM20.34 10.2451C20.0073 9.99542 19.6009 9.86349 19.185 9.87008C18.4572 9.93018 17.7485 10.1341 17.1 10.4701C16.7447 10.6341 16.3789 10.7744 16.005 10.8901H15.69C15.5961 10.9108 15.4989 10.9108 15.405 10.8901C15 9.97508 16.5 9.00008 18.285 7.93508C18.8914 7.60883 19.4599 7.21644 19.98 6.76508C20.3961 6.30667 20.646 5.72169 20.6895 5.10413C20.733 4.48658 20.5677 3.87232 20.22 3.36008C19.9329 2.89588 19.5307 2.51381 19.0523 2.25098C18.574 1.98815 18.0358 1.85349 17.49 1.86008C17.2067 1.85969 16.9245 1.89496 16.65 1.96508C16.1585 2.08101 15.7042 2.31914 15.3293 2.65739C14.9543 2.99565 14.6708 3.42308 14.505 3.90008C14.16 4.75508 13.14 7.30508 12.135 7.71008C12.0359 7.72949 11.9341 7.72949 11.835 7.71008C11.6138 7.70259 11.3956 7.65692 11.19 7.57508C9.96 7.12508 9.6 5.62508 9.225 4.03508C9.06457 3.15891 8.79234 2.30695 8.415 1.50008C8.17043 1.04181 7.80465 0.659541 7.3576 0.395014C6.91055 0.130487 6.39941 -0.00612938 5.88 8.05856e-05C5.30686 0.011692 4.74338 0.149999 4.23 0.405081C3.872 0.589131 3.5547 0.843345 3.297 1.15258C3.03931 1.46182 2.84648 1.81976 2.73 2.20508C2.58357 2.66415 2.532 3.1482 2.57841 3.62781C2.62483 4.10743 2.76826 4.57261 3 4.99508C3.63898 5.99088 4.39988 6.90294 5.265 7.71008C5.59239 8.0233 5.90283 8.35377 6.195 8.70008C6.41249 8.94283 6.57687 9.22833 6.67761 9.5383C6.77835 9.84826 6.81322 10.1759 6.78 10.5001C6.68279 10.762 6.52008 10.9947 6.30737 11.1759C6.09467 11.3571 5.83908 11.4808 5.565 11.5351H5.19C4.89755 11.5247 4.60651 11.4896 4.32 11.4301C3.94485 11.3508 3.56329 11.3056 3.18 11.2951H3C2.50224 11.3269 2.02675 11.513 1.63964 11.8275C1.25253 12.142 0.973032 12.5694 0.84 13.0501C0.685221 13.5092 0.678705 14.0053 0.821373 14.4683C0.964041 14.9313 1.24867 15.3377 1.635 15.6301C1.97288 15.8809 2.38429 16.0127 2.805 16.0051C3.4891 15.9504 4.15377 15.751 4.755 15.4201C5.18104 15.1991 5.64344 15.0568 6.12 15.0001H6.285C6.32317 15.0086 6.35846 15.0269 6.38739 15.0532C6.41632 15.0795 6.4379 15.1129 6.45 15.1501C6.52858 15.4213 6.49621 15.7127 6.36 15.9601C5.80418 16.8088 4.95508 17.4229 3.975 17.6851C3.38444 17.8608 2.85799 18.205 2.46025 18.6756C2.06252 19.1462 1.81078 19.7226 1.73592 20.3342C1.66107 20.9458 1.76635 21.5659 2.03886 22.1185C2.31136 22.6711 2.73924 23.1321 3.27 23.4451C3.81477 23.8292 4.46349 24.0384 5.13 24.0451C6.1389 23.9485 7.08103 23.4979 7.7894 22.773C8.49778 22.0482 8.92665 21.0959 9 20.0851V19.9501C9.135 19.0351 9.33 17.7751 10.05 17.3401C10.2442 17.2216 10.4675 17.1593 10.695 17.1601C11.0828 17.1781 11.4558 17.3142 11.7641 17.5501C12.0724 17.786 12.3012 18.1105 12.42 18.4801C13.155 21.2251 13.725 23.4001 16.14 23.4001C16.4527 23.3961 16.7643 23.361 17.07 23.2951C17.8256 23.2158 18.5231 22.8527 19.0214 22.2792C19.5198 21.7057 19.7819 20.9644 19.755 20.2051C19.6664 19.6213 19.4389 19.0673 19.0918 18.5896C18.7446 18.112 18.2879 17.7246 17.76 17.4601C17.4534 17.2574 17.1625 17.0317 16.89 16.7851C16.005 15.9301 15.855 15.4051 15.885 15.1051C15.9198 14.8698 16.0313 14.6526 16.2021 14.4871C16.373 14.3217 16.5937 14.2173 16.83 14.1901H17.055C17.31 14.1901 17.61 14.1901 17.895 14.1901C18.18 14.1901 18.57 14.1901 18.84 14.1901H19.14C19.6172 14.1642 20.0748 13.9919 20.4505 13.6967C20.8263 13.4014 21.102 12.9976 21.24 12.5401C21.3316 12.1166 21.2981 11.6757 21.1436 11.2709C20.9892 10.8661 20.7204 10.5149 20.37 10.2601L20.34 10.2451Z" d="M13.065 4.18508C12.5638 4.47334 11.9699 4.5547 11.4096 4.41183C10.8494 4.26896 10.367 3.91315 10.065 3.42008C9.70126 2.96799 9.52899 2.39146 9.58506 1.81392C9.64113 1.23639 9.92109 0.703759 10.365 0.330081C10.8662 0.0418164 11.4601 -0.0395341 12.0204 0.103332C12.5806 0.246199 13.063 0.602008 13.365 1.09508C13.7287 1.54717 13.901 2.12371 13.8449 2.70124C13.7889 3.27877 13.5089 3.8114 13.065 4.18508ZM2.565 6.76508C1.98518 6.6732 1.39241 6.81157 0.913189 7.15066C0.433971 7.48976 0.106262 8.00272 0 8.58008C0.0118186 9.17159 0.256137 9.73464 0.680058 10.1473C1.10398 10.56 1.67339 10.7891 2.265 10.7851C2.84509 10.8863 3.44175 10.7561 3.92691 10.4224C4.41207 10.0886 4.74707 9.57801 4.86 9.00008C4.85804 8.7046 4.79789 8.41241 4.683 8.14018C4.56811 7.86794 4.40072 7.62101 4.1904 7.41347C3.98007 7.20593 3.73093 7.04185 3.45719 6.9306C3.18345 6.81935 2.89048 6.7631 2.595 6.76508H2.565ZM22.2 15.1951C21.9286 15.0703 21.635 15.0008 21.3364 14.9907C21.0379 14.9806 20.7403 15.0301 20.461 15.1362C20.1818 15.2423 19.9264 15.403 19.7099 15.6088C19.4934 15.8146 19.3201 16.0615 19.2 16.3351C19.1369 16.6299 19.1337 16.9345 19.1906 17.2306C19.2475 17.5267 19.3634 17.8084 19.5313 18.0588C19.6992 18.3093 19.9157 18.5235 20.168 18.6886C20.4203 18.8537 20.7033 18.9665 21 19.0201C21.2714 19.1449 21.565 19.2143 21.8636 19.2244C22.1621 19.2346 22.4597 19.1851 22.739 19.079C23.0182 18.9729 23.2736 18.8122 23.4901 18.6064C23.7066 18.4005 23.8799 18.1536 24 17.8801C24.0634 17.5873 24.0677 17.2849 24.0127 16.9904C23.9577 16.696 23.8444 16.4155 23.6795 16.1654C23.5147 15.9153 23.3015 15.7007 23.0526 15.5341C22.8037 15.3674 22.524 15.2522 22.23 15.1951H22.2ZM20.34 10.2451C20.0073 9.99542 19.6009 9.86349 19.185 9.87008C18.4572 9.93018 17.7485 10.1341 17.1 10.4701C16.7447 10.6341 16.3789 10.7744 16.005 10.8901H15.69C15.5961 10.9108 15.4989 10.9108 15.405 10.8901C15 9.97508 16.5 9.00008 18.285 7.93508C18.8914 7.60883 19.4599 7.21644 19.98 6.76508C20.3961 6.30667 20.646 5.72169 20.6895 5.10413C20.733 4.48658 20.5677 3.87232 20.22 3.36008C19.9329 2.89588 19.5307 2.51381 19.0523 2.25098C18.574 1.98815 18.0358 1.85349 17.49 1.86008C17.2067 1.85969 16.9245 1.89496 16.65 1.96508C16.1585 2.08101 15.7042 2.31914 15.3293 2.65739C14.9543 2.99565 14.6708 3.42308 14.505 3.90008C14.16 4.75508 13.14 7.30508 12.135 7.71008C12.0359 7.72949 11.9341 7.72949 11.835 7.71008C11.6138 7.70259 11.3956 7.65692 11.19 7.57508C9.96 7.12508 9.6 5.62508 9.225 4.03508C9.06457 3.15891 8.79234 2.30695 8.415 1.50008C8.17043 1.04181 7.80465 0.659541 7.3576 0.395014C6.91055 0.130487 6.39941 -0.00612938 5.88 8.05856e-05C5.30686 0.011692 4.74338 0.149999 4.23 0.405081C3.872 0.589131 3.5547 0.843345 3.297 1.15258C3.03931 1.46182 2.84648 1.81976 2.73 2.20508C2.58357 2.66415 2.532 3.1482 2.57841 3.62781C2.62483 4.10743 2.76826 4.57261 3 4.99508C3.63898 5.99088 4.39988 6.90294 5.265 7.71008C5.59239 8.0233 5.90283 8.35377 6.195 8.70008C6.41249 8.94283 6.57687 9.22833 6.67761 9.5383C6.77835 9.84826 6.81322 10.1759 6.78 10.5001C6.68279 10.762 6.52008 10.9947 6.30737 11.1759C6.09467 11.3571 5.83908 11.4808 5.565 11.5351H5.19C4.89755 11.5247 4.60651 11.4896 4.32 11.4301C3.94485 11.3508 3.56329 11.3056 3.18 11.2951H3C2.50224 11.3269 2.02675 11.513 1.63964 11.8275C1.25253 12.142 0.973032 12.5694 0.84 13.0501C0.685221 13.5092 0.678705 14.0053 0.821373 14.4683C0.964041 14.9313 1.24867 15.3377 1.635 15.6301C1.97288 15.8809 2.38429 16.0127 2.805 16.0051C3.4891 15.9504 4.15377 15.751 4.755 15.4201C5.18104 15.1991 5.64344 15.0568 6.12 15.0001H6.285C6.32317 15.0086 6.35846 15.0269 6.38739 15.0532C6.41632 15.0795 6.4379 15.1129 6.45 15.1501C6.52858 15.4213 6.49621 15.7127 6.36 15.9601C5.80418 16.8088 4.95508 17.4229 3.975 17.6851C3.38444 17.8608 2.85799 18.205 2.46025 18.6756C2.06252 19.1462 1.81078 19.7226 1.73592 20.3342C1.66107 20.9458 1.76635 21.5659 2.03886 22.1185C2.31136 22.6711 2.73924 23.1321 3.27 23.4451C3.81477 23.8292 4.46349 24.0384 5.13 24.0451C6.1389 23.9485 7.08103 23.4979 7.7894 22.773C8.49778 22.0482 8.92665 21.0959 9 20.0851V19.9501C9.135 19.0351 9.33 17.7751 10.05 17.3401C10.2442 17.2216 10.4675 17.1593 10.695 17.1601C11.0828 17.1781 11.4558 17.3142 11.7641 17.5501C12.0724 17.786 12.3012 18.1105 12.42 18.4801C13.155 21.2251 13.725 23.4001 16.14 23.4001C16.4527 23.3961 16.7643 23.361 17.07 23.2951C17.8256 23.2158 18.5231 22.8527 19.0214 22.2792C19.5198 21.7057 19.7819 20.9644 19.755 20.2051C19.6664 19.6213 19.4389 19.0673 19.0918 18.5896C18.7446 18.112 18.2879 17.7246 17.76 17.4601C17.4534 17.2574 17.1625 17.0317 16.89 16.7851C16.005 15.9301 15.855 15.4051 15.885 15.1051C15.9198 14.8698 16.0313 14.6526 16.2021 14.4871C16.373 14.3217 16.5937 14.2173 16.83 14.1901H17.055C17.31 14.1901 17.61 14.1901 17.895 14.1901C18.18 14.1901 18.57 14.1901 18.84 14.1901H19.14C19.6172 14.1642 20.0748 13.9919 20.4505 13.6967C20.8263 13.4014 21.102 12.9976 21.24 12.5401C21.3316 12.1166 21.2981 11.6757 21.1436 11.2709C20.9892 10.8661 20.7204 10.5149 20.37 10.2601L20.34 10.2451Z"
@ -2021,4 +2054,15 @@ export const icons = {
<path d="M12.5,23.24v-1A10.74,10.74,0,0,1,23.24,11.52" /> <path d="M12.5,23.24v-1A10.74,10.74,0,0,1,23.24,11.52" />
</g> </g>
), ),
[ICONS.SIMPLE_EDITOR]: buildIcon(
<g>
<path d="M1 18V6c0-1 1-2 2-2h18c1 0 2 1 2 2v12c0 1-1 2-2 2H3c-1 0-2-1-2-2ZM5 7v4" />
</g>
),
[ICONS.ADVANCED_EDITOR]: buildIcon(
<g>
<path d="M1 20V4c0-1 1-2 2-2h18c1 0 2 1 2 2v16c0 1-1 2-2 2H3c-1 0-2-1-2-2ZM1 11h22" />
<path d="M5 8V6h2v2H5ZM11 8V6h2v2h-2ZM17 8V6h2v2h-2ZM5 14v4" />
</g>
),
}; };

View file

@ -33,6 +33,7 @@ type SimpleTextProps = {
type SimpleLinkProps = { type SimpleLinkProps = {
href?: string, href?: string,
title?: string, title?: string,
embed?: boolean,
children?: React.Node, children?: React.Node,
}; };
@ -66,7 +67,7 @@ const SimpleText = (props: SimpleTextProps) => {
// **************************************************************************** // ****************************************************************************
const SimpleLink = (props: SimpleLinkProps) => { const SimpleLink = (props: SimpleLinkProps) => {
const { title, children, href } = props; const { title, children, href, embed } = props;
if (!href) { if (!href) {
return children || null; return children || null;
@ -82,13 +83,13 @@ const SimpleLink = (props: SimpleLinkProps) => {
const [uri, search] = href.split('?'); const [uri, search] = href.split('?');
const urlParams = new URLSearchParams(search); const urlParams = new URLSearchParams(search);
const embed = urlParams.get('embed'); const embedParam = urlParams.get('embed');
if (embed) { if (embed || embedParam) {
// Decode this since users might just copy it from the url bar // Decode this since users might just copy it from the url bar
const decodedUri = decodeURI(uri); const decodedUri = decodeURI(uri);
return ( return (
<div className="embed__inline-button-preview"> <div className="embed__inline-button embed__inline-button--preview">
<pre>{decodedUri}</pre> <pre>{decodedUri}</pre>
</div> </div>
); );
@ -195,7 +196,11 @@ export default React.memo<MarkdownProps>(function MarkdownPreview(props: Markdow
// Workaraund of remarkOptions.Fragment // Workaraund of remarkOptions.Fragment
div: React.Fragment, div: React.Fragment,
img: (imgProps) => img: (imgProps) =>
isStakeEnoughForPreview(stakedLevel) && !isEmote(imgProps.title, imgProps.src) ? ( noDataStore ? (
<div className="file-viewer file-viewer--document">
<img {...imgProps} />
</div>
) : isStakeEnoughForPreview(stakedLevel) && !isEmote(imgProps.title, imgProps.src) ? (
<ZoomableImage {...imgProps} /> <ZoomableImage {...imgProps} />
) : ( ) : (
<SimpleImageLink src={imgProps.src} alt={imgProps.alt} title={imgProps.title} /> <SimpleImageLink src={imgProps.src} alt={imgProps.alt} title={imgProps.title} />

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