- client: Refactor Setup guide component: Merge pull request #633 in DNS/adguard-home from fix/1740 to master
Close #1740
Squashed commit of the following:
commit 13593ad7580a0ad5a4d5c0abcb4f67d01ddb944a
Merge: 8cdc68de 1356ac26
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Thu Jun 11 12:02:02 2020 +0300
Merge branch 'master' into fix/1740
commit 8cdc68debab3f0668ec4aa5cf9b55ce40ddd4985
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Wed Jun 10 19:35:51 2020 +0300
Update locales with link
commit 320d8d2f189dff594954b3f5964279410594ee29
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Wed Jun 3 16:40:36 2020 +0300
Refactor Tabs
commit 98bdcdb5eb35448d38ed42aa08cec2fce9ac849e
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Wed Jun 3 14:01:55 2020 +0300
Separate content from markup of dns privacy list
commit cee5e5c411d1e9a93a16eba9d78f2f9479d9e729
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Wed May 27 21:12:11 2020 +0300
- client: Refactor Setup guide component
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
@@ -63,7 +63,6 @@ const validate = (values) => {
|
||||
return errors;
|
||||
};
|
||||
|
||||
|
||||
const renderFieldsWrapper = (placeholder, buttonTitle) => function cell(row) {
|
||||
const {
|
||||
fields,
|
||||
@@ -122,7 +121,7 @@ const renderMultiselect = (props) => {
|
||||
renderMultiselect.propTypes = {
|
||||
input: PropTypes.object.isRequired,
|
||||
placeholder: PropTypes.string,
|
||||
options: PropTypes.object,
|
||||
options: PropTypes.array,
|
||||
};
|
||||
|
||||
let Form = (props) => {
|
||||
@@ -142,6 +141,101 @@ let Form = (props) => {
|
||||
tagsOptions,
|
||||
} = props;
|
||||
|
||||
const [activeTabLabel, setActiveTabLabel] = useState('settings');
|
||||
|
||||
const tabs = {
|
||||
settings: {
|
||||
title: 'settings',
|
||||
component: <div label="settings" title={props.t('main_settings')}>
|
||||
{settingsCheckboxes.map((setting) => (
|
||||
<div className="form__group" key={setting.name}>
|
||||
<Field
|
||||
name={setting.name}
|
||||
type="checkbox"
|
||||
component={renderSelectField}
|
||||
placeholder={t(setting.placeholder)}
|
||||
disabled={
|
||||
setting.name !== 'use_global_settings'
|
||||
? useGlobalSettings
|
||||
: false
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>,
|
||||
},
|
||||
block_services: {
|
||||
title: 'block_services',
|
||||
component: <div label="services" title={props.t('block_services')}>
|
||||
<div className="form__group">
|
||||
<Field
|
||||
name="use_global_blocked_services"
|
||||
type="checkbox"
|
||||
component={renderServiceField}
|
||||
placeholder={t('blocked_services_global')}
|
||||
modifier="service--global"
|
||||
/>
|
||||
<div className="row mb-4">
|
||||
<div className="col-6">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={useGlobalServices}
|
||||
onClick={() => toggleAllServices(SERVICES, change, true)}
|
||||
>
|
||||
<Trans>block_all</Trans>
|
||||
</button>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={useGlobalServices}
|
||||
onClick={() => toggleAllServices(SERVICES, change, false)}
|
||||
>
|
||||
<Trans>unblock_all</Trans>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="services">
|
||||
{SERVICES.map((service) => (
|
||||
<Field
|
||||
key={service.id}
|
||||
icon={`service_${service.id}`}
|
||||
name={`blocked_services.${service.id}`}
|
||||
type="checkbox"
|
||||
component={renderServiceField}
|
||||
placeholder={service.name}
|
||||
disabled={useGlobalServices}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
},
|
||||
upstream_dns: {
|
||||
title: 'upstream_dns',
|
||||
component: <div label="upstream" title={props.t('upstream_dns')}>
|
||||
<div className="form__desc mb-3">
|
||||
<Trans components={[<a href="#dns" key="0">link</a>]}>
|
||||
upstream_dns_client_desc
|
||||
</Trans>
|
||||
</div>
|
||||
<Field
|
||||
id="upstreams"
|
||||
name="upstreams"
|
||||
component="textarea"
|
||||
type="text"
|
||||
className="form-control form-control--textarea mb-5"
|
||||
placeholder={t('upstream_dns')}
|
||||
/>
|
||||
<Examples />
|
||||
</div>,
|
||||
},
|
||||
};
|
||||
|
||||
const activeTab = tabs[activeTabLabel].component;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="modal-body">
|
||||
@@ -207,86 +301,9 @@ let Form = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Tabs controlClass="form">
|
||||
<div label="settings" title={props.t('main_settings')}>
|
||||
{settingsCheckboxes.map((setting) => (
|
||||
<div className="form__group" key={setting.name}>
|
||||
<Field
|
||||
name={setting.name}
|
||||
type="checkbox"
|
||||
component={renderSelectField}
|
||||
placeholder={t(setting.placeholder)}
|
||||
disabled={
|
||||
setting.name !== 'use_global_settings'
|
||||
? useGlobalSettings
|
||||
: false
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div label="services" title={props.t('block_services')}>
|
||||
<div className="form__group">
|
||||
<Field
|
||||
name="use_global_blocked_services"
|
||||
type="checkbox"
|
||||
component={renderServiceField}
|
||||
placeholder={t('blocked_services_global')}
|
||||
modifier="service--global"
|
||||
/>
|
||||
<div className="row mb-4">
|
||||
<div className="col-6">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={useGlobalServices}
|
||||
onClick={() => toggleAllServices(SERVICES, change, true)}
|
||||
>
|
||||
<Trans>block_all</Trans>
|
||||
</button>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={useGlobalServices}
|
||||
onClick={() => toggleAllServices(SERVICES, change, false)}
|
||||
>
|
||||
<Trans>unblock_all</Trans>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="services">
|
||||
{SERVICES.map((service) => (
|
||||
<Field
|
||||
key={service.id}
|
||||
icon={`service_${service.id}`}
|
||||
name={`blocked_services.${service.id}`}
|
||||
type="checkbox"
|
||||
component={renderServiceField}
|
||||
placeholder={service.name}
|
||||
disabled={useGlobalServices}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div label="upstream" title={props.t('upstream_dns')}>
|
||||
<div className="form__desc mb-3">
|
||||
<Trans components={[<a href="#dns" key="0">link</a>]}>
|
||||
upstream_dns_client_desc
|
||||
</Trans>
|
||||
</div>
|
||||
<Field
|
||||
id="upstreams"
|
||||
name="upstreams"
|
||||
component="textarea"
|
||||
type="text"
|
||||
className="form-control form-control--textarea mb-5"
|
||||
placeholder={t('upstream_dns')}
|
||||
/>
|
||||
<Examples />
|
||||
</div>
|
||||
<Tabs controlClass="form" tabs={tabs} activeTabLabel={activeTabLabel}
|
||||
setActiveTabLabel={setActiveTabLabel}>
|
||||
{activeTab}
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,364 +1,293 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
|
||||
import Tabs from './Tabs';
|
||||
import Icons from './Icons';
|
||||
|
||||
const Guide = (props) => {
|
||||
const { dnsAddresses } = props;
|
||||
const dnsPrivacyList = [{
|
||||
title: 'Android',
|
||||
list: [
|
||||
{
|
||||
label: 'setup_dns_privacy_android_1',
|
||||
},
|
||||
{
|
||||
label: 'setup_dns_privacy_android_2',
|
||||
components: [
|
||||
{
|
||||
key: 0,
|
||||
href: 'https://adguard.com/adguard-android/overview.html',
|
||||
},
|
||||
<code key="1">text</code>,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'setup_dns_privacy_android_3',
|
||||
components: [
|
||||
{
|
||||
key: 0,
|
||||
href: 'https://getintra.org/',
|
||||
},
|
||||
<code key="1">text</code>,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'iOS',
|
||||
list: [
|
||||
{
|
||||
label: 'setup_dns_privacy_ios_1',
|
||||
components: [
|
||||
{
|
||||
key: 0,
|
||||
href: 'https://itunes.apple.com/app/id1452162351',
|
||||
},
|
||||
<code key="1">text</code>,
|
||||
{
|
||||
key: 2,
|
||||
href: 'https://dnscrypt.info/stamps',
|
||||
},
|
||||
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'setup_dns_privacy_ios_2',
|
||||
components: [
|
||||
{
|
||||
key: 0,
|
||||
href: 'https://adguard.com/adguard-ios/overview.html',
|
||||
},
|
||||
<code key="1">text</code>,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'setup_dns_privacy_other_title',
|
||||
list: [
|
||||
{
|
||||
label: 'setup_dns_privacy_other_1',
|
||||
},
|
||||
{
|
||||
label: 'setup_dns_privacy_other_2',
|
||||
components: [
|
||||
{
|
||||
key: 0,
|
||||
href: 'https://github.com/AdguardTeam/dnsproxy',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/jedisct1/dnscrypt-proxy',
|
||||
label: 'setup_dns_privacy_other_3',
|
||||
components: [
|
||||
{
|
||||
key: 0,
|
||||
href: 'https://github.com/jedisct1/dnscrypt-proxy',
|
||||
},
|
||||
<code key="1">text</code>,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'setup_dns_privacy_other_4',
|
||||
components: [
|
||||
{
|
||||
key: 0,
|
||||
href: 'https://github.com/jedisct1/dnscrypt-proxy',
|
||||
},
|
||||
<code key="1">text</code>,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'setup_dns_privacy_other_5',
|
||||
components: [
|
||||
{
|
||||
key: 0,
|
||||
href: 'https://dnscrypt.info/implementations',
|
||||
},
|
||||
{
|
||||
key: 1,
|
||||
href: 'https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Clients',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const renderDnsPrivacyList = ({ title, list }) => <div className="tab__paragraph">
|
||||
<strong><Trans>{title}</Trans></strong>
|
||||
<ul>{list.map(({ label, components }) => <li key={label}>
|
||||
<Trans
|
||||
components={components && components.map((props) => {
|
||||
if (React.isValidElement(props)) {
|
||||
return props;
|
||||
}
|
||||
const {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
href, target = '_blank', rel = 'noopener noreferrer', key = '0',
|
||||
} = props;
|
||||
|
||||
return <a
|
||||
href={href} target={target}
|
||||
rel={rel} key={key}>link</a>;
|
||||
})}>
|
||||
{label}
|
||||
</Trans>
|
||||
</li>)}
|
||||
</ul>
|
||||
</div>;
|
||||
|
||||
const getTabs = ({
|
||||
tlsAddress,
|
||||
httpsAddress,
|
||||
showDnsPrivacyNotice,
|
||||
t,
|
||||
}) => ({
|
||||
Router: {
|
||||
// eslint-disable-next-line react/display-name
|
||||
getTitle: () => <p>
|
||||
<Trans>install_devices_router_desc</Trans>
|
||||
</p>,
|
||||
title: 'Router',
|
||||
list: ['install_devices_router_list_1',
|
||||
'install_devices_router_list_2',
|
||||
'install_devices_router_list_3',
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<Trans components={[
|
||||
<a href="#dhcp" key="0">
|
||||
link
|
||||
</a>,
|
||||
]}>install_devices_router_list_4</Trans>,
|
||||
],
|
||||
},
|
||||
Windows: {
|
||||
title: 'Windows',
|
||||
list: ['install_devices_windows_list_1',
|
||||
'install_devices_windows_list_2',
|
||||
'install_devices_windows_list_3',
|
||||
'install_devices_windows_list_4',
|
||||
'install_devices_windows_list_5',
|
||||
'install_devices_windows_list_6'],
|
||||
},
|
||||
macOS: {
|
||||
title: 'macOS',
|
||||
list: ['install_devices_macos_list_1',
|
||||
'install_devices_macos_list_2',
|
||||
'install_devices_macos_list_3',
|
||||
'install_devices_macos_list_4'],
|
||||
},
|
||||
Android: {
|
||||
title: 'Android',
|
||||
list: ['install_devices_android_list_1',
|
||||
'install_devices_android_list_2',
|
||||
'install_devices_android_list_3',
|
||||
'install_devices_android_list_4',
|
||||
'install_devices_android_list_5'],
|
||||
},
|
||||
iOS: {
|
||||
title: 'iOS',
|
||||
list: ['install_devices_ios_list_1',
|
||||
'install_devices_ios_list_2',
|
||||
'install_devices_ios_list_3',
|
||||
'install_devices_ios_list_4'],
|
||||
},
|
||||
dns_privacy: {
|
||||
title: 'dns_privacy',
|
||||
// eslint-disable-next-line react/display-name
|
||||
getTitle: () => <div label="dns_privacy" title={t('dns_privacy')}>
|
||||
<div className="tab__text">
|
||||
{tlsAddress && tlsAddress.length > 0 && (
|
||||
<div className="tab__paragraph">
|
||||
<Trans
|
||||
values={{ address: tlsAddress[0] }}
|
||||
components={[
|
||||
<strong key="0">text</strong>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_1
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
{httpsAddress && httpsAddress.length > 0 && (
|
||||
<div className="tab__paragraph">
|
||||
<Trans
|
||||
values={{ address: httpsAddress[0] }}
|
||||
components={[
|
||||
<strong key="0">text</strong>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_2
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
{showDnsPrivacyNotice
|
||||
? <div className="tab__paragraph">
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://github.com/AdguardTeam/AdguardHome/wiki/Encryption"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_notice
|
||||
</Trans>
|
||||
</div>
|
||||
: <>
|
||||
<div className="tab__paragraph">
|
||||
<Trans components={[<p key="0">text</p>]}>
|
||||
setup_dns_privacy_3
|
||||
</Trans>
|
||||
</div>
|
||||
{dnsPrivacyList.map(renderDnsPrivacyList)}
|
||||
</>}
|
||||
</div>
|
||||
</div>,
|
||||
},
|
||||
});
|
||||
|
||||
const renderContent = ({ title, list, getTitle }, t) => <div key={title} label={t(title)}>
|
||||
<div className="tab__title">{t(title)}</div>
|
||||
<div className="tab__text">
|
||||
{typeof getTitle === 'function' && getTitle()}
|
||||
{list
|
||||
&& <ol>{list.map((item) => <li key={item}>
|
||||
<Trans>{item}</Trans>
|
||||
</li>)}
|
||||
</ol>}
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
const Guide = ({ dnsAddresses, t }) => {
|
||||
const tlsAddress = (dnsAddresses && dnsAddresses.filter((item) => item.includes('tls://'))) || '';
|
||||
const httpsAddress = (dnsAddresses && dnsAddresses.filter((item) => item.includes('https://'))) || '';
|
||||
const showDnsPrivacyNotice = httpsAddress.length < 1 && tlsAddress.length < 1;
|
||||
|
||||
const [activeTabLabel, setActiveTabLabel] = useState('Router');
|
||||
|
||||
const tabs = getTabs({
|
||||
tlsAddress,
|
||||
httpsAddress,
|
||||
showDnsPrivacyNotice,
|
||||
t,
|
||||
});
|
||||
|
||||
const activeTab = renderContent(tabs[activeTabLabel], t);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Icons />
|
||||
<Tabs>
|
||||
<div label="Router">
|
||||
<div className="tab__title">
|
||||
<Trans>install_devices_router</Trans>
|
||||
</div>
|
||||
<div className="tab__text">
|
||||
<p>
|
||||
<Trans>install_devices_router_desc</Trans>
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
<Trans>install_devices_router_list_1</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_router_list_2</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_router_list_3</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_router_list_4</Trans>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div label="Windows">
|
||||
<div className="tab__title">Windows</div>
|
||||
<div className="tab__text">
|
||||
<ol>
|
||||
<li>
|
||||
<Trans>install_devices_windows_list_1</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_windows_list_2</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_windows_list_3</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_windows_list_4</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_windows_list_5</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_windows_list_6</Trans>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div label="macOS">
|
||||
<div className="tab__title">macOS</div>
|
||||
<div className="tab__text">
|
||||
<ol>
|
||||
<li>
|
||||
<Trans>install_devices_macos_list_1</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_macos_list_2</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_macos_list_3</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_macos_list_4</Trans>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div label="Android">
|
||||
<div className="tab__title">Android</div>
|
||||
<div className="tab__text">
|
||||
<ol>
|
||||
<li>
|
||||
<Trans>install_devices_android_list_1</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_android_list_2</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_android_list_3</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_android_list_4</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_android_list_5</Trans>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div label="iOS">
|
||||
<div className="tab__title">iOS</div>
|
||||
<div className="tab__text">
|
||||
<ol>
|
||||
<li>
|
||||
<Trans>install_devices_ios_list_1</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_ios_list_2</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_ios_list_3</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>install_devices_ios_list_4</Trans>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div label="dns_privacy" title={props.t('dns_privacy')}>
|
||||
<div className="tab__title">
|
||||
<Trans>dns_privacy</Trans>
|
||||
</div>
|
||||
<div className="tab__text">
|
||||
{tlsAddress && tlsAddress.length > 0 && (
|
||||
<div className="tab__paragraph">
|
||||
<Trans
|
||||
values={{ address: tlsAddress[0] }}
|
||||
components={[
|
||||
<strong key="0">text</strong>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_1
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
{httpsAddress && httpsAddress.length > 0 && (
|
||||
<div className="tab__paragraph">
|
||||
<Trans
|
||||
values={{ address: httpsAddress[0] }}
|
||||
components={[
|
||||
<strong key="0">text</strong>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_2
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
{showDnsPrivacyNotice && (
|
||||
<div className="tab__paragraph">
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://github.com/AdguardTeam/AdguardHome/wiki/Encryption"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_notice
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
{!showDnsPrivacyNotice && (
|
||||
<Fragment>
|
||||
<div className="tab__paragraph">
|
||||
<Trans components={[<p key="0">text</p>]}>
|
||||
setup_dns_privacy_3
|
||||
</Trans>
|
||||
</div>
|
||||
<div className="tab__paragraph">
|
||||
<strong>Android</strong>
|
||||
<ul>
|
||||
<li>
|
||||
<Trans>setup_dns_privacy_android_1</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://adguard.com/adguard-android/overview.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_android_2
|
||||
</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://getintra.org/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_android_3
|
||||
</Trans>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="tab__paragraph">
|
||||
<strong>iOS</strong>
|
||||
<ul>
|
||||
<li>
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://itunes.apple.com/app/id1452162351"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
<code key="1">text</code>,
|
||||
<a
|
||||
href="https://dnscrypt.info/stamps"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="2"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_ios_1
|
||||
</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://adguard.com/adguard-ios/overview.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_ios_2
|
||||
</Trans>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="tab__paragraph">
|
||||
<strong>
|
||||
<Trans>setup_dns_privacy_other_title</Trans>
|
||||
</strong>
|
||||
<ul>
|
||||
<li>
|
||||
<Trans>setup_dns_privacy_other_1</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://github.com/AdguardTeam/dnsproxy"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_other_2
|
||||
</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://github.com/jedisct1/dnscrypt-proxy"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_other_3
|
||||
</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://www.mozilla.org/firefox/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
<code key="1">text</code>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_other_4
|
||||
</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href="https://dnscrypt.info/implementations"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
<a
|
||||
href="https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Clients"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="1"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
]}
|
||||
>
|
||||
setup_dns_privacy_other_5
|
||||
</Trans>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Tabs>
|
||||
<Tabs tabs={tabs} activeTabLabel={activeTabLabel}
|
||||
setActiveTabLabel={setActiveTabLabel}>{activeTab}</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -372,4 +301,15 @@ Guide.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
renderDnsPrivacyList.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
list: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
renderContent.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
list: PropTypes.array.isRequired,
|
||||
getTitle: PropTypes.func,
|
||||
};
|
||||
|
||||
export default withTranslation()(Guide);
|
||||
|
||||
@@ -1,40 +1,34 @@
|
||||
import React, { Component } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
class Tab extends Component {
|
||||
handleClick = () => {
|
||||
this.props.onClick(this.props.label);
|
||||
}
|
||||
const Tab = ({
|
||||
activeTabLabel, label, title, onClick,
|
||||
}) => {
|
||||
const [t] = useTranslation();
|
||||
const handleClick = () => onClick(label);
|
||||
|
||||
render() {
|
||||
const {
|
||||
activeTab,
|
||||
label,
|
||||
title,
|
||||
} = this.props;
|
||||
const tabClass = classnames({
|
||||
tab__control: true,
|
||||
'tab__control--active': activeTabLabel === label,
|
||||
});
|
||||
|
||||
const tabClass = classnames({
|
||||
tab__control: true,
|
||||
'tab__control--active': activeTab === label,
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={tabClass}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<svg className="tab__icon">
|
||||
<use xlinkHref={`#${label.toLowerCase()}`} />
|
||||
</svg>
|
||||
{title || label}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className={tabClass}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<svg className="tab__icon">
|
||||
<use xlinkHref={`#${label.toLowerCase()}`} />
|
||||
</svg>
|
||||
{t(title || label)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Tab.propTypes = {
|
||||
activeTab: PropTypes.string.isRequired,
|
||||
activeTabLabel: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
title: PropTypes.string,
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
}
|
||||
|
||||
.tab__control--active {
|
||||
font-weight: 700;
|
||||
color: #4a4a4a;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -1,68 +1,52 @@
|
||||
import React, { Component } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import Tab from './Tab';
|
||||
import './Tabs.css';
|
||||
|
||||
class Tabs extends Component {
|
||||
state = {
|
||||
activeTab: this.props.children[0].props.label,
|
||||
};
|
||||
const Tabs = (props) => {
|
||||
const {
|
||||
tabs, controlClass, activeTabLabel, setActiveTabLabel, children: activeTab,
|
||||
} = props;
|
||||
|
||||
onClickTabControl = (tab) => {
|
||||
this.setState({ activeTab: tab });
|
||||
}
|
||||
const onClickTabControl = (tabLabel) => setActiveTabLabel(tabLabel);
|
||||
|
||||
render() {
|
||||
const {
|
||||
props: {
|
||||
controlClass,
|
||||
children,
|
||||
},
|
||||
state: {
|
||||
activeTab,
|
||||
},
|
||||
} = this;
|
||||
|
||||
const getControlClass = classnames({
|
||||
tabs__controls: true,
|
||||
[`tabs__controls--${controlClass}`]: controlClass,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="tabs">
|
||||
<div className={getControlClass}>
|
||||
{children.map((child) => {
|
||||
const { label, title } = child.props;
|
||||
const getControlClass = classnames({
|
||||
tabs__controls: true,
|
||||
[`tabs__controls--${controlClass}`]: controlClass,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="tabs">
|
||||
<div className={getControlClass}>
|
||||
{Object.values(tabs)
|
||||
.map((props) => {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
const { title, label = title } = props;
|
||||
return (
|
||||
<Tab
|
||||
key={label}
|
||||
label={label}
|
||||
title={title}
|
||||
activeTab={activeTab}
|
||||
onClick={this.onClickTabControl}
|
||||
activeTabLabel={activeTabLabel}
|
||||
onClick={onClickTabControl}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="tabs__content">
|
||||
{children.map((child) => {
|
||||
if (child.props.label !== activeTab) {
|
||||
return false;
|
||||
}
|
||||
return child.props.children;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
<div className="tabs__content">
|
||||
{activeTab}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Tabs.propTypes = {
|
||||
controlClass: PropTypes.string,
|
||||
children: PropTypes.array.isRequired,
|
||||
tabs: PropTypes.object.isRequired,
|
||||
activeTabLabel: PropTypes.string.isRequired,
|
||||
setActiveTabLabel: PropTypes.func.isRequired,
|
||||
children: PropTypes.element.isRequired,
|
||||
};
|
||||
|
||||
export default Tabs;
|
||||
|
||||
Reference in New Issue
Block a user