Verified Commit 4cda850f authored by insert's avatar insert

New settings pages.

Co-authored-by: default avatarnizune <[email protected]>
parent daac05ba
Pipeline #268 failed with stage
in 1 minute and 47 seconds
......@@ -18,12 +18,30 @@
.content {
flex: 7;
display: flex;
padding: 80px 40px 40px;
@media screen and (max-width: 900px) {
padding: 20px 12px;
&:not(.shown) {
display: none;
}
}
.primary {
color: var(--body-text);
flex-grow: 1;
.title {
display: none;
@media screen and (min-width: 901px) {
display: block;
font-size: 20px;
font-weight: 600;
margin-bottom: 15px;
}
}
}
}
}
......@@ -47,11 +65,27 @@
flex: 1 1 auto;
}
.close {
.x {
height: 30px;
width: 30px;
margin-right: 10px;
fill: var(--icon); //a different className overwrites className icon, needs fix
}
}
}
.close {
display: none;
@media screen and (min-width: 901px) {
right: 100px;
position: absolute;
display: flex;
cursor: pointer;
justify-content: center;
height: 40px;
width: 40px;
fill: white;
border: 1px solid grey;
border-radius: 50%;
}
}
\ No newline at end of file
import React, { useState, createContext, useContext } from 'react';
import React, { useState, createContext, useContext, CSSProperties } from 'react';
import Helmet from 'react-helmet';
import styles from './Settings.module.scss';
import classNames from 'classnames';
......@@ -7,13 +7,46 @@ import { SettingsSidebar } from './settings/Sidebar';
import { scrollable } from '../components/util/Scrollbar';
import { Icon } from '../components/ui/elements/Icon';
import { AppContext, Page as AppPage } from '../App';
import { RenderPage } from './settings/pages';
export enum Page {
ACCOUNT
ACCOUNT,
APPS,
INTEGRATIONS,
PRO,
BILLING,
VOICE,
APPEARANCE,
ACCESSIBILITY,
STREAMER,
LANGUAGE,
DEVELOPER,
ABOUT,
CHANGELOG,
SUPPORT,
FEEDBACK
};
const PageTitles: { [key in Page]: string } = {
[Page.ACCOUNT]: 'Account'
export const PageTitles: { [key in Page]: string } = {
[Page.ACCOUNT]: 'My Account',
[Page.APPS]: 'Authorized Apps',
[Page.INTEGRATIONS]: 'Integrations',
[Page.PRO]: 'Riot PRO',
[Page.BILLING]: 'Billing',
[Page.VOICE]: 'Voice & Video',
[Page.APPEARANCE]: 'Appearance',
[Page.ACCESSIBILITY]: 'Accessibility',
[Page.STREAMER]: 'Streamer Mode',
[Page.LANGUAGE]: 'Language',
[Page.DEVELOPER]: 'Developer Mode',
[Page.ABOUT]: 'About',
[Page.CHANGELOG]: 'Changelog',
[Page.SUPPORT]: 'Support',
[Page.FEEDBACK]: 'Feedback'
};
export const SettingsContext = createContext<{
......@@ -52,6 +85,12 @@ export function Settings() {
}
}
let doHideTitle: CSSProperties = {
display: (tab === Page.ACCOUNT ||
tab === Page.PRO) ?
'none' : undefined
};
return (
<SettingsContext.Provider value={states}>
<Helmet>
......@@ -59,15 +98,19 @@ export function Settings() {
</Helmet>
<div className={styles.settings}>
<div className={styles.header}>
{ showContent ? <Icon className={styles.close} icon="leftArrowAltRegular" onClick={doClose} />
: <Icon className={styles.close} icon="xRegular" onClick={doClose} /> }
{ showContent ? <Icon className={styles.x} icon="leftArrowAltRegular" onClick={doClose} />
: <Icon className={styles.x} icon="xRegular" onClick={doClose} /> }
<span className={styles.title}>{showContent ? PageTitles[tab] : 'Settings'}</span>
<Icon icon="logoutRegular" onClick={() => alert('no leaving this place')}/>
</div>
<div className={styles.main}>
<SettingsSidebar />
<div className={content}>
yeet yeet yeet
<div className={styles.primary}>
<div className={styles.title} style={doHideTitle}>{PageTitles[tab]}</div>
{RenderPage(tab)}
</div>
<Icon className={styles.close} icon="xRegular" onClick={doClose} />
</div>
</div>
</div>
......
......@@ -6,8 +6,7 @@
padding: 0 10px;
@media screen and (min-width: 901px) {
//padding: 60px 6px 0 20px;
padding: 0 6px 0 20px;
padding: 60px 6px 0 20px;
max-height: 100%;
background: var(--secondary);
}
......@@ -29,8 +28,8 @@
}
.section {
//&:first-child {padding: 100px 0 0 0;}
padding: 20px 0 0 0;
.name {
font-size: 12px;
font-weight: 600;
......
......@@ -5,7 +5,7 @@ import classNames from 'classnames';
import logo from '../../assets/downloads/branding/logo-white-full.svg';
import { Icons, Icon } from '../../components/ui/elements/Icon';
import { SettingsContext, Page } from '../Settings';
import { SettingsContext, Page, PageTitles } from '../Settings';
import { Instance } from '../../internal/Client';
import { scrollable } from '../../components/util/Scrollbar';
import { VERSION } from '../../release';
......@@ -27,19 +27,20 @@ export const SettingsSidebar = memo(() => {
return <span className={classes}>{ props.type }</span>;
}
function Tab(props: { icon: Icons, for?: Page, name?: string, children?: ReactNode[] | ReactNode, beta?: boolean, classes?: any }) {
function Tab(props: { icon: Icons, for?: Page, custom?: boolean, children?: ReactNode[] | ReactNode, beta?: boolean, classes?: any }) {
let classes = classNames(props.classes, {
[styles.tab]: true,
[styles.canHide]: props.for === Page.ACCOUNT
});
let name = typeof props.for === 'undefined' ? undefined : PageTitles[props.for];
return (
<div className={classes} aria-label={props.name} onClick={() => {
<div className={classes} aria-label={name} onClick={() => {
settings.setShown(true);
props.for && settings.setTab(props.for);
typeof props.for !== 'undefined' && settings.setTab(props.for);
}}>
<Icon icon={props.icon} />
{props.name || props.children}
{props.custom ? props.children : name}
{props.beta && <Label type='beta' />}
</div>
);
......@@ -66,32 +67,34 @@ export const SettingsSidebar = memo(() => {
</div>
</div>
<Section title="User Settings">
<Tab icon="idCardSolid" name="My Account" for={Page.ACCOUNT} />
<Tab icon="shieldSolid" name="Authorized Apps" />
<Tab icon="extensionSolid" name="Integrations" beta/>
<Tab icon="idCardSolid" for={Page.ACCOUNT} />
<Tab icon="shieldSolid" for={Page.APPS} />
<Tab icon="extensionSolid" for={Page.INTEGRATIONS} beta/>
</Section>
<Section title="Riot PRO">
<Tab icon="idCardSolid" classes={styles.pro}>
<Tab icon="idCardSolid" classes={styles.pro} for={Page.PRO} custom>
RIOT IMAGE HERE
<Label type='pro' />
</Tab>
<Tab icon="cardSolid" name="Billing" />
<Tab icon="cardSolid" for={Page.BILLING} />
</Section>
<Section title="Client Settings">
<Tab icon="microphoneSolid" name="Voice & Video" />
<Tab icon="brushSolid" name="Appearance" />
<Tab icon="bodyRegular" name="Accessibility" />
<Tab icon="slideshowSolid" name="Streamer Mode" beta/>
<Tab icon="globeRegular" name="Language" />
<Tab icon="wrenchSolid" name="Developer Mode" />
<Tab icon="microphoneSolid" for={Page.VOICE} />
<Tab icon="brushSolid" for={Page.APPEARANCE} />
<Tab icon="bodyRegular" for={Page.ACCESSIBILITY} />
<Tab icon="slideshowSolid" for={Page.STREAMER} beta/>
<Tab icon="globeRegular" for={Page.LANGUAGE} />
<Tab icon="wrenchSolid" for={Page.DEVELOPER} />
</Section>
<Section title="About">
<Tab icon="infoCircleSolid" name="About" />
<Tab icon="fileRegular" name="Changelog" />
<Tab icon="helpCircleSolid" name="Support" />
<Tab icon="megaphoneSolid" name="Feedback" />
<Tab icon="infoCircleSolid" for={Page.ABOUT} />
<Tab icon="fileRegular" for={Page.CHANGELOG} />
<Tab icon="helpCircleSolid" for={Page.SUPPORT} />
<Tab icon="megaphoneSolid" for={Page.FEEDBACK} />
</Section>
<Tab icon="logoutRegular" name="Log Out" classes={styles.logoutButton}/>
<Tab icon="logoutRegular" classes={styles.logoutButton} custom>
Logout
</Tab>
<div className={styles.branding}>
<img src={logo} alt='Riot' draggable={false}/>
<span>Version {VERSION}</span>
......
import React from 'react';
export default function About() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Changelog() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Feedback() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Support() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Accessibility() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Appearance() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Developer() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Language() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Streamer() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Voice() {
return (
<div>
</div>
);
}
\ No newline at end of file
.category {
margin-bottom: 10px;
font-size: 0.875rem;
font-weight: 600;
text-transform: uppercase;
}
.section { margin-bottom: 20px; }
.footer {
padding-top: 8px;
border-top: 1px solid rgba(112, 112, 112, 0.5);
max-width: 500px;
font-size: 0.875rem;
font-weight: 600;
}
.link {
color: #2B8FF3;
text-decoration: none;
&:hover {text-decoration: underline;}
}
\ No newline at end of file
import React from 'react';
import { Page } from '../../Settings';
import Account from './userSettings/Account';
import AuthorizedApps from './userSettings/AuthorizedApps';
import Integrations from './userSettings/Integrations';
import Pro from './riotPRO/Pro';
import Billing from './riotPRO/Billing';
import Appearance from './clientSettings/Appearance';
import Voice from './clientSettings/Voice';
import Accessibility from './clientSettings/Accessibility';
import Streamer from './clientSettings/Streamer';
import Language from './clientSettings/Language';
import Developer from './clientSettings/Developer';
import About from './about/About';
import Changelog from './about/Changelog';
import Support from './about/Support';
import Feedback from './about/Feedback';
export function RenderPage(page: Page) {
switch (page) {
case Page.ACCOUNT: return <Account />
case Page.APPS: return <AuthorizedApps />
case Page.INTEGRATIONS: return <Integrations />
case Page.PRO: return <Pro />
case Page.BILLING: return <Billing />
case Page.VOICE: return <Voice />
case Page.APPEARANCE: return <Appearance />
case Page.ACCESSIBILITY: return <Accessibility />
case Page.STREAMER: return <Streamer />
case Page.LANGUAGE: return <Language />
case Page.DEVELOPER: return <Developer />
case Page.ABOUT: return <About />
case Page.CHANGELOG: return <Changelog />
case Page.SUPPORT: return <Support />
case Page.FEEDBACK: return <Feedback />
}
}
\ No newline at end of file
import React from 'react';
export default function Billing() {
return (
<div>
</div>
);
}
\ No newline at end of file
import React from 'react';
export default function Pro() {
return (
<div>
</div>
);
}
\ No newline at end of file
.account {
display: flex;
align-items: center;
margin-bottom: 40px;
.pfp {
position: relative;
display: flex;
height: 100px;
width: 100px;
background: #434343;
border-radius: 50%;
flex: 0 0 auto;
margin-right: 16px;
cursor: pointer;
background-size: cover;
background-position: center;
}
.edit {
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
position: absolute;
border-radius: 50%;
align-items: center;
justify-content: center;
opacity: 0;
background: rgba(112, 112, 112, .5);
transition: opacity .25s;
z-index: 1;
&:hover {
opacity: 1;
}
&:active {
background: rgba(112, 112, 112, .7);
}
.icon {
height: 30px;
width: 30px;
}
}
.details {
flex: 1 1 auto;
display: flex;
justify-content: center;
flex-direction: column;
.name {
font-size: 32px;
font-weight: 600;
}
.id {
color: gray;
@media screen and (max-width: 900px) {
display: none;
}
span {
svg { fill: gray; }
}
.title {
color: gray;
font-weight: 600;
margin-right: 4px;
@media screen and (max-width: 900px) {
display: block;
font-size: 12px;
}
}
}
}
}
.copy {
user-select: text;
}
.timeline {
.strike {
margin-left: 8px;
padding: 4px 4px 4px 16px;
border-left: 2px solid #707070;
.date {
display: block;
margin-bottom: 4px;
color: #818181;
font-size: 0.875rem;
}
.details {
margin: 14px 0;
}
.expires {
color: #818181;
font-size: 0.875rem;
}
.title {
display: block;
font-weight: bold;
.count {
color: white;
margin-left: 8px;
display: inline-block;
height: 20px;
width: 20px;
font-size: 0.75rem;
background: #D14F4F;
border-radius: 50%;
text-align: center;
}
}
}
}
.button {
box-sizing: border-box;
border: none;
height: 40px;
color: var(--accent-color-text, white);
padding: 10px 14px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 0.875rem;
font-weight: 600;
border: 1px solid var(--accent-color, #7B68EE);
border-radius: 4px;
cursor: pointer;
margin-right: 8px;
background-color: var(--accent-color, #7B68EE);
transition: border, background-color .3s;
&:hover {
/*border: 1px solid var(--accent-color-lighten-10, #{lighten(#7B68EE, 10%)});
background-color: var(--accent-color-lighten-10, #{lighten(#7B68EE, 10%)});*/
}
&:active {
/*border: 1px solid var(--accent-color-darken-10, #{darken(#7B68EE, 10%)});
background-color: var(--accent-color-darken-10, #{darken(#7B68EE, 10%)});*/
}
&.red {
background-color: transparent;
border: 1px solid red;
color: red;
}
}
.mobile {
@media screen and (min-width: 901px) {
display: none;
}
}
.infoTitle {
color: grey;
text-transform: uppercase;
font-weight: 600;
margin-right: 4px;
@media screen and (max-width: 900px) {
color: grey;
font-size: 12px;
}
}
.securityEnabled {
display: flex;
align-items: center;
margin-bottom: 12px;
font-weight: 600;
color: #14B89C;
.lock {
margin-right: 4px;
}
}
import React from 'react';
import main from '../index.module.scss';
import styles from './Account.module.scss';
import { Button } from '../../../../components/ui/elements/Button';
import { Instance } from '../../../../internal/Client';
export default function Account() {
return (
<div className={styles.panel}>
<div className={main.section}>
<div className={styles.account}>
<div className={styles.pfp} style={{ backgroundImage: `url("${Instance.client.user.avatarURL}")` }}>
<div className={styles.edit}>
</div>
</div>
<div className={styles.details}>
<span className={styles.name}>{Instance.client.user.username}</span>
<span className={styles.id}>
<span className={styles.title}>UID</span>
<span className={styles.copy}>{Instance.client.user.id}</span>
</span>
<span className={styles.infoTitle}>E-Mail</span>
<span className={styles.copy}>{Instance.client.user.email}</span>
</div>
<a className={styles.button}>Edit</a>
</div>
<a className={`${styles.button} ${styles.mobile}`}>Edit</a>
</div>
{/*!this.state.options.streamerMode.enabled && ( <div className={`${main.section} ${styles.mobile}`}>
<div className={main.category}>UID
</div>
<span className={styles.copy}>{Instance.client.user.id}</span>
</div> )*/}
<div className={main.section}>
<div className={main.category}>2FA Authentication</div>
<div className={styles.securityEnabled}>
<span>2FA has been enabled on this account.</span>
</div>
<a className={styles.button}>View Backup Codes</a>
<a className={`${styles.button} ${styles.red}`}>Remove 2FA</a>
</div>
<div className={main.section}>
<div className={main.category}>Pending Community Strikes</div>
<div className={styles.timeline}>
<div className={styles.strike}>
<div className={styles.date}>02/07/2019</div>
<div className={styles.title}>Strike<span className={styles.count}>2</span></div>
<div className={styles.details}>You have been issued a warning by a community moderator for playing Fortnite on a public server.</div>
&