From ed2fe16f45c96bb95376e4bab0912eccded8ef53 Mon Sep 17 00:00:00 2001 From: Daniel Dominguez Date: Wed, 16 May 2018 18:34:07 -0300 Subject: [PATCH 01/34] Add right click context menu on all text inputs. --- src/renderer/index.js | 3 ++ src/renderer/util/contextMenu.js | 65 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/renderer/util/contextMenu.js diff --git a/src/renderer/index.js b/src/renderer/index.js index c82db3287..fe0b9e695 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -16,6 +16,7 @@ import 'scss/all.scss'; import store from 'store'; import app from './app'; import analytics from './analytics'; +import getMenu from './util/contextMenu'; const { autoUpdater } = remote.require('electron-updater'); @@ -95,6 +96,8 @@ document.addEventListener('click', event => { } }); +document.addEventListener('contextmenu', getMenu); + const init = () => { autoUpdater.on('update-downloaded', () => { app.store.dispatch(doAutoUpdate()); diff --git a/src/renderer/util/contextMenu.js b/src/renderer/util/contextMenu.js new file mode 100644 index 000000000..0348423bf --- /dev/null +++ b/src/renderer/util/contextMenu.js @@ -0,0 +1,65 @@ +import { clipboard, remote } from 'electron'; +import isDev from 'electron-is-dev'; + +function textInputTemplate(target) { + const somethingSelected = target.selectionStart < target.selectionEnd; + const hasValue = target.value.length > 0; + + // Native Electron selectAll role does not work + function selectAll() { + target.selectionStart = 0; + target.selectionEnd = target.value.length + 1; + } + + const template = [ + { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut', enabled: somethingSelected }, + { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy', enabled: somethingSelected }, + { + label: 'Paste', + accelerator: 'CmdOrCtrl+V', + role: 'paste', + enabled: clipboard.readText().length > 0, + }, + { + label: 'Select All', + accelerator: 'CmdOrCtrl+A', + role: 'selectAll', + enabled: hasValue, + click: selectAll, + }, + ]; + + return template; +} + +function getTemplate(target) { + const { type } = target; + if (target.matches('input') && (type === 'text' || type === 'number')) { + return textInputTemplate(target); + } + return []; +} + +export default event => { + event.preventDefault(); + const { target } = event; + const template = getTemplate(target); + if (isDev) { + const { screenX, screenY } = event; + const separator = { type: 'separator' }; + const developmentTemplateAddition = [ + { + label: 'Inspect element', + accelerator: 'CmdOrCtrl+Shift+I', + click: () => { + remote.getCurrentWindow().inspectElement(screenX, screenY); + }, + }, + ]; + if (template.length > 0) { + template.push(separator); + } + template.push(...developmentTemplateAddition); + } + remote.Menu.buildFromTemplate(template).popup(); +}; From 86876d6a1982e55c0856efc9f6944d0113ea7417 Mon Sep 17 00:00:00 2001 From: Daniel Dominguez Date: Sun, 20 May 2018 22:00:59 -0300 Subject: [PATCH 02/34] Add context menu helper to be able to modify the menu templates in react way and not be static. --- src/main/createWindow.js | 2 - src/main/menu/setupContextMenu.js | 27 ------ src/renderer/component/fileCard/view.jsx | 5 ++ src/renderer/index.js | 6 +- src/renderer/util/contextMenu.js | 107 ++++++++++++----------- 5 files changed, 63 insertions(+), 84 deletions(-) delete mode 100644 src/main/menu/setupContextMenu.js diff --git a/src/main/createWindow.js b/src/main/createWindow.js index 738ab792a..764003c65 100644 --- a/src/main/createWindow.js +++ b/src/main/createWindow.js @@ -3,7 +3,6 @@ import isDev from 'electron-is-dev'; import windowStateKeeper from 'electron-window-state'; import setupBarMenu from './menu/setupBarMenu'; -import setupContextMenu from './menu/setupContextMenu'; export default appState => { // Get primary display dimensions from Electron. @@ -73,7 +72,6 @@ export default appState => { } setupBarMenu(); - setupContextMenu(window); window.on('close', event => { if (!appState.isQuitting && !appState.autoUpdateAccepted) { diff --git a/src/main/menu/setupContextMenu.js b/src/main/menu/setupContextMenu.js deleted file mode 100644 index 658ac731a..000000000 --- a/src/main/menu/setupContextMenu.js +++ /dev/null @@ -1,27 +0,0 @@ -// @flow -import { Menu, BrowserWindow } from 'electron'; -import isDev from 'electron-is-dev'; - -export default (rendererWindow: BrowserWindow) => { - rendererWindow.webContents.on('context-menu', (e, params) => { - const { x, y } = params; - - const template = [{ role: 'cut' }, { role: 'copy' }, { role: 'paste' }]; - - const developmentTemplateAddition = [ - { type: 'separator' }, - { - label: 'Inspect element', - click: () => { - rendererWindow.inspectElement(x, y); - }, - }, - ]; - - if (isDev) { - template.push(...developmentTemplateAddition); - } - - Menu.buildFromTemplate(template).popup(); - }); -}; diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx index 88bb99946..6fc765633 100644 --- a/src/renderer/component/fileCard/view.jsx +++ b/src/renderer/component/fileCard/view.jsx @@ -9,6 +9,7 @@ import FilePrice from 'component/filePrice'; import UriIndicator from 'component/uriIndicator'; import * as icons from 'constants/icons'; import classnames from 'classnames'; +import { openCopyLinkMenu } from '../../util/contextMenu'; // TODO: iron these out type Props = { @@ -60,6 +61,9 @@ class FileCard extends React.PureComponent { const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null; const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw; const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id); + const handleContextMenu = event => { + openCopyLinkMenu(uri, event); + }; // We should be able to tab through cards /* eslint-disable jsx-a11y/click-events-have-key-events */ @@ -72,6 +76,7 @@ class FileCard extends React.PureComponent { 'card--link': !pending, 'card--pending': pending, })} + onContextMenu={handleContextMenu} >
{showPrice && }
diff --git a/src/renderer/index.js b/src/renderer/index.js index fe0b9e695..c19790f06 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -16,7 +16,7 @@ import 'scss/all.scss'; import store from 'store'; import app from './app'; import analytics from './analytics'; -import getMenu from './util/contextMenu'; +import { initContextMenu } from './util/contextMenu'; const { autoUpdater } = remote.require('electron-updater'); @@ -96,7 +96,7 @@ document.addEventListener('click', event => { } }); -document.addEventListener('contextmenu', getMenu); +document.addEventListener('contextmenu', initContextMenu); const init = () => { autoUpdater.on('update-downloaded', () => { @@ -132,7 +132,7 @@ const init = () => { ReactDOM.render(
- + openContextMenu(e)} />
, diff --git a/src/renderer/util/contextMenu.js b/src/renderer/util/contextMenu.js index 0348423bf..79f47da5b 100644 --- a/src/renderer/util/contextMenu.js +++ b/src/renderer/util/contextMenu.js @@ -1,65 +1,68 @@ import { clipboard, remote } from 'electron'; import isDev from 'electron-is-dev'; -function textInputTemplate(target) { - const somethingSelected = target.selectionStart < target.selectionEnd; - const hasValue = target.value.length > 0; - - // Native Electron selectAll role does not work - function selectAll() { - target.selectionStart = 0; - target.selectionEnd = target.value.length + 1; - } - - const template = [ - { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut', enabled: somethingSelected }, - { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy', enabled: somethingSelected }, +function injectDevelopmentTemplate(event, templates) { + if (!isDev) return templates; + const { screenX, screenY } = event; + const separator = { type: 'separator' }; + const developmentTemplateAddition = [ { - label: 'Paste', - accelerator: 'CmdOrCtrl+V', - role: 'paste', - enabled: clipboard.readText().length > 0, - }, - { - label: 'Select All', - accelerator: 'CmdOrCtrl+A', - role: 'selectAll', - enabled: hasValue, - click: selectAll, + label: 'Inspect element', + accelerator: 'CmdOrCtrl+Shift+I', + click: () => { + remote.getCurrentWindow().inspectElement(screenX, screenY); + }, }, ]; - - return template; -} - -function getTemplate(target) { - const { type } = target; - if (target.matches('input') && (type === 'text' || type === 'number')) { - return textInputTemplate(target); + if (templates.length > 0) { + templates.push(separator); } - return []; + templates.push(...developmentTemplateAddition); + return templates; } -export default event => { - event.preventDefault(); - const { target } = event; - const template = getTemplate(target); - if (isDev) { - const { screenX, screenY } = event; - const separator = { type: 'separator' }; - const developmentTemplateAddition = [ +export function openContextMenu(event, templates = [], addDefaultTemplates = true) { + if (addDefaultTemplates) { + const { value } = event.target; + const inputTemplates = [ + { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' }, + { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' }, { - label: 'Inspect element', - accelerator: 'CmdOrCtrl+Shift+I', - click: () => { - remote.getCurrentWindow().inspectElement(screenX, screenY); - }, + label: 'Paste', + accelerator: 'CmdOrCtrl+V', + role: 'paste', + enabled: clipboard.readText().length > 0, + }, + { + label: 'Select All', + accelerator: 'CmdOrCtrl+A', + role: 'selectall', + enabled: !!value, }, ]; - if (template.length > 0) { - template.push(separator); - } - template.push(...developmentTemplateAddition); + templates.push(...inputTemplates); } - remote.Menu.buildFromTemplate(template).popup(); -}; + + injectDevelopmentTemplate(event, templates); + remote.Menu.buildFromTemplate(templates).popup(); +} +export function openCopyLinkMenu(text, event) { + const templates = [ + { + label: 'Copy link', + click: () => { + clipboard.writeText(text); + }, + }, + ]; + openContextMenu(event, templates, false); +} + +export function initContextMenu(event) { + const { type } = event.target; + if (event.target.matches('input') && (type === 'text' || type === 'number')) { + openContextMenu(event); + } else { + event.preventDefault(); + } +} From b4542517def09c07b423700fad15208b4f445cb0 Mon Sep 17 00:00:00 2001 From: Daniel Dominguez Date: Mon, 21 May 2018 14:18:02 -0300 Subject: [PATCH 03/34] Correctly copy an URI so it can be opened with lbry-app when shared. --- src/renderer/component/fileCard/view.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx index 6fc765633..818d8cd4a 100644 --- a/src/renderer/component/fileCard/view.jsx +++ b/src/renderer/component/fileCard/view.jsx @@ -1,6 +1,6 @@ // @flow import * as React from 'react'; -import { normalizeURI } from 'lbry-redux'; +import { normalizeURI, convertToShareLink } from 'lbry-redux'; import Button from 'component/button'; import CardMedia from 'component/cardMedia'; import TruncatedText from 'component/common/truncated-text'; @@ -62,7 +62,7 @@ class FileCard extends React.PureComponent { const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw; const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id); const handleContextMenu = event => { - openCopyLinkMenu(uri, event); + openCopyLinkMenu(convertToShareLink(uri), event); }; // We should be able to tab through cards From f54a24309e7320db1af59a3969cfb940aae23b78 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Wed, 23 May 2018 00:35:34 -0400 Subject: [PATCH 04/34] fix: use short form uri when preparingEdit so users know they are editing --- src/renderer/page/file/view.jsx | 10 +++++++++- src/renderer/redux/reducers/navigation.js | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx index bf7c34846..5ebe44876 100644 --- a/src/renderer/page/file/view.jsx +++ b/src/renderer/page/file/view.jsx @@ -129,6 +129,14 @@ class FilePage extends React.Component { subscriptionUri = buildURI({ channelName, claimId: channelClaimId }, false); } + // We want to use the short form uri for editing + // This is what the user is used to seeing, they don't care about the claim id + // We will select the claim id before they publish + let editUri; + if (claimIsMine) { + editUri = buildURI({ channelName, contentName: claim.name }); + } + const isPlaying = playingUri === uri && !isPaused; return ( @@ -170,7 +178,7 @@ class FilePage extends React.Component { icon={icons.EDIT} label={__('Edit')} onClick={() => { - prepareEdit(claim, uri); + prepareEdit(claim, editUri); navigate('/publish'); }} /> diff --git a/src/renderer/redux/reducers/navigation.js b/src/renderer/redux/reducers/navigation.js index e4544b4cc..80a5e0259 100644 --- a/src/renderer/redux/reducers/navigation.js +++ b/src/renderer/redux/reducers/navigation.js @@ -3,7 +3,7 @@ import * as ACTIONS from 'constants/action_types'; const getCurrentPath = () => { const { hash } = document.location; if (hash !== '') return hash.replace(/^#/, ''); - return '/discover'; + return '/publish'; }; const reducers = {}; From 8ca6e21969e5c081a553371b4ab2683f82932968 Mon Sep 17 00:00:00 2001 From: Daniel Dominguez Date: Wed, 23 May 2018 16:30:45 -0300 Subject: [PATCH 05/34] Allow https to follow redirections when requesting latest release data from github. --- src/main/index.js | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/main/index.js b/src/main/index.js index 2591e20f6..276212b59 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -176,11 +176,11 @@ ipcMain.on('version-info-requested', () => { }, }; let result = ''; - - const req = https.get(Object.assign(opts, url.parse(latestReleaseAPIURL)), res => { + const onSuccess = res => { res.on('data', data => { result += data; }); + res.on('end', () => { const tagName = JSON.parse(result).tag_name; const [, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/); @@ -199,14 +199,27 @@ ipcMain.on('version-info-requested', () => { } } }); - }); + }; - req.on('error', err => { - console.log('Failed to get current version from GitHub. Error:', err); - if (rendererWindow) { - rendererWindow.webContents.send('version-info-received', null); - } - }); + const requestLatestRelease = (apiUrl, alreadyRedirected = false) => { + const req = https.get(Object.assign(opts, url.parse(apiUrl)), res => { + if (res.statusCode === 301 || res.statusCode === 302) { + requestLatestRelease(res.headers.location, true); + } else { + onSuccess(res); + } + }); + + if (alreadyRedirected) return; + req.on('error', err => { + console.log('Failed to get current version from GitHub. Error:', err); + if (rendererWindow) { + rendererWindow.webContents.send('version-info-received', null); + } + }); + }; + + requestLatestRelease(latestReleaseAPIURL); }); ipcMain.on('get-auth-token', event => { From bd3936fc2be14c89c559b6ea16e9c842acb73393 Mon Sep 17 00:00:00 2001 From: Travis Eden Date: Tue, 15 May 2018 19:01:53 -0400 Subject: [PATCH 06/34] publish by channel_id rather than channel_name --- src/renderer/component/publishForm/view.jsx | 17 ++++++++++------- src/renderer/page/publish/index.js | 2 ++ src/renderer/redux/actions/publish.js | 5 ++--- src/renderer/redux/reducers/publish.js | 4 ++++ 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/renderer/component/publishForm/view.jsx b/src/renderer/component/publishForm/view.jsx index ff3850a2c..e93ebb95d 100644 --- a/src/renderer/component/publishForm/view.jsx +++ b/src/renderer/component/publishForm/view.jsx @@ -29,6 +29,8 @@ type Props = { currency: string, }, channel: string, + channelId: ?string, + myChannels: Array<{ name: string }>, name: ?string, tosAccepted: boolean, updatePublishForm: UpdatePublishFormData => void, @@ -137,13 +139,14 @@ class PublishForm extends React.PureComponent { } handleChannelChange(channelName: string) { - const { name, updatePublishForm } = this.props; + const { name, updatePublishForm, myChannels } = this.props; + const form = { channel: channelName }; + const namedChannelClaim = myChannels.find(channel => channel.name === channelName); + form.channelId = namedChannelClaim ? namedChannelClaim.claim_id : ''; if (name) { - const uri = this.getNewUri(name, channelName); - updatePublishForm({ channel: channelName, uri }); - } else { - updatePublishForm({ channel: channelName }); + form.uri = this.getNewUri(name, channelName); } + updatePublishForm(form); } handleBidChange(bid: number) { @@ -183,7 +186,7 @@ class PublishForm extends React.PureComponent { description, language, nsfw, - channel, + channelId, licenseType, licenseUrl, otherLicenseDescription, @@ -217,7 +220,7 @@ class PublishForm extends React.PureComponent { description, language, nsfw, - channel, + channelId, license: publishingLicense, licenseUrl: publishingLicenseUrl, otherLicenseDescription, diff --git a/src/renderer/page/publish/index.js b/src/renderer/page/publish/index.js index 864ab0df5..78950abe7 100644 --- a/src/renderer/page/publish/index.js +++ b/src/renderer/page/publish/index.js @@ -35,6 +35,7 @@ const select = (state, props) => { const claimsByUri = selectClaimsByUri(state); const myClaims = selectMyClaims(state); + const myChannels = selectMyChannelClaims(state); const claimForUri = claimsByUri[uri]; let winningBidForClaimUri; @@ -50,6 +51,7 @@ const select = (state, props) => { claimForUri, winningBidForClaimUri, myClaimForUri, + myChannels, costInfo: makeSelectCostInfoForUri(props.uri)(state), balance: selectBalance(state), }; diff --git a/src/renderer/redux/actions/publish.js b/src/renderer/redux/actions/publish.js index 2981299fc..270f156b4 100644 --- a/src/renderer/redux/actions/publish.js +++ b/src/renderer/redux/actions/publish.js @@ -6,7 +6,6 @@ import type { UpdatePublishFormAction, PublishParams, } from 'redux/reducers/publish'; -import { CHANNEL_NEW, CHANNEL_ANONYMOUS } from 'constants/claim'; type Action = UpdatePublishFormAction | { type: ACTIONS.CLEAR_PUBLISH }; type PromiseAction = Promise; @@ -86,6 +85,7 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat thumbnail, nsfw, channel, + channelId, title, contentIsFree, price, @@ -104,7 +104,6 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat } } - const channelName = channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : channel; const fee = contentIsFree || !price.amount ? undefined : { ...price }; const metadata = { @@ -126,7 +125,7 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat const publishPayload = { name, - channel_name: channelName, + channel_id: channelId, bid, metadata, }; diff --git a/src/renderer/redux/reducers/publish.js b/src/renderer/redux/reducers/publish.js index d20505598..048ca4ac5 100644 --- a/src/renderer/redux/reducers/publish.js +++ b/src/renderer/redux/reducers/publish.js @@ -18,6 +18,7 @@ type PublishState = { language: string, tosAccepted: boolean, channel: string, + channelId: ?string, name: string, nameError: ?string, bid: number, @@ -41,6 +42,7 @@ export type UpdatePublishFormData = { language?: string, tosAccepted?: boolean, channel?: string, + channelId?: string, name?: string, nameError?: string, bid?: number, @@ -66,6 +68,7 @@ export type PublishParams = { thumbnail: ?string, nsfw: boolean, channel: string, + channelId: string, title: string, contentIsFree: boolean, uri: string, @@ -97,6 +100,7 @@ const defaultState: PublishState = { language: 'en', nsfw: false, channel: CHANNEL_ANONYMOUS, + channelId: '', tosAccepted: false, name: '', nameError: undefined, From 938a8e1b7e6d1dc3f80e5d7cd1f981640717f0ca Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Wed, 23 May 2018 00:35:34 -0400 Subject: [PATCH 07/34] allow channels on Discover page --- src/renderer/component/categoryList/index.js | 18 +++++++++++++ .../view.jsx} | 27 +++++++++++++++++-- src/renderer/page/discover/view.jsx | 8 ++++-- src/renderer/page/file/view.jsx | 10 ++++++- src/renderer/redux/actions/content.js | 8 +++--- 5 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 src/renderer/component/categoryList/index.js rename src/renderer/component/{common/category-list.jsx => categoryList/view.jsx} (91%) diff --git a/src/renderer/component/categoryList/index.js b/src/renderer/component/categoryList/index.js new file mode 100644 index 000000000..7e728b9f4 --- /dev/null +++ b/src/renderer/component/categoryList/index.js @@ -0,0 +1,18 @@ +import { connect } from 'react-redux'; +import { doFetchClaimsByChannel } from 'redux/actions/content'; +import { + makeSelectClaimsInChannelForCurrentPage, + makeSelectFetchingChannelClaims, +} from 'lbry-redux'; +import CategoryList from './view'; + +const select = (state, props) => ({ + channelClaims: makeSelectClaimsInChannelForCurrentPage(props.categoryLink)(state), + fetching: makeSelectFetchingChannelClaims(props.categoryLink)(state), +}); + +const perform = dispatch => ({ + fetchChannel: channel => dispatch(doFetchClaimsByChannel(channel)), +}); + +export default connect(select, perform)(CategoryList); diff --git a/src/renderer/component/common/category-list.jsx b/src/renderer/component/categoryList/view.jsx similarity index 91% rename from src/renderer/component/common/category-list.jsx rename to src/renderer/component/categoryList/view.jsx index 4b1589cee..0afa57940 100644 --- a/src/renderer/component/common/category-list.jsx +++ b/src/renderer/component/categoryList/view.jsx @@ -5,11 +5,15 @@ import ToolTip from 'component/common/tooltip'; import FileCard from 'component/fileCard'; import Button from 'component/button'; import * as icons from 'constants/icons'; +import Claim from 'types/claim'; type Props = { category: string, names: Array, - categoryLink?: string, + categoryLink: ?string, + fetching: boolean, + channelClaims: Array, + fetchChannel: string => void, }; type State = { @@ -18,6 +22,11 @@ type State = { }; class CategoryList extends React.PureComponent { + static defaultProps = { + names: [], + categoryLink: '', + }; + constructor() { super(); @@ -32,6 +41,11 @@ class CategoryList extends React.PureComponent { } componentDidMount() { + const { fetching, categoryLink, fetchChannel } = this.props; + if (!fetching) { + fetchChannel(categoryLink); + } + const cardRow = this.rowItems; if (cardRow) { const cards = cardRow.getElementsByTagName('section'); @@ -109,6 +123,9 @@ class CategoryList extends React.PureComponent { // check if a card is fully visible horizontally isCardVisible = (section: HTMLElement) => { + if (!section) { + return false; + } const rect = section.getBoundingClientRect(); const isVisible = rect.left >= 0 && rect.right <= window.innerWidth; return isVisible; @@ -189,7 +206,7 @@ class CategoryList extends React.PureComponent { } render() { - const { category, names, categoryLink } = this.props; + const { category, categoryLink, names, channelClaims } = this.props; const { canScrollNext, canScrollPrevious } = this.state; // The lint was throwing an error saying we should use -
{body}
+ + {tooltipContent} + {body && ( + // body may be undefined for some icons until we add messages for them + {body} + )} ); } diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx index 88bb99946..460006f70 100644 --- a/src/renderer/component/fileCard/view.jsx +++ b/src/renderer/component/fileCard/view.jsx @@ -98,14 +98,16 @@ class FileCard extends React.PureComponent {
{title}
-
+
{pending ? (
Pending...
) : ( - {isRewardContent && } - {fileInfo && } +
+ {isRewardContent && } + {fileInfo && } +
)}
diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx index f6bec07aa..55a85904a 100644 --- a/src/renderer/page/file/view.jsx +++ b/src/renderer/page/file/view.jsx @@ -158,7 +158,7 @@ class FilePage extends React.Component {

{title}

- {isRewardContent && } + {isRewardContent && }
diff --git a/src/renderer/page/search/view.jsx b/src/renderer/page/search/view.jsx index 0535c34d7..763848def 100644 --- a/src/renderer/page/search/view.jsx +++ b/src/renderer/page/search/view.jsx @@ -5,6 +5,8 @@ import FileTile from 'component/fileTile'; import FileListSearch from 'component/fileListSearch'; import ToolTip from 'component/common/tooltip'; import Page from 'component/page'; +import Icon from 'component/common/icon'; +import * as icons from 'constants/icons'; const MODAL_ANIMATION_TIME = 250; @@ -50,10 +52,11 @@ class SearchPage extends React.PureComponent {
{__('Exact URL')} + > + +
diff --git a/src/renderer/scss/_gui.scss b/src/renderer/scss/_gui.scss index d49071623..0ad4197dc 100644 --- a/src/renderer/scss/_gui.scss +++ b/src/renderer/scss/_gui.scss @@ -122,12 +122,11 @@ input::placeholder { } select { - min-width: 100px; + min-width: 60px; height: 30px; border-radius: 8px; background-color: var(--input-select-bg-color); font: normal 12px/30px 'metropolis-medium'; - text-indent: 12px; color: var(--input-select-color); &:disabled { diff --git a/src/renderer/scss/_vars.scss b/src/renderer/scss/_vars.scss index ea591571e..db8bf3e9e 100644 --- a/src/renderer/scss/_vars.scss +++ b/src/renderer/scss/_vars.scss @@ -161,9 +161,8 @@ $large-breakpoint: 1760px; --modal-btn-bg-color: var(--btn-bg-alt); // /* Tooltip */ - --tooltip-width: 300px; - --tooltip-bg: var(--color-bg); - --tooltip-color: var(--text-color); + --tooltip-bg: #555; + --tooltip-color: var(--color-white); /* Scrollbar */ --scrollbar-radius: 10px; diff --git a/src/renderer/scss/component/_card.scss b/src/renderer/scss/component/_card.scss index 9d5404e42..b872a95e0 100644 --- a/src/renderer/scss/component/_card.scss +++ b/src/renderer/scss/component/_card.scss @@ -17,7 +17,6 @@ .card--small { width: var(--card-small-width); - overflow-x: hidden; white-space: normal; .card__media { @@ -86,8 +85,7 @@ align-items: center; .credit-amount, .icon { - margin-top: $spacing-vertical * 1/3; - margin-left: $spacing-vertical * 2/3; + margin: $spacing-vertical * 1/3; } } @@ -126,7 +124,11 @@ color: var(--card-text-color); .icon { - margin-left: $spacing-vertical * 1/3; + margin-top: $spacing-vertical * 1/6; + + &:not(:first-of-type) { + margin: 0 $spacing-vertical * 1/3; + } } } @@ -134,11 +136,6 @@ padding-top: $spacing-vertical * 1/3; } -.card__subtitle--file-info { - display: flex; - align-items: center; -} - .card__subtitle--block { display: block; } @@ -243,12 +240,11 @@ } /* - .card-row is used on the discover/subscriptions page + .card-row is used on the discover page It is a list of cards that extend past the right edge of the screen There are left/right arrows to scroll the cards and view hidden content */ .card-row { - overflow: hidden; white-space: nowrap; width: 100%; min-width: var(--card-small-width); @@ -289,6 +285,18 @@ padding-top: $spacing-vertical * 2/3; overflow: hidden; + .card { + display: inline-block; + vertical-align: top; + overflow-y: visible; + // 31 px to handle to padding between cards + width: calc((100% / 4) - 31px); + } + + .card:not(:first-of-type) { + margin-left: 20px; + } + .card:first-of-type { margin-left: $spacing-width; } @@ -327,27 +335,6 @@ } } -.card-row__scrollhouse { - padding-top: $spacing-vertical * 2/3; - overflow: hidden; - - .card { - display: inline-block; - vertical-align: top; - overflow: visible; - // 31 px to handle to padding between cards - width: calc((100% / 4) - 31px); - } - - .card:not(:first-of-type) { - margin-left: 20px; - } - - .card:last-of-type { - margin-right: 20px; - } -} - .card__success-msg { border-left: 2px solid var(--success-msg-border); color: var(--success-msg-color); diff --git a/src/renderer/scss/component/_tooltip.scss b/src/renderer/scss/component/_tooltip.scss index 504880b09..3e32a7fbe 100644 --- a/src/renderer/scss/component/_tooltip.scss +++ b/src/renderer/scss/component/_tooltip.scss @@ -1,30 +1,97 @@ -@import '../mixin/link.scss'; - .tooltip { position: relative; - padding: 0 $spacing-vertical / 3; - font-size: 12px; + display: inline-block; } -.tooltip__body { +// When there is a label for the tooltip and not just using a button or icon +.tooltip.tooltip--label { + font-size: 12px; + padding-left: $spacing-vertical * 1/3; + + .tooltip__body { + margin-top: 5px; + } +} + +.tooltip.tooltip--icon { + margin-top: 5px; +} + +/* Tooltip text */ +.tooltip .tooltip__body { + background-color: var(--tooltip-bg); + font-family: 'metropolis-medium'; + font-size: 12px; + color: var(--tooltip-color); + border-radius: 8px; position: absolute; z-index: 1; - left: 50%; - margin-left: calc(var(--tooltip-width) * -1 / 2); - white-space: normal; - box-sizing: border-box; - padding: $spacing-vertical / 2; - width: var(--tooltip-width); - color: var(--tooltip-color); - background-color: var(--tooltip-bg); - font-size: calc(var(--font-size) * 7 / 8); - line-height: var(--font-line-height); - box-shadow: var(--box-shadow-layer); - border-radius: var(--card-radius); + width: 200px; + text-align: center; + white-space: pre-wrap; + padding: $spacing-vertical * 1/3; + visibility: hidden; } -.tooltip__link { - font-size: calc(var(--font-size) * 3 / 4); - margin-left: var(--button-padding); - vertical-align: middle; +.tooltip .tooltip__body::after { + content: ' '; + width: 0; + height: 0; + position: absolute; + border-width: 5px; + border-style: solid; +} + +.tooltip.tooltip--top .tooltip__body { + bottom: 100%; + left: 50%; + margin-left: -100px; + + &::after { + top: 100%; + left: 50%; + margin-left: -5px; + border-color: var(--tooltip-bg) transparent transparent transparent; + } +} + +.tooltip.tooltip--right .tooltip__body { + margin-top: -5px; + margin-left: 10px; + + &::after { + top: 17px; + right: 100%; /* To the left of the tooltip */ + margin-top: -5px; + border-color: transparent var(--tooltip-bg) transparent transparent; + } +} + +.tooltip.tooltip--bottom .tooltip__body { + top: 90%; + left: 50%; + margin-left: -100px; + + &::after { + bottom: 100%; + left: 50%; + margin-left: -5px; + border-color: transparent transparent var(--tooltip-bg) transparent; + } +} + +.tooltip.tooltip--left .tooltip__body { + top: -5px; + right: 105%; + + &::after { + top: 17px; + left: 100%; + margin-top: -5px; + border-color: transparent transparent transparent var(--tooltip-bg); + } +} + +.tooltip:hover .tooltip__body { + visibility: visible; } diff --git a/src/renderer/scss/mixin/link.scss b/src/renderer/scss/mixin/link.scss deleted file mode 100644 index df55e49ba..000000000 --- a/src/renderer/scss/mixin/link.scss +++ /dev/null @@ -1,28 +0,0 @@ -@mixin text-link($color: var(--color-primary), $hover-opacity: 0.7) { - .icon { - &:first-child { - padding-right: 5px; - } - &:last-child:not(:only-child) { - padding-left: 5px; - } - } - - &:not(.no-underline) { - text-decoration: underline; - .icon { - text-decoration: none; - } - } - &:hover { - opacity: $hover-opacity; - transition: opacity var(--transition-duration) var(--transition-type); - text-decoration: underline; - .icon { - text-decoration: none; - } - } - - color: $color; - cursor: pointer; -} From 2f4395a9e3582d295cef7a20a738b2642def3c95 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Tue, 22 May 2018 20:29:29 -0400 Subject: [PATCH 14/34] cleanup FileDownloadLink --- .../component/fileDownloadLink/index.js | 2 -- .../component/fileDownloadLink/view.jsx | 27 ++++--------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/src/renderer/component/fileDownloadLink/index.js b/src/renderer/component/fileDownloadLink/index.js index d36f4c896..22f4f0a3f 100644 --- a/src/renderer/component/fileDownloadLink/index.js +++ b/src/renderer/component/fileDownloadLink/index.js @@ -5,7 +5,6 @@ import { makeSelectLoadingForUri, makeSelectCostInfoForUri, } from 'lbry-redux'; -import { doFetchAvailability } from 'redux/actions/availability'; import { doOpenFileInShell } from 'redux/actions/file'; import { doPurchaseUri, doStartDownload } from 'redux/actions/content'; import { doPause } from 'redux/actions/media'; @@ -20,7 +19,6 @@ const select = (state, props) => ({ }); const perform = dispatch => ({ - checkAvailability: uri => dispatch(doFetchAvailability(uri)), openInShell: path => dispatch(doOpenFileInShell(path)), purchaseUri: uri => dispatch(doPurchaseUri(uri)), restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)), diff --git a/src/renderer/component/fileDownloadLink/view.jsx b/src/renderer/component/fileDownloadLink/view.jsx index 0658ae253..8acc17db3 100644 --- a/src/renderer/component/fileDownloadLink/view.jsx +++ b/src/renderer/component/fileDownloadLink/view.jsx @@ -11,31 +11,19 @@ type Props = { total_bytes: number, outpoint: number, download_path: string, + completed: boolean, }, loading: boolean, costInfo: ?{}, restartDownload: (string, number) => void, - checkAvailability: string => void, openInShell: string => void, purchaseUri: string => void, doPause: () => void, }; class FileDownloadLink extends React.PureComponent { - componentWillMount() { - this.checkAvailability(this.props.uri); - } - - componentWillReceiveProps(nextProps: Props) { - this.checkAvailability(nextProps.uri); - this.restartDownload(nextProps); - } - - uri: ?string; - - restartDownload = (props: Props) => { - const { downloading, fileInfo, uri, restartDownload } = props; - + componentWillUpdate() { + const { downloading, fileInfo, uri, restartDownload } = this.props; if ( !downloading && fileInfo && @@ -45,15 +33,10 @@ class FileDownloadLink extends React.PureComponent { ) { restartDownload(uri, fileInfo.outpoint); } - }; - - checkAvailability(uri: string) { - if (!this.uri || uri !== this.uri) { - this.uri = uri; - this.props.checkAvailability(uri); - } } + uri: ?string; + render() { const { fileInfo, From e56c21fd22d73afa4be1922e5404545c005a25f8 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Tue, 22 May 2018 23:48:22 -0400 Subject: [PATCH 15/34] use color prop for icon color instead of relying on type of icon and tooltip cleanup --- src/renderer/component/button/view.jsx | 6 +++-- src/renderer/component/categoryList/view.jsx | 1 - src/renderer/component/common/icon.jsx | 23 ++++++++++++++----- src/renderer/component/common/tooltip.jsx | 9 +++----- src/renderer/component/fileActions/view.jsx | 1 + src/renderer/component/fileCard/view.jsx | 2 +- .../component/fileDownloadLink/view.jsx | 9 +++++++- .../component/subscribeButton/view.jsx | 3 ++- src/renderer/page/file/view.jsx | 4 ++-- src/renderer/scss/component/_file-list.scss | 4 ++++ 10 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/renderer/component/button/view.jsx b/src/renderer/component/button/view.jsx index f622ff28a..8b496ea12 100644 --- a/src/renderer/component/button/view.jsx +++ b/src/renderer/component/button/view.jsx @@ -22,6 +22,7 @@ type Props = { button: ?string, // primary, secondary, alt, link noPadding: ?boolean, // to remove padding and allow circular buttons uppercase: ?boolean, + iconColor: ?string, }; class Button extends React.PureComponent { @@ -48,6 +49,7 @@ class Button extends React.PureComponent { type, noPadding, uppercase, + iconColor, ...otherProps } = this.props; @@ -82,10 +84,10 @@ class Button extends React.PureComponent { const content = ( - {icon && } + {icon && } {label && {label}} {children && children} - {iconRight && } + {iconRight && } ); diff --git a/src/renderer/component/categoryList/view.jsx b/src/renderer/component/categoryList/view.jsx index 56c69f4c9..0afa57940 100644 --- a/src/renderer/component/categoryList/view.jsx +++ b/src/renderer/component/categoryList/view.jsx @@ -223,7 +223,6 @@ class CategoryList extends React.PureComponent { {category && category.match(/^community/i) && ( { @@ -23,8 +24,20 @@ class IconComponent extends React.PureComponent { return null; } }; + + getIconColor = (color: string) => { + switch (color) { + case 'red': + return RED_COLOR; + case 'purple': + return PURPLE_COLOR; + default: + return null; + } + }; + render() { - const { icon, tooltip } = this.props; + const { icon, tooltip, iconColor } = this.props; const Icon = FeatherIcons[icon]; if (!Icon) { @@ -32,10 +45,8 @@ class IconComponent extends React.PureComponent { } let color; - if (icon === icons.TRASH || icon === icons.FEATURED) { - color = RED_COLOR; - } else if (icon === icons.OPEN) { - color = PURPLE_COLOR; + if (iconColor) { + color = this.getIconColor(iconColor); } let size = 14; diff --git a/src/renderer/component/common/tooltip.jsx b/src/renderer/component/common/tooltip.jsx index f1c5ca893..4bd264516 100644 --- a/src/renderer/component/common/tooltip.jsx +++ b/src/renderer/component/common/tooltip.jsx @@ -3,7 +3,7 @@ import * as React from 'react'; import classnames from 'classnames'; type Props = { - body: ?string, + body: string, label?: string, children: ?React.Node, icon: ?boolean, @@ -12,7 +12,7 @@ type Props = { class ToolTip extends React.PureComponent { static defaultProps = { - direction: 'top', + direction: 'bottom', }; render() { @@ -32,10 +32,7 @@ class ToolTip extends React.PureComponent { })} > {tooltipContent} - {body && ( - // body may be undefined for some icons until we add messages for them - {body} - )} + {body}
); } diff --git a/src/renderer/component/fileActions/view.jsx b/src/renderer/component/fileActions/view.jsx index a485cc90e..4ab110fca 100644 --- a/src/renderer/component/fileActions/view.jsx +++ b/src/renderer/component/fileActions/view.jsx @@ -30,6 +30,7 @@ class FileActions extends React.PureComponent {