diff --git a/.env.defaults b/.env.defaults index 8489daf19..1c519e9bb 100644 --- a/.env.defaults +++ b/.env.defaults @@ -12,6 +12,8 @@ LBRY_WEB_API=https://api.na-backend.odysee.com LBRY_WEB_STREAMING_API=https://cdn.lbryplayer.xyz LBRY_WEB_BUFFER_API=https://collector-service.api.lbry.tv/api/v1/events/video COMMENT_SERVER_API=https://comments.odysee.com/api/v2 +SEARCH_SERVER_API=https://lighthouse.odysee.com/search +SOCKETY_SERVER_API=wss://sockety.odysee.com/ws THUMBNAIL_CDN_URL=https://image-processor.vanwanet.com/optimize/ WELCOME_VERSION=1.0 @@ -37,6 +39,8 @@ SITE_NAME=lbry.tv SITE_DESCRIPTION=Meet LBRY, an open, free, and community-controlled content wonderland. SITE_HELP_EMAIL=help@lbry.com LOGO_TITLE=lbry.tv +## Social media +TWITTER_ACCOUNT=LBRYcom ## IMAGE ASSETS YRBL_HAPPY_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a diff --git a/CHANGELOG.md b/CHANGELOG.md index ce020fc66..0164617eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,13 +9,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Show currently active playing item on playlist _community pr!_ ([#6453](https://github.com/lbryio/lbry-desktop/pull/6453)) - Add watch later to hover action for last used playlist on popup _community pr!_ ([#6274](https://github.com/lbryio/lbry-desktop/pull/6274)) - Open in desktop (web feature) _community pr!_ ([#6667](https://github.com/lbryio/lbry-desktop/pull/6667)) +- Add confirmation on comment removal _community pr!_ ([#6563](https://github.com/lbryio/lbry-desktop/pull/6563)) ### Changed - Use Canonical Url for copy link ([#6500](https://github.com/lbryio/lbry-desktop/pull/6500)) - Use better icon for copy link ([#6485](https://github.com/lbryio/lbry-desktop/pull/6485)) - Comments load paginated ([#6390](https://github.com/lbryio/lbry-desktop/pull/6390)) -- Update lighthouse search api _community pr!_ ([#6731](https://github.com/lbryio/lbry-desktop/pull/6731)) - Improve twitter share _community pr!_ ([#6690](https://github.com/lbryio/lbry-desktop/pull/6690)) +- Update lighthouse search api _community pr!_ ([#6731](https://github.com/lbryio/lbry-desktop/pull/6731)) +- Update sockety api _community pr!_ ([#6747](https://github.com/lbryio/lbry-desktop/pull/6747)) ### Fixed - App now supports '#' and ':' for claimId separator ([#6496](https://github.com/lbryio/lbry-desktop/pull/6496)) diff --git a/config.js b/config.js index 7918cef01..a6c6b2a5c 100644 --- a/config.js +++ b/config.js @@ -13,7 +13,9 @@ const config = { 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_BUFFER_API: process.env.LBRY_WEB_BUFFER_API, + SEARCH_SERVER_API: process.env.SEARCH_SERVER_API, COMMENT_SERVER_API: process.env.COMMENT_SERVER_API, + SOCKETY_SERVER_API: process.env.SOCKETY_SERVER_API, WELCOME_VERSION: process.env.WELCOME_VERSION, DOMAIN: process.env.DOMAIN, SHARE_DOMAIN_URL: process.env.SHARE_DOMAIN_URL, @@ -23,6 +25,8 @@ const config = { SITE_NAME: process.env.SITE_NAME, SITE_DESCRIPTION: process.env.SITE_DESCRIPTION, SITE_HELP_EMAIL: process.env.SITE_HELP_EMAIL, + // SOCIAL MEDIA + TWITTER_ACCOUNT: process.env.TWITTER_ACCOUNT, // LOGO LOGO_TITLE: process.env.LOGO_TITLE, FAVICON: process.env.FAVICON, @@ -69,7 +73,7 @@ const config = { BRANDED_SITE: process.env.BRANDED_SITE, }; -config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`; config.URL_DEV = `http://localhost:${config.WEBPACK_WEB_PORT}`; +config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`; module.exports = config; diff --git a/static/app-strings.json b/static/app-strings.json index 18cab4302..7058c195d 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -2057,17 +2057,14 @@ "Only select creators can receive tips at this time": "Only select creators can receive tips at this time", "The payment will be made from your saved card": "The payment will be made from your saved card", "Commenting...": "Commenting...", - "Show %count% replies": "Show %count% replies", - "Show reply": "Show reply", "added to": "added to", "removed from": "removed from", "Skip Navigation": "Skip Navigation", "Reset": "Reset", "Reset to original (previous) publish date": "Reset to original (previous) publish date", - "%title% by %channelTitle%": "%title% by %channelTitle%", - "%title% by %channelTitle% %ariaDate%": "%title% by %channelTitle% %ariaDate%", - "%title% by %channelTitle% %ariaDate%, %mediaDuration%": "%title% by %channelTitle% %ariaDate%, %mediaDuration%", "Search for something...": "Search for something...", "Open in Desktop": "Open in Desktop", + "Show %count% replies": "Show %count% replies", + "Show reply": "Show reply", "--end--": "--end--" } diff --git a/ui/component/claimPreviewTile/view.jsx b/ui/component/claimPreviewTile/view.jsx index 867fc89c7..d772241e8 100644 --- a/ui/component/claimPreviewTile/view.jsx +++ b/ui/component/claimPreviewTile/view.jsx @@ -120,7 +120,7 @@ function ClaimPreviewTile(props: Props) { const signingChannel = claim && claim.signing_channel; const isChannel = claim && claim.value_type === 'channel'; const channelUri = !isChannel ? signingChannel && signingChannel.permanent_url : claim && claim.permanent_url; - const channelTitle = signingChannel && (signingChannel.value.title || signingChannel.name); + const channelTitle = signingChannel && ((signingChannel.value && signingChannel.value.title) || signingChannel.name); // Aria-label value for claim preview let ariaLabelData = isChannel ? title : formatClaimPreviewTitle(title, channelTitle, date, mediaDuration); diff --git a/ui/component/comment/view.jsx b/ui/component/comment/view.jsx index 0b9fd71bc..5161382fa 100644 --- a/ui/component/comment/view.jsx +++ b/ui/component/comment/view.jsx @@ -270,6 +270,7 @@ function Comment(props: Props) { authorUri={authorUri} commentIsMine={commentIsMine} handleEditComment={handleEditComment} + supportAmount={supportAmount} /> diff --git a/ui/component/commentMenuList/index.js b/ui/component/commentMenuList/index.js index 105754466..5ebdf41b5 100644 --- a/ui/component/commentMenuList/index.js +++ b/ui/component/commentMenuList/index.js @@ -1,7 +1,6 @@ import { connect } from 'react-redux'; import { makeSelectChannelPermUrlForClaimUri, makeSelectClaimIsMine, makeSelectClaimForUri } from 'lbry-redux'; import { - doCommentAbandon, doCommentPin, doCommentModBlock, doCommentModBlockAsAdmin, @@ -10,6 +9,7 @@ import { } from 'redux/actions/comments'; import { doChannelMute } from 'redux/actions/blocked'; // import { doSetActiveChannel } from 'redux/actions/app'; +import { doOpenModal } from 'redux/actions/app'; import { doSetPlayingUri } from 'redux/actions/content'; import { selectActiveChannelClaim } from 'redux/selectors/app'; import { selectPlayingUri } from 'redux/selectors/content'; @@ -26,8 +26,8 @@ const select = (state, props) => ({ }); const perform = (dispatch) => ({ + openModal: (modal, props) => dispatch(doOpenModal(modal, props)), clearPlayingUri: () => dispatch(doSetPlayingUri({ uri: null })), - deleteComment: (commentId, creatorChannelUrl) => dispatch(doCommentAbandon(commentId, creatorChannelUrl)), muteChannel: (channelUri) => dispatch(doChannelMute(channelUri)), pinComment: (commentId, claimId, remove) => dispatch(doCommentPin(commentId, claimId, remove)), // setActiveChannel: channelId => dispatch(doSetActiveChannel(channelId)), diff --git a/ui/component/commentMenuList/view.jsx b/ui/component/commentMenuList/view.jsx index 222d3ad8a..e9f59bf4c 100644 --- a/ui/component/commentMenuList/view.jsx +++ b/ui/component/commentMenuList/view.jsx @@ -1,5 +1,6 @@ // @flow import * as ICONS from 'constants/icons'; +import * as MODALS from 'constants/modal_types'; import React from 'react'; import { MenuList, MenuItem } from '@reach/menu-button'; import ChannelThumbnail from 'component/channelThumbnail'; @@ -12,7 +13,6 @@ type Props = { authorUri: string, // full LBRY Channel URI: lbry://@channel#123... commentId: string, // sha256 digest identifying the comment commentIsMine: boolean, // if this comment was signed by an owned channel - deleteComment: (string, ?string) => void, isPinned: boolean, pinComment: (string, string, boolean) => Promise, muteChannel: (string) => void, @@ -28,6 +28,8 @@ type Props = { disableEdit?: boolean, disableRemove?: boolean, moderationDelegatorsById: { [string]: { global: boolean, delegators: { name: string, claimId: string } } }, + openModal: (id: string, {}) => void, + supportAmount?: any, }; function CommentMenuList(props: Props) { @@ -36,7 +38,6 @@ function CommentMenuList(props: Props) { authorUri, commentIsMine, commentId, - deleteComment, muteChannel, pinComment, clearPlayingUri, @@ -53,6 +54,8 @@ function CommentMenuList(props: Props) { disableEdit, disableRemove, moderationDelegatorsById, + openModal, + supportAmount, } = props; const contentChannelClaim = !claim @@ -80,7 +83,7 @@ function CommentMenuList(props: Props) { if (playingUri && playingUri.source === 'comment') { clearPlayingUri(); } - deleteComment(commentId, commentIsMine ? undefined : contentChannelPermanentUrl); + openModal(MODALS.CONFIRM_REMOVE_COMMENT, { commentId, commentIsMine, contentChannelPermanentUrl, supportAmount }); } function handleCommentBlock() { diff --git a/ui/component/livestreamLink/view.jsx b/ui/component/livestreamLink/view.jsx index 999239b51..08afa23b1 100644 --- a/ui/component/livestreamLink/view.jsx +++ b/ui/component/livestreamLink/view.jsx @@ -18,11 +18,16 @@ export default function LivestreamLink(props: Props) { const [livestreamClaim, setLivestreamClaim] = React.useState(false); const [isLivestreaming, setIsLivestreaming] = React.useState(false); const livestreamChannelId = (channelClaim && channelClaim.claim_id) || ''; // TODO: fail in a safer way, probably + const isChannelEmpty = !channelClaim || !channelClaim.meta || !channelClaim.meta.claims_in_channel; React.useEffect(() => { - if (livestreamChannelId) { + // Don't search empty channels + if (livestreamChannelId && !isChannelEmpty) { Lbry.claim_search({ channel_ids: [livestreamChannelId], + page: 1, + page_size: 1, + no_totals: true, has_no_source: true, claim_type: ['stream'], order_by: CS.ORDER_BY_NEW_VALUE, @@ -35,7 +40,7 @@ export default function LivestreamLink(props: Props) { }) .catch(() => {}); } - }, [livestreamChannelId]); + }, [livestreamChannelId, isChannelEmpty]); React.useEffect(() => { function fetchIsStreaming() { @@ -53,17 +58,23 @@ export default function LivestreamLink(props: Props) { } let interval; - if (livestreamChannelId) { + // Only call livestream api if channel has livestream claims + if (livestreamChannelId && livestreamClaim) { if (!interval) fetchIsStreaming(); interval = setInterval(fetchIsStreaming, 10 * 1000); } - + // Prevent any more api calls on update + if (!livestreamChannelId || !livestreamClaim) { + if (interval) { + clearInterval(interval); + } + } return () => { if (interval) { clearInterval(interval); } }; - }, [livestreamChannelId]); + }, [livestreamChannelId, livestreamClaim]); if (!livestreamClaim || !isLivestreaming) { return null; diff --git a/ui/component/logo/view.jsx b/ui/component/logo/view.jsx index 2251cd0e4..145219a1a 100644 --- a/ui/component/logo/view.jsx +++ b/ui/component/logo/view.jsx @@ -26,12 +26,12 @@ export default function Logo(props: Props) { ); if (type === 'small' || (isMobile && type !== 'embed')) { - return LOGO ? : ; + return LOGO ? : ; } else if (type === 'embed') { if (LOGO_TEXT_LIGHT) { return ( <> - + ); } else { @@ -41,7 +41,10 @@ export default function Logo(props: Props) { if (LOGO_TEXT_LIGHT && LOGO_TEXT_DARK) { return ( <> - + ); } else { diff --git a/ui/component/notification/view.jsx b/ui/component/notification/view.jsx index a372c299d..889d43ac4 100644 --- a/ui/component/notification/view.jsx +++ b/ui/component/notification/view.jsx @@ -193,7 +193,7 @@ export default function Notification(props: Props) {
- e.stopPropagation()}> + e.stopPropagation()}> diff --git a/ui/component/socialShare/view.jsx b/ui/component/socialShare/view.jsx index 005387538..9849bc098 100644 --- a/ui/component/socialShare/view.jsx +++ b/ui/component/socialShare/view.jsx @@ -9,12 +9,15 @@ import { useIsMobile } from 'effects/use-screensize'; import { FormField } from 'component/common/form'; import { hmsToSeconds, secondsToHms } from 'util/time'; import { generateLbryContentUrl, generateLbryWebUrl, generateEncodedLbryURL, generateShareUrl } from 'util/url'; -import { URL, SHARE_DOMAIN_URL } from 'config'; +import { URL, TWITTER_ACCOUNT, SHARE_DOMAIN_URL } from 'config'; const SHARE_DOMAIN = SHARE_DOMAIN_URL || URL; const IOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); const SUPPORTS_SHARE_API = typeof navigator.share !== 'undefined'; +// Twitter share +const TWITTER_INTENT_API = 'https://twitter.com/intent/tweet?'; + type Props = { claim: StreamClaim, title: ?string, @@ -68,6 +71,21 @@ function SocialShare(props: Props) { ); const downloadUrl = `${generateDownloadUrl(name, claimId)}`; + // Tweet params + let tweetIntentParams = { + url: shareUrl, + text: title || claim.name, + hashtags: 'LBRY', + }; + + if (TWITTER_ACCOUNT) { + // $FlowFixMe + tweetIntentParams.via = TWITTER_ACCOUNT; + } + + // Generate twitter web intent url + const tweetIntent = TWITTER_INTENT_API + new URLSearchParams(tweetIntentParams).toString(); + function handleWebShareClick() { if (navigator.share) { navigator.share({ @@ -115,7 +133,7 @@ function SocialShare(props: Props) { iconSize={24} icon={ICONS.TWITTER} title={__('Share on Twitter')} - href={`https://twitter.com/intent/tweet?text=${encodedLbryURL}`} + href={tweetIntent} />
+ + } + /> + + ); +} + +export default ModalRemoveComment; diff --git a/ui/modal/modalRouter/view.jsx b/ui/modal/modalRouter/view.jsx index 0d6ab4e08..3f8e729f2 100644 --- a/ui/modal/modalRouter/view.jsx +++ b/ui/modal/modalRouter/view.jsx @@ -30,6 +30,7 @@ const ModalPublish = lazyImport(() => import('modal/modalPublish' /* webpackChun const ModalPublishPreview = lazyImport(() => import('modal/modalPublishPreview' /* webpackChunkName: "modalPublishPreview" */)); const ModalRemoveBtcSwapAddress = lazyImport(() => import('modal/modalRemoveBtcSwapAddress' /* webpackChunkName: "modalRemoveBtcSwapAddress" */)); const ModalRemoveCard = lazyImport(() => import('modal/modalRemoveCard' /* webpackChunkName: "modalRemoveCard" */)); +const ModalRemoveComment = lazyImport(() => import('modal/modalRemoveComment' /* webpackChunkName: "modalRemoveComment" */)); const ModalRemoveFile = lazyImport(() => import('modal/modalRemoveFile' /* webpackChunkName: "modalRemoveFile" */)); const ModalRevokeClaim = lazyImport(() => import('modal/modalRevokeClaim' /* webpackChunkName: "modalRevokeClaim" */)); const ModalRewardCode = lazyImport(() => import('modal/modalRewardCode' /* webpackChunkName: "modalRewardCode" */)); @@ -154,6 +155,8 @@ function ModalRouter(props: Props) { return ModalDeleteCollection; case MODALS.CONFIRM_REMOVE_CARD: return ModalRemoveCard; + case MODALS.CONFIRM_REMOVE_COMMENT: + return ModalRemoveComment; default: return null; } diff --git a/ui/redux/actions/search.js b/ui/redux/actions/search.js index 714907c5e..0da0039d0 100644 --- a/ui/redux/actions/search.js +++ b/ui/redux/actions/search.js @@ -5,7 +5,7 @@ import { buildURI, doResolveUris, batchActions, isURIValid, makeSelectClaimForUr import { makeSelectSearchUris, selectSearchValue } from 'redux/selectors/search'; import handleFetchResponse from 'util/handle-fetch'; import { getSearchQueryString } from 'util/query-params'; -import { SIMPLE_SITE } from 'config'; +import { SIMPLE_SITE, SEARCH_SERVER_API } from 'config'; type Dispatch = (action: any) => any; type GetState = () => { search: SearchState }; @@ -19,7 +19,7 @@ type SearchOptions = { }; let lighthouse = { - CONNECTION_STRING: 'https://lighthouse.lbry.com/search', + CONNECTION_STRING: SEARCH_SERVER_API, search: (queryString: string) => fetch(`${lighthouse.CONNECTION_STRING}?${queryString}`).then(handleFetchResponse), }; diff --git a/ui/redux/actions/websocket.js b/ui/redux/actions/websocket.js index c4c6090b9..7c5532ea4 100644 --- a/ui/redux/actions/websocket.js +++ b/ui/redux/actions/websocket.js @@ -1,9 +1,10 @@ import * as ACTIONS from 'constants/action_types'; import { getAuthToken } from 'util/saved-passwords'; import { doNotificationList } from 'redux/actions/notifications'; +import { SOCKETY_SERVER_API } from 'config'; -const NOTIFICATION_WS_URL = 'wss://sockety.lbry.com/ws/internal?id='; -const COMMENT_WS_URL = 'wss://sockety.lbry.com/ws/commentron?id='; +const NOTIFICATION_WS_URL = `${SOCKETY_SERVER_API}/internal?id=`; +const COMMENT_WS_URL = `${SOCKETY_SERVER_API}/commentron?id=`; let sockets = {}; let closingSockets = {}; diff --git a/ui/scss/component/_header.scss b/ui/scss/component/_header.scss index 207f14eac..0c2044388 100644 --- a/ui/scss/component/_header.scss +++ b/ui/scss/component/_header.scss @@ -71,6 +71,13 @@ display: flex; } +.header__navigation-logo { + height: var(--height-button); + max-width: -webkit-fit-content; + max-width: -moz-fit-content; + max-width: fit-content; +} + .header__navigation-item { height: var(--height-button); display: flex; diff --git a/ui/scss/component/menu-button.scss b/ui/scss/component/menu-button.scss index bb94ec35e..5f32d66ad 100644 --- a/ui/scss/component/menu-button.scss +++ b/ui/scss/component/menu-button.scss @@ -51,10 +51,7 @@ padding: 0.3rem; .icon { - stroke: var(--color-menu); - } - - .comment__menu-icon--hovering { + stroke: var(--color-menu-icon); } &:focus, @@ -62,7 +59,7 @@ opacity: 1; background-color: var(--color-button-alt-bg); .icon { - stroke: var(--color-menu-hovering); + stroke: var(--color-menu-icon-active); } } } diff --git a/ui/scss/init/_base-theme.scss b/ui/scss/init/_base-theme.scss index 4a34619d0..58ca7b7a5 100644 --- a/ui/scss/init/_base-theme.scss +++ b/ui/scss/init/_base-theme.scss @@ -124,8 +124,7 @@ --color-menu-background: var(--color-header-background); --color-menu-background--active: var(--color-card-background-highlighted); --color-menu-icon: var(--color-navigation-link); - --color-menu: var(--color-gray-3); - --color-menu-hovering: var(--color-gray-6); + --color-menu-icon-active: var(--color-gray-6); // Comments --color-comment-highlighted: #fff2d9; diff --git a/ui/scss/themes/dark.scss b/ui/scss/themes/dark.scss index edc0bbf7c..bebc2af07 100644 --- a/ui/scss/themes/dark.scss +++ b/ui/scss/themes/dark.scss @@ -90,8 +90,7 @@ --color-menu-background: var(--color-header-background); --color-menu-background--active: var(--color-gray-7); --color-menu-icon: var(--color-gray-4); - --color-menu: var(--color-gray-5); - --color-menu-hovering: var(--color-gray-2); + --color-menu-icon-active: var(--color-gray-2); // Comments --color-comment-threadline: #434b54; diff --git a/web/scss/themes/lbrytv/dark.scss b/web/scss/themes/lbrytv/dark.scss index b244eefa6..ab79d895f 100644 --- a/web/scss/themes/lbrytv/dark.scss +++ b/web/scss/themes/lbrytv/dark.scss @@ -90,6 +90,7 @@ --color-menu-background: var(--color-header-background); --color-menu-background--active: var(--color-gray-7); --color-menu-icon: var(--color-gray-4); + --color-menu-icon-active: var(--color-gray-2); // Comments --color-comment-menu: var(--color-gray-5); diff --git a/web/scss/themes/odysee/init/_base-theme.scss b/web/scss/themes/odysee/init/_base-theme.scss index 02313f1e1..76096b53c 100644 --- a/web/scss/themes/odysee/init/_base-theme.scss +++ b/web/scss/themes/odysee/init/_base-theme.scss @@ -124,6 +124,7 @@ --color-menu-background: var(--color-header-background); --color-menu-background--active: var(--color-card-background-highlighted); --color-menu-icon: var(--color-navigation-link); + --color-menu-icon-active: var(--color-navigation-link); // Comments --color-comment-menu: var(--color-gray-3);