Skip to content

Commit

Permalink
new advanced search component
Browse files Browse the repository at this point in the history
  • Loading branch information
vmangwani committed Aug 29, 2024
1 parent 47a6506 commit 89b2495
Show file tree
Hide file tree
Showing 6 changed files with 324 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/components/AdvancedSearchBar/AdvancedSearchBar.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Usage

TBD
151 changes: 151 additions & 0 deletions src/components/AdvancedSearchBar/AdvancedSearchBar.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { AdvancedSearchBar } from '@/components';
import mdx from './AdvancedSearchBar.mdx';
import iconOverview from '@/assets/images/iconOverview.svg';
import routeDecorator, {
routeTemplate
} from '../../../.storybook/routeDecorator';

export default {
title: 'Components/Advanced Search Bar',
component: AdvancedSearchBar,
decorators: [
routeDecorator('/', [
{
path: '/advanced-search',
component: {
template: routeTemplate('advanced-search')
}
}
])
],
parameters: {
docs: {
page: mdx
}
}
};

const PrimaryTemplate = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { AdvancedSearchBar },
setup: () => ({ args }),
template: `
<AdvancedSearchBar v-bind='args'>
<template
#default="{ result }"
class="min-w-full"
>
<td>
<img class="w-5 h-5" :src="result.img" />
</td>
<td>
{{ result.description }}
</td>
<td>
{{ result.type }}
</td>
<td>
>
</td>
</template>
</AdvancedSearchBar>
`
});

export const Primary = PrimaryTemplate.bind({});
Primary.args = {
searchFunction: (searchTerm) => {
const allPostCards = [
{
img: `/${iconOverview}`,
description: 'campaign ad',
type: 'postcard'
},
{
img: `/${iconOverview}`,
description: 'soccer postcard',
type: 'postcard'
},
{
img: `/${iconOverview}`,
description: 'baseball mail',
type: 'postcard'
},
{
img: `/${iconOverview}`,
description: 'basketball email',
type: 'postcard'
},
{
img: 'https://upload.wikimedia.org/wikipedia/commons/1/13/Tunnel_View%2C_Yosemite_Valley%2C_Yosemite_NP_-_Diliff.jpg',
description: 'campaign ad 1000',
type: 'postcard'
},
{
img: 'https://upload.wikimedia.org/wikipedia/commons/1/13/Tunnel_View%2C_Yosemite_Valley%2C_Yosemite_NP_-_Diliff.jpg',
description: 'soccer postcard 1000',
type: 'postcard'
},
{
img: 'https://upload.wikimedia.org/wikipedia/commons/1/13/Tunnel_View%2C_Yosemite_Valley%2C_Yosemite_NP_-_Diliff.jpg',
description: 'baseball mail 1000',
type: 'postcard'
},
{
img: 'https://upload.wikimedia.org/wikipedia/commons/1/13/Tunnel_View%2C_Yosemite_Valley%2C_Yosemite_NP_-_Diliff.jpg',
description: 'basketball email 1000',
type: 'postcard'
},
{
img: `/${iconOverview}`,
description: 'campaign ad',
type: 'postcard'
},
{
img: `/${iconOverview}`,
description: 'soccer postcard',
type: 'postcard'
},
{
img: `/${iconOverview}`,
description: 'baseball mail',
type: 'postcard'
},
{
img: `/${iconOverview}`,
description: 'basketball email',
type: 'postcard'
},
{
img: 'https://upload.wikimedia.org/wikipedia/commons/1/13/Tunnel_View%2C_Yosemite_Valley%2C_Yosemite_NP_-_Diliff.jpg',
description: 'campaign ad 1000',
type: 'postcard'
},
{
img: 'https://upload.wikimedia.org/wikipedia/commons/1/13/Tunnel_View%2C_Yosemite_Valley%2C_Yosemite_NP_-_Diliff.jpg',
description: 'soccer postcard 1000',
type: 'postcard'
},
{
img: 'https://upload.wikimedia.org/wikipedia/commons/1/13/Tunnel_View%2C_Yosemite_Valley%2C_Yosemite_NP_-_Diliff.jpg',
description: 'baseball mail 1000',
type: 'postcard'
},
{
img: 'https://upload.wikimedia.org/wikipedia/commons/1/13/Tunnel_View%2C_Yosemite_Valley%2C_Yosemite_NP_-_Diliff.jpg',
description: 'basketball email 1000',
type: 'postcard'
}
];
const results = allPostCards.filter((postCard) =>
postCard.description.includes(searchTerm)
);
return new Promise((resolve) => {
setTimeout(() => {
resolve(results);
}, 1500); // waits for 1500ms before returning results, so it's more 'realistic'
});
},
link: '/advanced-search',
count: 10
};
165 changes: 165 additions & 0 deletions src/components/AdvancedSearchBar/AdvancedSearchBar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<template>
<div ref="searchBar" class="relative">
<TextInput
id="searchBar"
v-model="searchTerm"
class="min-w-full"
:label="t('search.textLabel')"
:sr-only-label="true"
>
<template #iconLeft>
<MagnifyingGlass size="l" />
</template>
<template #iconRight>
<button
:class="[
'block',
searchTerm ? 'opacity-100 cursor-pointer' : 'opacity-0'
]"
:aria-label="t('search.closeLabel')"
:disabled="disabled"
data-testid="clearSearchButton"
@click="clearSearch"
>
<XmarkLarge />
</button>
</template>
</TextInput>
<div
v-if="visible || searchTerm.value"
class="bg-white shadow overflow-y-auto min-w-full absolute"
role="results"
>
<!-- If search is still running do not perform any action and show a searching bar -->
<template v-if="searching">
{{ t('search.loading') }}
</template>
<!-- If search is done and seach has results, show the results -->
<template v-else-if="!searching && searchResults.length">
<div v-for="eachSearch in searchResults">
<LobTable
class="min-w-full divide-y divide-gray-200"
space="sm"
>
<TableHeader>
<slot name="header" :result="eachSearch" />
</TableHeader>
<TableBody>
<TableRow
v-for="result in eachSearch.results"
:key="result"
class="text-gray-500 hover:text-primary-700 cursor-pointer"
@click="hide"
>
<slot name="body" :result="result" />
</TableRow>
</TableBody>
</LobTable>
</div>
<!-- If search has results and user wants to show a footer, the total number of results -->
<div v-if="footer" class="flow-root">
<div class="float-left">
{{ totalResults }} {{ t('search.matchingResults') }}
</div>
<div class="float-right">
<LobLink
:to="link"
:underline="false"
class="hover:text-primary-700"
@click="hide"
>
{{ t('search.seeAllResults') }}
</LobLink>
</div>
</div>
</template>
<!-- If no results are found show a no results message -->
<template v-else>
{{ t('search.noResults') }}
</template>
</div>
</div>
</template>
<script setup lang="ts">
import TextInput from '../TextInput/TextInput';
import LobTable from '../Table/Table';
import TableHeader from '../Table/TableHeader';
import TableBody from '../Table/TableBody';
import TableRow from '../Table/TableRow';
import LobLink from '../Link/Link.vue';
import MagnifyingGlass from '../Icons/MagnifyingGlass';
import XmarkLarge from '../Icons/XmarkLarge';
import { ref, watch, computed } from 'vue';
const searchTerm = ref('');
const searchResults = ref([]);
const searching = ref(false);
const visible = ref(false);
const timeout = ref(null);
const props = withDefaults(
defineProps<{
searchFunction: Function;
count?: number;
link?: string;
footer?: boolean;
}>(),
{
count: 0,
link: '',
footer: true
}
);
const disabled = computed(() => !searchTerm);
const totalResults = computed(() => props.count);
watch(searchTerm, async (newSearchTerm) => {
if (newSearchTerm) {
visible.value = true;
debounceSearch();
}
});
function debounceSearch(searchTerm: string, delayMs: number = 500) {
searching.value = true;
clearTimeout(timeout);
timeout.value = setTimeout(async () => {
search(searchTerm);
}, delayMs);
}
function testFunction() {
return [
{
title: 'Test 1',
icon: 'Creative',
results: [
'tess1',
'test2'
]
}
]
}
function search(searchTerm: string) {
searchResults.value = ref([]);
searchResults.value = testFunction(searchTerm);

Check warning

Code scanning / CodeQL

Superfluous trailing arguments Warning

Superfluous argument passed to
function testFunction
.
searching.value = false;
}
function clearSearch(){
if(searchTerm.value){
searchTerm.value = '';
searchResults.value = [];
visible.value = false;
}
}
function hide(){
visible.value = false;
}
</script>
1 change: 1 addition & 0 deletions src/components/AdvancedSearchBar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as AdvancedSearchBar } from './AdvancedSearchBar.vue';
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as Accordion } from './Accordion/Accordion';
export { default as AdvancedSearchBar} from './AdvancedSearchBar/AdvancedSearchBar';
export { default as Alert } from './Alert/Alert';
export { default as Breadcrumb } from './Breadcrumb/Breadcrumb';
export { default as LobButton } from './Button/Button';
Expand Down
4 changes: 3 additions & 1 deletion src/mixins/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ export default {
loading: 'Loading, please wait...',
resultsPrefix: 'View all',
resultsSuffix: 'results...',
noResults: 'No results found'
noResults: 'No results found',
matchingResults: 'matching results',
seeAllResults: 'See all results'
},
dropzone: {
yourFile: 'your file',
Expand Down

0 comments on commit 89b2495

Please sign in to comment.