Pull request 1713: 613 dark theme vol.2
Updates #613. Squashed commit of the following: commit 9a3ba15bdb8476dde045631362d76572a68a4e5c Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jan 19 12:46:48 2023 +0700 client: review dark theme colors commit c456cdcb6ffec044917b0396ad3cfa8b5c3bce10 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jan 18 23:46:32 2023 +0700 client: review dark theme colors commit 4b042ba4f433c89488b18ec38f5864d5ffaf8657 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jan 18 23:34:37 2023 +0700 client: review dark theme colors commit 1ff34f751b4d9342495070af85f3dae86c285aee Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jan 18 18:59:46 2023 +0700 client: default language commit ca9abc11a8c155c78f73903906ed452e95764e99 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jan 18 12:23:50 2023 +0700 client: default language commit 01a057a40e879d1bc2013989d6eb56a296ba16a3 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jan 18 11:53:58 2023 +0700 client: review dark theme colors commit aa3658f35c49f8ae19077b333075207082383a17 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jan 18 11:14:08 2023 +0700 client: review dark theme colors commit 8df726382155fcc3b2e6e632d53f42d0be638c77 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jan 17 13:41:21 2023 +0700 client: dark theme colors commit bd84ae46272743874d2350291b22b90b7fbedf0e Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jan 17 13:05:46 2023 +0700 client: dark theme colors commit 136ea5608a1a22b6a54a362741b2fdd708f345e2 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jan 17 10:51:22 2023 +0700 all: docs commit 784be8741b730a12d665d7e2a29c140c0746e927 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jan 16 17:59:26 2023 +0700 client: imp code commit a83de0948fe034e7be35c04a607b1171915c0263 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jan 16 14:13:54 2023 +0700 client: dark theme login commit 6c4ef19da01efc6a1e4ea76085b7b7382c331eca Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jan 16 13:27:35 2023 +0700 client: dark theme css commit 5cf564ea1203e9472d200975ee98d93b6b868210 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jan 16 13:18:00 2023 +0700 client: imp code commit 1bbbd20972345c08e944b7c4bb0330c0d30d827a Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jan 16 12:49:03 2023 +0700 client: imp code commit cb07680d3cd7acdbdb7bdc9d9abaa388a9df8e4c Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jan 16 12:24:14 2023 +0700 client: auto theme handling commit d34910d4dd5edb694b6da55a2260b4fea784e7e0 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Fri Jan 13 23:31:24 2023 +0700 home: imp docs commit 8abe4f6f7182dc3dbcbbe73652294ee6584a4f2f Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jan 12 18:35:48 2023 +0700 client: theme dropdown
This commit is contained in:
parent
cd76a30790
commit
a7dca7aa56
|
@ -19,6 +19,7 @@ and this project adheres to
|
|||
|
||||
### Added
|
||||
|
||||
- Experimental Dark UI theme ([#613]).
|
||||
- The new HTTP API `PUT /control/profile/update`, that updates current user
|
||||
language and UI theme. The format of request body is described in
|
||||
`openapi/openapi.yaml`.
|
||||
|
|
|
@ -298,6 +298,9 @@
|
|||
"blocking_mode_nxdomain": "NXDOMAIN: Respond with NXDOMAIN code",
|
||||
"blocking_mode_null_ip": "Null IP: Respond with zero IP address (0.0.0.0 for A; :: for AAAA)",
|
||||
"blocking_mode_custom_ip": "Custom IP: Respond with a manually set IP address",
|
||||
"theme_auto": "Auto",
|
||||
"theme_light": "Light",
|
||||
"theme_dark": "Dark",
|
||||
"upstream_dns_client_desc": "If you keep this field empty, AdGuard Home will use the servers configured in the <0>DNS settings</0>.",
|
||||
"tracker_source": "Tracker source",
|
||||
"source_label": "Source",
|
||||
|
|
|
@ -363,18 +363,18 @@ export const changeLanguage = (lang) => async (dispatch) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const getLanguageRequest = createAction('GET_LANGUAGE_REQUEST');
|
||||
export const getLanguageFailure = createAction('GET_LANGUAGE_FAILURE');
|
||||
export const getLanguageSuccess = createAction('GET_LANGUAGE_SUCCESS');
|
||||
export const changeThemeRequest = createAction('CHANGE_THEME_REQUEST');
|
||||
export const changeThemeFailure = createAction('CHANGE_THEME_FAILURE');
|
||||
export const changeThemeSuccess = createAction('CHANGE_THEME_SUCCESS');
|
||||
|
||||
export const getLanguage = () => async (dispatch) => {
|
||||
dispatch(getLanguageRequest());
|
||||
export const changeTheme = (theme) => async (dispatch) => {
|
||||
dispatch(changeThemeRequest());
|
||||
try {
|
||||
const langSettings = await apiClient.getCurrentLanguage();
|
||||
dispatch(getLanguageSuccess(langSettings.language));
|
||||
await apiClient.changeTheme({ theme });
|
||||
dispatch(changeThemeSuccess({ theme }));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(getLanguageFailure());
|
||||
dispatch(changeThemeFailure());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import axios from 'axios';
|
||||
|
||||
import { getPathWithQueryString } from '../helpers/helpers';
|
||||
import { QUERY_LOGS_PAGE_LIMIT, HTML_PAGES, R_PATH_LAST_PART } from '../helpers/constants';
|
||||
import {
|
||||
QUERY_LOGS_PAGE_LIMIT, HTML_PAGES, R_PATH_LAST_PART, THEMES,
|
||||
} from '../helpers/constants';
|
||||
import { BASE_URL } from '../../constants';
|
||||
import i18n from '../i18n';
|
||||
import { LANGUAGES } from '../helpers/twosky';
|
||||
|
||||
class Api {
|
||||
baseUrl = BASE_URL;
|
||||
|
@ -224,21 +228,21 @@ class Api {
|
|||
}
|
||||
|
||||
// Language
|
||||
CURRENT_LANGUAGE = { path: 'i18n/current_language', method: 'GET' };
|
||||
|
||||
CHANGE_LANGUAGE = { path: 'i18n/change_language', method: 'POST' };
|
||||
async changeLanguage(config) {
|
||||
const profile = await this.getProfile();
|
||||
profile.language = config.language;
|
||||
|
||||
getCurrentLanguage() {
|
||||
const { path, method } = this.CURRENT_LANGUAGE;
|
||||
return this.makeRequest(path, method);
|
||||
return this.setProfile(profile);
|
||||
}
|
||||
|
||||
changeLanguage(config) {
|
||||
const { path, method } = this.CHANGE_LANGUAGE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
};
|
||||
return this.makeRequest(path, method, parameters);
|
||||
// Theme
|
||||
|
||||
async changeTheme(config) {
|
||||
const profile = await this.getProfile();
|
||||
profile.theme = config.theme;
|
||||
|
||||
return this.setProfile(profile);
|
||||
}
|
||||
|
||||
// DHCP
|
||||
|
@ -571,11 +575,24 @@ class Api {
|
|||
// Profile
|
||||
GET_PROFILE = { path: 'profile', method: 'GET' };
|
||||
|
||||
UPDATE_PROFILE = { path: 'profile/update', method: 'PUT' };
|
||||
|
||||
getProfile() {
|
||||
const { path, method } = this.GET_PROFILE;
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setProfile(data) {
|
||||
const theme = data.theme ? data.theme : THEMES.auto;
|
||||
const defaultLanguage = i18n.language ? i18n.language : LANGUAGES.en;
|
||||
const language = data.language ? data.language : defaultLanguage;
|
||||
|
||||
const { path, method } = this.UPDATE_PROFILE;
|
||||
const config = { data: { theme, language } };
|
||||
|
||||
return this.makeRequest(path, method, config);
|
||||
}
|
||||
|
||||
// DNS config
|
||||
GET_DNS_CONFIG = { path: 'dns_info', method: 'GET' };
|
||||
|
||||
|
|
|
@ -1,4 +1,26 @@
|
|||
:root {
|
||||
--bgcolor: #f5f7fb;
|
||||
--mcolor: #495057;
|
||||
--scolor: rgba(74, 74, 74, 0.7);
|
||||
--border-color: rgba(0, 40, 100, 0.12);
|
||||
--header-bgcolor: #fff;
|
||||
--card-bgcolor: #fff;
|
||||
--card-border-color: rgba(0, 40, 100, 0.12);
|
||||
--ctrl-bgcolor: #fff;
|
||||
--ctrl-select-bgcolor: rgba(69, 79, 94, 0.12);
|
||||
--ctrl-dropdown-color: #212529;
|
||||
--ctrl-dropdown-bgcolor-focus: #f8f9fa;
|
||||
--ctrl-dropdown-color-focus: #16181b;
|
||||
--btn-success-bgcolor: #5eba00;
|
||||
--form-disabled-bgcolor: #f8f9fa;
|
||||
--form-disabled-color: #495057;
|
||||
--rt-nodata-bgcolor: rgba(255,255,255,0.8);
|
||||
--rt-nodata-color: rgba(0,0,0,0.5);
|
||||
--modal-overlay-bgcolor: rgba(255, 255, 255, 0.75);
|
||||
--logs__table-bgcolor: #fff;
|
||||
--logs__row--blue-bgcolor: #e5effd;
|
||||
--logs__row--white-bgcolor: #fff;
|
||||
--detailed-info-color: #888888;
|
||||
--yellow-pale: rgba(247, 181, 0, 0.1);
|
||||
--green79: #67b279;
|
||||
--gray-a5: #a5a5a5;
|
||||
|
@ -8,6 +30,32 @@
|
|||
--font-size-disable-autozoom: 1rem;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--bgcolor: #131313;
|
||||
--mcolor: #e6e6e6;
|
||||
--scolor: #a5a5a5;
|
||||
--header-bgcolor: #131313;
|
||||
--border-color: #222;
|
||||
--card-bgcolor: #1c1c1c;
|
||||
--card-border-color: #3d3d3d;
|
||||
--ctrl-bgcolor: #1c1c1c;
|
||||
--ctrl-select-bgcolor: #3d3d3d;
|
||||
--ctrl-dropdown-color: #fff;
|
||||
--ctrl-dropdown-bgcolor-focus: #000;
|
||||
--ctrl-dropdown-color-focus: #fff;
|
||||
--btn-success-bgcolor: #67b279;
|
||||
--form-disabled-bgcolor: #3d3d3d;
|
||||
--form-disabled-color: #a5a5a5;
|
||||
--logs__text-color: #f3f3f3;
|
||||
--rt-nodata-bgcolor: #1c1c1c;
|
||||
--rt-nodata-color: #fff;
|
||||
--modal-overlay-bgcolor: #1c1c1c;
|
||||
--logs__table-bgcolor: #3d3d3d;
|
||||
--logs__row--blue-bgcolor: #467fcf;
|
||||
--logs__row--white-bgcolor: #1c1c1c;
|
||||
--detailed-info-color: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
|
|
@ -20,8 +20,13 @@ import EncryptionTopline from '../ui/EncryptionTopline';
|
|||
import Icons from '../ui/Icons';
|
||||
import i18n from '../../i18n';
|
||||
import Loading from '../ui/Loading';
|
||||
import { FILTERS_URLS, MENU_URLS, SETTINGS_URLS } from '../../helpers/constants';
|
||||
import { getLogsUrlParams, setHtmlLangAttr } from '../../helpers/helpers';
|
||||
import {
|
||||
FILTERS_URLS,
|
||||
MENU_URLS,
|
||||
SETTINGS_URLS,
|
||||
THEMES,
|
||||
} from '../../helpers/constants';
|
||||
import { getLogsUrlParams, setHtmlLangAttr, setUITheme } from '../../helpers/helpers';
|
||||
import Header from '../Header';
|
||||
import { changeLanguage, getDnsStatus } from '../../actions';
|
||||
|
||||
|
@ -109,6 +114,7 @@ const App = () => {
|
|||
isCoreRunning,
|
||||
isUpdateAvailable,
|
||||
processing,
|
||||
theme,
|
||||
} = useSelector((state) => state.dashboard, shallowEqual);
|
||||
|
||||
const { processing: processingEncryption } = useSelector((
|
||||
|
@ -138,6 +144,41 @@ const App = () => {
|
|||
setLanguage();
|
||||
}, [language]);
|
||||
|
||||
const handleAutoTheme = (e, accountTheme) => {
|
||||
if (accountTheme !== THEMES.auto) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.matches) {
|
||||
setUITheme(THEMES.dark);
|
||||
} else {
|
||||
setUITheme(THEMES.light);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (theme !== THEMES.auto) {
|
||||
setUITheme(theme);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const colorSchemeMedia = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const prefersDark = colorSchemeMedia.matches;
|
||||
setUITheme(prefersDark ? THEMES.dark : THEMES.light);
|
||||
|
||||
if (colorSchemeMedia.addEventListener !== undefined) {
|
||||
colorSchemeMedia.addEventListener('change', (e) => {
|
||||
handleAutoTheme(e, theme);
|
||||
});
|
||||
} else {
|
||||
// Deprecated addListener for older versions of Safari.
|
||||
colorSchemeMedia.addListener((e) => {
|
||||
handleAutoTheme(e, theme);
|
||||
});
|
||||
}
|
||||
}, [theme]);
|
||||
|
||||
const reloadPage = () => {
|
||||
window.location.reload();
|
||||
};
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
width: 250px;
|
||||
height: 100vh;
|
||||
transition: transform 0.3s ease;
|
||||
background-color: #fff;
|
||||
background-color: var(--header-bgcolor);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.2);
|
||||
border-radius: 4px !important;
|
||||
pointer-events: auto !important;
|
||||
background-color: var(--white);
|
||||
background-color: var(--ctrl-bgcolor);
|
||||
color: var(--scolor);
|
||||
z-index: 102;
|
||||
overflow-y: auto;
|
||||
max-height: 100%;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
overflow: hidden;
|
||||
font-size: 1rem;
|
||||
font-family: var(--font-family-sans-serif);
|
||||
color: var(--gray-4d);
|
||||
color: var(--logs__text-color);
|
||||
letter-spacing: 0;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
@ -48,7 +48,7 @@
|
|||
.detailed-info {
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.4;
|
||||
color: #888888;
|
||||
color: var(--detailed-info-color);
|
||||
}
|
||||
|
||||
.logs__text--link {
|
||||
|
@ -369,7 +369,7 @@
|
|||
|
||||
/* QUERY_STATUS_COLORS */
|
||||
.logs__row--blue {
|
||||
background-color: var(--blue);
|
||||
background-color: var(--logs__row--blue-bgcolor);
|
||||
}
|
||||
|
||||
.logs__row--green {
|
||||
|
@ -381,7 +381,7 @@
|
|||
}
|
||||
|
||||
.logs__row--white {
|
||||
background-color: var(--white);
|
||||
background-color: var(--logs__row--white-bgcolor);
|
||||
}
|
||||
|
||||
.logs__row--yellow {
|
||||
|
@ -389,8 +389,8 @@
|
|||
}
|
||||
|
||||
.logs__no-data {
|
||||
color: var(--gray-4d);
|
||||
background-color: var(--white80);
|
||||
color: var(--mcolor);
|
||||
background-color: var(--logs__table-bgcolor);
|
||||
pointer-events: none;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
|
@ -403,7 +403,7 @@
|
|||
}
|
||||
|
||||
.logs__table {
|
||||
background-color: var(--white);
|
||||
background-color: var(--logs__table-bgcolor);
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
min-height: 43rem;
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
.form__desc {
|
||||
margin-top: 10px;
|
||||
font-size: 13px;
|
||||
color: rgba(74, 74, 74, 0.7);
|
||||
color: var(--scolor);
|
||||
}
|
||||
|
||||
.form__desc--top {
|
||||
|
|
|
@ -107,5 +107,5 @@
|
|||
.checkbox__label-subtitle {
|
||||
display: block;
|
||||
line-height: 1.5;
|
||||
color: rgba(74, 74, 74, 0.7);
|
||||
color: var(--scolor);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.footer__column--theme {
|
||||
min-width: 220px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.footer__column--language {
|
||||
min-width: 220px;
|
||||
margin-bottom: 0;
|
||||
|
@ -49,6 +54,11 @@
|
|||
}
|
||||
|
||||
.footer__column--language {
|
||||
min-width: initial;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.footer__column--theme {
|
||||
min-width: initial;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { REPOSITORY, PRIVACY_POLICY_LINK } from '../../helpers/constants';
|
||||
import { REPOSITORY, PRIVACY_POLICY_LINK, THEMES } from '../../helpers/constants';
|
||||
import { LANGUAGES } from '../../helpers/twosky';
|
||||
import i18n from '../../i18n';
|
||||
|
||||
|
@ -10,6 +11,7 @@ import Version from './Version';
|
|||
import './Footer.css';
|
||||
import './Select.css';
|
||||
import { setHtmlLangAttr } from '../../helpers/helpers';
|
||||
import { changeTheme } from '../../actions';
|
||||
|
||||
const linksData = [
|
||||
{
|
||||
|
@ -29,6 +31,11 @@ const linksData = [
|
|||
|
||||
const Footer = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const currentTheme = useSelector((state) => (state.dashboard ? state.dashboard.theme : 'auto'));
|
||||
const profileName = useSelector((state) => (state.dashboard ? state.dashboard.name : ''));
|
||||
const isLoggedIn = profileName !== '';
|
||||
|
||||
const getYear = () => {
|
||||
const today = new Date();
|
||||
|
@ -41,6 +48,11 @@ const Footer = () => {
|
|||
setHtmlLangAttr(value);
|
||||
};
|
||||
|
||||
const onThemeChanged = (event) => {
|
||||
const { value } = event.target;
|
||||
dispatch(changeTheme(value));
|
||||
};
|
||||
|
||||
const renderCopyright = () => <div className="footer__column">
|
||||
<div className="footer__copyright">
|
||||
{t('copyright')} © {getYear()}{' '}
|
||||
|
@ -58,6 +70,25 @@ const Footer = () => {
|
|||
{t(name)}
|
||||
</a>);
|
||||
|
||||
const renderThemeSelect = (currentTheme, isLoggedIn) => {
|
||||
if (!isLoggedIn) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return <select
|
||||
className="form-control select select--theme"
|
||||
value={currentTheme}
|
||||
onChange={onThemeChanged}
|
||||
>
|
||||
{Object.values(THEMES)
|
||||
.map((theme) => (
|
||||
<option key={theme} value={theme}>
|
||||
{t(`theme_${theme}`)}
|
||||
</option>
|
||||
))}
|
||||
</select>;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<footer className="footer">
|
||||
|
@ -66,6 +97,9 @@ const Footer = () => {
|
|||
<div className="footer__column footer__column--links">
|
||||
{renderLinks(linksData)}
|
||||
</div>
|
||||
<div className="footer__column footer__column--theme">
|
||||
{renderThemeSelect(currentTheme, isLoggedIn)}
|
||||
</div>
|
||||
<div className="footer__column footer__column--language">
|
||||
<select
|
||||
className="form-control select select--language"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
.ReactModal__Overlay--after-open {
|
||||
opacity: 1;
|
||||
transition: opacity 150ms ease-out;
|
||||
background-color: var(--modal-overlay-bgcolor) !important;
|
||||
}
|
||||
|
||||
.ReactModal__Content {
|
||||
|
|
|
@ -13,6 +13,26 @@
|
|||
overflow: visible;
|
||||
}
|
||||
|
||||
.ReactTable .rt-noData {
|
||||
color: var(--rt-nodata-color);
|
||||
background-color: var(--rt-nodata-bgcolor);
|
||||
}
|
||||
|
||||
.ReactTable .-loading {
|
||||
color: var(--rt-nodata-color);
|
||||
background-color: var(--rt-nodata-bgcolor);
|
||||
}
|
||||
|
||||
.ReactTable .-pagination input, .ReactTable .-pagination select {
|
||||
color: var(--rt-nodata-color);
|
||||
background-color: var(--rt-nodata-bgcolor);
|
||||
}
|
||||
|
||||
[data-theme=dark] .ReactTable .-pagination .-btn {
|
||||
color: var(--scolor);
|
||||
background-color: var(--ctrl-bgcolor);
|
||||
}
|
||||
|
||||
.rt-tr-group.logs__row--red {
|
||||
background-color: rgba(223, 56, 18, 0.05);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,25 @@
|
|||
.select.select--theme {
|
||||
height: 45px;
|
||||
padding: 0 32px 2px 11px;
|
||||
outline: 0;
|
||||
border-color: var(--ctrl-select-bgcolor);
|
||||
background-image: url("./svg/chevron-down.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 9px center;
|
||||
background-size: 17px 20px;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.select--theme::-ms-expand {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.select.select--language {
|
||||
height: 45px;
|
||||
padding: 0 32px 2px 33px;
|
||||
outline: 0;
|
||||
border-color: rgba(69, 79, 94, 0.12);
|
||||
border-color: var(--ctrl-select-bgcolor);
|
||||
background-image: url("./svg/globe.svg"), url("./svg/chevron-down.svg");
|
||||
background-repeat: no-repeat, no-repeat;
|
||||
background-position: left 11px center, right 9px center;
|
||||
|
@ -16,8 +33,9 @@
|
|||
}
|
||||
|
||||
.basic-multi-select .select__control {
|
||||
border: 1px solid rgba(0, 40, 100, 0.12);
|
||||
border: 1px solid var(--card-border-color);;
|
||||
border-radius: 3px;
|
||||
background-color: var(--ctrl-bgcolor);
|
||||
}
|
||||
|
||||
.basic-multi-select .select__control:hover {
|
||||
|
@ -36,4 +54,16 @@
|
|||
|
||||
.basic-multi-select .select__menu {
|
||||
z-index: 3;
|
||||
background-color: var(--ctrl-bgcolor);
|
||||
}
|
||||
|
||||
[data-theme=dark] .basic-multi-select .select__option:hover,
|
||||
[data-theme=dark] .basic-multi-select .select__option--is-focused,
|
||||
[data-theme=dark] .basic-multi-select .select__option--is-focused:hover {
|
||||
background-color: var(--ctrl-select-bgcolor);
|
||||
color: var(--ctrl-dropdown-color);
|
||||
}
|
||||
|
||||
[data-theme=dark] .select__multi-value__remove svg {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
|
|
@ -85,9 +85,9 @@ body {
|
|||
font-size: 0.9375rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
color: var(--mcolor);
|
||||
text-align: left;
|
||||
background-color: #f5f7fb;
|
||||
background-color: var(--bgcolor);
|
||||
}
|
||||
|
||||
[tabindex="-1"]:focus {
|
||||
|
@ -1943,10 +1943,10 @@ pre code {
|
|||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.6;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
color: var(--mcolor);
|
||||
background-color: var(--card-bgcolor);
|
||||
background-clip: padding-box;
|
||||
border: 1px solid rgba(0, 40, 100, 0.12);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 3px;
|
||||
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
|
@ -1957,8 +1957,8 @@ pre code {
|
|||
}
|
||||
|
||||
.form-control:focus {
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
color: var(--mcolor);
|
||||
background-color: var(--ctrl-bgcolor);
|
||||
border-color: #1991eb;
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 2px rgba(70, 127, 207, 0.25);
|
||||
|
@ -1991,7 +1991,8 @@ pre code {
|
|||
|
||||
.form-control:disabled,
|
||||
.form-control[readonly] {
|
||||
background-color: #f8f9fa;
|
||||
background-color: var(--form-disabled-bgcolor);
|
||||
color: var(--form-disabled-color);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
@ -2580,7 +2581,7 @@ fieldset:disabled a.btn {
|
|||
|
||||
.btn-success {
|
||||
color: #fff;
|
||||
background-color: #5eba00;
|
||||
background-color: var(--btn-success-bgcolor);
|
||||
border-color: #5eba00;
|
||||
}
|
||||
|
||||
|
@ -3244,7 +3245,7 @@ tbody.collapse.show {
|
|||
color: #495057;
|
||||
text-align: left;
|
||||
list-style: none;
|
||||
background-color: #fff;
|
||||
background-color: var(--ctrl-bgcolor);
|
||||
background-clip: padding-box;
|
||||
border: 1px solid rgba(0, 40, 100, 0.12);
|
||||
border-radius: 3px;
|
||||
|
@ -3348,7 +3349,7 @@ tbody.collapse.show {
|
|||
padding: 0.25rem 1.5rem;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
color: #212529;
|
||||
color: var(--ctrl-dropdown-color);
|
||||
text-align: inherit;
|
||||
white-space: nowrap;
|
||||
background-color: transparent;
|
||||
|
@ -3357,9 +3358,9 @@ tbody.collapse.show {
|
|||
|
||||
.dropdown-item:hover,
|
||||
.dropdown-item:focus {
|
||||
color: #16181b;
|
||||
color: var(--ctrl-dropdown-color-focus);
|
||||
text-decoration: none;
|
||||
background-color: #f8f9fa;
|
||||
background-color: var(--ctrl-dropdown-bgcolor-focus);
|
||||
}
|
||||
|
||||
.dropdown-item.active,
|
||||
|
@ -3794,11 +3795,11 @@ tbody.collapse.show {
|
|||
height: 2.375rem;
|
||||
padding: 0.5rem 1.75rem 0.5rem 0.75rem;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
color: var(--mcolor);
|
||||
vertical-align: middle;
|
||||
background: #fff url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxMCA1Jz48cGF0aCBmaWxsPScjOTk5JyBkPSdNMCAwTDEwIDBMNSA1TDAgMCcvPjwvc3ZnPg==") no-repeat right 0.75rem center;
|
||||
background: var(--card-bgcolor) url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxMCA1Jz48cGF0aCBmaWxsPScjOTk5JyBkPSdNMCAwTDEwIDBMNSA1TDAgMCcvPjwvc3ZnPg==") no-repeat right 0.75rem center;
|
||||
background-size: 8px 10px;
|
||||
border: 1px solid rgba(0, 40, 100, 0.12);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 3px;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
@ -4469,9 +4470,9 @@ tbody.collapse.show {
|
|||
flex-direction: column;
|
||||
min-width: 0;
|
||||
word-wrap: break-word;
|
||||
background-color: #fff;
|
||||
background-color: var(--card-bgcolor);
|
||||
background-clip: border-box;
|
||||
border: 1px solid rgba(0, 40, 100, 0.12);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
|
@ -5475,9 +5476,9 @@ button.close {
|
|||
flex-direction: column;
|
||||
width: 100%;
|
||||
pointer-events: auto;
|
||||
background-color: #fff;
|
||||
background-color: var(--card-bgcolor);
|
||||
background-clip: padding-box;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 3px;
|
||||
outline: 0;
|
||||
}
|
||||
|
@ -10268,8 +10269,8 @@ body.fixed-header .page {
|
|||
.header {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid rgba(0, 40, 100, 0.12);
|
||||
background: var(--header-bgcolor);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
body.fixed-header .header {
|
||||
|
@ -10325,6 +10326,10 @@ body.fixed-header .header {
|
|||
width: auto;
|
||||
}
|
||||
|
||||
[data-theme=dark] .header-brand-img {
|
||||
filter:invert(1);
|
||||
}
|
||||
|
||||
.header-avatar {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
|
@ -10382,8 +10387,8 @@ body.fixed-header .header {
|
|||
}
|
||||
|
||||
.footer {
|
||||
background: #fff;
|
||||
border-top: 1px solid rgba(0, 40, 100, 0.12);
|
||||
background: var(--card-bgcolor);
|
||||
border-top: 1px solid var(--card-border-color);
|
||||
font-size: 0.875rem;
|
||||
padding: 1.25rem 0;
|
||||
color: #9aa0ac;
|
||||
|
@ -13686,13 +13691,17 @@ Card alert
|
|||
content: "";
|
||||
}
|
||||
|
||||
[data-theme=dark] .dropdown-menu-arrow:before {
|
||||
border-bottom-color: var(--ctrl-bgcolor);
|
||||
}
|
||||
|
||||
.dropdown-menu-arrow:after {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 12px;
|
||||
display: inline-block;
|
||||
border-right: 5px solid transparent;
|
||||
border-bottom: 5px solid #fff;
|
||||
border-bottom: 5px solid var(--ctrl-bgcolor);
|
||||
border-left: 5px solid transparent;
|
||||
content: "";
|
||||
}
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
[data-theme=dark] .tooltip-container {
|
||||
background-color: var(--ctrl-select-bgcolor);
|
||||
color: var(--mcolor);
|
||||
}
|
||||
|
||||
.tooltip-custom--narrow {
|
||||
max-width: 14rem;
|
||||
}
|
||||
|
|
|
@ -227,6 +227,14 @@ export const BLOCKING_MODES = {
|
|||
custom_ip: 'custom_ip',
|
||||
};
|
||||
|
||||
// Note that translation strings contain these modes (theme_CONSTANT)
|
||||
// i.e. theme_auto, theme_light.
|
||||
export const THEMES = {
|
||||
auto: 'auto',
|
||||
dark: 'dark',
|
||||
light: 'light',
|
||||
};
|
||||
|
||||
export const WHOIS_ICONS = {
|
||||
location: 'location',
|
||||
orgname: 'network',
|
||||
|
|
|
@ -670,6 +670,15 @@ export const setHtmlLangAttr = (language) => {
|
|||
window.document.documentElement.lang = language;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets UI theme.
|
||||
*
|
||||
* @param theme
|
||||
*/
|
||||
export const setUITheme = (theme) => {
|
||||
document.body.dataset.theme = theme;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param values {object}
|
||||
* @returns {object}
|
||||
|
|
|
@ -112,14 +112,6 @@ const dashboard = handleActions(
|
|||
return newState;
|
||||
},
|
||||
|
||||
[actions.getLanguageSuccess]: (state, { payload }) => {
|
||||
const newState = {
|
||||
...state,
|
||||
language: payload,
|
||||
};
|
||||
return newState;
|
||||
},
|
||||
|
||||
[actions.getClientsRequest]: (state) => ({
|
||||
...state,
|
||||
processingClients: true,
|
||||
|
@ -148,8 +140,13 @@ const dashboard = handleActions(
|
|||
[actions.getProfileSuccess]: (state, { payload }) => ({
|
||||
...state,
|
||||
name: payload.name,
|
||||
theme: payload.theme,
|
||||
processingProfile: false,
|
||||
}),
|
||||
[actions.changeThemeSuccess]: (state, { payload }) => ({
|
||||
...state,
|
||||
theme: payload.theme,
|
||||
}),
|
||||
},
|
||||
{
|
||||
processing: true,
|
||||
|
@ -168,6 +165,7 @@ const dashboard = handleActions(
|
|||
autoClients: [],
|
||||
supportedTags: [],
|
||||
name: '',
|
||||
theme: 'auto',
|
||||
checkUpdateFlag: false,
|
||||
},
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue