mirror of
https://github.com/LBRYFoundation/lbry-desktop.git
synced 2025-08-23 17:47:24 +00:00
Setings Page Side Navigation
Utilizing previous work in d8787cb4
for anchor navigation, navigate to the specific card in the settings page when clicked.
I like this model mainly because in Mobile, users don't need to keep opening the drawer to navigate -- they just need to scroll. This allows us to use the same design for Mobile and App.
# Conflicts:
# ui/page/settings/view.jsx
This commit is contained in:
parent
7695af6a59
commit
e9034a03c2
13 changed files with 240 additions and 30 deletions
|
@ -10,6 +10,7 @@ type Props = {
|
|||
title?: string | Node,
|
||||
subtitle?: string | Node,
|
||||
titleActions?: string | Node,
|
||||
id?: string,
|
||||
body?: string | Node,
|
||||
actions?: string | Node,
|
||||
icon?: string,
|
||||
|
@ -30,6 +31,7 @@ export default function Card(props: Props) {
|
|||
title,
|
||||
subtitle,
|
||||
titleActions,
|
||||
id,
|
||||
body,
|
||||
actions,
|
||||
icon,
|
||||
|
@ -53,6 +55,7 @@ export default function Card(props: Props) {
|
|||
className={classnames(className, 'card', {
|
||||
'card__multi-pane': Boolean(secondPane),
|
||||
})}
|
||||
id={id}
|
||||
onClick={(e) => {
|
||||
if (onClick) {
|
||||
onClick();
|
||||
|
|
|
@ -2318,6 +2318,23 @@ export const icons = {
|
|||
<path d="M.75 19.497a3.75 3.75 0 107.5 0 3.75 3.75 0 10-7.5 0zM.75 8.844a11.328 11.328 0 0114.4 14.4M.75 1.113a18.777 18.777 0 0122.139 22.123" />
|
||||
</g>
|
||||
),
|
||||
[ICONS.APPEARANCE]: buildIcon(
|
||||
<g>
|
||||
<path d="M16.022,15.624c.3,3.856,6.014,1.2,5.562,2.54-2.525,7.481-12.648,5.685-16.966,1.165A10.9,10.9,0,0,1,4.64,4.04C8.868-.188,16.032-.495,19.928,4.018,27.56,12.858,15.758,12.183,16.022,15.624Z" />
|
||||
<path d="M5.670 13.309 A1.520 1.520 0 1 0 8.710 13.309 A1.520 1.520 0 1 0 5.670 13.309 Z" />
|
||||
<path d="M9.430 18.144 A1.520 1.520 0 1 0 12.470 18.144 A1.520 1.520 0 1 0 9.430 18.144 Z" />
|
||||
<path d="M13.066 5.912 A1.520 1.520 0 1 0 16.106 5.912 A1.520 1.520 0 1 0 13.066 5.912 Z" />
|
||||
<path d="M6.620 7.524 A1.520 1.520 0 1 0 9.660 7.524 A1.520 1.520 0 1 0 6.620 7.524 Z" />
|
||||
</g>
|
||||
),
|
||||
[ICONS.CONTENT]: buildIcon(
|
||||
<g>
|
||||
<path d="M15.750 16.500 A1.500 1.500 0 1 0 18.750 16.500 A1.500 1.500 0 1 0 15.750 16.500 Z" />
|
||||
<path d="M18.524,10.7l.442,1.453a.994.994,0,0,0,1.174.681l1.472-.341a1.339,1.339,0,0,1,1.275,2.218l-1.031,1.111a1,1,0,0,0,0,1.362l1.031,1.111a1.339,1.339,0,0,1-1.275,2.218l-1.472-.341a.994.994,0,0,0-1.174.681L18.524,22.3a1.33,1.33,0,0,1-2.548,0l-.442-1.453a.994.994,0,0,0-1.174-.681l-1.472.341a1.339,1.339,0,0,1-1.275-2.218l1.031-1.111a1,1,0,0,0,0-1.362l-1.031-1.111a1.339,1.339,0,0,1,1.275-2.218l1.472.341a.994.994,0,0,0,1.174-.681l.442-1.453A1.33,1.33,0,0,1,18.524,10.7Z" />
|
||||
<path d="M8.25,20.25h-6a1.5,1.5,0,0,1-1.5-1.5V2.25A1.5,1.5,0,0,1,2.25.75H12.879a1.5,1.5,0,0,1,1.06.439l2.872,2.872a1.5,1.5,0,0,1,.439,1.06V6.75" />
|
||||
<path d="M6.241,12.678a.685.685,0,0,1-.991-.613V7.435a.685.685,0,0,1,.991-.613l4.631,2.316a.684.684,0,0,1,0,1.224Z" />
|
||||
</g>
|
||||
),
|
||||
[ICONS.STAR]: buildIcon(
|
||||
<g>
|
||||
<path d="M12.729 1.2l3.346 6.629 6.44.638a.805.805 0 01.5 1.374l-5.3 5.253 1.965 7.138a.813.813 0 01-1.151.935L12 19.934l-6.52 3.229a.813.813 0 01-1.151-.935l1.965-7.138L.99 9.837a.805.805 0 01.5-1.374l6.44-.638L11.271 1.2a.819.819 0 011.458 0z" />
|
||||
|
|
|
@ -23,6 +23,7 @@ type Props = {
|
|||
isUpgradeAvailable: boolean,
|
||||
authPage: boolean,
|
||||
filePage: boolean,
|
||||
settingsPage?: boolean,
|
||||
noHeader: boolean,
|
||||
noFooter: boolean,
|
||||
noSideNavigation: boolean,
|
||||
|
@ -45,6 +46,7 @@ function Page(props: Props) {
|
|||
children,
|
||||
className,
|
||||
filePage = false,
|
||||
settingsPage,
|
||||
authPage = false,
|
||||
fullWidthPage = false,
|
||||
noHeader = false,
|
||||
|
@ -114,6 +116,7 @@ function Page(props: Props) {
|
|||
'main--full-width': fullWidthPage,
|
||||
'main--auth-page': authPage,
|
||||
'main--file-page': filePage,
|
||||
'main--settings-page': settingsPage,
|
||||
'main--markdown': isMarkdown,
|
||||
'main--theater-mode': isOnFilePage && videoTheaterMode && !livestream,
|
||||
'main--livestream': livestream && !chatDisabled,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import { SETTINGS_GRP } from 'constants/settings';
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import Card from 'component/common/card';
|
||||
|
@ -37,6 +38,7 @@ export default function SettingAccount(props: Props) {
|
|||
|
||||
return (
|
||||
<Card
|
||||
id={SETTINGS_GRP.ACCOUNT}
|
||||
title={__('Account')}
|
||||
subtitle=""
|
||||
isBodyList
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @flow
|
||||
import { SETTINGS_GRP } from 'constants/settings';
|
||||
import React from 'react';
|
||||
import { SETTINGS } from 'lbry-redux';
|
||||
import Card from 'component/common/card';
|
||||
|
@ -24,6 +25,7 @@ export default function SettingAppearance(props: Props) {
|
|||
|
||||
return (
|
||||
<Card
|
||||
id={SETTINGS_GRP.APPEARANCE}
|
||||
title={__('Appearance')}
|
||||
subtitle=""
|
||||
isBodyList
|
||||
|
|
|
@ -6,6 +6,7 @@ import { SETTINGS } from 'lbry-redux';
|
|||
import { Lbryio } from 'lbryinc';
|
||||
import { SIMPLE_SITE } from 'config';
|
||||
import * as MODALS from 'constants/modal_types';
|
||||
import { SETTINGS_GRP } from 'constants/settings';
|
||||
import Button from 'component/button';
|
||||
import Card from 'component/common/card';
|
||||
import { FormField, FormFieldPrice } from 'component/common/form';
|
||||
|
@ -52,6 +53,7 @@ export default function SettingContent(props: Props) {
|
|||
|
||||
return (
|
||||
<Card
|
||||
id={SETTINGS_GRP.CONTENT}
|
||||
title={__('Content settings')}
|
||||
subtitle=""
|
||||
isBodyList
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// @flow
|
||||
import { ALERT } from 'constants/icons';
|
||||
import { SETTINGS_GRP } from 'constants/settings';
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import Card from 'component/common/card';
|
||||
|
@ -120,6 +121,7 @@ export default function SettingSystem(props: Props) {
|
|||
|
||||
return (
|
||||
<Card
|
||||
id={SETTINGS_GRP.SYSTEM}
|
||||
title={__('System')}
|
||||
subtitle=""
|
||||
isBodyList
|
||||
|
|
3
ui/component/settingsSideNavigation/index.js
Normal file
3
ui/component/settingsSideNavigation/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import SettingsSideNavigation from './view';
|
||||
|
||||
export default SettingsSideNavigation;
|
134
ui/component/settingsSideNavigation/view.jsx
Normal file
134
ui/component/settingsSideNavigation/view.jsx
Normal file
|
@ -0,0 +1,134 @@
|
|||
// @flow
|
||||
import * as PAGES from 'constants/pages';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import type { Node } from 'react';
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import Button from 'component/button';
|
||||
// @if TARGET='app'
|
||||
import { IS_MAC } from 'component/app/view';
|
||||
// @endif
|
||||
import { useIsMediumScreen } from 'effects/use-screensize';
|
||||
|
||||
type SideNavLink = {
|
||||
title: string,
|
||||
link?: string,
|
||||
route?: string,
|
||||
onClick?: () => any,
|
||||
icon: string,
|
||||
extra?: Node,
|
||||
};
|
||||
|
||||
export default function SettingsSideNavigation() {
|
||||
const sidebarOpen = true;
|
||||
const isMediumScreen = useIsMediumScreen();
|
||||
|
||||
const SIDE_LINKS: Array<SideNavLink> = [
|
||||
{
|
||||
title: 'Appearance',
|
||||
link: `/$/${PAGES.SETTINGS}#appearance`,
|
||||
icon: ICONS.APPEARANCE,
|
||||
},
|
||||
{
|
||||
title: 'Account',
|
||||
link: `/$/${PAGES.SETTINGS}#account`,
|
||||
icon: ICONS.ACCOUNT,
|
||||
},
|
||||
{
|
||||
title: 'Content settings',
|
||||
link: `/$/${PAGES.SETTINGS}#content`,
|
||||
icon: ICONS.CONTENT,
|
||||
},
|
||||
{
|
||||
title: 'System',
|
||||
link: `/$/${PAGES.SETTINGS}#system`,
|
||||
icon: ICONS.SETTINGS,
|
||||
},
|
||||
];
|
||||
|
||||
const isAbsolute = isMediumScreen;
|
||||
const microNavigation = !sidebarOpen || isMediumScreen;
|
||||
|
||||
if (isMediumScreen) {
|
||||
// I think it's ok to hide it for now on medium/small screens given that
|
||||
// we are using a scrolling Settings Page that displays everything. If we
|
||||
// really need this, most likely we can display it as a Tab at the top
|
||||
// of the page.
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('navigation__wrapper', {
|
||||
'navigation__wrapper--micro': microNavigation,
|
||||
'navigation__wrapper--absolute': isAbsolute,
|
||||
})}
|
||||
>
|
||||
<nav
|
||||
aria-label={'Sidebar'}
|
||||
className={classnames('navigation', {
|
||||
'navigation--micro': microNavigation,
|
||||
// @if TARGET='app'
|
||||
'navigation--mac': IS_MAC,
|
||||
// @endif
|
||||
})}
|
||||
>
|
||||
<div>
|
||||
<ul className={classnames('navigation-links', { 'navigation-links--micro': !sidebarOpen })}>
|
||||
{SIDE_LINKS.map((linkProps) => {
|
||||
// $FlowFixMe
|
||||
return (
|
||||
<li key={linkProps.route || linkProps.link}>
|
||||
<Button
|
||||
{...linkProps}
|
||||
label={__(linkProps.title)}
|
||||
title={__(linkProps.title)}
|
||||
// $FlowFixMe
|
||||
navigate={linkProps.route || linkProps.link}
|
||||
icon={linkProps.icon}
|
||||
className={classnames('navigation-link', {})}
|
||||
/>
|
||||
{linkProps.extra && linkProps.extra}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{isMediumScreen && sidebarOpen && (
|
||||
<>
|
||||
<nav
|
||||
className={classnames('navigation--absolute', {
|
||||
// @if TARGET='app'
|
||||
'navigation--mac': IS_MAC,
|
||||
// @endif
|
||||
})}
|
||||
>
|
||||
<div>
|
||||
<ul className="navigation-links--absolute">
|
||||
{SIDE_LINKS.map((linkProps) => {
|
||||
// $FlowFixMe
|
||||
const { link, route, ...passedProps } = linkProps;
|
||||
return (
|
||||
<li key={route || link}>
|
||||
<Button
|
||||
{...passedProps}
|
||||
navigate={route || link}
|
||||
label={__(linkProps.title)}
|
||||
title={__(linkProps.title)}
|
||||
icon={linkProps.icon}
|
||||
className={classnames('navigation-link', {})}
|
||||
/>
|
||||
{linkProps.extra && linkProps.extra}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -163,5 +163,7 @@ export const STACK = 'stack';
|
|||
export const TIME = 'time';
|
||||
export const GLOBE = 'globe';
|
||||
export const RSS = 'rss';
|
||||
export const APPEARANCE = 'Appearance';
|
||||
export const CONTENT = 'Content';
|
||||
export const STAR = 'star';
|
||||
export const MUSIC = 'MusicCategory';
|
||||
|
|
|
@ -26,3 +26,10 @@ export const ENABLE_SYNC = 'enable_sync';
|
|||
export const TO_TRAY_WHEN_CLOSED = 'to_tray_when_closed';
|
||||
export const ENABLE_PUBLISH_PREVIEW = 'enable-publish-preview';
|
||||
export const DESKTOP_WINDOW_ZOOM = 'desktop_window_zoom';
|
||||
|
||||
export const SETTINGS_GRP = {
|
||||
APPEARANCE: 'appearance',
|
||||
ACCOUNT: 'account',
|
||||
CONTENT: 'content',
|
||||
SYSTEM: 'system',
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ import Page from 'component/page';
|
|||
import SettingAccount from 'component/settingAccount';
|
||||
import SettingAppearance from 'component/settingAppearance';
|
||||
import SettingContent from 'component/settingContent';
|
||||
import SettingsSideNavigation from 'component/settingsSideNavigation';
|
||||
import SettingSystem from 'component/settingSystem';
|
||||
import SettingUnauthenticated from 'component/settingUnauthenticated';
|
||||
import Yrbl from 'component/yrbl';
|
||||
|
@ -40,7 +41,16 @@ class SettingsPage extends React.PureComponent<Props> {
|
|||
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
||||
|
||||
return (
|
||||
<Page noFooter noSideNavigation backout={{ title: __('Settings'), backLabel: __('Done') }} className="card-stack">
|
||||
<Page
|
||||
noFooter
|
||||
settingsPage
|
||||
noSideNavigation
|
||||
backout={{ title: __('Settings'), backLabel: __('Done') }}
|
||||
className="card-stack"
|
||||
>
|
||||
<SettingsSideNavigation />
|
||||
|
||||
<div>
|
||||
{!isAuthenticated && IS_WEB && (
|
||||
<>
|
||||
<SettingUnauthenticated />
|
||||
|
@ -51,7 +61,12 @@ class SettingsPage extends React.PureComponent<Props> {
|
|||
subtitle={__('Unlock new buttons that change things.')}
|
||||
actions={
|
||||
<div className="section__actions">
|
||||
<Button button="primary" icon={ICONS.SIGN_UP} label={__('Sign Up')} navigate={`/$/${PAGES.AUTH}`} />
|
||||
<Button
|
||||
button="primary"
|
||||
icon={ICONS.SIGN_UP}
|
||||
label={__('Sign Up')}
|
||||
navigate={`/$/${PAGES.AUTH}`}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
@ -71,6 +86,7 @@ class SettingsPage extends React.PureComponent<Props> {
|
|||
<SettingSystem />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -221,6 +221,23 @@
|
|||
}
|
||||
}
|
||||
|
||||
.main--settings-page {
|
||||
width: 100%;
|
||||
max-width: 70rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: var(--spacing-m);
|
||||
padding: 0 var(--spacing-m);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
|
||||
@media (min-width: $breakpoint-small) {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.main--markdown {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue