diff options
| -rw-r--r-- | gui/src/renderer/components/SelectLocation.tsx | 53 | ||||
| -rw-r--r-- | gui/src/renderer/components/SelectLocationStyles.tsx | 37 | ||||
| -rw-r--r-- | gui/src/renderer/containers/SelectLocationPage.tsx | 2 |
3 files changed, 90 insertions, 2 deletions
diff --git a/gui/src/renderer/components/SelectLocation.tsx b/gui/src/renderer/components/SelectLocation.tsx index a8375a178c..b3226821a0 100644 --- a/gui/src/renderer/components/SelectLocation.tsx +++ b/gui/src/renderer/components/SelectLocation.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { colors } from '../../config.json'; import { LiftedConstraint, RelayLocation } from '../../shared/daemon-rpc-types'; import { messages } from '../../shared/gettext'; import { IRelayLocationRedux } from '../redux/settings/reducers'; @@ -6,6 +7,7 @@ import { LocationScope } from '../redux/userinterface/reducers'; import BridgeLocations, { SpecialBridgeLocationType } from './BridgeLocations'; import CustomScrollbars from './CustomScrollbars'; import ExitLocations from './ExitLocations'; +import ImageView from './ImageView'; import { Layout } from './Layout'; import LocationList, { LocationSelection, LocationSelectionType } from './LocationList'; import { @@ -20,8 +22,12 @@ import { ScopeBarItem } from './ScopeBar'; import { StyledContainer, StyledContent, + StyledFilterIconButton, + StyledFilterContainer, + StyledFilterMenu, StyledNavigationBarAttachment, StyledScopeBar, + StyledFilterByProviderButton, } from './SelectLocationStyles'; import { HeaderSubTitle } from './SettingsHeader'; @@ -33,18 +39,25 @@ interface IProps { bridgeLocations: IRelayLocationRedux[]; allowBridgeSelection: boolean; onClose: () => void; + onViewFilterByProvider: () => void; onChangeLocationScope: (location: LocationScope) => void; onSelectExitLocation: (location: RelayLocation) => void; onSelectBridgeLocation: (location: RelayLocation) => void; onSelectClosestToExit: () => void; } +interface IState { + showFilterMenu: boolean; +} + interface ISelectLocationSnapshot { scrollPosition: [number, number]; expandedLocations: RelayLocation[]; } -export default class SelectLocation extends React.Component<IProps> { +export default class SelectLocation extends React.Component<IProps, IState> { + public state = { showFilterMenu: false }; + private scrollView = React.createRef<CustomScrollbars>(); private spacePreAllocationViewRef = React.createRef<SpacePreAllocationView>(); private selectedExitLocationRef = React.createRef<React.ReactInstance>(); @@ -55,6 +68,8 @@ export default class SelectLocation extends React.Component<IProps> { private snapshotByScope: { [index: number]: ISelectLocationSnapshot } = {}; + private filterButtonRef = React.createRef<HTMLDivElement>(); + public componentDidMount() { this.scrollToSelectedCell(); } @@ -92,7 +107,7 @@ export default class SelectLocation extends React.Component<IProps> { public render() { return ( - <Layout> + <Layout onClick={this.onClickAnywhere}> <StyledContainer> <NavigationContainer> <NavigationBar alwaysDisplayBarTitle={true}> @@ -104,6 +119,25 @@ export default class SelectLocation extends React.Component<IProps> { messages.pgettext('select-location-nav', 'Select location') } </TitleBarItem> + + <StyledFilterContainer ref={this.filterButtonRef}> + <StyledFilterIconButton onClick={this.toggleFilterMenu}> + <ImageView + source="icon-filter-round" + tintColor={colors.white60} + tintHoverColor={colors.white80} + height={24} + width={24} + /> + </StyledFilterIconButton> + {this.state.showFilterMenu && ( + <StyledFilterMenu> + <StyledFilterByProviderButton onClick={this.props.onViewFilterByProvider}> + {messages.pgettext('select-location-view', 'Filter by provider')} + </StyledFilterByProviderButton> + </StyledFilterMenu> + )} + </StyledFilterContainer> </NavigationItems> <StyledNavigationBarAttachment> <HeaderSubTitle> @@ -232,6 +266,21 @@ export default class SelectLocation extends React.Component<IProps> { this.spacePreAllocationViewRef.current?.allocate(expandedContentHeight); this.scrollView.current?.scrollIntoView(locationRect); }; + + private toggleFilterMenu = () => { + this.setState((state) => ({ + showFilterMenu: !state.showFilterMenu, + })); + }; + + private onClickAnywhere = (event: React.MouseEvent<HTMLDivElement>) => { + if ( + this.state.showFilterMenu && + !this.filterButtonRef.current?.contains(event.target as HTMLElement) + ) { + this.setState({ showFilterMenu: false }); + } + }; } interface ISpacePreAllocationView { diff --git a/gui/src/renderer/components/SelectLocationStyles.tsx b/gui/src/renderer/components/SelectLocationStyles.tsx index 6a3685ffb4..2c317ddddc 100644 --- a/gui/src/renderer/components/SelectLocationStyles.tsx +++ b/gui/src/renderer/components/SelectLocationStyles.tsx @@ -1,5 +1,6 @@ import styled from 'styled-components'; import { colors } from '../../config.json'; +import { smallText } from './common-styles'; import { Container } from './Layout'; import { ScopeBar } from './ScopeBar'; @@ -22,3 +23,39 @@ export const StyledNavigationBarAttachment = styled.div({ marginTop: '8px', paddingHorizontal: '4px', }); + +export const StyledFilterContainer = styled.div({ + position: 'relative', +}); + +export const StyledFilterIconButton = styled.button({ + borderWidth: 0, + padding: 0, + margin: 0, + cursor: 'default', + backgroundColor: 'transparent', +}); + +export const StyledFilterMenu = styled.div({ + position: 'absolute', + top: 'calc(100% + 4px)', + right: '0', + borderRadius: '4px', + backgroundColor: colors.darkBlue, + overflow: 'hidden', +}); + +export const StyledFilterByProviderButton = styled.button({ + ...smallText, + borderWidth: 0, + margin: 0, + cursor: 'default', + color: colors.white, + padding: '7px 15px', + whiteSpace: 'nowrap', + borderRadius: 0, + backgroundColor: colors.blue, + ':hover': { + backgroundColor: colors.blue80, + }, +}); diff --git a/gui/src/renderer/containers/SelectLocationPage.tsx b/gui/src/renderer/containers/SelectLocationPage.tsx index b3aab7eb69..7511a75fe1 100644 --- a/gui/src/renderer/containers/SelectLocationPage.tsx +++ b/gui/src/renderer/containers/SelectLocationPage.tsx @@ -7,6 +7,7 @@ import RelaySettingsBuilder from '../../shared/relay-settings-builder'; import SelectLocation from '../components/SelectLocation'; import withAppContext, { IAppContext } from '../context'; import { IHistoryProps, withHistory } from '../lib/history'; +import { RoutePath } from '../lib/routes'; import { IReduxState, ReduxDispatch } from '../redux/store'; import userInterfaceActions from '../redux/userinterface/actions'; import { LocationScope } from '../redux/userinterface/reducers'; @@ -45,6 +46,7 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, props: IHistoryProps & IApp return { onClose: () => props.history.dismiss(), + onViewFilterByProvider: () => props.history.push(RoutePath.filterByProvider), onChangeLocationScope: (scope: LocationScope) => { userInterface.setLocationScope(scope); }, |
