Redesign fixes (#2164)

* fix: share modal not opening

* fix: add more spacing above snackbar link

* fix: properly close thumbnail error modal

* fix: better align media property icons

* fix: tx filter alignment and prevent hiding filter if no current tx's

* fix: publish markdown on dark mode

* fix: add max-width on container for large screens

* fix: channel pagination aligmnent and spacing

* fix: modal spacing and flow errors

* fix: home page scrolling (now with mouse scrolling)

* fix: hover color in dark mode for outline buttons

* fix: improve file page spacing/layout

* cleanup

* fix: wrap file actions on smaller screens

* fix: comment button spacing
This commit is contained in:
Sean Yesmunt 2019-01-07 18:29:40 -05:00 committed by GitHub
parent 42e3d74805
commit ad90c1f96e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 384 additions and 347 deletions

View file

@ -115,7 +115,7 @@
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-prettier": "^2.6.0",
"eslint-plugin-react": "^7.7.0",
"flow-bin": "^0.69.0",
"flow-bin": "^0.89.0",
"flow-typed": "^2.3.0",
"husky": "^0.14.3",
"i18n-extract": "^0.5.1",

View file

@ -1,12 +1,13 @@
// @flow
import type { Claim } from 'types/claim';
import * as ICONS from 'constants/icons';
import React, { PureComponent } from 'react';
import React, { PureComponent, createRef } from 'react';
import { normalizeURI } from 'lbry-redux';
import ToolTip from 'component/common/tooltip';
import FileCard from 'component/fileCard';
import Button from 'component/button';
import SubscribeButton from 'component/subscribeButton';
import throttle from 'util/throttle';
type Props = {
category: string,
@ -33,12 +34,14 @@ class CategoryList extends PureComponent<Props, State> {
this.state = {
canScrollPrevious: false,
canScrollNext: false,
canScrollNext: true,
};
(this: any).handleScrollNext = this.handleScrollNext.bind(this);
(this: any).handleScrollPrevious = this.handleScrollPrevious.bind(this);
this.rowItems = undefined;
(this: any).handleArrowButtonsOnScroll = this.handleArrowButtonsOnScroll.bind(this);
this.scrollWrapper = createRef();
}
componentDidMount() {
@ -47,54 +50,50 @@ class CategoryList extends PureComponent<Props, State> {
fetchChannel(categoryLink);
}
const cardRow = this.rowItems;
if (cardRow) {
const cards = cardRow.getElementsByTagName('section');
const lastCard = cards[cards.length - 1];
const isCompletelyVisible = this.isCardVisible(lastCard);
if (!isCompletelyVisible) {
// not sure how we can avoid doing this
/* eslint-disable react/no-did-mount-set-state */
this.setState({
canScrollNext: true,
});
/* eslint-enable react/no-did-mount-set-state */
}
const scrollWrapper = this.scrollWrapper.current;
if (scrollWrapper) {
scrollWrapper.addEventListener('scroll', throttle(this.handleArrowButtonsOnScroll, 500));
}
}
rowItems: ?HTMLDivElement;
scrollWrapper: { current: null | HTMLUListElement };
handleArrowButtonsOnScroll() {
// Determine if the arrow buttons should be disabled
const scrollWrapper = this.scrollWrapper.current;
if (scrollWrapper) {
// firstElementChild and lastElementChild will always exist
// $FlowFixMe
const hasHiddenCardToLeft = !this.isCardVisible(scrollWrapper.firstElementChild);
// $FlowFixMe
const hasHiddenCardToRight = !this.isCardVisible(scrollWrapper.lastElementChild);
handleScroll(cardRow: HTMLDivElement, scrollTarget: number) {
const cards = cardRow.getElementsByTagName('section');
const animationCallback = () => {
const firstCard = cards[0];
const lastCard = cards[cards.length - 1];
const firstCardVisible = this.isCardVisible(firstCard);
const lastCardVisible = this.isCardVisible(lastCard);
this.setState({
canScrollNext: !lastCardVisible,
canScrollPrevious: !firstCardVisible,
canScrollPrevious: hasHiddenCardToLeft,
canScrollNext: hasHiddenCardToRight,
});
};
}
}
const currentScrollLeft = cardRow.scrollLeft;
const direction = currentScrollLeft > scrollTarget ? 'left' : 'right';
this.scrollCardsAnimated(cardRow, scrollTarget, direction, animationCallback);
handleScroll(scrollTarget: number) {
const scrollWrapper = this.scrollWrapper.current;
if (scrollWrapper) {
const currentScrollLeft = scrollWrapper.scrollLeft;
const direction = currentScrollLeft > scrollTarget ? 'left' : 'right';
this.scrollCardsAnimated(scrollWrapper, scrollTarget, direction);
}
}
scrollCardsAnimated = (
cardRow: HTMLDivElement,
scrollWrapper: HTMLUListElement,
scrollTarget: number,
direction: string,
callback: () => any
direction: string
) => {
let start;
const step = timestamp => {
if (!start) start = timestamp;
const currentLeftVal = cardRow.scrollLeft;
const currentLeftVal = scrollWrapper.scrollLeft;
let newTarget;
let shouldContinue;
@ -110,12 +109,10 @@ class CategoryList extends PureComponent<Props, State> {
shouldContinue = newTarget > scrollTarget;
}
cardRow.scrollLeft = newTarget; // eslint-disable-line no-param-reassign
scrollWrapper.scrollLeft = newTarget; // eslint-disable-line no-param-reassign
if (shouldContinue) {
window.requestAnimationFrame(step);
} else {
callback();
}
};
@ -123,85 +120,93 @@ class CategoryList extends PureComponent<Props, State> {
};
// check if a card is fully visible horizontally
isCardVisible = (section: HTMLElement) => {
if (!section) {
isCardVisible = (card: HTMLLIElement): boolean => {
if (!card) {
return false;
}
const rect = section.getBoundingClientRect();
const isVisible = rect.left >= 0 && rect.right <= window.innerWidth;
return isVisible;
const scrollWrapper = this.scrollWrapper.current;
if (scrollWrapper) {
const rect = card.getBoundingClientRect();
const isVisible =
scrollWrapper.scrollLeft < card.offsetLeft &&
rect.left >= 0 &&
rect.right <= window.innerWidth;
return isVisible;
}
return false;
};
handleScrollNext() {
const cardRow = this.rowItems;
if (cardRow) {
const cards = cardRow.getElementsByTagName('section');
const scrollWrapper = this.scrollWrapper.current;
if (!scrollWrapper) {
return;
}
// loop over items until we find one that is on the screen
// continue searching until a card isn't fully visible, this is the new target
let firstFullVisibleCard;
let firstSemiVisibleCard;
const cards = scrollWrapper.getElementsByTagName('li');
for (let i = 0; i < cards.length; i += 1) {
const currentCardVisible = this.isCardVisible(cards[i]);
// Loop over items until we find one that is visible
// The card before that (starting from the end) is the new "first" card on the screen
if (firstFullVisibleCard && !currentCardVisible) {
firstSemiVisibleCard = cards[i];
break;
} else if (currentCardVisible) {
[firstFullVisibleCard] = cards;
}
let previousCard: ?HTMLLIElement;
for (let i = cards.length - 1; i > 0; i -= 1) {
const currentCard: HTMLLIElement = cards[i];
const currentCardVisible = this.isCardVisible(currentCard);
if (currentCardVisible && previousCard) {
const scrollTarget = previousCard.offsetLeft;
this.handleScroll(scrollTarget);
break;
}
if (firstFullVisibleCard && firstSemiVisibleCard) {
const scrollTarget = firstSemiVisibleCard.offsetLeft - firstFullVisibleCard.offsetLeft;
this.handleScroll(cardRow, scrollTarget);
}
previousCard = currentCard;
}
}
handleScrollPrevious() {
const cardRow = this.rowItems;
if (cardRow) {
const cards = cardRow.getElementsByTagName('section');
const scrollWrapper = this.scrollWrapper.current;
if (!scrollWrapper) {
return;
}
let hasFoundCard;
let numberOfCardsThatCanFit = 0;
const cards = scrollWrapper.getElementsByTagName('li');
// loop starting at the end until we find a visible card
// then count to find how many cards can fit on the screen
for (let i = cards.length - 1; i >= 0; i -= 1) {
const currentCard = cards[i];
const isCurrentCardVisible = this.isCardVisible(currentCard);
let hasFoundCard;
let numberOfCardsThatCanFit = 0;
if (isCurrentCardVisible) {
if (!hasFoundCard) {
hasFoundCard = true;
}
// loop starting at the end until we find a visible card
// then count to find how many cards can fit on the screen
for (let i = cards.length - 1; i >= 0; i -= 1) {
const currentCard = cards[i];
const isCurrentCardVisible = this.isCardVisible(currentCard);
numberOfCardsThatCanFit += 1;
} else if (hasFoundCard) {
// this card is off the screen to the left
// we know how many cards can fit on a screen
// find the new target and scroll
const firstCardOffsetLeft = cards[0].offsetLeft;
const cardIndexToScrollTo = i + 1 - numberOfCardsThatCanFit;
const newFirstCard = cards[cardIndexToScrollTo];
let scrollTarget;
if (newFirstCard) {
scrollTarget = newFirstCard.offsetLeft;
} else {
// more cards can fit on the screen than are currently hidden
// just scroll to the first card
scrollTarget = cards[0].offsetLeft;
}
scrollTarget -= firstCardOffsetLeft; // to play nice with the margins
this.handleScroll(cardRow, scrollTarget);
break;
if (isCurrentCardVisible) {
if (!hasFoundCard) {
hasFoundCard = true;
}
numberOfCardsThatCanFit += 1;
} else if (hasFoundCard) {
// this card is off the screen to the left
// we know how many cards can fit on a screen
// find the new target and scroll
const firstCardOffsetLeft = cards[0].offsetLeft;
const cardIndexToScrollTo = i + 1 - numberOfCardsThatCanFit;
const newFirstCard = cards[cardIndexToScrollTo];
let scrollTarget;
if (newFirstCard) {
scrollTarget = newFirstCard.offsetLeft;
} else {
// more cards can fit on the screen than are currently hidden
// just scroll to the first card
scrollTarget = cards[0].offsetLeft;
}
scrollTarget -= firstCardOffsetLeft; // to play nice with the margins
this.handleScroll(scrollTarget);
break;
}
}
}
@ -266,12 +271,7 @@ class CategoryList extends PureComponent<Props, State> {
<Button button="link" navigate="/settings" label={__('here')} />.
</p>
) : (
<ul
className="media-scrollhouse"
ref={ref => {
this.rowItems = ref;
}}
>
<ul className="media-scrollhouse" ref={this.scrollWrapper}>
{names &&
names.length &&
names.map(name => (

View file

@ -64,11 +64,7 @@ class CreditAmount extends React.PureComponent<Props> {
}
if (showLBC) {
amountText = (
<span>
{amountText} {__('LBC')}
</span>
);
amountText = `${amountText} ${__('LBC')}`;
}
if (fee) {

View file

@ -81,6 +81,7 @@ class FileCard extends React.PureComponent<Props> {
<div className="media__title media__title--placeholder" />
<div className="media__channel media__channel--placeholder" />
<div className="media__date media__date--placeholder" />
<div className="media__properties media__properties--placeholder" />
</li>
);
}

View file

@ -108,7 +108,7 @@ class FileDetails extends PureComponent<Props> {
<div className="media__info-title">Comments</div>
<div className="card__actions">
<div className="card__actions--center">
<Button
data-id="add-comment"
disabled={hasClickedComment}
@ -119,7 +119,7 @@ class FileDetails extends PureComponent<Props> {
</div>
<br />
{hasClickedComment && (
<p className="main--for-content">
<p className="media__info-text media__info-text--center">
{user
? __('Your support has been added. You will be notified when comments are available.')
: __('Your support has been added. Comments are coming soon.')}

View file

@ -292,9 +292,9 @@ class PublishForm extends React.PureComponent<Props> {
{uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS && (
<div>{__('Please wait for thumbnail to finish uploading')}</div>
)}
{!!editingURI && !isStillEditing && !filePath && (
<div>{__('You need to reselect a file after changing the LBRY URL')}</div>
)}
{!!editingURI &&
!isStillEditing &&
!filePath && <div>{__('You need to reselect a file after changing the LBRY URL')}</div>}
</div>
)
);
@ -351,7 +351,9 @@ class PublishForm extends React.PureComponent<Props> {
<header className="card__header">
<h2 className="card__title">{__('Content')}</h2>
<p className="card__subtitle">
{isStillEditing ? __('Editing a claim') : __('What are you publishing?')}{' '}
{isStillEditing
? __('You are currently editing a claim.')
: __('What are you publishing?')}{' '}
{__('Read our')}{' '}
<Button button="link" label={__('FAQ')} href="https://lbry.io/faq/how-to-publish" />{' '}
{__('to learn more.')}
@ -370,13 +372,14 @@ class PublishForm extends React.PureComponent<Props> {
)}
<div className="card__content">
<FileSelector currentPath={filePath} onFileChosen={this.handleFileChange} />
{!!isStillEditing && name && (
<p className="help">
{__("If you don't choose a file, the file from your existing claim")}
{` "${name}" `}
{__('will be used.')}
</p>
)}
{!!isStillEditing &&
name && (
<p className="help">
{__("If you don't choose a file, the file from your existing claim")}
{` "${name}" `}
{__('will be used.')}
</p>
)}
</div>
</section>
<div className={classnames({ 'card--disabled': formDisabled })}>

View file

@ -12,7 +12,7 @@ type Props = {
formDisabled: boolean,
uploadThumbnailStatus: string,
thumbnailPath: ?string,
openModal: ({ id: string }, {}) => void,
openModal: (id: string, {}) => void,
updatePublishForm: ({}) => void,
resetThumbnailStatus: () => void,
};

View file

@ -9,6 +9,7 @@ type Props = {
linkTarget: ?string,
linkText: ?string,
message: string,
isError: boolean,
},
};
@ -20,6 +21,9 @@ class SnackBar extends React.PureComponent<Props> {
this.hideTimeout = null;
}
hideTimeout: ?TimeoutID;
displayTime: number;
render() {
const { snack, removeSnack } = this.props;
@ -47,9 +51,10 @@ class SnackBar extends React.PureComponent<Props> {
<div>&#9432;</div>
<div>{message}</div>
</div>
{linkText && linkTarget && (
<Button navigate={linkTarget} className="snack-bar__action" label={linkText} />
)}
{linkText &&
linkTarget && (
<Button navigate={linkTarget} className="snack-bar__action" label={linkText} />
)}
</div>
);
}

View file

@ -16,7 +16,7 @@ type Props = {
subscriptions: Array<string>,
doChannelSubscribe: ({ channelName: string, uri: string }) => void,
doChannelUnsubscribe: SubscribtionArgs => void,
doOpenModal: ({ id: string }) => void,
doOpenModal: (id: string) => void,
firstRunCompleted: boolean,
showSnackBarOnSubscribe: boolean,
doToast: ({ message: string }) => void,
@ -46,7 +46,7 @@ export default (props: Props) => {
<Button
iconColor="red"
icon={isSubscribed ? undefined : ICONS.HEART}
button={buttonStyle ? buttonStyle : 'alt'}
button={buttonStyle || 'alt'}
label={subscriptionLabel}
onClick={e => {
e.stopPropagation();

View file

@ -24,7 +24,7 @@ type Props = {
slim?: boolean,
transactions: Array<Transaction>,
rewards: {},
openModal: ({ id: string }, { nout: number, txid: string }) => void,
openModal: (id: string, { nout: number, txid: string }) => void,
myClaims: any,
filterSetting: string,
setTransactionFilter: string => void,
@ -79,43 +79,44 @@ class TransactionList extends React.PureComponent<Props> {
return (
<React.Fragment>
<header className="card__header">
{!transactionList.length && (
<p className="card__content">{emptyMessage || __('No transactions to list.')}</p>
)}
{!slim && !!transactionList.length && (
<div className="card__actions card__actions--between card__actions--top-space">
<FileExporter
data={transactionList}
label={__('Export')}
title={__('Export Transactions')}
filters={['nout']}
defaultPath={__('lbry-transactions-history')}
/>
{!slim &&
!!transactions.length && (
<div className="card__actions card__actions--between card__actions--top-space">
<FileExporter
data={transactionList}
label={__('Export')}
title={__('Export Transactions')}
filters={['nout']}
defaultPath={__('lbry-transactions-history')}
/>
<FormField
type="select"
value={filterSetting || TRANSACTIONS.ALL}
onChange={this.handleFilterChanged}
affixClass="form-field--align-center"
prefix={__('Show')}
postfix={
<Button
button="link"
icon={icons.HELP}
href="https://lbry.io/faq/transaction-types"
title={__('Help')}
/>
}
>
{transactionTypes.map(tt => (
<option key={tt} value={tt}>
{__(`${this.capitalize(tt)}`)}
</option>
))}
</FormField>
</div>
)}
<FormField
type="select"
value={filterSetting || TRANSACTIONS.ALL}
onChange={this.handleFilterChanged}
affixClass="form-field--align-center"
prefix={__('Show')}
postfix={
<Button
button="link"
icon={icons.HELP}
href="https://lbry.io/faq/transaction-types"
title={__('Help')}
/>
}
>
{transactionTypes.map(tt => (
<option key={tt} value={tt}>
{__(`${this.capitalize(tt)}`)}
</option>
))}
</FormField>
</div>
)}
</header>
{!transactionList.length && (
<p className="card__content">{emptyMessage || __('No transactions to list.')}</p>
)}
{!!transactionList.length && (
<div className="card__content">

View file

@ -12,7 +12,7 @@ type DraftTransaction = {
};
type Props = {
openModal: ({ id: string }, { address: string, amount: number }) => void,
openModal: (id: string, { address: string, amount: number }) => void,
balance: number,
};

View file

@ -69,27 +69,24 @@ export class Modal extends React.PureComponent<ModalProps> {
>
<h1 className="card__title">{title}</h1>
<div className="card__content">{children}</div>
<div className="card__content">
{type === 'custom' ? null : ( // custom modals define their own buttons
<div className="card__actions">
{type === 'custom' ? null : ( // custom modals define their own buttons
<div className="card__actions">
<Button
button="primary"
label={confirmButtonLabel}
disabled={confirmButtonDisabled}
onClick={onConfirmed}
/>
{type === 'confirm' ? (
<Button
button="primary"
label={confirmButtonLabel}
disabled={confirmButtonDisabled}
onClick={onConfirmed}
button="link"
label={abortButtonLabel}
disabled={abortButtonDisabled}
onClick={onAborted}
/>
{type === 'confirm' ? (
<Button
button="link"
label={abortButtonLabel}
disabled={abortButtonDisabled}
onClick={onAborted}
/>
) : null}
</div>
)}
</div>
) : null}
</div>
)}
</ReactModal>
);
}

View file

@ -6,13 +6,23 @@ import Button from 'component/button';
type Props = {
closeModal: () => void,
unlockWallet: string => void,
walletEncryptSucceded: boolean,
walletEncryptResult: boolean,
updateWalletStatus: boolean,
encryptWallet: string => void,
updateWalletStatus: () => void,
};
class ModalWalletEncrypt extends React.PureComponent<Props> {
type State = {
newPassword: ?string,
newPasswordConfirm: ?string,
passwordMismatch: boolean,
understandConfirmed: boolean,
understandError: boolean,
submitted: boolean,
failMessage: boolean,
};
class ModalWalletEncrypt extends React.PureComponent<Props, State> {
state = {
newPassword: null,
newPasswordConfirm: null,
@ -23,15 +33,30 @@ class ModalWalletEncrypt extends React.PureComponent<Props> {
failMessage: false,
};
onChangeNewPassword(event) {
componentDidUpdate() {
const { props, state } = this;
if (state.submitted) {
if (props.walletEncryptSucceded === true) {
props.closeModal();
props.updateWalletStatus();
} else if (props.walletEncryptSucceded === false) {
// See https://github.com/lbryio/lbry/issues/1307
// eslint-disable-next-line react/no-did-update-set-state
this.setState({ failMessage: 'Unable to encrypt wallet.' });
}
}
}
onChangeNewPassword(event: SyntheticInputEvent<>) {
this.setState({ newPassword: event.target.value });
}
onChangeNewPasswordConfirm(event) {
onChangeNewPasswordConfirm(event: SyntheticInputEvent<>) {
this.setState({ newPasswordConfirm: event.target.value });
}
onChangeUnderstandConfirm(event) {
onChangeUnderstandConfirm(event: SyntheticInputEvent<>) {
this.setState({
understandConfirmed: /^.?i understand.?$/i.test(event.target.value),
});
@ -60,20 +85,6 @@ class ModalWalletEncrypt extends React.PureComponent<Props> {
this.props.encryptWallet(state.newPassword);
}
componentDidUpdate() {
const { props, state } = this;
if (state.submitted) {
if (props.walletEncryptSucceded === true) {
props.closeModal();
props.updateWalletStatus();
} else if (props.walletEncryptSucceded === false) {
// See https://github.com/lbryio/lbry/issues/1307
this.setState({ failMessage: 'Unable to encrypt wallet.' });
}
}
}
render() {
const { closeModal } = this.props;

View file

@ -23,7 +23,7 @@ type Props = {
channelIsMine: boolean,
fetchClaims: (string, number) => void,
navigate: (string, {}) => void,
openModal: ({ id: string }, { uri: string }) => void,
openModal: (id: string, { uri: string }) => void,
};
class ChannelPage extends React.PureComponent<Props> {
@ -99,10 +99,7 @@ class ChannelPage extends React.PureComponent<Props> {
icon={icons.GLOBE}
label={__('Share Channel')}
onClick={() =>
openModal(
{ id: MODALS.SOCIAL_SHARE },
{ uri, speechShareable: true, isChannel: true }
)
openModal(MODALS.SOCIAL_SHARE, { uri, speechShareable: true, isChannel: true })
}
/>
</div>
@ -111,33 +108,34 @@ class ChannelPage extends React.PureComponent<Props> {
<section className="media-group--list">{contentList}</section>
{(!fetching || (claimsInChannel && claimsInChannel.length)) && totalPages > 1 && (
<FormRow verticallyCentered centered>
<ReactPaginate
pageCount={totalPages}
pageRangeDisplayed={2}
previousLabel=""
nextLabel=""
activeClassName="pagination__item--selected"
pageClassName="pagination__item"
previousClassName="pagination__item pagination__item--previous"
nextClassName="pagination__item pagination__item--next"
breakClassName="pagination__item pagination__item--break"
marginPagesDisplayed={2}
onPageChange={e => this.changePage(e.selected + 1)}
forcePage={currentPage}
initialPage={currentPage}
containerClassName="pagination"
/>
{(!fetching || (claimsInChannel && claimsInChannel.length)) &&
totalPages > 1 && (
<FormRow verticallyCentered centered>
<ReactPaginate
pageCount={totalPages}
pageRangeDisplayed={2}
previousLabel=""
nextLabel=""
activeClassName="pagination__item--selected"
pageClassName="pagination__item"
previousClassName="pagination__item pagination__item--previous"
nextClassName="pagination__item pagination__item--next"
breakClassName="pagination__item pagination__item--break"
marginPagesDisplayed={2}
onPageChange={e => this.changePage(e.selected + 1)}
forcePage={currentPage}
initialPage={currentPage}
containerClassName="pagination"
/>
<FormField
className="paginate-channel"
onKeyUp={e => this.paginate(e, totalPages)}
prefix={__('Go to page:')}
type="text"
/>
</FormRow>
)}
<FormField
className="paginate-channel"
onKeyUp={e => this.paginate(e, totalPages)}
prefix={__('Go to page:')}
type="text"
/>
</FormRow>
)}
{!channelIsMine && <HiddenNsfwClaims className="card__content help" uri={uri} />}
</Page>

View file

@ -216,14 +216,14 @@ class FilePage extends React.Component<Props> {
button="alt"
icon={icons.GIFT}
label={__('Send a tip')}
onClick={() => openModal({ id: MODALS.SEND_TIP }, { uri })}
onClick={() => openModal(MODALS.SEND_TIP, { uri })}
/>
)}
<Button
button="alt"
icon={icons.GLOBE}
label={__('Share')}
onClick={() => openModal({ id: MODALS.SOCIAL_SHARE }, { uri, speechShareable })}
onClick={() => openModal(MODALS.SOCIAL_SHARE, { uri, speechShareable })}
/>
</div>

View file

@ -191,8 +191,8 @@ class HelpPage extends React.PureComponent<Props, State> {
<h2 className="card__title">{__('Report a Bug or Suggest a New Feature')}</h2>
<p className="card__subtitle">
{__('Did you find something wrong? Think LBRY could add something useful and cool?')}
<Button button="link" label={__('Learn more')} href="https://lbry.io/faq/support" />
{__('Did you find something wrong? Think LBRY could add something useful and cool?')}{' '}
<Button button="link" label={__('Learn more')} href="https://lbry.io/faq/support" />.
</p>
</header>
@ -274,14 +274,15 @@ class HelpPage extends React.PureComponent<Props, State> {
{this.state.accessTokenHidden && (
<Button button="link" label={__('View')} onClick={this.showAccessToken} />
)}
{!this.state.accessTokenHidden && accessToken && (
<div>
<p>{accessToken}</p>
<div className="alert-text">
{__('This is equivalent to a password. Do not post or share this.')}
{!this.state.accessTokenHidden &&
accessToken && (
<div>
<p>{accessToken}</p>
<div className="alert-text">
{__('This is equivalent to a password. Do not post or share this.')}
</div>
</div>
</div>
)}
)}
</td>
</tr>
</tbody>

View file

@ -99,7 +99,7 @@ export const doUploadThumbnail = (filePath: string, nsfw: boolean) => (
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: { uploadThumbnailStatus: THUMBNAIL_STATUSES.API_DOWN },
},
dispatch(doOpenModal(MODALS.ERROR, { error }))
doError(MODALS.ERROR, { error })
)
);
@ -119,16 +119,17 @@ export const doUploadThumbnail = (filePath: string, nsfw: boolean) => (
body: data,
})
.then(response => response.json())
.then(json =>
json.success
? dispatch({
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE,
thumbnail: `${json.data.url}${fileExt}`,
},
})
: uploadError(json.message)
.then(
json =>
json.success
? dispatch({
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE,
thumbnail: `${json.data.url}${fileExt}`,
},
})
: uploadError(json.message)
)
.catch(err => uploadError(err.message));
};

View file

@ -21,7 +21,6 @@
@import 'component/form-field';
@import 'component/form-row';
@import 'component/header';
@import 'component/icon';
@import 'component/item-list';
@import 'component/load-screen';
@import 'component/main';

View file

@ -91,7 +91,6 @@
&:hover {
background-color: $lbry-gray-1;
color: $lbry-black;
html[data-theme='dark'] & {
background-color: rgba($lbry-white, 0.1);

View file

@ -60,6 +60,7 @@
}
.card__actions--center {
display: flex;
align-items: center;
justify-content: center;
}

View file

@ -19,13 +19,12 @@
display: flex;
justify-content: center;
position: absolute;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: contain;
&:not(.card__media--nsfw) {
background-color: $lbry-black;
html[data-theme='dark'] & {
background-color: rgba($lbry-white, 0.1);
}
background-color: #000; // solid black to blend nicely when the video starts (if it doesn't take the full width)
}
&:hover {
@ -76,7 +75,6 @@
height: 100%;
align-items: center;
background-color: rgba($lbry-black, 0.5);
display: flex;
flex-direction: column;
justify-content: center;
@ -93,6 +91,7 @@
top: 0;
left: 0;
background-color: #000;
align-items: center;
display: flex;
justify-content: center;

View file

@ -18,7 +18,6 @@
align-items: center;
display: flex;
font-size: 1.25rem;
margin-bottom: var(--spacing-vertical-small);
&.form-field--auto-height {
height: auto;
@ -95,7 +94,7 @@
.form-field__select-wrapper {
position: relative;
width: 20rem;
height: 3rem;
height: 2rem;
&::after {
width: 100%;
@ -104,8 +103,7 @@
left: 0;
// TRIANGLE_DOWN
// background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cpath d='M3 4 L21 4 12 20 3 4 Z' stroke='black' stroke-width='2' fill='black' fill-rule='evenodd' stroke-linejoin='round'/%3E %3C/svg%3E"),
// linear-gradient(to right, transparent 80%, $lbry-gray-1 85%);
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cpath d='M3 4 L21 4 12 20 3 4 Z' stroke='black' stroke-width='2' fill='black' fill-rule='evenodd' stroke-linejoin='round'/%3E %3C/svg%3E");
background-position: 95% center, right top;
background-repeat: no-repeat;
background-size: 0.8rem, 100%;
@ -121,7 +119,7 @@
background-color: $lbry-gray-1;
border-radius: 0;
padding: var(--spacing-vertical-small);
padding: 0 var(--spacing-vertical-small);
-webkit-appearance: none;

View file

@ -1,6 +0,0 @@
// Icons with icons directly following should have a margin-right for proper spacing
// Same for prices on cards
.icon + .icon,
.credit-amount + .icon {
margin-left: var(--spacing-vertical-small);
}

View file

@ -4,6 +4,10 @@
position: relative;
z-index: 1;
&.main--contained {
max-width: 1000px;
}
&:not(.main--no-padding) {
padding: var(--spacing-vertical-large);
}

View file

@ -15,20 +15,28 @@
opacity: 0.5;
}
.CodeMirror-selected {
// background-color: transparent;
}
.CodeMirror-selectedtext {
background-color: $lbry-teal-5 !important;
color: $lbry-white;
}
.cm-spell-error:not(.cm-url):not(.cm-comment):not(.cm-tag):not(.cm-word) {
text-decoration: underline;
text-decoration-color: $lbry-red-3;
text-decoration-style: dotted;
}
html[data-theme='dark'] & {
border-left: 1px solid rgba($lbry-white, 0.2);
border-right: 1px solid rgba($lbry-white, 0.2);
border-bottom: 1px solid rgba($lbry-white, 0.2);
background-color: rgba($lbry-white, 0.1);
color: $lbry-white;
.CodeMirror-selectedtext {
color: $lbry-black;
}
.editor-preview.editor-preview-active {
background-color: $lbry-gray-5;
color: $lbry-black;
}
}
}
// Fix selection
@ -82,6 +90,33 @@
i.separator {
border: none;
}
html[data-theme='dark'] & {
background-color: rgba($lbry-white, 0.2);
a {
color: $lbry-white !important; // We need to use !important to override the CodeMirror styles
&.active {
background-color: rgba($lbry-black, 0.4);
}
&:hover {
color: $lbry-black !important;
}
}
&.disabled-for-preview {
a:not(.no-disable) {
background-color: transparent;
}
// The markdown preview button is highlighted during preview when the other buttons are disabled
a.no-disable {
background-color: rgba($lbry-white, 0.3);
}
}
}
}
.editor-statusbar {

View file

@ -44,7 +44,8 @@
.media--placeholder {
.media__channel,
.media__date,
.media__title {
.media__title,
.media__properties {
min-height: 1rem;
}
@ -154,6 +155,7 @@
.media__actions {
display: flex;
flex-wrap: wrap;
padding-top: var(--spacing-vertical-large);
padding-bottom: var(--spacing-vertical-large);
}
@ -254,11 +256,16 @@
&:not(:last-of-type) {
margin-bottom: var(--spacing-vertical-large);
}
&.media__info-text--center {
text-align: center;
}
}
.media__info-title {
font-size: 1.25rem;
font-weight: 500;
margin-bottom: var(--spacing-vertical-small);
}
// M E D I A
@ -298,10 +305,6 @@
position: relative;
top: 0.2rem;
}
svg {
padding-top: 0.2rem;
}
}
svg {
@ -328,6 +331,10 @@
}
}
.media__properties--placeholder {
@include placeholder;
}
// M E D I A
// S U B T I T L E
@ -518,18 +525,6 @@
rgba(mix($lbry-blue-3, $lbry-black, 70%), 0.8) 100%
);
}
// The featured row needs different top spacing
// depending on screen width
@media (min-width: 601px) {
padding-bottom: var(--spacing-vertical-large);
}
@media (max-width: 600px) {
padding-bottom: var(--spacing-vertical-medium);
}
.media-group__header-title {
background-image: linear-gradient(to right, $lbry-white 80%, transparent 100%);
}
@ -548,8 +543,6 @@
}
&:not(:first-of-type) {
padding-bottom: var(--spacing-vertical-large);
.media-group__header-title {
background-image: linear-gradient(to right, $lbry-black 80%, transparent 100%);
}
@ -643,7 +636,15 @@
.media-scrollhouse {
min-height: 200px;
overflow: hidden;
padding-bottom: var(--spacing-vertical-large);
// Show the scroll bar on hover
// `overlay` doesn't take up any vertical space
overflow-x: hidden;
overflow-y: hidden;
&:hover {
overflow-x: overlay;
}
// The media queries in this block ensure that a row of
// content and its' child elements look good at certain breakpoints
@ -666,35 +667,30 @@
@media (min-width: 601px) {
width: calc((100% / 6) - 2.25rem);
&:not(:first-of-type) {
margin-left: var(--spacing-vertical-large);
}
&:first-of-type {
margin-left: var(--spacing-vertical-large);
}
margin-left: var(--spacing-vertical-large);
&:last-of-type {
margin-right: var(--spacing-vertical-large);
// For some reason margin doesn't work here.
padding-right: var(--spacing-vertical-large);
}
}
@media (max-width: 600px) {
width: calc((100% / 3) - 3rem);
&:not(:first-of-type) {
margin-left: var(--spacing-vertical-medium);
}
&:first-of-type {
margin-left: var(--spacing-vertical-large);
}
&:last-of-type {
margin-right: var(--spacing-vertical-large);
}
}
// May be needed for mobile design
// @media (max-width: 600px) {
// width: calc((100% / 3) - 3rem);
//
// &:not(:first-of-type) {
// margin-left: var(--spacing-vertical-medium);
// }
//
// &:first-of-type {
// margin-left: var(--spacing-vertical-large);
// }
//
// &:last-of-type {
// margin-right: var(--spacing-vertical-large);
// }
// }
}
.media__title {

View file

@ -1,4 +1,7 @@
.pagination {
display: flex;
align-items: center;
+ .form-field {
margin-left: var(--spacing-vertical-medium);
}
@ -9,19 +12,19 @@
height: 3rem;
border-radius: 50%;
display: inline-block;
text-align: center;
&:not(&--selected):not(&--break):not(.disabled):hover {
&:not(.pagination__item--selected):not(.pagination__item--break):not(.disabled):hover {
background-color: $lbry-gray-1;
}
&:not(&--previous):not(&--next) {
&:not(.pagination__item--previous):not(.pagination__item--next) {
font-weight: 600;
line-height: 3rem;
margin: 0 0.5em;
}
&:not(&--break):not(.disabled) {
&:not(.pagination__item--break):not(.disabled) {
cursor: pointer;
}
@ -36,7 +39,6 @@
.pagination__item--previous,
.pagination__item--next {
bottom: -0.4rem;
font-size: 2.5rem;
line-height: 1;
position: relative;

View file

@ -5,7 +5,6 @@
background-color: $lbry-teal-4;
border-radius: 0.5rem;
color: $lbry-white;
max-width: var(--snack-bar-width);
padding: var(--spacing-vertical-small) var(--spacing-vertical-large) var(--spacing-vertical-small)
var(--spacing-vertical-medium);
position: fixed;
@ -19,7 +18,7 @@
.snack-bar__action {
display: inline-block;
margin-bottom: var(--spacing-vertical-small);
margin: var(--spacing-vertical-small) 0;
min-width: min-content;
text-transform: uppercase;

View file

@ -69,12 +69,6 @@ input {
&:not(.input-copyable):not(.wunderbar__input) {
border-bottom: var(--input-border-size) solid $lbry-gray-5;
}
&:not(.input-copyable):not(.wunderbar__input):not(:placeholder-shown):not(:disabled) {
&:hover {
border-color: rgba($lbry-black, 0.8);
}
}
}
.input--price-amount {

View file

@ -19,7 +19,6 @@ $large-breakpoint: 1921px;
--spacing-vertical-large: 2rem;
--video-aspect-ratio: 56.25%; // 9 x 16
--snack-bar-width: 756px;
// Text
--text-max-width: 660px;

View file

@ -105,6 +105,10 @@
version "1.0.3"
resolved "https://registry.yarnpkg.com/@lbry/color/-/color-1.0.3.tgz#ec22b2c48b0e358759528fb3bbe7ba468d4e41ca"
"@lbry/components@^1.5.1":
version "1.6.3"
resolved "https://registry.yarnpkg.com/@lbry/components/-/components-1.6.3.tgz#5187736e8d51d24a4678f972d3c062d880d6d853"
"@mapbox/hast-util-table-cell-style@^0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.1.3.tgz#5b7166ae01297d72216932b245e4b2f0b642dca6"
@ -4074,9 +4078,9 @@ flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
flow-bin@^0.69.0:
version "0.69.0"
resolved "http://registry.npmjs.org/flow-bin/-/flow-bin-0.69.0.tgz#053159a684a6051fcbf0b71a2eb19a9679082da6"
flow-bin@^0.89.0:
version "0.89.0"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.89.0.tgz#6bd29c2af7e0f429797f820662f33749105c32fa"
flow-typed@^2.3.0:
version "2.5.1"