summaryrefslogtreecommitdiffhomepage
path: root/desktop
diff options
context:
space:
mode:
authorOliver <oliver@mohlin.dev>2025-02-21 13:11:27 +0100
committerTobias Järvelöv <tobias.jarvelov@mullvad.net>2025-05-28 10:28:14 +0200
commit17d23f45692d95deb06ce366c6743b8c38f84cb7 (patch)
tree67ad903841ca3d627caac7b8f04a9cc782037497 /desktop
parente8c12071375ee7147cc2b50fa2790d0060cfa308 (diff)
downloadmullvadvpn-17d23f45692d95deb06ce366c6743b8c38f84cb7.tar.xz
mullvadvpn-17d23f45692d95deb06ce366c6743b8c38f84cb7.zip
Use ListItem components in settings view
Diffstat (limited to 'desktop')
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/Settings.tsx213
1 files changed, 114 insertions, 99 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/Settings.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/Settings.tsx
index 53dded0411..a729a56d1f 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/Settings.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/Settings.tsx
@@ -1,14 +1,15 @@
-import { useCallback } from 'react';
+import styled from 'styled-components';
import { strings } from '../../shared/constants';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
-import { Button, TitleBig } from '../lib/components';
+import { Button, Flex, Icon, TitleBig } from '../lib/components';
+import { Dot } from '../lib/components/dot';
+import { ListItem } from '../lib/components/list-item';
import { useHistory } from '../lib/history';
import { RoutePath } from '../lib/routes';
import { useSelector } from '../redux/store';
import { AppNavigationHeader } from './';
-import * as Cell from './cell';
import { BackAction } from './KeyboardNavigation';
import {
ButtonStack,
@@ -16,13 +17,17 @@ import {
Layout,
SettingsContainer,
SettingsContent,
- SettingsGroup,
SettingsNavigationScrollbars,
SettingsStack,
} from './Layout';
import { NavigationContainer } from './NavigationContainer';
+import { NavigationListItem } from './NavigationListItem';
import SettingsHeader from './SettingsHeader';
+export const StyledFlex = styled(Flex).attrs({ $flexDirection: 'column' })`
+ gap: 1px;
+`;
+
export default function Support() {
const history = useHistory();
@@ -48,45 +53,38 @@ export default function Support() {
<SettingsNavigationScrollbars fillContainer>
<SettingsContent>
<SettingsHeader>
- <TitleBig>{messages.pgettext('navigation-bar', 'Settings')}</TitleBig>
+ <TitleBig>
+ {
+ // TRANSLATORS: Main title for settings view
+ messages.pgettext('navigation-bar', 'Settings')
+ }
+ </TitleBig>
</SettingsHeader>
<SettingsStack>
{showSubSettings ? (
<>
- <SettingsGroup>
- <DaitaButton />
- <MultihopButton />
- <VpnSettingsButton />
- <UserInterfaceSettingsButton />
- </SettingsGroup>
+ <StyledFlex>
+ <DaitaListItem />
+ <MultihopListItem />
+ <VpnSettingsListItem />
+ <UserInterfaceSettingsListItem />
+ </StyledFlex>
- {showSplitTunneling && (
- <SettingsGroup>
- <SplitTunnelingButton />
- </SettingsGroup>
- )}
+ {showSplitTunneling && <SplitTunnelingListItem />}
</>
) : (
- <SettingsGroup>
- <UserInterfaceSettingsButton />
- </SettingsGroup>
+ <UserInterfaceSettingsListItem />
)}
- <SettingsGroup>
- <ApiAccessMethodsButton />
- </SettingsGroup>
+ <ApiAccessMethodsButton />
- <SettingsGroup>
- <SupportButton />
- <AppInfoButton />
- </SettingsGroup>
+ <StyledFlex>
+ <SupportListItem />
+ <AppInfoListItem />
+ </StyledFlex>
- {window.env.development && (
- <SettingsGroup>
- <DebugButton />
- </SettingsGroup>
- )}
+ {window.env.development && <DebugButton />}
</SettingsStack>
<Footer>
<ButtonStack>
@@ -102,133 +100,150 @@ export default function Support() {
);
}
-function UserInterfaceSettingsButton() {
- const history = useHistory();
- const navigate = useCallback(() => history.push(RoutePath.userInterfaceSettings), [history]);
-
+function UserInterfaceSettingsListItem() {
return (
- <Cell.CellNavigationButton onClick={navigate}>
- <Cell.Label>
+ <NavigationListItem to={RoutePath.userInterfaceSettings}>
+ <ListItem.Label>
{
// TRANSLATORS: Navigation button to the 'User interface settings' view
messages.pgettext('settings-view', 'User interface settings')
}
- </Cell.Label>
- </Cell.CellNavigationButton>
+ </ListItem.Label>
+ <Icon icon="chevron-right" />
+ </NavigationListItem>
);
}
-function MultihopButton() {
- const history = useHistory();
- const navigate = useCallback(() => history.push(RoutePath.multihopSettings), [history]);
+function MultihopListItem() {
const relaySettings = useSelector((state) => state.settings.relaySettings);
const multihop = 'normal' in relaySettings ? relaySettings.normal.wireguard.useMultihop : false;
const unavailable =
'normal' in relaySettings ? relaySettings.normal.tunnelProtocol === 'openvpn' : true;
return (
- <Cell.CellNavigationButton onClick={navigate}>
- <Cell.Label>{messages.pgettext('settings-view', 'Multihop')}</Cell.Label>
- <Cell.SubText>
- {multihop && !unavailable ? messages.gettext('On') : messages.gettext('Off')}
- </Cell.SubText>
- </Cell.CellNavigationButton>
+ <NavigationListItem to={RoutePath.multihopSettings}>
+ <ListItem.Label>{messages.pgettext('settings-view', 'Multihop')}</ListItem.Label>
+ <ListItem.Group>
+ <ListItem.Text>
+ {multihop && !unavailable ? messages.gettext('On') : messages.gettext('Off')}
+ </ListItem.Text>
+ <Icon icon="chevron-right" />
+ </ListItem.Group>
+ </NavigationListItem>
);
}
-function DaitaButton() {
- const history = useHistory();
- const navigate = useCallback(() => history.push(RoutePath.daitaSettings), [history]);
+function DaitaListItem() {
const daita = useSelector((state) => state.settings.wireguard.daita?.enabled ?? false);
const relaySettings = useSelector((state) => state.settings.relaySettings);
const unavailable =
'normal' in relaySettings ? relaySettings.normal.tunnelProtocol === 'openvpn' : true;
return (
- <Cell.CellNavigationButton onClick={navigate}>
- <Cell.Label>{strings.daita}</Cell.Label>
- <Cell.SubText>
- {daita && !unavailable ? messages.gettext('On') : messages.gettext('Off')}
- </Cell.SubText>
- </Cell.CellNavigationButton>
+ <NavigationListItem to={RoutePath.daitaSettings}>
+ <ListItem.Label>{strings.daita}</ListItem.Label>
+ <ListItem.Group>
+ <ListItem.Text>
+ {daita && !unavailable ? messages.gettext('On') : messages.gettext('Off')}
+ </ListItem.Text>
+ <Icon icon="chevron-right" />
+ </ListItem.Group>
+ </NavigationListItem>
);
}
-function VpnSettingsButton() {
- const history = useHistory();
- const navigate = useCallback(() => history.push(RoutePath.vpnSettings), [history]);
-
+function VpnSettingsListItem() {
return (
- <Cell.CellNavigationButton onClick={navigate}>
- <Cell.Label>
+ <NavigationListItem to={RoutePath.vpnSettings}>
+ <ListItem.Label>
{
// TRANSLATORS: Navigation button to the 'VPN settings' view
messages.pgettext('settings-view', 'VPN settings')
}
- </Cell.Label>
- </Cell.CellNavigationButton>
+ </ListItem.Label>
+ <Icon icon="chevron-right" />
+ </NavigationListItem>
);
}
-function SplitTunnelingButton() {
- const history = useHistory();
- const navigate = useCallback(() => history.push(RoutePath.splitTunneling), [history]);
-
+function SplitTunnelingListItem() {
return (
- <Cell.CellNavigationButton onClick={navigate}>
- <Cell.Label>{strings.splitTunneling}</Cell.Label>
- </Cell.CellNavigationButton>
+ <NavigationListItem to={RoutePath.splitTunneling}>
+ <ListItem.Label>{strings.splitTunneling}</ListItem.Label>
+ <Icon icon="chevron-right" />
+ </NavigationListItem>
);
}
function ApiAccessMethodsButton() {
- const history = useHistory();
- const navigate = useCallback(() => history.push(RoutePath.apiAccessMethods), [history]);
-
return (
- <Cell.CellNavigationButton onClick={navigate}>
- <Cell.Label>
+ <NavigationListItem to={RoutePath.apiAccessMethods}>
+ <ListItem.Label>
{
// TRANSLATORS: Navigation button to the 'API access methods' view
messages.pgettext('settings-view', 'API access')
}
- </Cell.Label>
- </Cell.CellNavigationButton>
+ </ListItem.Label>
+ <Icon icon="chevron-right" />
+ </NavigationListItem>
);
}
-function AppInfoButton() {
- const history = useHistory();
- const navigate = useCallback(() => history.push(RoutePath.appInfo), [history]);
+const StyledText = styled(ListItem.Text)`
+ margin-top: -4px;
+`;
+
+function AppInfoListItem() {
const appVersion = useSelector((state) => state.version.current);
+ const suggestedUpgrade = useSelector((state) => state.version.suggestedUpgrade);
return (
- <Cell.CellNavigationButton onClick={navigate}>
- <Cell.Label>{messages.pgettext('settings-view', 'App info')}</Cell.Label>
- <Cell.SubText>{appVersion}</Cell.SubText>
- </Cell.CellNavigationButton>
+ <NavigationListItem to={RoutePath.appInfo}>
+ <Flex $flexDirection="column">
+ <ListItem.Label>
+ {
+ // TRANSLATORS: Navigation button to the 'App info' view
+ messages.pgettext('settings-view', 'App info')
+ }
+ </ListItem.Label>
+ {suggestedUpgrade && (
+ <StyledText variant="footnoteMini">
+ {
+ // TRANSLATORS: Label for the app info list item indicating that an update is available and can be downloaded
+ messages.pgettext('settings-view', 'Update available')
+ }
+ </StyledText>
+ )}
+ </Flex>
+ <ListItem.Group>
+ <ListItem.Text>{appVersion}</ListItem.Text>
+ {suggestedUpgrade && <Dot variant="warning" size="small" />}
+ <Icon icon="chevron-right" />
+ </ListItem.Group>
+ </NavigationListItem>
);
}
-function SupportButton() {
- const history = useHistory();
- const navigate = useCallback(() => history.push(RoutePath.support), [history]);
-
+function SupportListItem() {
return (
- <Cell.CellNavigationButton onClick={navigate}>
- <Cell.Label>{messages.pgettext('settings-view', 'Support')}</Cell.Label>
- </Cell.CellNavigationButton>
+ <NavigationListItem to={RoutePath.support}>
+ <ListItem.Label>
+ {
+ // TRANSLATORS: Navigation button to the 'Support' view
+ messages.pgettext('settings-view', 'Support')
+ }
+ </ListItem.Label>
+ <Icon icon="chevron-right" />
+ </NavigationListItem>
);
}
function DebugButton() {
- const history = useHistory();
- const navigate = useCallback(() => history.push(RoutePath.debug), [history]);
-
return (
- <Cell.CellNavigationButton onClick={navigate}>
- <Cell.Label>Developer tools</Cell.Label>
- </Cell.CellNavigationButton>
+ <NavigationListItem to={RoutePath.debug}>
+ <ListItem.Label>Developer tools</ListItem.Label>
+ <Icon icon="chevron-right" />
+ </NavigationListItem>
);
}