Skip to content

Commit aa5bf2c

Browse files
authored
Merge pull request #185 from performant-software/feature/basira187_search_ui
BASIRA #187 - Search UI
2 parents de6f251 + 1fe8d51 commit aa5bf2c

39 files changed

+1085
-72
lines changed

packages/controlled-vocabulary/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@performant-software/controlled-vocabulary",
3-
"version": "1.0.12",
3+
"version": "1.0.13",
44
"description": "A package of components to allow user to configure dropdown elements. Use with the \"controlled_vocabulary\" gem.",
55
"license": "MIT",
66
"main": "./build/index.js",
@@ -12,8 +12,8 @@
1212
"build": "webpack --mode production && flow-copy-source -v src types"
1313
},
1414
"dependencies": {
15-
"@performant-software/semantic-components": "^1.0.12",
16-
"@performant-software/shared-components": "^1.0.12",
15+
"@performant-software/semantic-components": "^1.0.13",
16+
"@performant-software/shared-components": "^1.0.13",
1717
"i18next": "^21.9.2",
1818
"semantic-ui-react": "^2.1.2",
1919
"underscore": "^1.13.2"

packages/semantic-ui/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@performant-software/semantic-components",
3-
"version": "1.0.12",
3+
"version": "1.0.13",
44
"description": "A package of shared components based on the Semantic UI Framework.",
55
"license": "MIT",
66
"main": "./build/index.js",
@@ -12,16 +12,17 @@
1212
"build": "webpack --mode production && flow-copy-source -v src types"
1313
},
1414
"dependencies": {
15-
"@performant-software/shared-components": "^1.0.12",
15+
"@performant-software/shared-components": "^1.0.13",
1616
"@react-google-maps/api": "^2.8.1",
1717
"axios": "^0.26.1",
1818
"i18next": "^19.4.4",
19+
"rc-slider": "^10.2.0",
1920
"react-calendar": "^3.3.0",
2021
"react-color": "^2.18.1",
2122
"react-dnd": "^11.1.3",
2223
"react-dnd-html5-backend": "^11.1.3",
2324
"react-i18next": "^11.4.0",
24-
"react-pdf": "^5.7.2",
25+
"react-pdf": "^7.1.1",
2526
"react-syntax-highlighter": "^15.5.0",
2627
"react-uuid": "^1.0.2",
2728
"semantic-ui-less": "2.4.1",

packages/semantic-ui/src/components/CurrentFacetLabels.css

Whitespace-only changes.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// @flow
2+
3+
import React from 'react';
4+
import { Button, Label } from 'semantic-ui-react';
5+
import _ from 'underscore';
6+
7+
type Item = {
8+
label: string,
9+
onClick: () => void
10+
};
11+
12+
type Props = {
13+
count?: number,
14+
items: Array<Item>,
15+
onShowMore?: () => void
16+
};
17+
18+
const CurrentFacetLabels = (props: Props) => (
19+
<Label.Group>
20+
{ _.map(props.items, (item) => (
21+
<Label
22+
content={item.label}
23+
onRemove={item.onClick}
24+
/>
25+
))}
26+
{ props.count && props.count > props.items.length && props.onShowMore && (
27+
<Label
28+
as={Button}
29+
content={`+${props.count - props.items.length}`}
30+
onClick={props.onShowMore}
31+
/>
32+
)}
33+
</Label.Group>
34+
);
35+
36+
CurrentFacetLabels.defaultProps = {
37+
count: undefined,
38+
onShowMore: undefined
39+
};
40+
41+
export default CurrentFacetLabels;
42+
43+
export type {
44+
Item
45+
};

packages/semantic-ui/src/components/CurrentFacets.css

Whitespace-only changes.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// @flow
2+
3+
import React, { useMemo, useState } from 'react';
4+
import _ from 'underscore';
5+
import CurrentFacetLabels from './CurrentFacetLabels';
6+
import CurrentFacetsModal from './CurrentFacetsModal';
7+
import { type CurrentRefinementsProps } from '../types/InstantSearch';
8+
9+
type Props = CurrentRefinementsProps & {
10+
limit?: number
11+
};
12+
13+
const CurrentFacets = ({ useCurrentRefinements, ...props }: Props) => {
14+
const [modal, setModal] = useState(false);
15+
const { items } = useCurrentRefinements(props);
16+
17+
/**
18+
* Sets the facet items based on the current refinements.
19+
*/
20+
const facets = useMemo(() => (
21+
_.flatten(_.map(items, (group) => _.map(group.refinements, (refinement) => ({
22+
label: `${group.label}: ${refinement.label}`,
23+
onClick: () => group.refine(refinement)
24+
}))))
25+
), [items]);
26+
27+
/**
28+
* Limits the list of facets to the passed "limit" prop.
29+
*/
30+
const filteredFacets = useMemo(() => _.filter(facets, (facet, index) => (
31+
!props.limit || index < props.limit
32+
)), [facets, props.limit]);
33+
34+
/**
35+
* Don't render the component if no refinements are applied.
36+
*/
37+
if (_.isEmpty(facets)) {
38+
return null;
39+
}
40+
41+
return (
42+
<>
43+
<CurrentFacetLabels
44+
count={facets.length}
45+
items={filteredFacets}
46+
onShowMore={() => setModal(true)}
47+
/>
48+
<CurrentFacetsModal
49+
items={facets}
50+
open={modal}
51+
onClose={() => setModal(false)}
52+
/>
53+
</>
54+
);
55+
};
56+
57+
CurrentFacets.defaultProps = {
58+
limit: undefined
59+
};
60+
61+
export default CurrentFacets;

packages/semantic-ui/src/components/CurrentFacetsModal.css

Whitespace-only changes.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// @flow
2+
3+
import React from 'react';
4+
import { Button, Modal } from 'semantic-ui-react';
5+
import CurrentFacetLabels, { type Item } from './CurrentFacetLabels';
6+
import i18n from '../i18n/i18n';
7+
8+
type Props = {
9+
items: Array<Item>,
10+
onClose: () => void,
11+
open?: boolean
12+
};
13+
14+
const CurrentFacetsModal = (props: Props) => (
15+
<Modal
16+
centered={false}
17+
open={props.open}
18+
>
19+
<Modal.Header
20+
content={i18n.t('CurrentFacetsModal.title')}
21+
/>
22+
<Modal.Content>
23+
<CurrentFacetLabels
24+
items={props.items}
25+
/>
26+
</Modal.Content>
27+
<Modal.Actions>
28+
<Button
29+
content={i18n.t('Common.buttons.done')}
30+
onClick={props.onClose}
31+
primary
32+
/>
33+
</Modal.Actions>
34+
</Modal>
35+
);
36+
37+
CurrentFacetsModal.defaultProps = {
38+
open: undefined
39+
};
40+
41+
export default CurrentFacetsModal;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.facet.ui.accordion {
2+
padding-bottom: 1em;
3+
}
4+
5+
.facet.ui.accordion > .title > .facet-title {
6+
display: flex;
7+
justify-content: space-between;
8+
}
9+
10+
.facet.ui.accordion > .title > .facet-title .header {
11+
margin-bottom: 0;
12+
}
13+
14+
.facet.ui.accordion > .title:not(.ui) {
15+
padding-top: 0;
16+
}
17+
18+
.facet.ui.accordion .content {
19+
margin-bottom: 1em;
20+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// @flow
2+
3+
import React, { useState, type Node } from 'react';
4+
import {
5+
Accordion,
6+
Divider,
7+
Header,
8+
Icon
9+
} from 'semantic-ui-react';
10+
import './Facet.css';
11+
12+
type Props = {
13+
children?: Node,
14+
defaultActive?: boolean,
15+
divided?: boolean,
16+
title: string
17+
};
18+
19+
const Facet = (props: Props) => {
20+
const [active, setActive] = useState(props.defaultActive);
21+
22+
return (
23+
<>
24+
<Accordion
25+
className='facet'
26+
>
27+
<Accordion.Title
28+
active={active}
29+
index={0}
30+
onClick={() => setActive((prevActive) => !prevActive)}
31+
>
32+
<div
33+
className='facet-title'
34+
>
35+
<Header
36+
content={props.title}
37+
size='tiny'
38+
/>
39+
<Icon
40+
name='dropdown'
41+
/>
42+
</div>
43+
</Accordion.Title>
44+
<Accordion.Content
45+
active={active}
46+
>
47+
{ props.children }
48+
</Accordion.Content>
49+
</Accordion>
50+
{ props.divided && (
51+
<Divider />
52+
)}
53+
</>
54+
);
55+
};
56+
57+
Facet.defaultProps = {
58+
children: undefined,
59+
defaultActive: true,
60+
divided: false
61+
};
62+
63+
export type {
64+
Props
65+
};
66+
67+
export default Facet;

0 commit comments

Comments
 (0)