Additional UX fixes #1661

Merged
neb-b merged 6 commits from ux-fixes into master 2018-06-25 17:38:12 +02:00
16 changed files with 103 additions and 92 deletions

View file

@ -82,10 +82,10 @@ class App extends React.PureComponent<Props> {
return ( return (
<div id="window" onContextMenu={e => openContextMenu(e)}> <div id="window" onContextMenu={e => openContextMenu(e)}>
<Theme /> <Theme />
<Header />
<main className="page"> <main className="page">
<SideBar /> <SideBar />
<div className="content" id="content"> <div className="content" id="content">
<Header />
<Router /> <Router />
<ModalRouter /> <ModalRouter />
</div> </div>

View file

@ -4,8 +4,10 @@ import * as FeatherIcons from 'react-feather';
import * as icons from 'constants/icons'; import * as icons from 'constants/icons';
import Tooltip from 'component/common/tooltip'; import Tooltip from 'component/common/tooltip';
// It would be nice to standardize this somehow
// These are copied from `scss/vars`, can they both come from the same source?
const RED_COLOR = '#e2495e'; const RED_COLOR = '#e2495e';
const PURPLE_COLOR = '#8165b0'; const GREEN_COLOR = '#44b098';
type Props = { type Props = {
icon: string, icon: string,
@ -29,10 +31,10 @@ class IconComponent extends React.PureComponent<Props> {
switch (color) { switch (color) {
case 'red': case 'red':
return RED_COLOR; return RED_COLOR;
case 'purple': case 'green':
return PURPLE_COLOR; return GREEN_COLOR;
default: default:
return null; return undefined;
} }
}; };

View file

@ -77,7 +77,7 @@ class FileDownloadLink extends React.PureComponent<Props> {
<Button <Button
button="alt" button="alt"
icon={icons.DOWNLOAD} icon={icons.DOWNLOAD}
iconColor="purple" iconColor="green"
onClick={() => { onClick={() => {
purchaseUri(uri); purchaseUri(uri);
}} }}
@ -87,7 +87,7 @@ class FileDownloadLink extends React.PureComponent<Props> {
} else if (fileInfo && fileInfo.download_path) { } else if (fileInfo && fileInfo.download_path) {
return ( return (
<ToolTip onComponent body={__('Open file')}> <ToolTip onComponent body={__('Open file')}>
<Button button="alt" iconColor="purple" icon={icons.LOCAL} onClick={() => openFile()} /> <Button button="alt" iconColor="green" icon={icons.LOCAL} onClick={() => openFile()} />
</ToolTip> </ToolTip>
); );
} }

View file

@ -1,7 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectBalance } from 'lbry-redux'; import { selectBalance, selectIsBackDisabled, selectIsForwardDisabled } from 'lbry-redux';
import { formatCredits } from 'util/formatCredits'; import { formatCredits } from 'util/formatCredits';
import { doNavigate } from 'redux/actions/navigation'; import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app';
import { doDownloadUpgradeRequested } from 'redux/actions/app'; import { doDownloadUpgradeRequested } from 'redux/actions/app';
import Header from './view'; import Header from './view';
@ -11,11 +11,18 @@ const select = state => ({
balance: selectBalance(state), balance: selectBalance(state),
isUpgradeAvailable: selectIsUpgradeAvailable(state), isUpgradeAvailable: selectIsUpgradeAvailable(state),
roundedBalance: formatCredits(selectBalance(state) || 0, 2), roundedBalance: formatCredits(selectBalance(state) || 0, 2),
isBackDisabled: selectIsBackDisabled(state),
isForwardDisabled: selectIsForwardDisabled(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
downloadUpgradeRequested: () => dispatch(doDownloadUpgradeRequested()), downloadUpgradeRequested: () => dispatch(doDownloadUpgradeRequested()),
navigate: path => dispatch(doNavigate(path)), navigate: path => dispatch(doNavigate(path)),
back: () => dispatch(doHistoryBack()),
forward: () => dispatch(doHistoryForward()),
}); });
export default connect(select, perform)(Header); export default connect(
select,
perform
)(Header);

View file

@ -7,10 +7,14 @@ import * as icons from 'constants/icons';
type Props = { type Props = {
autoUpdateDownloaded: boolean, autoUpdateDownloaded: boolean,
balance: string, balance: string,
downloadUpgradeRequested: any => void,
isUpgradeAvailable: boolean, isUpgradeAvailable: boolean,
navigate: any => void,
roundedBalance: string, roundedBalance: string,
isBackDisabled: boolean,
isForwardDisabled: boolean,
back: () => void,
forward: () => void,
downloadUpgradeRequested: any => void,
navigate: any => void,
}; };
const Header = (props: Props) => { const Header = (props: Props) => {
@ -21,6 +25,10 @@ const Header = (props: Props) => {
isUpgradeAvailable, isUpgradeAvailable,
navigate, navigate,
roundedBalance, roundedBalance,
back,
isBackDisabled,
forward,
isForwardDisabled,
} = props; } = props;
const showUpgradeButton = const showUpgradeButton =
@ -28,6 +36,32 @@ const Header = (props: Props) => {
return ( return (
<header className="header"> <header className="header">
<div className="header__navigation">
<Button
noPadding
button="alt"
icon={icons.HOME}
className="btn--home-nav"
description={__('Home')}
onClick={() => navigate('/discover')}
/>
<div className="header__history">
<Button
className="btn--arrow"
icon={icons.ARROW_LEFT}
description={__('Navigate back')}
onClick={back}
disabled={isBackDisabled}
/>
<Button
className="btn--arrow"
icon={icons.ARROW_RIGHT}
description={__('Navigate forward')}
onClick={forward}
disabled={isForwardDisabled}
/>
</div>
</div>
<WunderBar /> <WunderBar />
<div className="header__actions-right"> <div className="header__actions-right">
<Button <Button

View file

@ -1,20 +1,16 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation'; import { selectNavLinks } from 'lbry-redux';
import { selectIsBackDisabled, selectIsForwardDisabled, selectNavLinks } from 'lbry-redux';
import { selectNotifications } from 'redux/selectors/subscriptions'; import { selectNotifications } from 'redux/selectors/subscriptions';
import SideBar from './view'; import SideBar from './view';
const select = state => ({ const select = state => ({
navLinks: selectNavLinks(state), navLinks: selectNavLinks(state),
isBackDisabled: selectIsBackDisabled(state),
isForwardDisabled: selectIsForwardDisabled(state),
notifications: selectNotifications(state), notifications: selectNotifications(state),
}); });
const perform = dispatch => ({ const perform = () => ({});
navigate: path => dispatch(doNavigate(path)),
back: () => dispatch(doHistoryBack()),
forward: () => dispatch(doHistoryForward()),
});
export default connect(select, perform)(SideBar); export default connect(
select,
perform
)(SideBar);

View file

@ -2,7 +2,6 @@
import * as React from 'react'; import * as React from 'react';
import Button from 'component/button'; import Button from 'component/button';
import classnames from 'classnames'; import classnames from 'classnames';
import * as icons from 'constants/icons';
import * as NOTIFICATION_TYPES from 'constants/notification_types'; import * as NOTIFICATION_TYPES from 'constants/notification_types';
type SideBarLink = { type SideBarLink = {
@ -14,11 +13,6 @@ type SideBarLink = {
}; };
type Props = { type Props = {
navigate: any => void,
back: any => void,
forward: any => void,
isBackDisabled: boolean,
isForwardDisabled: boolean,
navLinks: { navLinks: {
primary: Array<SideBarLink>, primary: Array<SideBarLink>,
secondary: Array<SideBarLink>, secondary: Array<SideBarLink>,
@ -29,15 +23,7 @@ type Props = {
}; };
const SideBar = (props: Props) => { const SideBar = (props: Props) => {
const { const { navLinks, notifications } = props;
navigate,
back,
forward,
isBackDisabled,
isForwardDisabled,
navLinks,
notifications,
} = props;
const badges = Object.keys(notifications).reduce( const badges = Object.keys(notifications).reduce(
(acc, cur) => (notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING ? acc : acc + 1), (acc, cur) => (notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING ? acc : acc + 1),
@ -46,33 +32,6 @@ const SideBar = (props: Props) => {
return ( return (
<nav className="nav"> <nav className="nav">
<div className="nav__actions-top">
<Button
noPadding
button="alt"
icon={icons.HOME}
className="btn--home-nav"
description={__('Home')}
onClick={() => navigate('/discover')}
/>
<div className="nav__actions-history">
<Button
className="btn--arrow"
icon={icons.ARROW_LEFT}
description={__('Navigate back')}
onClick={back}
disabled={isBackDisabled}
/>
<Button
className="btn--arrow"
icon={icons.ARROW_RIGHT}
description={__('Navigate forward')}
onClick={forward}
disabled={isForwardDisabled}
/>
</div>
</div>
<div className="nav__links"> <div className="nav__links">
<ul className="nav__primary"> <ul className="nav__primary">
{navLinks.primary.map(({ label, path, active, icon }) => ( {navLinks.primary.map(({ label, path, active, icon }) => (

View file

@ -27,3 +27,4 @@ export const UNLOCK = 'Unlock';
export const CHECK_SIMPLE = 'Check'; export const CHECK_SIMPLE = 'Check';
export const GLOBE = 'Globe'; export const GLOBE = 'Globe';
export const EXTERNAL_LINK = 'ExternalLink'; export const EXTERNAL_LINK = 'ExternalLink';
export const GIFT = 'Gift';

View file

@ -181,7 +181,7 @@ class FilePage extends React.Component<Props> {
<div className="card__channel-info"> <div className="card__channel-info">
<UriIndicator uri={uri} link /> <UriIndicator uri={uri} link />
</div> </div>
<div className="card__actions card__actions--between"> <div className="card__actions card__actions--no-margin card__actions--between">
{(claimIsMine || subscriptionUri || speechSharable) && ( {(claimIsMine || subscriptionUri || speechSharable) && (
<div className="card__actions"> <div className="card__actions">
{claimIsMine ? ( {claimIsMine ? (
@ -200,7 +200,7 @@ class FilePage extends React.Component<Props> {
{!claimIsMine && ( {!claimIsMine && (
<Button <Button
button="alt" button="alt"
icon="Send" icon={icons.GIFT}
label={__('Enjoy this? Send a tip')} label={__('Enjoy this? Send a tip')}
onClick={() => openModal({ id: MODALS.SEND_TIP }, { uri })} onClick={() => openModal({ id: MODALS.SEND_TIP }, { uri })}
/> />

View file

@ -157,14 +157,13 @@ p {
} }
.page { .page {
display: grid; position: absolute;
grid-template-rows: var(--header-height) calc(100vh - var(--header-height)); top: var(--header-height);
grid-template-columns: var(--side-nav-width) auto; left: 0;
grid-template-areas: right: 0;
'nav content' bottom: 0;
'nav content'; display: flex;
background-color: var(--color-bg); background-color: var(--color-bg);
height: 100vh;
@media only screen and (min-width: $medium-breakpoint) { @media only screen and (min-width: $medium-breakpoint) {
grid-template-columns: var(--side-nav-width-m) auto; grid-template-columns: var(--side-nav-width-m) auto;
@ -179,8 +178,8 @@ p {
Page content Page content
*/ */
.content { .content {
grid-area: content; flex: 1;
overflow-y: auto; overflow: auto;
} }
.main { .main {

View file

@ -54,6 +54,7 @@ $large-breakpoint: 1921px;
--box-shadow-layer: transparent; // 0 2px 4px rgba(0,0,0,0.25); --box-shadow-layer: transparent; // 0 2px 4px rgba(0,0,0,0.25);
--box-shadow-button: 0 10px 20px rgba(0, 0, 0, 0.1); --box-shadow-button: 0 10px 20px rgba(0, 0, 0, 0.1);
--box-shadow-wunderbar: 0 10px 20px rgba(0, 0, 0, 0.03); --box-shadow-wunderbar: 0 10px 20px rgba(0, 0, 0, 0.03);
--box-shadow-header: 0px 6px 20px 1px rgba(0, 0, 0, 0.05);
/* Text */ /* Text */
--text-color: var(--color-black); --text-color: var(--color-black);
@ -118,7 +119,7 @@ $large-breakpoint: 1921px;
--header-bg: var(--color-white); --header-bg: var(--color-white);
--header-color: var(--color-text); --header-color: var(--color-text);
--header-active-color: rgba(0, 0, 0, 0.85); --header-active-color: rgba(0, 0, 0, 0.85);
--header-height: 75px; --header-height: 60px;
--header-button-bg: transparent; --header-button-bg: transparent;
--header-button-hover-bg: rgba(100, 100, 100, 0.15); --header-button-hover-bg: rgba(100, 100, 100, 0.15);
--header-primary-color: var(--color-primary); --header-primary-color: var(--color-primary);

View file

@ -195,7 +195,7 @@
} }
.card__content--extra-padding { .card__content--extra-padding {
margin-top: $spacing-vertical; margin-top: $spacing-vertical * 3/2;
} }
.card__subtext-title { .card__subtext-title {

View file

@ -1,17 +1,37 @@
.header { .header {
position: fixed;
kauffj commented 2018-06-25 16:41:06 +02:00 (Migrated from github.com)
Review

Now that the header is fixed, should the address bar stretch to take the remaining space available?

Now that the header is fixed, should the address bar stretch to take the remaining space available?
neb-b commented 2018-06-25 17:28:02 +02:00 (Migrated from github.com)
Review

yes

yes
height: var(--header-height);
width: 100%;
display: flex; display: flex;
z-index: 1; z-index: 1;
justify-content: space-between; justify-content: space-between;
padding: $spacing-width $spacing-width 0 $spacing-width; align-items: center;
padding: 0 $spacing-width;
background-color: var(--color-bg); background-color: var(--color-bg);
box-shadow: var(--box-shadow-header);
}
.header__navigation {
display: flex;
justify-content: space-between;
}
.header__history {
display: flex;
padding: 0 $spacing-width * 1/2;
@media only screen and (min-width: $medium-breakpoint) {
.btn {
kauffj commented 2018-06-25 16:41:37 +02:00 (Migrated from github.com)
Review

Is there a reason we set rules to only screen?

Is there a reason we set rules to only screen?
neb-b commented 2018-06-25 17:30:41 +02:00 (Migrated from github.com)
Review

I guess not since screen will be the only one used.

I guess not since screen will be the only one used.
QuirkyRobots commented 2018-06-25 17:38:25 +02:00 (Migrated from github.com)
Review

Media Types are optional and if not used it defaults to All. Unless targeting a printer or screen reader, there is no need for them.

`Media Types` are **optional** and if **not** used it defaults to `All`. Unless targeting a **printer** or **screen reader**, there is no need for them.
padding: 0 $spacing-width * 1/6;
}
}
} }
.header__actions-right { .header__actions-right {
margin-left: auto; margin-left: auto;
padding-left: $spacing-vertical / 2;
display: flex; display: flex;
.btn { .btn {
margin-left: $spacing-vertical * 1/3; margin-left: $spacing-width * 1/3;
} }
} }

View file

@ -1,5 +1,5 @@
.nav { .nav {
grid-area: nav; width: var(--side-nav-width);
background-color: var(--nav-bg-color); background-color: var(--nav-bg-color);
padding: $spacing-width; padding: $spacing-width;
color: var(--nav-color); color: var(--nav-color);
@ -7,21 +7,11 @@
hr { hr {
width: 24px; width: 24px;
margin: 36px 0; margin: 36px 0;
// width: 40px;
border: solid 1px var(--color-divider); border: solid 1px var(--color-divider);
margin: $spacing-vertical $spacing-vertical * 2/3; margin: $spacing-vertical $spacing-vertical * 2/3;
} }
} }
.nav__actions-top {
display: flex;
justify-content: space-between;
}
.nav__actions-history {
display: flex;
}
// Sidebar links // Sidebar links
.nav__primary { .nav__primary {
padding-top: 80px; padding-top: 80px;

View file

@ -18,7 +18,6 @@
height: var(--btn-height); height: var(--btn-height);
border-radius: var(--btn-radius); border-radius: var(--btn-radius);
width: 100%; width: 100%;
max-width: 700px;
color: var(--search-color); color: var(--search-color);
background-color: var(--search-bg-color); background-color: var(--search-bg-color);
box-shadow: var(--box-shadow-wunderbar); box-shadow: var(--box-shadow-wunderbar);

View file

@ -90,4 +90,7 @@
/* Scrollbar */ /* Scrollbar */
--scrollbar-thumb-bg: rgba(255, 255, 255, 0.20); --scrollbar-thumb-bg: rgba(255, 255, 255, 0.20);
--scrollbar-thumb-hover-bg: #8696AF; --scrollbar-thumb-hover-bg: #8696AF;
/* Shadows */
--box-shadow-header: 0px 6px 20px 1px rgba(0, 0, 0, 0.2);
} }