@ndla/ui 23.0.0 → 24.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/Article/ArticleAuthorContent.js +2 -4
- package/es/AuthorInfo/AuthorInfo.js +29 -16
- package/es/ContentCard/ContentCard.js +66 -25
- package/es/FileList/File.js +34 -8
- package/es/FileList/FileList.js +29 -3
- package/es/InfoBox/InfoBox.js +10 -3
- package/es/InfoWidget/InfoWidget.js +67 -22
- package/es/Portrait/Portrait.js +19 -13
- package/es/Search/ActiveFilterContent.js +4 -14
- package/es/Search/ActiveFilters.js +8 -19
- package/es/Search/SearchField.js +31 -52
- package/es/Search/SearchResult.js +113 -136
- package/es/Search/ToggleSearchButton.js +34 -43
- package/es/Search/index.js +2 -8
- package/es/all.css +1 -1
- package/es/index-javascript.js +0 -1
- package/es/index.js +2 -1
- package/lib/Article/ArticleAuthorContent.js +9 -4
- package/lib/AuthorInfo/AuthorInfo.d.ts +1 -11
- package/lib/AuthorInfo/AuthorInfo.js +36 -20
- package/lib/ContentCard/ContentCard.d.ts +1 -15
- package/lib/ContentCard/ContentCard.js +60 -28
- package/lib/FileList/File.js +36 -12
- package/lib/FileList/FileList.js +28 -5
- package/lib/InfoBox/InfoBox.js +11 -4
- package/lib/InfoWidget/InfoWidget.js +61 -25
- package/lib/Portrait/Portrait.js +19 -14
- package/lib/Search/ActiveFilterContent.d.ts +13 -0
- package/lib/Search/ActiveFilterContent.js +4 -15
- package/lib/Search/ActiveFilters.d.ts +13 -0
- package/lib/Search/ActiveFilters.js +8 -20
- package/lib/Search/SearchField.d.ts +19 -0
- package/lib/Search/SearchField.js +32 -56
- package/lib/Search/SearchResult.d.ts +36 -0
- package/lib/Search/SearchResult.js +116 -159
- package/lib/Search/ToggleSearchButton.d.ts +16 -0
- package/lib/Search/ToggleSearchButton.js +36 -46
- package/lib/Search/index.d.ts +12 -0
- package/lib/Search/index.js +0 -54
- package/lib/SearchTypeResult/SearchTypeHeader.d.ts +1 -1
- package/lib/all.css +1 -1
- package/lib/index-javascript.js +0 -74
- package/lib/index.d.ts +1 -0
- package/lib/index.js +38 -1
- package/package.json +5 -5
- package/src/Article/ArticleAuthorContent.tsx +1 -1
- package/src/AuthorInfo/AuthorInfo.tsx +53 -19
- package/src/ContentCard/ContentCard.tsx +127 -35
- package/src/FileList/File.tsx +47 -17
- package/src/FileList/FileList.tsx +37 -8
- package/src/InfoBox/InfoBox.tsx +24 -4
- package/src/InfoWidget/InfoWidget.tsx +83 -34
- package/src/Portrait/Portrait.tsx +25 -10
- package/src/Search/{ActiveFilterContent.jsx → ActiveFilterContent.tsx} +11 -12
- package/src/Search/{ActiveFilters.jsx → ActiveFilters.tsx} +20 -17
- package/src/Search/{SearchField.jsx → SearchField.tsx} +58 -68
- package/src/Search/SearchResult.tsx +360 -0
- package/src/Search/ToggleSearchButton.tsx +73 -0
- package/src/Search/component.search.scss +0 -4
- package/src/Search/index.ts +16 -0
- package/src/all.scss +0 -1
- package/src/index-javascript.js +0 -15
- package/src/index.ts +2 -0
- package/src/main.scss +0 -6
- package/es/Search/SearchFilter.js +0 -72
- package/es/Search/SearchFilterList.js +0 -115
- package/es/Search/SearchOverlay.js +0 -39
- package/es/Search/SearchPage.js +0 -178
- package/es/Search/SearchPopoverFilter.js +0 -152
- package/es/Search/SearchResultAuthor.js +0 -51
- package/lib/Search/SearchFilter.js +0 -88
- package/lib/Search/SearchFilterList.js +0 -137
- package/lib/Search/SearchOverlay.js +0 -62
- package/lib/Search/SearchPage.js +0 -207
- package/lib/Search/SearchPopoverFilter.js +0 -172
- package/lib/Search/SearchResultAuthor.js +0 -60
- package/src/AuthorInfo/component.author-info.scss +0 -54
- package/src/ContentCard/component.content-card.scss +0 -109
- package/src/FileList/component.file-list.scss +0 -102
- package/src/InfoBox/component.info-box.scss +0 -21
- package/src/InfoWidget/component.info-widget.scss +0 -52
- package/src/Portrait/component.portrait.scss +0 -29
- package/src/Search/SearchFilter.jsx +0 -82
- package/src/Search/SearchFilterList.jsx +0 -110
- package/src/Search/SearchOverlay.jsx +0 -38
- package/src/Search/SearchPage.jsx +0 -178
- package/src/Search/SearchPopoverFilter.jsx +0 -109
- package/src/Search/SearchResult.jsx +0 -239
- package/src/Search/SearchResultAuthor.jsx +0 -54
- package/src/Search/ToggleSearchButton.jsx +0 -64
- package/src/Search/component.search-filter.scss +0 -67
- package/src/Search/component.search-overlay.scss +0 -103
- package/src/Search/component.search-page.scss +0 -125
- package/src/Search/component.search-result-author.scss +0 -65
- package/src/Search/index.js +0 -34
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
.c-file-list {
|
|
2
|
-
margin: $spacing--large 0;
|
|
3
|
-
padding: $spacing--small 0 $spacing $spacing;
|
|
4
|
-
border-left: 2px solid $brand-grey--lightest;
|
|
5
|
-
font-family: $font;
|
|
6
|
-
|
|
7
|
-
&__heading {
|
|
8
|
-
@include font-size(16px, 18px);
|
|
9
|
-
letter-spacing: 0.05em;
|
|
10
|
-
margin: 0 0 $spacing--small / 2 0;
|
|
11
|
-
padding-bottom: $spacing--small / 2;
|
|
12
|
-
|
|
13
|
-
border-bottom: 2px solid $brand-grey--light;
|
|
14
|
-
font-weight: $font-weight-bold;
|
|
15
|
-
text-transform: uppercase;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
&__files {
|
|
19
|
-
margin: 0;
|
|
20
|
-
padding: 0;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
&__item {
|
|
24
|
-
@include font-size(18px, 26px);
|
|
25
|
-
font-weight: $font-weight-semibold;
|
|
26
|
-
min-height: 60px;
|
|
27
|
-
background: $brand-grey--lighter;
|
|
28
|
-
display: flex;
|
|
29
|
-
align-items: center;
|
|
30
|
-
flex-wrap: wrap;
|
|
31
|
-
margin-bottom: $spacing--small / 2;
|
|
32
|
-
padding: $spacing--small;
|
|
33
|
-
|
|
34
|
-
@include mq(tablet) {
|
|
35
|
-
padding: $spacing--small $spacing;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
&__link {
|
|
40
|
-
box-shadow: none;
|
|
41
|
-
position: relative;
|
|
42
|
-
color: $brand-color;
|
|
43
|
-
margin-right: $spacing;
|
|
44
|
-
display: flex;
|
|
45
|
-
align-items: center;
|
|
46
|
-
|
|
47
|
-
&:last-child {
|
|
48
|
-
margin-right: 0;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
&:hover,
|
|
52
|
-
&:focus,
|
|
53
|
-
&:active {
|
|
54
|
-
.c-file-list__link-text {
|
|
55
|
-
& > span {
|
|
56
|
-
box-shadow: $link--hover;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
&__link-text {
|
|
63
|
-
& > span {
|
|
64
|
-
box-shadow: $link;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
&__tooltip {
|
|
69
|
-
position: absolute;
|
|
70
|
-
display: none;
|
|
71
|
-
left: 50%;
|
|
72
|
-
top: -$spacing--small;
|
|
73
|
-
transform: translate3d(-50%, -100%, 0);
|
|
74
|
-
width: 300px;
|
|
75
|
-
text-align: center;
|
|
76
|
-
z-index: 1;
|
|
77
|
-
|
|
78
|
-
&[aria-hidden='false'] {
|
|
79
|
-
display: block;
|
|
80
|
-
animation-name: fadeIn;
|
|
81
|
-
animation-duration: 0.3s;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
&__tooltip-text {
|
|
86
|
-
display: inline-block;
|
|
87
|
-
text-align: left;
|
|
88
|
-
background: $brand-color;
|
|
89
|
-
padding: $spacing--small;
|
|
90
|
-
@include font-size(14px, 18px);
|
|
91
|
-
font-weight: $font-weight-normal;
|
|
92
|
-
color: $white;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.c-icon {
|
|
96
|
-
margin-top: 3px;
|
|
97
|
-
flex-shrink: 0;
|
|
98
|
-
margin-right: $spacing--small;
|
|
99
|
-
height: 18px;
|
|
100
|
-
width: 18px;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
.c-info-box {
|
|
2
|
-
background: $yellow-light;
|
|
3
|
-
padding: $spacing--small $spacing;
|
|
4
|
-
font-family: $font;
|
|
5
|
-
@include font-size(14px, 18px);
|
|
6
|
-
|
|
7
|
-
margin-bottom: $spacing--medium;
|
|
8
|
-
|
|
9
|
-
@include mq(tablet) {
|
|
10
|
-
@include font-size(16px, 20px);
|
|
11
|
-
padding: $spacing;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
& > *:first-child {
|
|
15
|
-
margin-top: 0;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
& > *:last-child {
|
|
19
|
-
margin-bottom: 0;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
.c-info-widget {
|
|
2
|
-
max-width: 600px;
|
|
3
|
-
|
|
4
|
-
&--center {
|
|
5
|
-
margin: 0 auto;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
&__description {
|
|
9
|
-
padding: $spacing;
|
|
10
|
-
background: $brand-color--lighter;
|
|
11
|
-
color: $brand-color--dark;
|
|
12
|
-
@include font-size(18px, 26px);
|
|
13
|
-
|
|
14
|
-
p {
|
|
15
|
-
margin-top: 0;
|
|
16
|
-
|
|
17
|
-
&:last-child {
|
|
18
|
-
margin-bottom: 0;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
&__links {
|
|
24
|
-
display: flex;
|
|
25
|
-
align-items: center;
|
|
26
|
-
justify-content: flex-end;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
&__main-link {
|
|
30
|
-
color: $brand-color--dark;
|
|
31
|
-
@include font-size(16px, 24px);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
&__icon-link {
|
|
35
|
-
width: 47px;
|
|
36
|
-
height: 47px;
|
|
37
|
-
border-radius: 100%;
|
|
38
|
-
background: $brand-color--lighter;
|
|
39
|
-
color: $brand-color--dark;
|
|
40
|
-
box-shadow: none;
|
|
41
|
-
display: flex;
|
|
42
|
-
justify-content: center;
|
|
43
|
-
align-items: center;
|
|
44
|
-
|
|
45
|
-
.c-icon {
|
|
46
|
-
width: 20px;
|
|
47
|
-
height: 20px;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
margin-right: $spacing--small;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
.c-portrait {
|
|
2
|
-
width: 7rem;
|
|
3
|
-
height: 7rem;
|
|
4
|
-
span {
|
|
5
|
-
display: block;
|
|
6
|
-
border-radius: 50%;
|
|
7
|
-
background-color: rgba(0,0,0,0.16);
|
|
8
|
-
background-size: cover;
|
|
9
|
-
background-position: center center;
|
|
10
|
-
width: 7rem;
|
|
11
|
-
height: 7rem;
|
|
12
|
-
}
|
|
13
|
-
&--small {
|
|
14
|
-
width: 4rem;
|
|
15
|
-
height: 4rem;
|
|
16
|
-
span {
|
|
17
|
-
width: 4rem;
|
|
18
|
-
height: 4rem;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
&--large {
|
|
22
|
-
width: 10rem;
|
|
23
|
-
height: 10rem;
|
|
24
|
-
span {
|
|
25
|
-
width: 10rem;
|
|
26
|
-
height: 10rem;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import BEMHelper from 'react-bem-helper';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
|
|
5
|
-
import { FilterList } from '../Filter';
|
|
6
|
-
|
|
7
|
-
const searchFilterClasses = BEMHelper({
|
|
8
|
-
prefix: 'c-',
|
|
9
|
-
name: 'search-filter',
|
|
10
|
-
outputIsString: true,
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const valueShape = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
|
|
14
|
-
|
|
15
|
-
const SearchFilter = ({
|
|
16
|
-
label,
|
|
17
|
-
options,
|
|
18
|
-
values,
|
|
19
|
-
defaultVisibleCount,
|
|
20
|
-
showLabel,
|
|
21
|
-
hideLabel,
|
|
22
|
-
narrowScreenOnly,
|
|
23
|
-
contextFilter,
|
|
24
|
-
onChange,
|
|
25
|
-
noFilterSelectedLabel,
|
|
26
|
-
children,
|
|
27
|
-
}) => {
|
|
28
|
-
const modifiers = [];
|
|
29
|
-
|
|
30
|
-
if (narrowScreenOnly) {
|
|
31
|
-
modifiers.push('narrow-screen-only');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (contextFilter) {
|
|
35
|
-
modifiers.push('context-filter');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<div className={searchFilterClasses('', modifiers)}>
|
|
40
|
-
<FilterList
|
|
41
|
-
options={options}
|
|
42
|
-
label={label}
|
|
43
|
-
labelNotVisible={contextFilter}
|
|
44
|
-
values={values}
|
|
45
|
-
defaultVisibleCount={defaultVisibleCount}
|
|
46
|
-
modifiers={!contextFilter ? 'search' : null}
|
|
47
|
-
showLabel={showLabel}
|
|
48
|
-
hideLabel={hideLabel}
|
|
49
|
-
onChange={onChange}
|
|
50
|
-
alignedGroup
|
|
51
|
-
noFilterSelectedLabel={noFilterSelectedLabel}
|
|
52
|
-
/>
|
|
53
|
-
{children}
|
|
54
|
-
</div>
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
SearchFilter.propTypes = {
|
|
59
|
-
label: PropTypes.string.isRequired,
|
|
60
|
-
options: PropTypes.arrayOf(
|
|
61
|
-
PropTypes.shape({
|
|
62
|
-
value: valueShape.isRequired,
|
|
63
|
-
title: PropTypes.string.isRequired,
|
|
64
|
-
noResults: PropTypes.bool,
|
|
65
|
-
}),
|
|
66
|
-
).isRequired,
|
|
67
|
-
values: PropTypes.arrayOf(valueShape),
|
|
68
|
-
defaultVisibleCount: PropTypes.number,
|
|
69
|
-
onChange: PropTypes.func,
|
|
70
|
-
showLabel: PropTypes.string,
|
|
71
|
-
hideLabel: PropTypes.string,
|
|
72
|
-
narrowScreenOnly: PropTypes.bool,
|
|
73
|
-
noFilterSelectedLabel: PropTypes.string,
|
|
74
|
-
contextFilter: PropTypes.bool,
|
|
75
|
-
children: PropTypes.node,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
SearchFilter.defaultProps = {
|
|
79
|
-
values: [],
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export default SearchFilter;
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import React, { Fragment } from 'react';
|
|
2
|
-
import BEMHelper from 'react-bem-helper';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
|
|
5
|
-
import { FilterList, ToggleItem } from '../Filter';
|
|
6
|
-
|
|
7
|
-
const searchFilterClasses = BEMHelper({
|
|
8
|
-
prefix: 'c-',
|
|
9
|
-
name: 'search-filter',
|
|
10
|
-
outputIsString: true,
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const valueShape = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
|
|
14
|
-
|
|
15
|
-
const SearchFilterList = ({
|
|
16
|
-
label,
|
|
17
|
-
options,
|
|
18
|
-
values,
|
|
19
|
-
narrowScreenOnly,
|
|
20
|
-
onChange,
|
|
21
|
-
onSubfilterChange,
|
|
22
|
-
preid,
|
|
23
|
-
noFilterSelectedLabel,
|
|
24
|
-
subjectValues,
|
|
25
|
-
children,
|
|
26
|
-
}) => {
|
|
27
|
-
return (
|
|
28
|
-
<div className={searchFilterClasses('')}>
|
|
29
|
-
<div>
|
|
30
|
-
{options.map((option, index) => {
|
|
31
|
-
const itemModifiers = [];
|
|
32
|
-
const checked = values.some((value) => value === option.value);
|
|
33
|
-
|
|
34
|
-
if (!checked && index + 1 > this.state.visibleCount) {
|
|
35
|
-
itemModifiers.push('hidden');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const disabled = option.noResults || option.hits === 0;
|
|
39
|
-
|
|
40
|
-
if (disabled) {
|
|
41
|
-
itemModifiers.push('no-results');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<Fragment key={option.value}>
|
|
46
|
-
<ToggleItem
|
|
47
|
-
modifiers={itemModifiers}
|
|
48
|
-
id={preid + option.value}
|
|
49
|
-
value={option.value}
|
|
50
|
-
disabled={disabled}
|
|
51
|
-
tabIndex={disabled ? -1 : 0}
|
|
52
|
-
checked={checked}
|
|
53
|
-
icon={option.icon}
|
|
54
|
-
label={option.title}
|
|
55
|
-
component="div"
|
|
56
|
-
onChange={(event) => {
|
|
57
|
-
let newValues = null;
|
|
58
|
-
if (event.currentTarget.checked) {
|
|
59
|
-
newValues = [...values, option.value];
|
|
60
|
-
} else {
|
|
61
|
-
newValues = values.filter((value) => value !== option.value);
|
|
62
|
-
}
|
|
63
|
-
if (onChange) {
|
|
64
|
-
onChange(newValues, option.value);
|
|
65
|
-
}
|
|
66
|
-
}}
|
|
67
|
-
/>
|
|
68
|
-
<div className={searchFilterClasses()}>
|
|
69
|
-
<FilterList
|
|
70
|
-
options={option.subjectFilters}
|
|
71
|
-
label={label}
|
|
72
|
-
labelNotVisible
|
|
73
|
-
values={subjectValues[option.value]}
|
|
74
|
-
onChange={(subjectFilters, subjectFilter) =>
|
|
75
|
-
onSubfilterChange(option.value, subjectFilters, subjectFilter)
|
|
76
|
-
}
|
|
77
|
-
alignedGroup
|
|
78
|
-
noFilterSelectedLabel={noFilterSelectedLabel}
|
|
79
|
-
/>
|
|
80
|
-
</div>
|
|
81
|
-
</Fragment>
|
|
82
|
-
);
|
|
83
|
-
})}
|
|
84
|
-
</div>
|
|
85
|
-
{children}
|
|
86
|
-
</div>
|
|
87
|
-
);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
SearchFilterList.propTypes = {
|
|
91
|
-
label: PropTypes.string.isRequired,
|
|
92
|
-
options: PropTypes.arrayOf(
|
|
93
|
-
PropTypes.shape({
|
|
94
|
-
value: valueShape.isRequired,
|
|
95
|
-
title: PropTypes.string.isRequired,
|
|
96
|
-
noResults: PropTypes.bool,
|
|
97
|
-
}),
|
|
98
|
-
).isRequired,
|
|
99
|
-
values: PropTypes.arrayOf(valueShape),
|
|
100
|
-
onChange: PropTypes.func,
|
|
101
|
-
onSubfilterChange: PropTypes.func,
|
|
102
|
-
noFilterSelectedLabel: PropTypes.string,
|
|
103
|
-
children: PropTypes.node,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
SearchFilterList.defaultProps = {
|
|
107
|
-
values: [],
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
export default SearchFilterList;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import React, { Fragment } from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import BEMHelper from 'react-bem-helper';
|
|
4
|
-
import { Cross } from '@ndla/icons/action';
|
|
5
|
-
import { CSSTransition } from 'react-transition-group';
|
|
6
|
-
|
|
7
|
-
import Fade from '../Animation/Fade';
|
|
8
|
-
|
|
9
|
-
const classes = BEMHelper({
|
|
10
|
-
prefix: 'c-',
|
|
11
|
-
name: 'search-overlay',
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
const SearchOverlay = ({ close, isOpen, children }) => (
|
|
15
|
-
<Fragment>
|
|
16
|
-
<Fade in={isOpen}>
|
|
17
|
-
<div className="o-backdrop" />
|
|
18
|
-
</Fade>
|
|
19
|
-
<CSSTransition timeout={300} classNames={classes().className} unmountOnExit in={isOpen}>
|
|
20
|
-
<div {...classes()}>
|
|
21
|
-
<div {...classes('container o-wrapper')}>
|
|
22
|
-
{children}
|
|
23
|
-
<button {...classes('close-button')} type="button" onClick={close}>
|
|
24
|
-
<Cross />
|
|
25
|
-
</button>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
</CSSTransition>
|
|
29
|
-
</Fragment>
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
SearchOverlay.propTypes = {
|
|
33
|
-
isOpen: PropTypes.bool.isRequired,
|
|
34
|
-
close: PropTypes.func,
|
|
35
|
-
children: PropTypes.node.isRequired,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export default SearchOverlay;
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import React, { Component, Fragment, createRef } from 'react';
|
|
2
|
-
import BEMHelper from 'react-bem-helper';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import { Back } from '@ndla/icons/common';
|
|
5
|
-
import { debounce } from 'lodash';
|
|
6
|
-
import { getCurrentBreakpoint, breakpoints } from '@ndla/util';
|
|
7
|
-
import Modal, { ModalHeader, ModalBody, ModalCloseButton } from '@ndla/modal';
|
|
8
|
-
import Button from '@ndla/button';
|
|
9
|
-
import { withTranslation } from 'react-i18next';
|
|
10
|
-
|
|
11
|
-
import SearchField from './SearchField';
|
|
12
|
-
import ActiveFilters from './ActiveFilters';
|
|
13
|
-
import { SearchFieldForm } from './SearchFieldForm';
|
|
14
|
-
|
|
15
|
-
const classes = BEMHelper('c-search-page');
|
|
16
|
-
const filterClasses = BEMHelper('c-filter');
|
|
17
|
-
|
|
18
|
-
class SearchPage extends Component {
|
|
19
|
-
constructor(props) {
|
|
20
|
-
super(props);
|
|
21
|
-
this.state = {
|
|
22
|
-
isNarrowScreen: false,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
this.filterCloseButton = null;
|
|
26
|
-
this.inputRef = createRef();
|
|
27
|
-
this.checkScreenSize = this.checkScreenSize.bind(this);
|
|
28
|
-
this.checkScreenSizeDebounce = debounce(() => this.checkScreenSize(), 100);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
componentDidMount() {
|
|
32
|
-
window.addEventListener('resize', this.checkScreenSizeDebounce);
|
|
33
|
-
this.checkScreenSize();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
componentWillUnmount() {
|
|
37
|
-
window.removeEventListener('resize', this.checkScreenSizeDebounce);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
checkScreenSize() {
|
|
41
|
-
const currentBreakpoint = getCurrentBreakpoint();
|
|
42
|
-
const isNarrowScreen = currentBreakpoint === breakpoints.mobile || currentBreakpoint === breakpoints.tablet;
|
|
43
|
-
|
|
44
|
-
/* eslint react/no-did-mount-set-state: 0 */
|
|
45
|
-
if (isNarrowScreen !== this.state.isNarrowScreen) {
|
|
46
|
-
this.setState({
|
|
47
|
-
isNarrowScreen,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
render() {
|
|
53
|
-
const {
|
|
54
|
-
searchString,
|
|
55
|
-
onSearchFieldChange,
|
|
56
|
-
onSearchFieldFilterRemove,
|
|
57
|
-
searchFieldFilters,
|
|
58
|
-
onSearch,
|
|
59
|
-
// only on narrow screen
|
|
60
|
-
activeFilters,
|
|
61
|
-
resourceToLinkProps,
|
|
62
|
-
filters,
|
|
63
|
-
children,
|
|
64
|
-
messages,
|
|
65
|
-
author,
|
|
66
|
-
t,
|
|
67
|
-
} = this.props;
|
|
68
|
-
|
|
69
|
-
return (
|
|
70
|
-
<main {...classes()}>
|
|
71
|
-
<div {...classes('search-field-wrapper')}>
|
|
72
|
-
<SearchFieldForm onSubmit={onSearch}>
|
|
73
|
-
<SearchField
|
|
74
|
-
inputRef={this.inputRef}
|
|
75
|
-
value={searchString}
|
|
76
|
-
onChange={onSearchFieldChange}
|
|
77
|
-
placeholder={t('searchPage.searchFieldPlaceholder')}
|
|
78
|
-
filters={searchFieldFilters}
|
|
79
|
-
onFilterRemove={onSearchFieldFilterRemove}
|
|
80
|
-
resourceToLinkProps={resourceToLinkProps}
|
|
81
|
-
messages={{
|
|
82
|
-
searchFieldTitle: t('searchPage.search'),
|
|
83
|
-
}}
|
|
84
|
-
/>
|
|
85
|
-
</SearchFieldForm>
|
|
86
|
-
</div>
|
|
87
|
-
{author}
|
|
88
|
-
<div {...classes('filter-result-wrapper')}>
|
|
89
|
-
<aside {...classes('filter-wrapper')}>
|
|
90
|
-
<h1 {...classes('filter-heading')}>{t('searchPage.searchPageMessages.filterHeading')}</h1>
|
|
91
|
-
<div {...classes('filters')}>{!this.state.isNarrowScreen && filters}</div>
|
|
92
|
-
</aside>
|
|
93
|
-
<div {...classes('result-wrapper')}>
|
|
94
|
-
<div {...classes('active-filters')}>
|
|
95
|
-
<ActiveFilters
|
|
96
|
-
filters={activeFilters}
|
|
97
|
-
showOnSmallScreen
|
|
98
|
-
onFilterRemove={(value, filterName) => onSearchFieldFilterRemove(value, filterName)}
|
|
99
|
-
/>
|
|
100
|
-
</div>
|
|
101
|
-
<div {...classes('toggle-filter')}>
|
|
102
|
-
<Modal
|
|
103
|
-
animation="subtle"
|
|
104
|
-
animationDuration={150}
|
|
105
|
-
size="fullscreen"
|
|
106
|
-
backgroundColor="grey"
|
|
107
|
-
activateButton={<Button outline>{t('searchPage.searchPageMessages.filterHeading')}</Button>}>
|
|
108
|
-
{(onClose) => (
|
|
109
|
-
<Fragment>
|
|
110
|
-
<ModalHeader modifier="white left-align">
|
|
111
|
-
<ModalCloseButton
|
|
112
|
-
title={
|
|
113
|
-
<Fragment>
|
|
114
|
-
<Back /> {messages.narrowScreenFilterHeading}
|
|
115
|
-
</Fragment>
|
|
116
|
-
}
|
|
117
|
-
onClick={onClose}>
|
|
118
|
-
Close
|
|
119
|
-
</ModalCloseButton>
|
|
120
|
-
</ModalHeader>
|
|
121
|
-
<ModalBody modifier="slide-in-left no-side-padding-mobile">
|
|
122
|
-
{filters}
|
|
123
|
-
<div {...filterClasses('usefilter-wrapper')}>
|
|
124
|
-
<Button outline onClick={onClose}>
|
|
125
|
-
{t('searchPage.searchFilterMessages.useFilter')}
|
|
126
|
-
</Button>
|
|
127
|
-
</div>
|
|
128
|
-
</ModalBody>
|
|
129
|
-
</Fragment>
|
|
130
|
-
)}
|
|
131
|
-
</Modal>
|
|
132
|
-
</div>
|
|
133
|
-
|
|
134
|
-
{children}
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
</main>
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
SearchPage.propTypes = {
|
|
143
|
-
// should be <Fragment />
|
|
144
|
-
filters: PropTypes.node.isRequired,
|
|
145
|
-
children: PropTypes.node.isRequired,
|
|
146
|
-
searchString: PropTypes.string.isRequired,
|
|
147
|
-
onSearchFieldChange: PropTypes.func.isRequired,
|
|
148
|
-
onSearch: PropTypes.func.isRequired,
|
|
149
|
-
onSearchFieldFilterRemove: PropTypes.func.isRequired,
|
|
150
|
-
resourceToLinkProps: PropTypes.func.isRequired,
|
|
151
|
-
searchFieldFilters: PropTypes.arrayOf(
|
|
152
|
-
PropTypes.shape({
|
|
153
|
-
value: PropTypes.string.isRequired,
|
|
154
|
-
title: PropTypes.string.isRequired,
|
|
155
|
-
filterName: PropTypes.string.isRequired,
|
|
156
|
-
}),
|
|
157
|
-
),
|
|
158
|
-
activeFilters: PropTypes.arrayOf(
|
|
159
|
-
PropTypes.shape({
|
|
160
|
-
value: PropTypes.string.isRequired,
|
|
161
|
-
title: PropTypes.string.isRequired,
|
|
162
|
-
filterName: PropTypes.string.isRequired,
|
|
163
|
-
}),
|
|
164
|
-
),
|
|
165
|
-
messages: PropTypes.shape({
|
|
166
|
-
narrowScreenFilterHeading: PropTypes.string.isRequired,
|
|
167
|
-
}).isRequired,
|
|
168
|
-
author: PropTypes.node,
|
|
169
|
-
hideResultText: PropTypes.bool,
|
|
170
|
-
filterScreenChange: PropTypes.func,
|
|
171
|
-
t: PropTypes.func.isRequired,
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
SearchPage.defaultProps = {
|
|
175
|
-
author: null,
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
export default withTranslation()(SearchPage);
|