(Very) experimental dark theme (only localhost) (#3731)

* (Very) experimental dark theme (only localhost)

* Listener for theme changes

* ThemeProps

* Use actual theme with colors

* Page background

* Adjust with theme.bgPage

* Table adjustments

* Some progress (menu & inputs)

* Adjustments in a number of places

* Progress colors

* Modals

* Some calandar stuff

* Toggle

* Updates

* Hack around dropdowns

* Popup menus

* Overlays

* Connecting overlays
This commit is contained in:
Jaco Greeff 2020-10-01 15:50:33 +02:00 committed by GitHub
parent f53c667fc4
commit 59623f419b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 376 additions and 224 deletions

View File

@ -6,50 +6,23 @@ import '@polkadot/apps/initSettings';
import 'semantic-ui-css/semantic.min.css';
import '@polkadot/react-components/i18n';
import React, { Suspense } from 'react';
import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';
import { Api } from '@polkadot/react-api';
import Apps from '@polkadot/apps/Apps';
import WindowDimensions from '@polkadot/apps/WindowDimensions';
import Queue from '@polkadot/react-components/Status/Queue';
import { BlockAuthors, Events } from '@polkadot/react-query';
import settings from '@polkadot/ui-settings';
import Root from '@polkadot/apps/Root';
import { electronMainApi } from './api/global-exported-api';
import { RemoteElectronStore } from './renderer/remote-electron-store';
const rootId = 'root';
const rootElement = document.getElementById(rootId);
const theme = { theme: settings.uiTheme };
const store = new RemoteElectronStore(electronMainApi.accountStore);
if (!rootElement) {
throw new Error(`Unable to find element with id '${rootId}'`);
}
const store = new RemoteElectronStore(electronMainApi.accountStore);
ReactDOM.render(
<Suspense fallback='...'>
<ThemeProvider theme={theme}>
<Queue>
<Api
store={store}
url={settings.apiUrl}
>
<BlockAuthors>
<Events>
<HashRouter>
<WindowDimensions>
<Apps />
</WindowDimensions>
</HashRouter>
</Events>
</BlockAuthors>
</Api>
</Queue>
</ThemeProvider>
</Suspense>,
<Root store={store} />,
rootElement
);

View File

@ -1,10 +1,10 @@
// Copyright 2017-2020 @polkadot/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { BareProps as Props } from '@polkadot/react-components/types';
import { BareProps as Props, ThemeDef, ThemeProps } from '@polkadot/react-components/types';
import React, { useMemo } from 'react';
import styled from 'styled-components';
import React, { useContext, useMemo } from 'react';
import styled, { ThemeContext } from 'styled-components';
import AccountSidebar from '@polkadot/app-accounts/Sidebar';
import { getSystemChainColor } from '@polkadot/apps-config/ui';
import GlobalStyle from '@polkadot/react-components/styles';
@ -19,6 +19,7 @@ import WarmUp from './WarmUp';
export const PORTAL_ID = 'portals';
function Apps ({ className = '' }: Props): React.ReactElement<Props> {
const { theme } = useContext<ThemeDef>(ThemeContext);
const { systemChain, systemName } = useApi();
const uiHighlight = useMemo(
@ -29,7 +30,7 @@ function Apps ({ className = '' }: Props): React.ReactElement<Props> {
return (
<>
<GlobalStyle uiHighlight={uiHighlight} />
<div className={`apps--Wrapper theme--default ${className}`}>
<div className={`apps--Wrapper theme--${theme} ${className}`}>
<Menu />
<AccountSidebar>
<Signer>
@ -44,9 +45,10 @@ function Apps ({ className = '' }: Props): React.ReactElement<Props> {
);
}
export default React.memo(styled(Apps)`
export default React.memo(styled(Apps)(({ theme }: ThemeProps) => `
background: ${theme.bgPage};
box-sizing: border-box;
display: flex;
flex-direction: column;
min-height: 100vh;
`);
`));

View File

@ -1,6 +1,7 @@
// Copyright 2017-2020 @polkadot/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '@polkadot/react-components/types';
import { Group } from './types';
import React, { useCallback } from 'react';
@ -54,7 +55,7 @@ function GroupDisplay ({ apiUrl, children, className = '', index, isSelected, se
);
}
export default React.memo(styled(GroupDisplay)`
export default React.memo(styled(GroupDisplay)(({ theme }: ThemeProps) => `
.groupHeader {
border-radius: 0.25rem;
cursor: pointer;
@ -64,7 +65,7 @@ export default React.memo(styled(GroupDisplay)`
text-transform: uppercase;
&:hover {
background: white;
background: ${theme.bgTable};
}
.ui--Icon {
@ -75,4 +76,4 @@ export default React.memo(styled(GroupDisplay)`
.groupNetworks {
padding: 0.25rem 0 0.5rem 1rem;
}
`);
`));

View File

@ -1,6 +1,7 @@
// Copyright 2017-2020 @polkadot/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '@polkadot/react-components/types';
import { Network } from './types';
import React, { useCallback, useMemo } from 'react';
@ -52,7 +53,7 @@ function NetworkDisplay ({ apiUrl, className = '', setApiUrl, value: { icon, isC
);
}
export default React.memo(styled(NetworkDisplay)`
export default React.memo(styled(NetworkDisplay)(({ theme }: ThemeProps) => `
border-left: 0.25rem solid transparent;
border-radius: 0.25rem;
cursor: pointer;
@ -62,7 +63,7 @@ export default React.memo(styled(NetworkDisplay)`
&.isSelected,
&:hover {
background: #fffefd;
background: ${theme.bgTable};
}
.endpointIcon {
@ -85,4 +86,4 @@ export default React.memo(styled(NetworkDisplay)`
margin-top: -0.125rem;
}
}
`);
`));

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import type { LinkOption } from '@polkadot/apps-config/settings/endpoints';
import { ThemeProps } from '@polkadot/react-components/types';
import { Group } from './types';
import React, { useCallback, useMemo, useState } from 'react';
@ -250,8 +251,8 @@ function Endpoints ({ className = '', offset, onClose }: Props): React.ReactElem
);
}
export default React.memo(styled(Endpoints)`
color: #4e4e4e;
export default React.memo(styled(Endpoints)(({ theme }: ThemeProps) => `
color: ${theme.color};
padding-top: 3.5rem;
.customButton {
@ -269,4 +270,4 @@ export default React.memo(styled(Endpoints)`
.endpointCustomWrapper {
position: relative;
}
`);
`));

View File

@ -1,6 +1,7 @@
// Copyright 2017-2020 @polkadot/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '@polkadot/react-components/types';
import { Group } from './types';
import React from 'react';
@ -28,7 +29,7 @@ function Grouping ({ className = '', name, routes }: Props): React.ReactElement<
return (
<li className={className}>
<div className='groupHdr highlight--color-contrast'>
<div className='groupHdr highlight--color-contrast'>
<span>{name}</span>
<Icon icon='caret-down' />
</div>
@ -44,7 +45,7 @@ function Grouping ({ className = '', name, routes }: Props): React.ReactElement<
);
}
export default React.memo(styled(Grouping)`
export default React.memo(styled(Grouping)(({ theme }: ThemeProps) => `
cursor: pointer;
position: relative;
@ -79,8 +80,8 @@ export default React.memo(styled(Grouping)`
&:hover {
.groupHdr,
.groupMenu li {
background: #fff;
color: #4e4e4e;
background: ${theme.bgMenu};
color: ${theme.color};
}
.groupHdr {
@ -91,8 +92,8 @@ export default React.memo(styled(Grouping)`
display: block;
> li:hover {
background: rgba(255, 255, 255, 0.5);
background: ${theme.bgMenuHover};
}
}
}
`);
`));

View File

@ -3,6 +3,7 @@
import { Route, Routes } from '@polkadot/apps-routing/types';
import { ApiProps } from '@polkadot/react-api/types';
import { ThemeProps } from '@polkadot/react-components/types';
import { AccountId } from '@polkadot/types/interfaces';
import { Group, Groups, ItemRoute } from './types';
@ -158,7 +159,7 @@ function Menu ({ className = '' }: Props): React.ReactElement<Props> {
);
}
export default React.memo(styled(Menu)`
export default React.memo(styled(Menu)(({ theme }: ThemeProps) => `
align-items: center;
display: flex;
justify-content: space-between;
@ -168,12 +169,12 @@ export default React.memo(styled(Menu)`
&.isLoading {
background: #999 !important;
&:before {
filter: grayscale(1);
.menuActive {
background: ${theme.bgPage};
}
.menuActive {
background: #f5f3f1;
&:before {
filter: grayscale(1);
}
.menuItems {
@ -188,10 +189,10 @@ export default React.memo(styled(Menu)`
}
.menuActive {
background: #fff;
background: ${theme.bgTabs};
border-bottom: none;
border-radius: 0.25rem 0.25rem 0 0;
color: #4e4e4e;
color: ${theme.color};
padding: 1rem 1.5rem;
margin: 0 1rem -1px;
z-index: 1;
@ -211,4 +212,4 @@ export default React.memo(styled(Menu)`
display: inline-block;
}
}
`);
`));

View File

@ -0,0 +1,60 @@
// Copyright 2017-2020 @polkadot/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeDef } from '@polkadot/react-components/types';
import { KeyringStore } from '@polkadot/ui-keyring/types';
import React, { Suspense, useEffect, useState } from 'react';
import { ThemeProvider } from 'styled-components';
import { HashRouter } from 'react-router-dom';
import { Api } from '@polkadot/react-api';
import Queue from '@polkadot/react-components/Status/Queue';
import { BlockAuthors, Events } from '@polkadot/react-query';
import settings from '@polkadot/ui-settings';
import Apps from './Apps';
import WindowDimensions from './WindowDimensions';
import { darkTheme, lightTheme } from './themes';
interface Props {
store?: KeyringStore;
}
function createTheme ({ uiTheme }: { uiTheme: string }): ThemeDef {
return uiTheme === 'dark'
? darkTheme
: lightTheme;
}
function Root ({ store }: Props): React.ReactElement<Props> {
const [theme, setTheme] = useState(createTheme(settings));
useEffect((): void => {
settings.on('change', (settings) => setTheme(createTheme(settings)));
}, []);
return (
<Suspense fallback='...'>
<ThemeProvider theme={theme}>
<Queue>
<Api
store={store}
url={settings.apiUrl}
>
<BlockAuthors>
<Events>
<HashRouter>
<WindowDimensions>
<Apps />
</WindowDimensions>
</HashRouter>
</Events>
</BlockAuthors>
</Api>
</Queue>
</ThemeProvider>
</Suspense>
);
}
export default React.memo(Root);

View File

@ -6,43 +6,19 @@ import './initSettings';
import 'semantic-ui-css/semantic.min.css';
import '@polkadot/react-components/i18n';
import React, { Suspense } from 'react';
import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';
import { Api } from '@polkadot/react-api';
import Queue from '@polkadot/react-components/Status/Queue';
import { BlockAuthors, Events } from '@polkadot/react-query';
import settings from '@polkadot/ui-settings';
import Apps from './Apps';
import WindowDimensions from './WindowDimensions';
import Root from './Root';
const rootId = 'root';
const rootElement = document.getElementById(rootId);
const theme = { theme: settings.uiTheme };
if (!rootElement) {
throw new Error(`Unable to find element with id '${rootId}'`);
}
ReactDOM.render(
<Suspense fallback='...'>
<ThemeProvider theme={theme}>
<Queue>
<Api url={settings.apiUrl}>
<BlockAuthors>
<Events>
<HashRouter>
<WindowDimensions>
<Apps />
</WindowDimensions>
</HashRouter>
</Events>
</BlockAuthors>
</Api>
</Queue>
</ThemeProvider>
</Suspense>,
<Root />,
rootElement
);

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '@polkadot/react-components/types';
import React from 'react';
import styled from 'styled-components';
import { IconName } from '@fortawesome/fontawesome-svg-core';
@ -44,8 +46,8 @@ function BaseOverlay ({ children, className = '', icon, type }: Props): React.Re
);
}
export default React.memo(styled(BaseOverlay)`
background: white;
export default React.memo(styled(BaseOverlay)(({ theme }: ThemeProps) => `
background: ${theme.bgMenu};
border: 1px solid transparent;
border-radius: 0.25rem;
border-left-width: 0.25rem;
@ -111,4 +113,4 @@ export default React.memo(styled(BaseOverlay)`
right: 0em;
top: 0.75rem;
}
`);
`));

View File

@ -0,0 +1,40 @@
// Copyright 2017-2020 @polkadot/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeDef } from '@polkadot/react-components/types';
export const darkTheme: ThemeDef = {
bgInput: '#38393f',
bgInverse: 'rgba(64, 64, 64, 0.8)',
bgMenu: '#26272c',
bgMenuHover: 'rgba(255, 255, 255, 0.05)',
bgPage: '#26272c',
bgTable: '#38393f',
bgTabs: '#38393f',
bgToggle: '#58595f',
borderTable: 'transparent',
borderTabs: 'transparent',
color: 'rgba(254, 242, 240, 0.9)',
colorError: 'rgba(255, 0, 0, 0.85)',
colorLabel: 'rgba(254, 242, 240, 0.45)',
colorSummary: 'rgba(254, 242, 240, 0.75)',
theme: 'dark'
};
export const lightTheme: ThemeDef = {
bgInput: '#fff',
bgInverse: 'rgba(254, 242, 240, 0.91)',
bgMenu: '#fff',
bgMenuHover: 'rgba(255, 255, 255, 0.5)',
bgPage: '#f5f3f1',
bgTable: '#fff',
bgTabs: '#fff',
bgToggle: '#e4e5e6',
borderTable: '#eeecea',
borderTabs: '#eeecea',
color: '#4e4e4e',
colorError: 'rgba(139, 0, 0)',
colorLabel: 'rgba(78, 78, 78, 0.66)',
colorSummary: 'rgba(0, 0, 0, 0.6)',
theme: 'light'
};

View File

@ -4,13 +4,14 @@
import { SubmittableExtrinsic } from '@polkadot/api/types';
import { DeriveBalancesAll, DeriveDemocracyLock } from '@polkadot/api-derive/types';
import { ActionStatus } from '@polkadot/react-components/Status/types';
import { ThemeDef } from '@polkadot/react-components/types';
import { ProxyDefinition, RecoveryConfig } from '@polkadot/types/interfaces';
import { KeyringAddress } from '@polkadot/ui-keyring/types';
import { Delegation } from '../types';
import BN from 'bn.js';
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
import styled, { ThemeContext } from 'styled-components';
import { ApiPromise } from '@polkadot/api';
import { getLedger } from '@polkadot/react-api';
import { AddressInfo, AddressMini, AddressSmall, Badge, Button, ChainLock, CryptoType, Forget, Icon, IdentityIcon, LinkExternal, Menu, Popup, StatusContext, Tags } from '@polkadot/react-components';
@ -78,6 +79,7 @@ const transformRecovery = {
function Account ({ account: { address, meta }, className = '', delegation, filter, isFavorite, proxy, setBalance, toggleFavorite }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { theme } = useContext<ThemeDef>(ThemeContext);
const { queueExtrinsic } = useContext(StatusContext);
const api = useApi();
const bestNumber = useCall<BN>(api.api.derive.chain.bestNumber);
@ -416,7 +418,7 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
/>
)}
<Popup
className='theme--default'
className={`theme--${theme}`}
isOpen={isSettingsOpen}
onClose={toggleSettings}
trigger={

View File

@ -4,9 +4,10 @@
import { DeriveAccountInfo, DeriveBalancesAll } from '@polkadot/api-derive/types';
import { KeyringAddress } from '@polkadot/ui-keyring/types';
import { ActionStatus } from '@polkadot/react-components/Status/types';
import { ThemeDef } from '@polkadot/react-components/types';
import React, { useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
import React, { useCallback, useContext, useEffect, useState } from 'react';
import styled, { ThemeContext } from 'styled-components';
import Transfer from '@polkadot/app-accounts/modals/Transfer';
import { AddressSmall, AddressInfo, Button, ChainLock, Icon, LinkExternal, Forget, Menu, Popup, Tags } from '@polkadot/react-components';
import { useApi, useCall } from '@polkadot/react-hooks';
@ -29,6 +30,7 @@ const isEditable = true;
function Address ({ address, className = '', filter, isFavorite, toggleFavorite }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { theme } = useContext<ThemeDef>(ThemeContext);
const api = useApi();
const info = useCall<DeriveAccountInfo>(api.api.derive.accounts.info, [address]);
const balancesAll = useCall<DeriveBalancesAll>(api.api.derive.balances.all, [address]);
@ -203,7 +205,7 @@ function Address ({ address, className = '', filter, isFavorite, toggleFavorite
/>
)}
<Popup
className='theme--default'
className={`theme--${theme}`}
isOpen={isSettingPopupOpen}
onClose={_toggleSettingPopup}
trigger={

View File

@ -1,6 +1,7 @@
// Copyright 2017-2020 @polkadot/app-calendar authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '@polkadot/react-components/types';
import { DateState } from './types';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
@ -138,15 +139,15 @@ function CalendarApp ({ basePath, className }: Props): React.ReactElement<Props>
);
}
export default React.memo(styled(CalendarApp)`
export default React.memo(styled(CalendarApp)(({ theme }: ThemeProps) => `
.calendarFlex {
align-items: flex-start;
display: flex;
flex-wrap: nowrap;
> div {
background-color: #fff;
border: 1px solid #eeecea;
background-color: ${theme.bgTable};
border: 1px solid ${theme.borderTable};
border-radius: 0.25rem;
&+div {
@ -169,4 +170,4 @@ export default React.memo(styled(CalendarApp)`
}
}
}
`);
`));

View File

@ -1,6 +1,7 @@
// Copyright 2017-2020 @polkadot/app-claims authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '@polkadot/react-components/types';
import { StatementKind } from '@polkadot/types/interfaces';
import React from 'react';
@ -56,7 +57,7 @@ function Statement ({ className, kind, systemChain }: Props): React.ReactElement
);
}
export default React.memo(styled(Statement)`
export default React.memo(styled(Statement)(({ theme }: ThemeProps) => `
.statement{
border: 1px solid #c2c2c2;
background: #f2f2f2;
@ -67,7 +68,7 @@ export default React.memo(styled(Statement)`
white-space: normal;
p {
color: #4e4e4e !important;
color: ${theme.color} !important;
}
iframe {
@ -80,4 +81,4 @@ export default React.memo(styled(Statement)`
.statementUrl{
margin-left: 0.3rem
}
`);
`));

View File

@ -17,12 +17,17 @@ interface Props {
}
const ledgerConnOptions = uiSettings.availableLedgerConn;
const isLocalDev = window.location.host === 'localhost:3000';
function General ({ className = '' }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
// tri-state: null = nothing changed, false = no reload, true = reload required
const [changed, setChanged] = useState<boolean | null>(null);
const [settings, setSettings] = useState(uiSettings.get());
const [settings, setSettings] = useState((): SettingsStruct => {
const settings = uiSettings.get();
return { ...settings, uiTheme: settings.uiTheme === 'dark' ? 'dark' : 'light' };
});
const iconOptions = useMemo(
() => uiSettings.availableIcons
@ -36,6 +41,14 @@ function General ({ className = '' }: Props): React.ReactElement<Props> {
[t]
);
const themeOptions = useMemo(
() => [
{ text: t('Light theme (default)'), value: 'light' },
{ text: t('Dark theme (experimental, work-in-progress)'), value: 'dark' }
],
[t]
);
const translateLanguages = useMemo(
() => createLanguages(t),
[t]
@ -54,7 +67,7 @@ function General ({ className = '' }: Props): React.ReactElement<Props> {
}, [settings]);
const _handleChange = useCallback(
(key: keyof SettingsStruct) => <T extends string | number>(value: T): void =>
(key: keyof SettingsStruct) => <T extends string | number>(value: T) =>
setSettings((settings) => ({ ...settings, [key]: value })),
[]
);
@ -72,7 +85,7 @@ function General ({ className = '' }: Props): React.ReactElement<Props> {
[settings]
);
const { i18nLang, icon, ledgerConn, prefix } = settings;
const { i18nLang, icon, ledgerConn, prefix, uiTheme } = settings;
return (
<div className={className}>
@ -105,6 +118,16 @@ function General ({ className = '' }: Props): React.ReactElement<Props> {
/>
</div>
)}
{isLocalDev && (
<div className='ui--row'>
<Dropdown
defaultValue={uiTheme}
label={t<string>('default interface theme')}
onChange={_handleChange('uiTheme')}
options={themeOptions}
/>
</div>
)}
<div className='ui--row'>
<Dropdown
defaultValue={i18nLang}

View File

@ -79,7 +79,7 @@ export function save (settings: SettingsStruct): void {
export function saveAndReload (settings: SettingsStruct): void {
save(settings);
// HACK This is terrible, but since the API needs to re-connect, but since
// HACK This is terrible, but since the API needs to re-connect and
// the API does not yet handle re-connections properly, it is what it is
window.location.reload();
}

View File

@ -351,10 +351,4 @@ export default React.memo(styled(Account)`
margin-right: 0.25rem;
vertical-align: inherit;
}
.ui--Expander.stakeOver {
.ui--Expander-summary {
color: darkred;
}
}
`);

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import { DeriveStakingOverview } from '@polkadot/api-derive/types';
import { AppProps as Props } from '@polkadot/react-components/types';
import { AppProps as Props, ThemeProps } from '@polkadot/react-components/types';
import { ElectionStatus } from '@polkadot/types/interfaces';
import React, { useMemo } from 'react';
@ -175,7 +175,7 @@ function StakingApp ({ basePath, className = '' }: Props): React.ReactElement<Pr
);
}
export default React.memo(styled(StakingApp)`
export default React.memo(styled(StakingApp)(({ theme }: ThemeProps) => `
.staking--hidden {
display: none;
}
@ -204,7 +204,7 @@ export default React.memo(styled(StakingApp)`
.ui--Expander.stakeOver {
.ui--Expander-summary {
color: darkred;
color: ${theme.colorError};
}
}
`);
`));

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import { InjectedExtension } from '@polkadot/extension-inject/types';
import { KeyringStore } from '@polkadot/ui-keyring/types';
import { ChainProperties, ChainType } from '@polkadot/types/interfaces';
import { ApiProps, ApiState } from './types';
@ -16,7 +17,6 @@ import { WsProvider } from '@polkadot/rpc-provider';
import { StatusContext } from '@polkadot/react-components/Status';
import { TokenUnit } from '@polkadot/react-components/InputNumber';
import keyring from '@polkadot/ui-keyring';
import { KeyringStore } from '@polkadot/ui-keyring/types';
import uiSettings from '@polkadot/ui-settings';
import ApiSigner from '@polkadot/react-signer/signers/ApiSigner';

View File

@ -1,6 +1,7 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '../types';
import { ButtonProps } from './types';
import React, { useCallback } from 'react';
@ -36,7 +37,7 @@ function Button ({ children, className = '', icon, isBasic, isBusy, isCircular,
const ICON_PADDING = 0.5;
export default React.memo(styled(Button)`
export default React.memo(styled(Button)(({ theme }: ThemeProps) => `
background: transparent;
border: none;
color: inherit;
@ -73,7 +74,7 @@ export default React.memo(styled(Button)`
}
&.isBasic {
background: #fff;
background: ${theme.bgTable};
}
&.isCircular {
@ -131,4 +132,4 @@ export default React.memo(styled(Button)`
&.isDisabled {
color: #bcbbba;
}
`);
`));

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from './types';
import BN from 'bn.js';
import React from 'react';
import styled from 'styled-components';
@ -91,12 +93,12 @@ function CardSummary ({ children, className = '', help, label, progress }: Props
);
}
export default React.memo(styled(CardSummary)`
export default React.memo(styled(CardSummary)(({ theme }: ThemeProps) => `
align-items: center;
background: transparent !important;
border: none !important;
box-shadow: none !important;
color: rgba(0, 0, 0, 0.6);
color: ${theme.colorSummary};
display: flex;
flex: 0 1 auto;
flex-flow: row wrap;
@ -152,4 +154,4 @@ export default React.memo(styled(CardSummary)`
font-size: 1.4rem;
}
}
`);
`));

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from './types';
import React from 'react';
import ReactMd from 'react-markdown';
import styled from 'styled-components';
@ -17,7 +19,7 @@ function HelpOverlay ({ className = '', md }: Props): React.ReactElement<Props>
const [isVisible, toggleVisible] = useToggle();
return (
<div className={className}>
<div className={`ui--HelpOverlay ${className}`}>
<div className='help-button'>
<Icon
icon='question-circle'
@ -41,8 +43,9 @@ function HelpOverlay ({ className = '', md }: Props): React.ReactElement<Props>
);
}
export default React.memo(styled(HelpOverlay)`
export default React.memo(styled(HelpOverlay)(({ theme }: ThemeProps) => `
.help-button {
color: ${theme.color};
cursor: pointer;
font-size: 2rem;
padding: 1rem 1.5rem 0 0;
@ -79,4 +82,4 @@ export default React.memo(styled(HelpOverlay)`
right: 0;
}
}
`);
`));

View File

@ -1,9 +1,11 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeDef } from '@polkadot/react-components/types';
import { ActionsProps, ColumnProps, ModalProps } from './types';
import React from 'react';
import React, { useContext } from 'react';
import { ThemeContext } from 'styled-components';
import SUIModal from 'semantic-ui-react/dist/commonjs/modules/Modal/Modal';
import Actions from './Actions';
@ -20,12 +22,13 @@ type ModalType = React.FC<ModalProps> & {
};
function ModalBase (props: ModalProps): React.ReactElement<ModalProps> {
const { theme } = useContext<ThemeDef>(ThemeContext);
const { children, className = '', header, open = true } = props;
return (
<SUIModal
{...props}
className={`theme--default ui--Modal ${className}`}
className={`theme--${theme} ui--Modal ${className}`}
header={undefined}
open={open}
>
@ -47,21 +50,3 @@ Modal.Header = SUIModal.Header;
Modal.Description = SUIModal.Description;
export default Modal;
// rgba(0, 0, 0, 0.5);
// @media only screen and (min-width: 1200px)
// .ui.large.modal {
// width: 1080px;
// margin: 0;
// }
// @media only screen and (min-width: 992px)
// .ui.large.modal {
// width: 1020px;
// margin: 0;
// }
// @media only screen and (min-width: 768px)
// .ui.large.modal {
// width: 88%;
// margin: 0;
// }

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from './types';
import BN from 'bn.js';
import React from 'react';
import styled from 'styled-components';
@ -69,7 +71,7 @@ function Progress ({ className = '', isDisabled, size = 'normal', total, value }
);
}
export default React.memo(styled(Progress)`
export default React.memo(styled(Progress)(({ theme }: ThemeProps) => `
border-radius: 100%;
clip-path: circle(50%);
height: 4.5rem;
@ -125,9 +127,10 @@ export default React.memo(styled(Progress)`
.inner {
align-items: center;
background: rgba(245, 243, 241, 0.91);
background: ${theme.bgInverse};
border-radius: 100%;
bottom: 0.375rem;
color: ${theme.colorSummary};
display: flex;
justify-content: center;
left: 0.375rem;
@ -157,4 +160,4 @@ export default React.memo(styled(Progress)`
font-size: 0.625rem;
}
}
`);
`));

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/app-accounts authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from './types';
import React from 'react';
import styled from 'styled-components';
@ -32,8 +34,8 @@ function Sidebar ({ button, children, className = '', onClose }: Props): React.R
);
}
export default React.memo(styled(Sidebar)(({ offset = 0, position }: Props) => `
background: #f5f3f1;
export default React.memo(styled(Sidebar)(({ offset = 0, position, theme }: Props & ThemeProps) => `
background: ${theme.bgPage};
bottom: 0;
box-shadow: ${position === 'right' ? '-6px' : '6px'} 0px 20px 0px rgba(0, 0, 0, 0.3);
margin-left: -0.125rem;

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '../types';
import React from 'react';
import styled from 'styled-components';
import { isString } from '@polkadot/util';
@ -28,7 +30,7 @@ function Body ({ children, className = '', empty, emptySpinner }: Props): React.
);
}
export default React.memo(styled(Body)`
export default React.memo(styled(Body)(({ theme }: ThemeProps) => `
position: relative;
td {
@ -37,11 +39,11 @@ export default React.memo(styled(Body)`
vertical-align: middle;
&:first-child {
border-left: 1px solid #eeecea;
border-left: 1px solid ${theme.borderTable};
}
&:last-child {
border-right: 1px solid #eeecea;
border-right: 1px solid ${theme.borderTable};
}
label {
@ -158,7 +160,7 @@ export default React.memo(styled(Body)`
// }
&:nth-child(odd) {
background: white;
background: ${theme.bgTable};
}
&:first-child {
@ -173,7 +175,7 @@ export default React.memo(styled(Body)`
&:last-child {
td {
border-bottom: 1px solid #eeecea;
border-bottom: 1px solid ${theme.borderTable};
&:first-child {
border-bottom-left-radius: 0.25rem;
@ -203,4 +205,4 @@ export default React.memo(styled(Body)`
background-color: #eee !important;
}
}
`);
`));

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '../types';
import React from 'react';
import styled from 'styled-components';
@ -22,9 +24,9 @@ function Foot ({ className = '', footer, isEmpty }: Props): React.ReactElement<P
);
}
export default React.memo(styled(Foot)`
export default React.memo(styled(Foot)(({ theme }: ThemeProps) => `
td {
color: rgba(78, 78, 78, .66);
color: rgba(${theme.theme === 'dark' ? '254, 240, 240' : '78, 78, 78'}, 0.66);
font-family: sans-serif;
font-weight: 100;
padding: 0.75rem 1rem 0.25rem;
@ -34,6 +36,6 @@ export default React.memo(styled(Foot)`
}
tr {
background: #f5f3f1;
background: ${theme.bgPage};
}
`);
`));

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '../types';
import React from 'react';
import styled from 'styled-components';
@ -46,7 +48,7 @@ function Head ({ className = '', filter, header, isEmpty }: Props): React.ReactE
);
}
export default React.memo(styled(Head)`
export default React.memo(styled(Head)(({ theme }: ThemeProps) => `
position: relative;
z-index: 1;
@ -63,11 +65,11 @@ export default React.memo(styled(Head)`
}
&:first-child {
border-left: 1px solid #eeecea;
border-left: 1px solid ${theme.borderTable};
}
&:last-child {
border-right: 1px solid #eeecea;
border-right: 1px solid ${theme.borderTable};
}
&.address {
@ -98,18 +100,12 @@ export default React.memo(styled(Head)`
}
tr {
background: white;
background: ${theme.bgTable};
text-transform: lowercase;
&:first-child {
th {
border-top: 1px solid #eeecea;
}
}
&:not(.filter) {
th {
color: rgba(78, 78, 78, 0.66);
border-top: 1px solid ${theme.borderTable};
}
}
@ -126,5 +122,11 @@ export default React.memo(styled(Head)`
padding: 0;
}
}
&:not(.filter) {
th {
color: rgba(${theme.theme === 'dark' ? '254, 240, 240' : '78, 78, 78'}, 0.66);
}
}
}
`);
`));

View File

@ -1,6 +1,7 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '../types';
import { TabItem } from './types';
import React from 'react';
@ -31,7 +32,7 @@ function Tab ({ basePath, className = '', count, hasParams, index, isExact, isRo
return (
<NavLink
activeClassName='tabLinkActive'
className={`ui--Tabs-Tab ${className}`}
className={`ui--Tab ${className}`}
exact={tabIsExact}
strict={tabIsExact}
to={to}
@ -53,9 +54,9 @@ function Tab ({ basePath, className = '', count, hasParams, index, isExact, isRo
);
}
export default React.memo(styled(Tab)`
export default React.memo(styled(Tab)(({ theme }: ThemeProps) => `
border-bottom: 2px solid transparent;
color: #4e4e4e !important;
color: ${theme.color} !important;
margin-bottom: -3px;
padding: 0.5rem 1.5rem 0.75rem;
@ -64,7 +65,7 @@ export default React.memo(styled(Tab)`
}
&:hover {
color: inherit !important;
filter: highlight(120%);
&:not(.tabLinkActive) {
border-bottom-color: #e6e6e6;
@ -78,4 +79,4 @@ export default React.memo(styled(Tab)`
.tabIcon {
margin-left: 0.75rem;
}
`);
`));

View File

@ -1,6 +1,7 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '../types';
import { TabItem } from './types';
import React, { useEffect } from 'react';
@ -57,10 +58,10 @@ function Tabs ({ basePath, className = '', hidden, isSequence, items }: Props):
);
}
export default React.memo(styled(Tabs)`
export default React.memo(styled(Tabs)(({ theme }: ThemeProps) => `
align-items: flex-end;
background: #fff;
border-bottom: 1px solid #eeecea;
background: ${theme.bgTabs};
border-bottom: 1px solid ${theme.borderTabs};
display: flex;
margin: 0 -1.5rem;
padding: 1.5rem 1.5rem 0;
@ -71,4 +72,4 @@ export default React.memo(styled(Tabs)`
display: none;
width: 0px;
}
`);
`));

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from './types';
import React, { useCallback } from 'react';
import styled from 'styled-components';
@ -41,9 +43,8 @@ function Toggle ({ className = '', isDisabled, isOverlay, isRadio, label, onChan
);
}
export default React.memo(styled(Toggle)`
export default React.memo(styled(Toggle)(({ theme }: ThemeProps) => `
> label {
color: rgba(78, 78, 78, 0.75);
display: inline-block;
margin: 0 0.5rem;
}
@ -54,7 +55,7 @@ export default React.memo(styled(Toggle)`
}
.ui--Toggle-Slider {
background: #e4e5e6;
background: ${theme.bgToggle};
border-radius: 1.5rem;
display: inline-block;
height: 1.5rem;
@ -62,8 +63,8 @@ export default React.memo(styled(Toggle)`
width: 3rem;
&::before {
background: white;
border: 0.125rem solid #e4e5e6;
background: ${theme.bgTable};
border: 0.125rem solid ${theme.bgToggle};
border-radius: 50%;
content: "";
height: 1.5rem;
@ -107,4 +108,4 @@ export default React.memo(styled(Toggle)`
position: absolute;
right: 3.5rem;
}
`);
`));

View File

@ -1,11 +1,13 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '../types';
import { css } from 'styled-components';
export default css`
.ui--output {
background: #fefefe;
background: ${({ theme }: ThemeProps) => theme.bgInput};
border-radius: 4px;
border: 1px dashed #eee;
box-sizing: border-box;

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '../types';
import { createGlobalStyle } from 'styled-components';
import cssComponents from './components';
@ -20,8 +22,8 @@ const PARTS = [0, 2, 4];
const defaultHighlight = '#f19135'; // '#f19135'; // #999
function getHighlight (props: Props): string {
return (props.uiHighlight || defaultHighlight);
function getHighlight ({ uiHighlight }: Props): string {
return (uiHighlight || defaultHighlight);
}
function getContrast (props: Props): string {
@ -33,7 +35,7 @@ function getContrast (props: Props): string {
: 'rgba(255, 253, 251, 0.875)';
}
export default createGlobalStyle<Props>`
export default createGlobalStyle<Props & ThemeProps>`
.highlight--all {
background: ${getHighlight} !important;
border-color: ${getHighlight} !important;
@ -58,7 +60,7 @@ export default createGlobalStyle<Props>`
.highlight--bg-faint,
.highlight--bg-light {
background: white;
background: ${({ theme }) => theme.bgTable};
position: relative;
&:before {
@ -98,7 +100,7 @@ export default createGlobalStyle<Props>`
}
.highlight--gradient {
background: ${(props: Props) => `linear-gradient(90deg, ${props.uiHighlight || defaultHighlight}, transparent)`};
background: ${({ uiHighlight }: Props) => `linear-gradient(90deg, ${uiHighlight || defaultHighlight}, transparent)`};
}
.highlight--hover-bg:hover {
@ -177,14 +179,12 @@ export default createGlobalStyle<Props>`
}
}
.theme--default {
.ui--Tabs-Tab.tabLinkActive {
border-bottom-color: ${getHighlight};
}
.ui.negative.button,
.ui.buttons .negative.button {
background: #666 !important;
.theme--dark,
.theme--light {
.ui--Tabs {
.ui--Tab.tabLinkActive {
border-bottom-color: ${getHighlight};
}
}
.ui.primary.button,
@ -213,7 +213,8 @@ export default createGlobalStyle<Props>`
}
#root {
color: #4e4e4e;
background: ${({ theme }) => theme.bgPage};
color: ${({ theme }) => theme.color};
font-family: sans-serif;
height: 100%;
}
@ -223,7 +224,7 @@ export default createGlobalStyle<Props>`
}
article {
background: white;
background: ${({ theme }) => theme.bgTable};
border: 1px solid #f2f2f2;
border-radius: 0.25rem;
box-sizing: border-box;
@ -297,7 +298,6 @@ export default createGlobalStyle<Props>`
}
body {
background: #f5f3f1;
height: 100%;
margin: 0;
}
@ -330,7 +330,7 @@ export default createGlobalStyle<Props>`
}
h1, h2, h3, h4, h5 {
color: rgba(0, 0, 0, .6);
color: ${({ theme }) => theme.colorSummary};
font-family: sans-serif;
font-weight: 100;
}
@ -363,7 +363,7 @@ export default createGlobalStyle<Props>`
label {
box-sizing: border-box;
color: rgba(78, 78, 78, .66);
color: ${({ theme }) => theme.colorLabel};
display: block;
font-family: sans-serif;
font-size: 1rem;

View File

@ -1,6 +1,8 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ThemeProps } from '../types';
import { css } from 'styled-components';
export default css`
@ -21,7 +23,13 @@ export default css`
.ui.selection.dropdown,
.ui.input > input {
color: inherit;
background: ${({ theme }: ThemeProps) => theme.bgInput};
color: ${({ theme }: ThemeProps) => theme.color};
&:focus {
background: ${({ theme }: ThemeProps) => theme.bgInput};
color: ${({ theme }: ThemeProps) => theme.color};
}
}
.ui.action.input > .buttons {
@ -39,21 +47,40 @@ export default css`
}
}
&.selection.visible {
background: ${({ theme }: ThemeProps) => theme.bgInput};
color: ${({ theme }: ThemeProps) => theme.color};
}
.menu {
background: ${({ theme }: ThemeProps) => theme.bgInput};
color: ${({ theme }: ThemeProps) => theme.color};
> .item {
border-color: transparent !important;
color: ${({ theme }: ThemeProps) => theme.color} !important;
&.header.disabled {
margin: 1em 0 0 0;
opacity: 1;
&:hover,
&.selected {
background: ${({ theme }: ThemeProps) => theme.bgInput};
}
}
}
}
> .text {
min-height: 1em;
&:not(.default) {
color: ${({ theme }: ThemeProps) => theme.color} !important;
}
}
}
.ui.dropdown .menu > .item.header.disabled {
margin: 1em 0 0 0;
opacity: 1;
}
.ui.dropdown .menu > .item.header.disabled:hover,
.ui.dropdown .menu > .item.header.disabled.selected {
background: white;
}
.ui.input {
width: 100%;
@ -96,9 +123,9 @@ export default css`
}
.ui.modal {
background: #f9f8f7;
background: ${({ theme }: ThemeProps) => theme.bgPage};
box-shadow: none;
color: #4e4e4e;
color: ${({ theme }: ThemeProps) => theme.color};
font-family: sans-serif;
> .actions,
@ -116,7 +143,7 @@ export default css`
> .header:not(.ui) {
background: transparent;
border-bottom: none;
color: rgba(0, 0, 0, .6);
color: ${({ theme }: ThemeProps) => theme.colorSummary};
font-family: sans-serif;
font-size: 1.75rem;
font-weight: 100;
@ -139,6 +166,15 @@ export default css`
display: flex !important;
}
.ui.popup {
background: ${({ theme }: ThemeProps) => theme.bgMenu};
color: ${({ theme }: ThemeProps) => theme.color};
.ui.text.menu .item {
color: ${({ theme }: ThemeProps) => theme.color};
}
}
.ui.secondary.vertical.menu > .item {
margin: 0;
}

View File

@ -20,8 +20,9 @@ export const colorBtnText = '#f9f8f7';
export const colorLink = '#2e86ab';
export default css`
.theme--default {
a {
.theme--dark,
.theme--light {
a:not(.ui--Tab) {
color: ${colorLink};
&:hover,
@ -41,5 +42,10 @@ export default css`
.ui.modal > .header:not(.ui) {
border-bottom-color: ${colorBtnDefault};
}
.ui.negative.button,
.ui.buttons .negative.button {
background: #666 !important;
}
}
`;

View File

@ -124,3 +124,25 @@ export interface NullContract {
abi: null;
address: null;
}
export interface ThemeDef {
bgInput: string;
bgInverse: string;
bgMenu: string;
bgMenuHover: string;
bgPage: string;
bgTable: string;
bgTabs: string;
bgToggle: string;
borderTable: string;
borderTabs: string;
color: string;
colorError: string;
colorLabel: string;
colorSummary: string;
theme: 'dark' | 'light';
}
export interface ThemeProps {
theme: ThemeDef;
}