Skip to content

Commit

Permalink
Sites Management Dashboard: add search mechanism (#65505)
Browse files Browse the repository at this point in the history
* Extract the sites table to a component with the search bar

* Extract search logic into its own file

* Implement search logic into SearchableSitesTable

* Fix page layout styling

* Style search bar

* Add search placeholder

* Get rid of lodash's get helper

* Trim search input before processing

* Add ellipsis to translatable string

* Add custom search icon component instead of modifying existing one's styles
  • Loading branch information
zaguiini authored Jul 14, 2022
1 parent a1a450f commit 397541b
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 21 deletions.
8 changes: 1 addition & 7 deletions client/components/search-sites/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { get } from 'lodash';
import { Component } from 'react';
import { connect } from 'react-redux';
import getSites from 'calypso/state/selectors/get-sites';

const matches = ( item, term, keys ) =>
keys.some( ( key ) => get( item, key, '' ).toLowerCase().indexOf( term ) > -1 );

const searchCollection = ( collection, term, keys ) =>
collection.filter( ( item ) => matches( item, term, keys ) );
import { searchCollection } from './utils';

const mapState = ( state ) => ( {
sites: getSites( state ),
Expand Down
13 changes: 13 additions & 0 deletions client/components/search-sites/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const matches = < T >( item: T, term: string, keys: ( keyof T )[] ) =>
keys.some( ( key ) => {
const value = item[ key ];

if ( ! value || typeof value !== 'string' ) {
return false;
}

return value.toLowerCase().indexOf( term ) > -1;
} );

export const searchCollection = < T >( collection: T[], term: string, keys: ( keyof T )[] ) =>
collection.filter( ( item ) => item && matches( item, term, keys ) );
53 changes: 53 additions & 0 deletions client/sites-dashboard/components/searchable-sites-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ClassNames } from '@emotion/react';
import { useI18n } from '@wordpress/react-i18n';
import { useMemo, useState } from 'react';
import { searchCollection } from 'calypso/components/search-sites/utils';
import { SitesSearch } from './sites-search';
import { SitesSearchIcon } from './sites-search-icon';
import { SitesTable } from './sites-table';
import type { SiteData } from 'calypso/state/ui/selectors/site-data';

interface SearchableSitesTableProps {
sites: SiteData[];
}

export function SearchableSitesTable( { sites }: SearchableSitesTableProps ) {
const { __ } = useI18n();

const [ term, setTerm ] = useState( '' );

const filteredSites = useMemo( () => {
if ( ! term ) {
return sites;
}

return searchCollection( sites, term.toLowerCase(), [ 'URL', 'domain', 'name', 'slug' ] );
}, [ term, sites ] );

const handleSearch = ( rawTerm: string ) => setTerm( rawTerm.trim() );

return (
<ClassNames>
{ ( { css } ) => (
<>
<div
className={ css`
margin: 32px 0;
width: 286px;
max-width: 100%;
` }
>
<SitesSearch
searchIcon={ <SitesSearchIcon /> }
onSearch={ handleSearch }
delaySearch
isReskinned
placeholder={ __( 'Search by name or domain…' ) }
/>
</div>
<SitesTable sites={ filteredSites } />
</>
) }
</ClassNames>
);
}
15 changes: 2 additions & 13 deletions client/sites-dashboard/components/sites-dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useI18n } from '@wordpress/react-i18n';
import { useSelector } from 'react-redux';
import getSites from 'calypso/state/selectors/get-sites';
import { notNullish } from '../util';
import { SitesTable } from './sites-table';
import { SearchableSitesTable } from './searchable-sites-table';
import { SitesTableFilterTabs } from './sites-table-filter-tabs';

interface SitesDashboardProps {
Expand Down Expand Up @@ -85,18 +85,7 @@ export function SitesDashboard( { launchStatus }: SitesDashboardProps ) {
` }
launchStatus={ launchStatus }
>
{ ( filteredSites ) => (
<ClassNames>
{ ( { css } ) => (
<SitesTable
className={ css`
margin-top: 32px;
` }
sites={ filteredSites }
/>
) }
</ClassNames>
) }
{ ( filteredSites ) => <SearchableSitesTable sites={ filteredSites } /> }
</SitesTableFilterTabs>
) }
</ClassNames>
Expand Down
32 changes: 32 additions & 0 deletions client/sites-dashboard/components/sites-search-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export const SitesSearchIcon = () => {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={ {
paddingLeft: '16px',
paddingRight: '10px',
height: '100%',
backgroundColor: 'var( --color-surface )',
} }
>
<path
d="M9.16667 15.8333C12.8486 15.8333 15.8333 12.8486 15.8333 9.16667C15.8333 5.48477 12.8486 2.5 9.16667 2.5C5.48477 2.5 2.5 5.48477 2.5 9.16667C2.5 12.8486 5.48477 15.8333 9.16667 15.8333Z"
stroke="#8C8F94"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M17.5 17.5L13.875 13.875"
stroke="#8C8F94"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
};
14 changes: 14 additions & 0 deletions client/sites-dashboard/components/sites-search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Search from '@automattic/search';
import styled from '@emotion/styled';

export const SitesSearch = styled( Search )`
--color-surface: #f6f7f7;
border-radius: 4px;
overflow: hidden;
height: 44px;
// TODO: make the fade optional in the component
.search-component__input-fade::before {
display: none !important;
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ interface SiteTab extends Omit< TabPanel.Tab, 'title' > {
const SitesTabPanel = styled( TabPanel )`
.components-tab-panel__tabs {
overflow-x: auto;
padding-bottom: 10px;
}
.components-tab-panel__tabs-item {
Expand Down

0 comments on commit 397541b

Please sign in to comment.