summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOliver <oliver@mohlin.dev>2025-07-25 11:18:49 +0200
committerTobias Järvelöv <tobias.jarvelov@mullvad.net>2025-09-22 12:35:43 +0200
commit44b7244df4ae14bceca6cbcc717ce7132680c942 (patch)
tree00053110ed047ee19d56e0bfda083109683073d9
parent5e2d8957bd305d3ced615e9d8afb1ce35b3157dc (diff)
downloadmullvadvpn-44b7244df4ae14bceca6cbcc717ce7132680c942.tar.xz
mullvadvpn-44b7244df4ae14bceca6cbcc717ce7132680c942.zip
Move DnsBlockers component to separate folder
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/VpnSettingsView.tsx271
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/DnsBlockers.tsx75
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-ads/BlockAds.tsx40
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-ads/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-adult-content/BlockAdultContent.tsx40
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-adult-content/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-gambling/BlockGambling.tsx40
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-gambling/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-malware/BlockMalware.tsx56
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-malware/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-social-media/BlockSocialMedia.tsx66
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-social-media/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-trackers/BlockTrackers.tsx40
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-trackers/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/index.ts6
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/hooks/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/hooks/useDns.ts24
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/index.ts1
19 files changed, 399 insertions, 268 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/VpnSettingsView.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/VpnSettingsView.tsx
index d611b33b63..50a7f004a3 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/VpnSettingsView.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/VpnSettingsView.tsx
@@ -3,16 +3,15 @@ import { sprintf } from 'sprintf-js';
import styled from 'styled-components';
import { strings, urls } from '../../../../shared/constants';
-import { IDnsOptions, TunnelProtocol } from '../../../../shared/daemon-rpc-types';
+import { TunnelProtocol } from '../../../../shared/daemon-rpc-types';
import { messages } from '../../../../shared/gettext';
import log from '../../../../shared/logging';
import { RoutePath } from '../../../../shared/routes';
import { useAppContext } from '../../../context';
import { Button } from '../../../lib/components';
import { useRelaySettingsUpdater } from '../../../lib/constraint-updater';
-import { colors, spacings } from '../../../lib/foundations';
+import { spacings } from '../../../lib/foundations';
import { useHistory } from '../../../lib/history';
-import { formatHtml } from '../../../lib/html-formatter';
import { useTunnelProtocol } from '../../../lib/relay-settings-hooks';
import { useBoolean } from '../../../lib/utility-hooks';
import { RelaySettingsRedux } from '../../../redux/settings/reducers';
@@ -43,24 +42,12 @@ import { NavigationContainer } from '../../NavigationContainer';
import { NavigationListItem } from '../../NavigationListItem';
import { NavigationScrollbars } from '../../NavigationScrollbars';
import SettingsHeader, { HeaderTitle } from '../../SettingsHeader';
-import { AllowLan, AutoConnect, AutoStart } from './components';
+import { AllowLan, AutoConnect, AutoStart, DnsBlockers } from './components';
const StyledInfoButton = styled(InfoButton)({
marginRight: spacings.medium,
});
-const StyledTitleLabel = styled(Cell.SectionTitle)({
- flex: 1,
-});
-
-const StyledSectionItem = styled(Cell.Container)({
- backgroundColor: colors.blue40,
-});
-
-const IndentedValueLabel = styled(Cell.ValueLabel)({
- marginLeft: spacings.medium,
-});
-
export function VpnSettingsView() {
const { pop } = useHistory();
@@ -131,258 +118,6 @@ export function VpnSettingsView() {
);
}
-function useDns(setting: keyof IDnsOptions['defaultOptions']) {
- const dns = useSelector((state) => state.settings.dns);
- const { setDnsOptions } = useAppContext();
-
- const updateBlockSetting = useCallback(
- (enabled: boolean) =>
- setDnsOptions({
- ...dns,
- defaultOptions: {
- ...dns.defaultOptions,
- [setting]: enabled,
- },
- }),
- [setting, dns, setDnsOptions],
- );
-
- return [dns, updateBlockSetting] as const;
-}
-
-function DnsBlockers() {
- const dns = useSelector((state) => state.settings.dns);
- const customDnsFeatureName = messages.pgettext('vpn-settings-view', 'Use custom DNS server');
-
- const title = (
- <>
- <StyledTitleLabel as="label" disabled={dns.state === 'custom'}>
- {messages.pgettext('vpn-settings-view', 'DNS content blockers')}
- </StyledTitleLabel>
- <StyledInfoButton>
- <ModalMessage>
- {messages.pgettext(
- 'vpn-settings-view',
- 'When this feature is enabled it stops the device from contacting certain domains or websites known for distributing ads, malware, trackers and more.',
- )}
- </ModalMessage>
- <ModalMessage>
- {messages.pgettext(
- 'vpn-settings-view',
- 'This might cause issues on certain websites, services, and apps.',
- )}
- </ModalMessage>
- <ModalMessage>
- {formatHtml(
- sprintf(
- messages.pgettext(
- 'vpn-settings-view',
- 'Attention: this setting cannot be used in combination with <b>%(customDnsFeatureName)s</b>',
- ),
- { customDnsFeatureName },
- ),
- )}
- </ModalMessage>
- </StyledInfoButton>
- </>
- );
-
- return (
- <Cell.ExpandableSection sectionTitle={title} expandableId="dns-blockers">
- <BlockAds />
- <BlockTrackers />
- <BlockMalware />
- <BlockGambling />
- <BlockAdultContent />
- <BlockSocialMedia />
- </Cell.ExpandableSection>
- );
-}
-
-function BlockAds() {
- const [dns, setBlockAds] = useDns('blockAds');
-
- return (
- <AriaInputGroup>
- <StyledSectionItem disabled={dns.state === 'custom'}>
- <AriaLabel>
- <IndentedValueLabel>
- {
- // TRANSLATORS: Label for settings that enables ad blocking.
- messages.pgettext('vpn-settings-view', 'Ads')
- }
- </IndentedValueLabel>
- </AriaLabel>
- <AriaInput>
- <Cell.Switch
- isOn={dns.state === 'default' && dns.defaultOptions.blockAds}
- onChange={setBlockAds}
- />
- </AriaInput>
- </StyledSectionItem>
- </AriaInputGroup>
- );
-}
-
-function BlockTrackers() {
- const [dns, setBlockTrackers] = useDns('blockTrackers');
-
- return (
- <AriaInputGroup>
- <StyledSectionItem disabled={dns.state === 'custom'}>
- <AriaLabel>
- <IndentedValueLabel>
- {
- // TRANSLATORS: Label for settings that enables tracker blocking.
- messages.pgettext('vpn-settings-view', 'Trackers')
- }
- </IndentedValueLabel>
- </AriaLabel>
- <AriaInput>
- <Cell.Switch
- isOn={dns.state === 'default' && dns.defaultOptions.blockTrackers}
- onChange={setBlockTrackers}
- />
- </AriaInput>
- </StyledSectionItem>
- </AriaInputGroup>
- );
-}
-
-function BlockMalware() {
- const [dns, setBlockMalware] = useDns('blockMalware');
-
- return (
- <AriaInputGroup>
- <StyledSectionItem disabled={dns.state === 'custom'}>
- <AriaLabel>
- <IndentedValueLabel>
- {
- // TRANSLATORS: Label for settings that enables malware blocking.
- messages.pgettext('vpn-settings-view', 'Malware')
- }
- </IndentedValueLabel>
- </AriaLabel>
- <AriaDetails>
- <StyledInfoButton>
- <ModalMessage>
- {messages.pgettext(
- 'vpn-settings-view',
- 'Warning: The malware blocker is not an anti-virus and should not be treated as such, this is just an extra layer of protection.',
- )}
- </ModalMessage>
- </StyledInfoButton>
- </AriaDetails>
- <AriaInput>
- <Cell.Switch
- isOn={dns.state === 'default' && dns.defaultOptions.blockMalware}
- onChange={setBlockMalware}
- />
- </AriaInput>
- </StyledSectionItem>
- </AriaInputGroup>
- );
-}
-
-function BlockGambling() {
- const [dns, setBlockGambling] = useDns('blockGambling');
-
- return (
- <AriaInputGroup>
- <StyledSectionItem disabled={dns.state === 'custom'}>
- <AriaLabel>
- <IndentedValueLabel>
- {
- // TRANSLATORS: Label for settings that enables block of gamling related websites.
- messages.pgettext('vpn-settings-view', 'Gambling')
- }
- </IndentedValueLabel>
- </AriaLabel>
- <AriaInput>
- <Cell.Switch
- isOn={dns.state === 'default' && dns.defaultOptions.blockGambling}
- onChange={setBlockGambling}
- />
- </AriaInput>
- </StyledSectionItem>
- </AriaInputGroup>
- );
-}
-
-function BlockAdultContent() {
- const [dns, setBlockAdultContent] = useDns('blockAdultContent');
-
- return (
- <AriaInputGroup>
- <StyledSectionItem disabled={dns.state === 'custom'}>
- <AriaLabel>
- <IndentedValueLabel>
- {
- // TRANSLATORS: Label for settings that enables block of adult content.
- messages.pgettext('vpn-settings-view', 'Adult content')
- }
- </IndentedValueLabel>
- </AriaLabel>
- <AriaInput>
- <Cell.Switch
- isOn={dns.state === 'default' && dns.defaultOptions.blockAdultContent}
- onChange={setBlockAdultContent}
- />
- </AriaInput>
- </StyledSectionItem>
- </AriaInputGroup>
- );
-}
-
-function BlockSocialMedia() {
- const [dns, setBlockSocialMedia] = useDns('blockSocialMedia');
-
- return (
- <AriaInputGroup>
- <StyledSectionItem disabled={dns.state === 'custom'}>
- <AriaLabel>
- <IndentedValueLabel>
- {
- // TRANSLATORS: Label for settings that enables block of social media.
- messages.pgettext('vpn-settings-view', 'Social media')
- }
- </IndentedValueLabel>
- </AriaLabel>
- <AriaInput>
- <Cell.Switch
- isOn={dns.state === 'default' && dns.defaultOptions.blockSocialMedia}
- onChange={setBlockSocialMedia}
- />
- </AriaInput>
- </StyledSectionItem>
- {dns.state === 'custom' && <CustomDnsEnabledFooter />}
- </AriaInputGroup>
- );
-}
-
-function CustomDnsEnabledFooter() {
- const customDnsFeatureName = messages.pgettext('vpn-settings-view', 'Use custom DNS server');
-
- // TRANSLATORS: This is displayed when the custom DNS setting is turned on which makes the block
- // TRANSLATORS: ads/trackers settings disabled. The text enclosed in "<b></b>" will appear bold.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(customDnsFeatureName)s - The name displayed next to the custom DNS toggle.
- const blockingDisabledText = messages.pgettext(
- 'vpn-settings-view',
- 'Disable <b>%(customDnsFeatureName)s</b> below to activate these settings.',
- );
-
- return (
- <Cell.CellFooter>
- <AriaDescription>
- <Cell.CellFooterText>
- {formatHtml(sprintf(blockingDisabledText, { customDnsFeatureName }))}
- </Cell.CellFooterText>
- </AriaDescription>
- </Cell.CellFooter>
- );
-}
-
function EnableIpv6() {
const enableIpv6 = useSelector((state) => state.settings.enableIpv6);
const { setEnableIpv6: setEnableIpv6Impl } = useAppContext();
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/DnsBlockers.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/DnsBlockers.tsx
new file mode 100644
index 0000000000..bb31589b75
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/DnsBlockers.tsx
@@ -0,0 +1,75 @@
+import { sprintf } from 'sprintf-js';
+import styled from 'styled-components';
+
+import { messages } from '../../../../../../shared/gettext';
+import { spacings } from '../../../../../lib/foundations';
+import { formatHtml } from '../../../../../lib/html-formatter';
+import { useSelector } from '../../../../../redux/store';
+import * as Cell from '../../../../cell';
+import InfoButton from '../../../../InfoButton';
+import { ModalMessage } from '../../../../Modal';
+import {
+ BlockAds,
+ BlockAdultContent,
+ BlockGambling,
+ BlockMalware,
+ BlockSocialMedia,
+ BlockTrackers,
+} from './components';
+
+const StyledInfoButton = styled(InfoButton)({
+ marginRight: spacings.medium,
+});
+
+const StyledTitleLabel = styled(Cell.SectionTitle)({
+ flex: 1,
+});
+
+export function DnsBlockers() {
+ const dns = useSelector((state) => state.settings.dns);
+ const customDnsFeatureName = messages.pgettext('vpn-settings-view', 'Use custom DNS server');
+
+ const title = (
+ <>
+ <StyledTitleLabel as="label" disabled={dns.state === 'custom'}>
+ {messages.pgettext('vpn-settings-view', 'DNS content blockers')}
+ </StyledTitleLabel>
+ <StyledInfoButton>
+ <ModalMessage>
+ {messages.pgettext(
+ 'vpn-settings-view',
+ 'When this feature is enabled it stops the device from contacting certain domains or websites known for distributing ads, malware, trackers and more.',
+ )}
+ </ModalMessage>
+ <ModalMessage>
+ {messages.pgettext(
+ 'vpn-settings-view',
+ 'This might cause issues on certain websites, services, and apps.',
+ )}
+ </ModalMessage>
+ <ModalMessage>
+ {formatHtml(
+ sprintf(
+ messages.pgettext(
+ 'vpn-settings-view',
+ 'Attention: this setting cannot be used in combination with <b>%(customDnsFeatureName)s</b>',
+ ),
+ { customDnsFeatureName },
+ ),
+ )}
+ </ModalMessage>
+ </StyledInfoButton>
+ </>
+ );
+
+ return (
+ <Cell.ExpandableSection sectionTitle={title} expandableId="dns-blockers">
+ <BlockAds />
+ <BlockTrackers />
+ <BlockMalware />
+ <BlockGambling />
+ <BlockAdultContent />
+ <BlockSocialMedia />
+ </Cell.ExpandableSection>
+ );
+}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-ads/BlockAds.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-ads/BlockAds.tsx
new file mode 100644
index 0000000000..a4925def63
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-ads/BlockAds.tsx
@@ -0,0 +1,40 @@
+import styled from 'styled-components';
+
+import { messages } from '../../../../../../../../shared/gettext';
+import { colors, spacings } from '../../../../../../../lib/foundations';
+import { AriaInput, AriaInputGroup, AriaLabel } from '../../../../../../AriaGroup';
+import * as Cell from '../../../../../../cell';
+import { useDns } from '../../hooks';
+
+const StyledSectionItem = styled(Cell.Container)({
+ backgroundColor: colors.blue40,
+});
+
+const IndentedValueLabel = styled(Cell.ValueLabel)({
+ marginLeft: spacings.medium,
+});
+
+export function BlockAds() {
+ const [dns, setBlockAds] = useDns('blockAds');
+
+ return (
+ <AriaInputGroup>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
+ <AriaLabel>
+ <IndentedValueLabel>
+ {
+ // TRANSLATORS: Label for settings that enables ad blocking.
+ messages.pgettext('vpn-settings-view', 'Ads')
+ }
+ </IndentedValueLabel>
+ </AriaLabel>
+ <AriaInput>
+ <Cell.Switch
+ isOn={dns.state === 'default' && dns.defaultOptions.blockAds}
+ onChange={setBlockAds}
+ />
+ </AriaInput>
+ </StyledSectionItem>
+ </AriaInputGroup>
+ );
+}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-ads/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-ads/index.ts
new file mode 100644
index 0000000000..ee78af1dc2
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-ads/index.ts
@@ -0,0 +1 @@
+export * from './BlockAds';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-adult-content/BlockAdultContent.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-adult-content/BlockAdultContent.tsx
new file mode 100644
index 0000000000..a3d6a86519
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-adult-content/BlockAdultContent.tsx
@@ -0,0 +1,40 @@
+import styled from 'styled-components';
+
+import { messages } from '../../../../../../../../shared/gettext';
+import { colors, spacings } from '../../../../../../../lib/foundations';
+import { AriaInput, AriaInputGroup, AriaLabel } from '../../../../../../AriaGroup';
+import * as Cell from '../../../../../../cell';
+import { useDns } from '../../hooks';
+
+const StyledSectionItem = styled(Cell.Container)({
+ backgroundColor: colors.blue40,
+});
+
+const IndentedValueLabel = styled(Cell.ValueLabel)({
+ marginLeft: spacings.medium,
+});
+
+export function BlockAdultContent() {
+ const [dns, setBlockAdultContent] = useDns('blockAdultContent');
+
+ return (
+ <AriaInputGroup>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
+ <AriaLabel>
+ <IndentedValueLabel>
+ {
+ // TRANSLATORS: Label for settings that enables block of adult content.
+ messages.pgettext('vpn-settings-view', 'Adult content')
+ }
+ </IndentedValueLabel>
+ </AriaLabel>
+ <AriaInput>
+ <Cell.Switch
+ isOn={dns.state === 'default' && dns.defaultOptions.blockAdultContent}
+ onChange={setBlockAdultContent}
+ />
+ </AriaInput>
+ </StyledSectionItem>
+ </AriaInputGroup>
+ );
+}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-adult-content/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-adult-content/index.ts
new file mode 100644
index 0000000000..42c8ec5853
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-adult-content/index.ts
@@ -0,0 +1 @@
+export * from './BlockAdultContent';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-gambling/BlockGambling.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-gambling/BlockGambling.tsx
new file mode 100644
index 0000000000..7d16198520
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-gambling/BlockGambling.tsx
@@ -0,0 +1,40 @@
+import styled from 'styled-components';
+
+import { messages } from '../../../../../../../../shared/gettext';
+import { colors, spacings } from '../../../../../../../lib/foundations';
+import { AriaInput, AriaInputGroup, AriaLabel } from '../../../../../../AriaGroup';
+import * as Cell from '../../../../../../cell';
+import { useDns } from '../../hooks';
+
+const StyledSectionItem = styled(Cell.Container)({
+ backgroundColor: colors.blue40,
+});
+
+const IndentedValueLabel = styled(Cell.ValueLabel)({
+ marginLeft: spacings.medium,
+});
+
+export function BlockGambling() {
+ const [dns, setBlockGambling] = useDns('blockGambling');
+
+ return (
+ <AriaInputGroup>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
+ <AriaLabel>
+ <IndentedValueLabel>
+ {
+ // TRANSLATORS: Label for settings that enables block of gamling related websites.
+ messages.pgettext('vpn-settings-view', 'Gambling')
+ }
+ </IndentedValueLabel>
+ </AriaLabel>
+ <AriaInput>
+ <Cell.Switch
+ isOn={dns.state === 'default' && dns.defaultOptions.blockGambling}
+ onChange={setBlockGambling}
+ />
+ </AriaInput>
+ </StyledSectionItem>
+ </AriaInputGroup>
+ );
+}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-gambling/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-gambling/index.ts
new file mode 100644
index 0000000000..fb76afe26a
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-gambling/index.ts
@@ -0,0 +1 @@
+export * from './BlockGambling';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-malware/BlockMalware.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-malware/BlockMalware.tsx
new file mode 100644
index 0000000000..5e5cfb03c1
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-malware/BlockMalware.tsx
@@ -0,0 +1,56 @@
+import styled from 'styled-components';
+
+import { messages } from '../../../../../../../../shared/gettext';
+import { colors, spacings } from '../../../../../../../lib/foundations';
+import { AriaDetails, AriaInput, AriaInputGroup, AriaLabel } from '../../../../../../AriaGroup';
+import * as Cell from '../../../../../../cell';
+import InfoButton from '../../../../../../InfoButton';
+import { ModalMessage } from '../../../../../../Modal';
+import { useDns } from '../../hooks';
+
+const StyledInfoButton = styled(InfoButton)({
+ marginRight: spacings.medium,
+});
+
+const StyledSectionItem = styled(Cell.Container)({
+ backgroundColor: colors.blue40,
+});
+
+const IndentedValueLabel = styled(Cell.ValueLabel)({
+ marginLeft: spacings.medium,
+});
+
+export function BlockMalware() {
+ const [dns, setBlockMalware] = useDns('blockMalware');
+
+ return (
+ <AriaInputGroup>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
+ <AriaLabel>
+ <IndentedValueLabel>
+ {
+ // TRANSLATORS: Label for settings that enables malware blocking.
+ messages.pgettext('vpn-settings-view', 'Malware')
+ }
+ </IndentedValueLabel>
+ </AriaLabel>
+ <AriaDetails>
+ <StyledInfoButton>
+ <ModalMessage>
+ {messages.pgettext(
+ 'vpn-settings-view',
+ 'Warning: The malware blocker is not an anti-virus and should not be treated as such, this is just an extra layer of protection.',
+ )}
+ </ModalMessage>
+ </StyledInfoButton>
+ </AriaDetails>
+ <AriaInput>
+ <Cell.Switch
+ isOn={dns.state === 'default' && dns.defaultOptions.blockMalware}
+ onChange={setBlockMalware}
+ />
+ </AriaInput>
+ </StyledSectionItem>
+ </AriaInputGroup>
+ );
+}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-malware/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-malware/index.ts
new file mode 100644
index 0000000000..e42f64bef1
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-malware/index.ts
@@ -0,0 +1 @@
+export * from './BlockMalware';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-social-media/BlockSocialMedia.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-social-media/BlockSocialMedia.tsx
new file mode 100644
index 0000000000..f613f16efd
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-social-media/BlockSocialMedia.tsx
@@ -0,0 +1,66 @@
+import { sprintf } from 'sprintf-js';
+import styled from 'styled-components';
+
+import { messages } from '../../../../../../../../shared/gettext';
+import { colors, spacings } from '../../../../../../../lib/foundations';
+import { formatHtml } from '../../../../../../../lib/html-formatter';
+import { AriaDescription, AriaInput, AriaInputGroup, AriaLabel } from '../../../../../../AriaGroup';
+import * as Cell from '../../../../../../cell';
+import { useDns } from '../../hooks';
+
+const StyledSectionItem = styled(Cell.Container)({
+ backgroundColor: colors.blue40,
+});
+
+const IndentedValueLabel = styled(Cell.ValueLabel)({
+ marginLeft: spacings.medium,
+});
+
+export function BlockSocialMedia() {
+ const [dns, setBlockSocialMedia] = useDns('blockSocialMedia');
+
+ return (
+ <AriaInputGroup>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
+ <AriaLabel>
+ <IndentedValueLabel>
+ {
+ // TRANSLATORS: Label for settings that enables block of social media.
+ messages.pgettext('vpn-settings-view', 'Social media')
+ }
+ </IndentedValueLabel>
+ </AriaLabel>
+ <AriaInput>
+ <Cell.Switch
+ isOn={dns.state === 'default' && dns.defaultOptions.blockSocialMedia}
+ onChange={setBlockSocialMedia}
+ />
+ </AriaInput>
+ </StyledSectionItem>
+ {dns.state === 'custom' && <CustomDnsEnabledFooter />}
+ </AriaInputGroup>
+ );
+}
+
+function CustomDnsEnabledFooter() {
+ const customDnsFeatureName = messages.pgettext('vpn-settings-view', 'Use custom DNS server');
+
+ // TRANSLATORS: This is displayed when the custom DNS setting is turned on which makes the block
+ // TRANSLATORS: ads/trackers settings disabled. The text enclosed in "<b></b>" will appear bold.
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(customDnsFeatureName)s - The name displayed next to the custom DNS toggle.
+ const blockingDisabledText = messages.pgettext(
+ 'vpn-settings-view',
+ 'Disable <b>%(customDnsFeatureName)s</b> below to activate these settings.',
+ );
+
+ return (
+ <Cell.CellFooter>
+ <AriaDescription>
+ <Cell.CellFooterText>
+ {formatHtml(sprintf(blockingDisabledText, { customDnsFeatureName }))}
+ </Cell.CellFooterText>
+ </AriaDescription>
+ </Cell.CellFooter>
+ );
+}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-social-media/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-social-media/index.ts
new file mode 100644
index 0000000000..4c558c7e09
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-social-media/index.ts
@@ -0,0 +1 @@
+export * from './BlockSocialMedia';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-trackers/BlockTrackers.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-trackers/BlockTrackers.tsx
new file mode 100644
index 0000000000..340da4bd5d
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-trackers/BlockTrackers.tsx
@@ -0,0 +1,40 @@
+import styled from 'styled-components';
+
+import { messages } from '../../../../../../../../shared/gettext';
+import { colors, spacings } from '../../../../../../../lib/foundations';
+import { AriaInput, AriaInputGroup, AriaLabel } from '../../../../../../AriaGroup';
+import * as Cell from '../../../../../../cell';
+import { useDns } from '../../hooks';
+
+const StyledSectionItem = styled(Cell.Container)({
+ backgroundColor: colors.blue40,
+});
+
+const IndentedValueLabel = styled(Cell.ValueLabel)({
+ marginLeft: spacings.medium,
+});
+
+export function BlockTrackers() {
+ const [dns, setBlockTrackers] = useDns('blockTrackers');
+
+ return (
+ <AriaInputGroup>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
+ <AriaLabel>
+ <IndentedValueLabel>
+ {
+ // TRANSLATORS: Label for settings that enables tracker blocking.
+ messages.pgettext('vpn-settings-view', 'Trackers')
+ }
+ </IndentedValueLabel>
+ </AriaLabel>
+ <AriaInput>
+ <Cell.Switch
+ isOn={dns.state === 'default' && dns.defaultOptions.blockTrackers}
+ onChange={setBlockTrackers}
+ />
+ </AriaInput>
+ </StyledSectionItem>
+ </AriaInputGroup>
+ );
+}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-trackers/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-trackers/index.ts
new file mode 100644
index 0000000000..cf9d2db210
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/block-trackers/index.ts
@@ -0,0 +1 @@
+export * from './BlockTrackers';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/index.ts
new file mode 100644
index 0000000000..f63c378e58
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/components/index.ts
@@ -0,0 +1,6 @@
+export * from './block-ads';
+export * from './block-adult-content';
+export * from './block-gambling';
+export * from './block-malware';
+export * from './block-social-media';
+export * from './block-trackers';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/hooks/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/hooks/index.ts
new file mode 100644
index 0000000000..1e0f813a16
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/hooks/index.ts
@@ -0,0 +1 @@
+export * from './useDns';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/hooks/useDns.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/hooks/useDns.ts
new file mode 100644
index 0000000000..096427fc69
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/hooks/useDns.ts
@@ -0,0 +1,24 @@
+import { useCallback } from 'react';
+
+import { IDnsOptions } from '../../../../../../../shared/daemon-rpc-types';
+import { useAppContext } from '../../../../../../context';
+import { useSelector } from '../../../../../../redux/store';
+
+export function useDns(setting: keyof IDnsOptions['defaultOptions']) {
+ const dns = useSelector((state) => state.settings.dns);
+ const { setDnsOptions } = useAppContext();
+
+ const updateBlockSetting = useCallback(
+ (enabled: boolean) =>
+ setDnsOptions({
+ ...dns,
+ defaultOptions: {
+ ...dns.defaultOptions,
+ [setting]: enabled,
+ },
+ }),
+ [setting, dns, setDnsOptions],
+ );
+
+ return [dns, updateBlockSetting] as const;
+}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/index.ts
new file mode 100644
index 0000000000..07a2ca3108
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/dns-blockers/index.ts
@@ -0,0 +1 @@
+export * from './DnsBlockers';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/index.ts b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/index.ts
index 085052f389..14b08e40ba 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/index.ts
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/vpn-settings/components/index.ts
@@ -1,3 +1,4 @@
export * from './allow-lan';
export * from './auto-connect';
export * from './auto-start';
+export * from './dns-blockers';