diff options
| author | Joakim Hulthe <joakim.hulthe@mullvad.net> | 2024-09-09 10:20:31 +0200 |
|---|---|---|
| committer | Joakim Hulthe <joakim.hulthe@mullvad.net> | 2024-09-17 11:29:36 +0200 |
| commit | cd78ee2663ad8effcd639a07050e948cabee2416 (patch) | |
| tree | f5e6e907d25f148ca2442eedd7d7a64e84cd39da /gui/src/renderer/components/main-view | |
| parent | db82d8936172a82ef82c206f2bcf47ef099c302f (diff) | |
| download | mullvadvpn-cd78ee2663ad8effcd639a07050e948cabee2416.tar.xz mullvadvpn-cd78ee2663ad8effcd639a07050e948cabee2416.zip | |
Align Smart routing GUI with design spec
Diffstat (limited to 'gui/src/renderer/components/main-view')
| -rw-r--r-- | gui/src/renderer/components/main-view/FeatureIndicators.tsx | 88 |
1 files changed, 73 insertions, 15 deletions
diff --git a/gui/src/renderer/components/main-view/FeatureIndicators.tsx b/gui/src/renderer/components/main-view/FeatureIndicators.tsx index 97ff92742b..4d189e712c 100644 --- a/gui/src/renderer/components/main-view/FeatureIndicators.tsx +++ b/gui/src/renderer/components/main-view/FeatureIndicators.tsx @@ -5,9 +5,13 @@ import styled from 'styled-components'; import { colors, strings } from '../../../config.json'; import { FeatureIndicator } from '../../../shared/daemon-rpc-types'; import { messages } from '../../../shared/gettext'; -import { useStyledRef } from '../../lib/utilityHooks'; +import { useBoolean, useStyledRef } from '../../lib/utilityHooks'; import { useSelector } from '../../redux/store'; import { tinyText } from '../common-styles'; +import { SmartRoutingModalMessage } from '../DaitaSettings'; +import { InfoIcon } from '../InfoButton'; +import { ModalAlert, ModalAlertType } from '../Modal'; +import { SmallButton, SmallButtonColor } from '../SmallButton'; import { ConnectionPanelAccordion } from './styles'; const LINE_HEIGHT = 22; @@ -43,8 +47,9 @@ const StyledFeatureIndicatorsWrapper = styled.div<{ $expanded: boolean }>((props })); const StyledFeatureIndicatorLabel = styled.span<{ $expanded: boolean }>(tinyText, (props) => ({ - display: 'inline', - padding: '2px 8px', + display: 'flex', + gap: '4px', + padding: '1px 7px', justifyContent: 'center', alignItems: 'center', borderRadius: '4px', @@ -53,6 +58,15 @@ const StyledFeatureIndicatorLabel = styled.span<{ $expanded: boolean }>(tinyText fontWeight: 400, whiteSpace: 'nowrap', visibility: props.$expanded ? 'visible' : 'hidden', + + // Style clickable feature indicators with a border and on-hover effect + boxSizing: 'border-box', // make border act as padding rather than margin + border: 'solid 1px', + borderColor: props.onClick ? colors.blue : colors.darkerBlue, + transition: 'background ease-in-out 300ms', + '&&:hover': { + background: props.onClick ? colors.blue60 : undefined, + }, })); const StyledBaseEllipsis = styled.span<{ $display: boolean }>(tinyText, (props) => ({ @@ -88,6 +102,11 @@ interface FeatureIndicatorsProps { // we can count those and add another ellipsis element which is visible and place it after the last // visible indicator. export default function FeatureIndicators(props: FeatureIndicatorsProps) { + const [ + daitaSmartRoutingDialogueVisible, + showDaitaSmartRoutingDialogue, + hideDaitaSmartRoutingDialogue, + ] = useBoolean(); const tunnelState = useSelector((state) => state.connection.status); const ellipsisRef = useStyledRef<HTMLSpanElement>(); const ellipsisSpacerRef = useStyledRef<HTMLSpanElement>(); @@ -106,6 +125,16 @@ export default function FeatureIndicators(props: FeatureIndicatorsProps) { const ellipsis = messages.gettext('%(amount)d more...'); + // Returns an optional callback for clickable feature indicators, or undefined. + const getFeatureIndicatorOnClick = (indicator: FeatureIndicator) => { + switch (indicator) { + case FeatureIndicator.daitaSmartRouting: + return showDaitaSmartRoutingDialogue; + default: + return undefined; + } + }; + useEffect(() => { // We need to defer the visibility logic one painting cycle to make sure the elements are // rendered and available. @@ -164,7 +193,7 @@ export default function FeatureIndicators(props: FeatureIndicatorsProps) { return ( <StyledAccordion expanded={featureIndicatorsVisible && featureIndicators.current.length > 0}> - <StyledFeatureIndicatorsContainer onClick={props.expandIsland} $expanded={props.expanded}> + <StyledFeatureIndicatorsContainer $expanded={props.expanded}> <StyledAccordion expanded={props.expanded}> <StyledTitle>{messages.pgettext('connect-view', 'Active features')}</StyledTitle> </StyledAccordion> @@ -172,16 +201,20 @@ export default function FeatureIndicators(props: FeatureIndicatorsProps) { <StyledFeatureIndicatorsWrapper ref={featureIndicatorsContainerRef} $expanded={props.expanded}> - {sortedIndicators.map((indicator) => ( - <StyledFeatureIndicatorLabel - key={indicator.toString()} - data-testid="feature-indicator" - $expanded={props.expanded}> - {getFeatureIndicatorLabel(indicator)} - </StyledFeatureIndicatorLabel> - ))} + {sortedIndicators.map((indicator) => { + const onClick = getFeatureIndicatorOnClick(indicator); + return ( + <StyledFeatureIndicatorLabel + key={indicator.toString()} + data-testid="feature-indicator" + onClick={onClick} + $expanded={props.expanded}> + {getFeatureIndicatorLabel(indicator)} + {onClick ? <InfoIcon size={10} /> : null} + </StyledFeatureIndicatorLabel> + ); + })} </StyledFeatureIndicatorsWrapper> - <StyledEllipsis $display={!props.expanded} ref={ellipsisRef} /> <StyledEllipsisSpacer $display={!props.expanded} ref={ellipsisSpacerRef}> { // Mock amount for the spacer ellipsis. This needs to be wider than the real @@ -189,8 +222,28 @@ export default function FeatureIndicators(props: FeatureIndicatorsProps) { sprintf(ellipsis, { amount: 222 }) } </StyledEllipsisSpacer> + <StyledEllipsis + onClick={props.expandIsland} + $display={!props.expanded} + ref={ellipsisRef} + /> </StyledFeatureIndicators> </StyledFeatureIndicatorsContainer> + + <ModalAlert + isOpen={daitaSmartRoutingDialogueVisible} + type={ModalAlertType.info} + gridButtons={[ + <SmallButton + key="dismiss" + onClick={hideDaitaSmartRoutingDialogue} + color={SmallButtonColor.blue}> + {messages.gettext('Got it!')} + </SmallButton>, + ]} + close={hideDaitaSmartRoutingDialogue}> + <SmartRoutingModalMessage /> + </ModalAlert> </StyledAccordion> ); } @@ -216,8 +269,13 @@ function getFeatureIndicatorLabel(indicator: FeatureIndicator) { switch (indicator) { case FeatureIndicator.daita: return strings.daita; - case FeatureIndicator.daitaUseAnywhere: - return messages.pgettext('wireguard-settings-view', 'DAITA: Use Anywhere'); + case FeatureIndicator.daitaSmartRouting: + return sprintf( + // TRANSLATORS: This refers to the Smart Routing setting in the VPN settings view. + // TRANSLATORS: This is displayed when both Smart Routing and DAITA features are on. + messages.gettext('%(daita)s: Smart routing'), + { daita: strings.daita }, + ); case FeatureIndicator.udp2tcp: case FeatureIndicator.shadowsocks: return messages.pgettext('wireguard-settings-view', 'Obfuscation'); |
