summaryrefslogtreecommitdiffhomepage
path: root/gui/src/renderer/components
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-08-17 07:57:39 +0200
committerOskar Nyberg <oskar@mullvad.net>2021-08-17 09:41:03 +0200
commitccafdf50c837fd1de68ecb26364cb4100ada593e (patch)
tree6311696843a86f9cd619480537ebbf4a74a7c0dc /gui/src/renderer/components
parent8fd9f53a8c909bd757cc777d4e8d66fe6097a4a8 (diff)
downloadmullvadvpn-ccafdf50c837fd1de68ecb26364cb4100ada593e.tar.xz
mullvadvpn-ccafdf50c837fd1de68ecb26364cb4100ada593e.zip
Add filter box to select location view
Diffstat (limited to 'gui/src/renderer/components')
-rw-r--r--gui/src/renderer/components/SelectLocation.tsx61
-rw-r--r--gui/src/renderer/components/SelectLocationStyles.tsx33
-rw-r--r--gui/src/renderer/components/SettingsHeader.tsx3
3 files changed, 79 insertions, 18 deletions
diff --git a/gui/src/renderer/components/SelectLocation.tsx b/gui/src/renderer/components/SelectLocation.tsx
index b3226821a0..3ac5147ea0 100644
--- a/gui/src/renderer/components/SelectLocation.tsx
+++ b/gui/src/renderer/components/SelectLocation.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import { sprintf } from 'sprintf-js';
import { colors } from '../../config.json';
import { LiftedConstraint, RelayLocation } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
@@ -28,8 +29,12 @@ import {
StyledNavigationBarAttachment,
StyledScopeBar,
StyledFilterByProviderButton,
+ StyledProvidersCount,
+ StyledProviderCountRow,
+ StyledClearProvidersButton,
+ StyledSettingsHeader,
} from './SelectLocationStyles';
-import { HeaderSubTitle } from './SettingsHeader';
+import { HeaderTitle } from './SettingsHeader';
interface IProps {
locationScope: LocationScope;
@@ -38,12 +43,14 @@ interface IProps {
relayLocations: IRelayLocationRedux[];
bridgeLocations: IRelayLocationRedux[];
allowBridgeSelection: boolean;
+ providers: string[];
onClose: () => void;
onViewFilterByProvider: () => void;
onChangeLocationScope: (location: LocationScope) => void;
onSelectExitLocation: (location: RelayLocation) => void;
onSelectBridgeLocation: (location: RelayLocation) => void;
onSelectClosestToExit: () => void;
+ onClearProviders: () => void;
}
interface IState {
@@ -113,12 +120,7 @@ export default class SelectLocation extends React.Component<IProps, IState> {
<NavigationBar alwaysDisplayBarTitle={true}>
<NavigationItems>
<CloseBarItem action={this.props.onClose} />
- <TitleBarItem>
- {
- // TRANSLATORS: Title label in navigation bar
- messages.pgettext('select-location-nav', 'Select location')
- }
- </TitleBarItem>
+ <TitleBarItem />
<StyledFilterContainer ref={this.filterButtonRef}>
<StyledFilterIconButton onClick={this.toggleFilterMenu}>
@@ -140,17 +142,42 @@ export default class SelectLocation extends React.Component<IProps, IState> {
</StyledFilterContainer>
</NavigationItems>
<StyledNavigationBarAttachment>
- <HeaderSubTitle>
- {this.props.allowBridgeSelection
- ? messages.pgettext(
- 'select-location-view',
- 'While connected, your traffic will be routed through two secure locations, the entry point (a bridge server) and the exit point (a VPN server).',
- )
- : messages.pgettext(
- 'select-location-view',
- 'While connected, your real location is masked with a private and secure location in the selected region.',
+ <StyledSettingsHeader>
+ <HeaderTitle>
+ {
+ // TRANSLATORS: Heading in select location view
+ messages.pgettext('select-location-nav', 'Select location')
+ }
+ </HeaderTitle>
+ </StyledSettingsHeader>
+
+ {this.props.providers.length > 0 && (
+ <StyledProviderCountRow>
+ {messages.pgettext('select-location-view', 'Filtered:')}
+ <StyledProvidersCount>
+ {sprintf(
+ messages.pgettext(
+ 'select-location-view',
+ 'Providers: %(numberOfProviders)d',
+ ),
+ {
+ numberOfProviders: this.props.providers.length,
+ },
)}
- </HeaderSubTitle>
+ <StyledClearProvidersButton
+ aria-label={messages.gettext('Clear')}
+ onClick={this.props.onClearProviders}>
+ <ImageView
+ height={16}
+ width={16}
+ source="icon-close"
+ tintColor={colors.white60}
+ tintHoverColor={colors.white80}
+ />
+ </StyledClearProvidersButton>
+ </StyledProvidersCount>
+ </StyledProviderCountRow>
+ )}
{this.props.allowBridgeSelection && (
<StyledScopeBar
defaultSelectedIndex={this.props.locationScope}
diff --git a/gui/src/renderer/components/SelectLocationStyles.tsx b/gui/src/renderer/components/SelectLocationStyles.tsx
index 2c317ddddc..bf0dc038e8 100644
--- a/gui/src/renderer/components/SelectLocationStyles.tsx
+++ b/gui/src/renderer/components/SelectLocationStyles.tsx
@@ -3,6 +3,7 @@ import { colors } from '../../config.json';
import { smallText } from './common-styles';
import { Container } from './Layout';
import { ScopeBar } from './ScopeBar';
+import SettingsHeader from './SettingsHeader';
export const StyledContainer = styled(Container)({
backgroundColor: colors.darkBlue,
@@ -59,3 +60,35 @@ export const StyledFilterByProviderButton = styled.button({
backgroundColor: colors.blue80,
},
});
+
+export const StyledSettingsHeader = styled(SettingsHeader)({
+ paddingLeft: '6px',
+ paddingBottom: '11px',
+});
+
+export const StyledProviderCountRow = styled.div({
+ ...smallText,
+ color: colors.white,
+ marginLeft: '6px',
+ marginBottom: '8px',
+});
+
+export const StyledProvidersCount = styled.div({
+ ...smallText,
+ display: 'inline-flex',
+ alignItems: 'center',
+ backgroundColor: colors.blue,
+ borderRadius: '4px',
+ padding: '3px 8px',
+ marginLeft: '6px',
+ color: colors.white,
+});
+
+export const StyledClearProvidersButton = styled.div({
+ display: 'inline-block',
+ borderWidth: 0,
+ padding: 0,
+ margin: '0 0 0 6px',
+ cursor: 'default',
+ backgroundColor: 'transparent',
+});
diff --git a/gui/src/renderer/components/SettingsHeader.tsx b/gui/src/renderer/components/SettingsHeader.tsx
index 808b6f80c7..ea1d2ab634 100644
--- a/gui/src/renderer/components/SettingsHeader.tsx
+++ b/gui/src/renderer/components/SettingsHeader.tsx
@@ -18,11 +18,12 @@ export const HeaderSubTitle = styled.span(smallText);
interface ISettingsHeaderProps {
children?: React.ReactNode;
+ className?: string;
}
export default function SettingsHeader(props: ISettingsHeaderProps) {
return (
- <Container>
+ <Container className={props.className}>
{React.Children.map(props.children, (child) => {
return React.isValidElement(child) ? <ContentWrapper>{child}</ContentWrapper> : undefined;
})}