@blocklet/list 0.8.19 → 0.8.22
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/lib/base.js +37 -49
- package/lib/components/aside.js +53 -0
- package/lib/components/{filter-author.js → filter/custom-chip.js} +21 -28
- package/lib/components/filter/group.js +53 -0
- package/lib/components/filter/icon.js +93 -0
- package/lib/components/filter/index.js +31 -0
- package/lib/components/list/list.js +2 -3
- package/lib/components/search.js +1 -1
- package/lib/contexts/filter.js +5 -5
- package/lib/libs/utils.js +13 -2
- package/package.json +3 -3
- package/src/base.js +65 -78
- package/src/components/aside.js +36 -0
- package/src/components/filter/custom-chip.js +33 -0
- package/src/components/filter/group.js +64 -0
- package/src/components/filter/icon.js +69 -0
- package/src/components/filter/index.js +5 -0
- package/src/components/list/list.js +8 -3
- package/src/components/search.js +3 -11
- package/src/contexts/filter.js +9 -15
- package/src/libs/utils.js +4 -0
- package/lib/components/aside/aside.js +0 -64
- package/lib/components/aside/category-link-list.js +0 -78
- package/lib/components/aside/index.js +0 -13
- package/lib/components/category-select.js +0 -55
- package/src/components/aside/aside.js +0 -90
- package/src/components/aside/category-link-list.js +0 -53
- package/src/components/aside/index.js +0 -3
- package/src/components/category-select.js +0 -43
- package/src/components/filter-author.js +0 -38
package/src/base.js
CHANGED
|
@@ -1,50 +1,54 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
import SortIcon from '@mui/icons-material/Sort';
|
|
4
|
-
import FilterListIcon from '@mui/icons-material/FilterList';
|
|
5
4
|
import { Box, Hidden } from '@mui/material';
|
|
5
|
+
import FaceIcon from '@mui/icons-material/Face';
|
|
6
6
|
|
|
7
7
|
import { useFilterContext } from './contexts/filter';
|
|
8
8
|
import CustomSelect from './components/custom-select';
|
|
9
|
-
import
|
|
10
|
-
import { getSortOptions
|
|
9
|
+
import { CustomChip, FilterIcon } from './components/filter';
|
|
10
|
+
import { getSortOptions } from './libs/utils';
|
|
11
11
|
import BlockletList from './components/list';
|
|
12
12
|
import Aside from './components/aside';
|
|
13
13
|
import Search from './components/search';
|
|
14
|
-
import CategorySelect from './components/category-select';
|
|
15
14
|
|
|
16
15
|
const ListBase = () => {
|
|
17
|
-
const {
|
|
16
|
+
const {
|
|
17
|
+
handleDeveloper,
|
|
18
|
+
blockletList,
|
|
19
|
+
filters,
|
|
20
|
+
developerName,
|
|
21
|
+
handleSort,
|
|
22
|
+
handleCategory,
|
|
23
|
+
handlePrice,
|
|
24
|
+
t,
|
|
25
|
+
getCategoryLocale,
|
|
26
|
+
priceOptions,
|
|
27
|
+
} = useFilterContext();
|
|
28
|
+
|
|
29
|
+
const sortOptions = getSortOptions(t);
|
|
30
|
+
const sortLocale = sortOptions.find((f) => f.value === filters.sortBy)?.name || t('sort.sort');
|
|
31
|
+
const categoryLocale = getCategoryLocale(filters.category);
|
|
32
|
+
const priceLocale = priceOptions.find((price) => price.value === filters.price)?.name;
|
|
33
|
+
|
|
18
34
|
return (
|
|
19
35
|
<Box display="flex" alignItems="flex-start" height="100%">
|
|
20
36
|
<Hidden mdDown>
|
|
21
37
|
<Aside />
|
|
22
38
|
</Hidden>
|
|
23
39
|
<StyledMin>
|
|
24
|
-
<Box className="
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
<FilterAuthor
|
|
28
|
-
user={developerName}
|
|
29
|
-
deleteUserTag={() => {
|
|
30
|
-
handleDeveloper(null);
|
|
31
|
-
}}
|
|
32
|
-
/>
|
|
33
|
-
)}
|
|
34
|
-
</Hidden>
|
|
35
|
-
<Box mt={0} className="searchContainer">
|
|
36
|
-
<Hidden mdUp>
|
|
37
|
-
<StyledSearch className="search" placeholder={t('common.searchStore')} />
|
|
38
|
-
</Hidden>
|
|
39
|
-
</Box>
|
|
40
|
-
<Box mt={0} ml="10px" className="filterContainer">
|
|
40
|
+
<Box className="filter-bar" display="flex" alignItems="center">
|
|
41
|
+
<StyledSearch className="search-container" placeholder={t('common.searchStore')} />
|
|
42
|
+
<Box mt={0} ml="16px" className="filter-container">
|
|
41
43
|
<Hidden mdUp>
|
|
42
|
-
|
|
44
|
+
{/* 小屏幕下类别 */}
|
|
45
|
+
<FilterIcon />
|
|
43
46
|
</Hidden>
|
|
47
|
+
{/* 排序选择器 */}
|
|
44
48
|
<CustomSelect
|
|
45
49
|
value={filters.sortBy}
|
|
46
|
-
options={
|
|
47
|
-
title={
|
|
50
|
+
options={sortOptions}
|
|
51
|
+
title={sortLocale}
|
|
48
52
|
icon={<SortIcon />}
|
|
49
53
|
onChange={(v) => {
|
|
50
54
|
handleSort(v);
|
|
@@ -52,34 +56,27 @@ const ListBase = () => {
|
|
|
52
56
|
/>
|
|
53
57
|
</Box>
|
|
54
58
|
</Box>
|
|
55
|
-
<
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
onChange={(v) => {
|
|
77
|
-
handlePrice(v);
|
|
78
|
-
}}
|
|
79
|
-
style={{ marginBottom: '16px' }}
|
|
80
|
-
/>
|
|
81
|
-
</Box>
|
|
82
|
-
</Hidden>
|
|
59
|
+
<Box display="flex" flexWrap="wrap" alignItems="center" mb="16px">
|
|
60
|
+
<CustomChip
|
|
61
|
+
label={developerName}
|
|
62
|
+
icon={<FaceIcon />}
|
|
63
|
+
onDelete={() => {
|
|
64
|
+
handleDeveloper(null);
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
<CustomChip
|
|
68
|
+
label={categoryLocale}
|
|
69
|
+
onDelete={() => {
|
|
70
|
+
handleCategory(null);
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
<CustomChip
|
|
74
|
+
label={priceLocale}
|
|
75
|
+
onDelete={() => {
|
|
76
|
+
handlePrice(null);
|
|
77
|
+
}}
|
|
78
|
+
/>
|
|
79
|
+
</Box>
|
|
83
80
|
<BlockletList blocklets={blockletList} />
|
|
84
81
|
</StyledMin>
|
|
85
82
|
</Box>
|
|
@@ -90,44 +87,34 @@ const StyledMin = styled.main`
|
|
|
90
87
|
flex: 1;
|
|
91
88
|
width: 100%;
|
|
92
89
|
min-width: 0;
|
|
93
|
-
.
|
|
90
|
+
.filter-bar {
|
|
94
91
|
justify-content: space-between;
|
|
95
|
-
margin-bottom:
|
|
92
|
+
margin-bottom: ${(props) => props.theme.spacing(2)};
|
|
96
93
|
}
|
|
97
94
|
.sort-button {
|
|
98
95
|
white-space: nowrap;
|
|
99
96
|
}
|
|
100
|
-
.search {
|
|
97
|
+
.search-container {
|
|
98
|
+
flex: 2;
|
|
101
99
|
margin-left: 0px;
|
|
102
100
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
width: 100%;
|
|
109
|
-
}
|
|
110
|
-
.filterContainer {
|
|
111
|
-
flex: 1;
|
|
112
|
-
display: flex;
|
|
113
|
-
justify-content: flex-end;
|
|
114
|
-
}
|
|
101
|
+
|
|
102
|
+
.filter-container {
|
|
103
|
+
flex: 1;
|
|
104
|
+
display: flex;
|
|
105
|
+
justify-content: flex-end;
|
|
115
106
|
}
|
|
116
|
-
@media (max-width:
|
|
117
|
-
.
|
|
107
|
+
@media (max-width: ${(props) => props.theme.breakpoints.values.md}px) {
|
|
108
|
+
.search-container {
|
|
118
109
|
width: 100%;
|
|
110
|
+
margin-bottom: ${(props) => props.theme.spacing(2)};
|
|
119
111
|
}
|
|
120
|
-
.
|
|
121
|
-
width: 100%;
|
|
112
|
+
.filter-container {
|
|
122
113
|
margin-left: 0;
|
|
123
114
|
display: flex;
|
|
124
|
-
justify-content:
|
|
125
|
-
}
|
|
126
|
-
.search {
|
|
127
|
-
margin-bottom: 20px;
|
|
128
|
-
width: 100%;
|
|
115
|
+
justify-content: flex-start;
|
|
129
116
|
}
|
|
130
|
-
.
|
|
117
|
+
.filter-bar {
|
|
131
118
|
display: flex;
|
|
132
119
|
flex-direction: column;
|
|
133
120
|
align-items: flex-start;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import { useFilterContext } from '../contexts/filter';
|
|
5
|
+
import { FilterGroup } from './filter';
|
|
6
|
+
|
|
7
|
+
const Aside = () => {
|
|
8
|
+
const { selectedCategory, handleCategory, t, handlePrice, filters, categoryOptions, priceOptions } =
|
|
9
|
+
useFilterContext();
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<StyledAside>
|
|
13
|
+
<div>
|
|
14
|
+
<FilterGroup title={t('common.price')} options={priceOptions} value={filters.price} onChange={handlePrice} />
|
|
15
|
+
</div>
|
|
16
|
+
<div style={{ marginTop: '32px' }}>
|
|
17
|
+
<FilterGroup
|
|
18
|
+
title={t('common.category')}
|
|
19
|
+
options={categoryOptions}
|
|
20
|
+
value={selectedCategory}
|
|
21
|
+
onChange={handleCategory}
|
|
22
|
+
/>
|
|
23
|
+
</div>
|
|
24
|
+
</StyledAside>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const StyledAside = styled.aside`
|
|
29
|
+
width: 220px;
|
|
30
|
+
margin-right: ${(props) => props.theme.spacing(2)};
|
|
31
|
+
height: 100%;
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
Aside.propTypes = {};
|
|
35
|
+
Aside.defaultProps = {};
|
|
36
|
+
export default Aside;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { Chip } from '@mui/material';
|
|
5
|
+
|
|
6
|
+
const StyleDiv = styled.div`
|
|
7
|
+
.MuiChip-root {
|
|
8
|
+
border-radius: 4px;
|
|
9
|
+
height: initial;
|
|
10
|
+
text-transform: capitalize;
|
|
11
|
+
margin-right: ${(props) => props.theme.spacing(2)};
|
|
12
|
+
padding: 4px 0;
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
15
|
+
const FilterChip = ({ label, icon, onDelete, ...containerProps }) => {
|
|
16
|
+
if (!label) return null;
|
|
17
|
+
return (
|
|
18
|
+
<StyleDiv {...containerProps}>
|
|
19
|
+
<Chip icon={icon} label={label} onDelete={onDelete} />
|
|
20
|
+
</StyleDiv>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
FilterChip.propTypes = {
|
|
24
|
+
label: PropTypes.string,
|
|
25
|
+
onDelete: PropTypes.func,
|
|
26
|
+
icon: PropTypes.element,
|
|
27
|
+
};
|
|
28
|
+
FilterChip.defaultProps = {
|
|
29
|
+
onDelete: () => {},
|
|
30
|
+
icon: null,
|
|
31
|
+
label: null,
|
|
32
|
+
};
|
|
33
|
+
export default FilterChip;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
function FilterGroup({ options, onChange, title, value }) {
|
|
6
|
+
return (
|
|
7
|
+
<StyledDiv>
|
|
8
|
+
<div className="title">{title}</div>
|
|
9
|
+
<div className="list">
|
|
10
|
+
{options.map((item) => {
|
|
11
|
+
return (
|
|
12
|
+
<div
|
|
13
|
+
title={item.name}
|
|
14
|
+
key={item.value}
|
|
15
|
+
data-cy="filter"
|
|
16
|
+
className={value === item.value ? 'select item' : 'item'}
|
|
17
|
+
onClick={() => onChange(item.value)}>
|
|
18
|
+
{item.name}
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
})}
|
|
22
|
+
</div>
|
|
23
|
+
</StyledDiv>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const StyledDiv = styled.div`
|
|
28
|
+
.title {
|
|
29
|
+
font-size: 18px;
|
|
30
|
+
font-weight: bold;
|
|
31
|
+
margin-bottom: ${(props) => props.theme.spacing(2)};
|
|
32
|
+
}
|
|
33
|
+
.list {
|
|
34
|
+
}
|
|
35
|
+
.item {
|
|
36
|
+
font-size: 16px;
|
|
37
|
+
font-weight: bold;
|
|
38
|
+
padding: ${(props) => props.theme.spacing(2)} ${(props) => props.theme.spacing(1)};
|
|
39
|
+
color: #9397a1;
|
|
40
|
+
overflow: hidden;
|
|
41
|
+
text-overflow: ellipsis;
|
|
42
|
+
white-space: nowrap;
|
|
43
|
+
text-transform: capitalize;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
&:hover {
|
|
46
|
+
background-color: ${(props) => props.theme.palette.grey[50]};
|
|
47
|
+
color: initial;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
.select {
|
|
51
|
+
color: ${(props) => props.theme.palette.primary.main};
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
FilterGroup.propTypes = {
|
|
56
|
+
title: PropTypes.string.isRequired,
|
|
57
|
+
options: PropTypes.array.isRequired,
|
|
58
|
+
onChange: PropTypes.func.isRequired,
|
|
59
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
60
|
+
};
|
|
61
|
+
FilterGroup.defaultProps = {
|
|
62
|
+
value: null,
|
|
63
|
+
};
|
|
64
|
+
export default FilterGroup;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import FilterAltOutlinedIcon from '@mui/icons-material/FilterAltOutlined';
|
|
4
|
+
import Dialog from '@arcblock/ux/lib/Dialog';
|
|
5
|
+
import Button from '@mui/material/Button';
|
|
6
|
+
|
|
7
|
+
import { useFilterContext } from '../../contexts/filter';
|
|
8
|
+
import FilterGroup from './group';
|
|
9
|
+
|
|
10
|
+
function FilterIcon() {
|
|
11
|
+
const { selectedCategory, handleCategory, t, handlePrice, filters, categoryOptions, priceOptions } =
|
|
12
|
+
useFilterContext();
|
|
13
|
+
const [open, setOpen] = useState(false);
|
|
14
|
+
|
|
15
|
+
const handelChange = (type, value) => {
|
|
16
|
+
if (type === 'category') {
|
|
17
|
+
handleCategory(value);
|
|
18
|
+
}
|
|
19
|
+
if (type === 'price') {
|
|
20
|
+
handlePrice(value);
|
|
21
|
+
}
|
|
22
|
+
setOpen(false);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<StyledDiv>
|
|
27
|
+
<Button variant="outlined" className="filter-button" onClick={() => setOpen(true)}>
|
|
28
|
+
<FilterAltOutlinedIcon className="filter-icon" fontSize="small" />
|
|
29
|
+
</Button>
|
|
30
|
+
<Dialog fullWidth title="" open={open} onClose={() => setOpen(false)}>
|
|
31
|
+
<FilterGroup
|
|
32
|
+
title={t('common.price')}
|
|
33
|
+
options={priceOptions}
|
|
34
|
+
value={filters.price}
|
|
35
|
+
onChange={(v) => {
|
|
36
|
+
handelChange('price', v);
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
<div style={{ marginTop: '32px' }}>
|
|
40
|
+
<FilterGroup
|
|
41
|
+
title={t('common.category')}
|
|
42
|
+
options={categoryOptions}
|
|
43
|
+
value={selectedCategory}
|
|
44
|
+
onChange={(v) => {
|
|
45
|
+
handelChange('category', v);
|
|
46
|
+
}}
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
</Dialog>
|
|
50
|
+
</StyledDiv>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const StyledDiv = styled.div`
|
|
55
|
+
.filter-button {
|
|
56
|
+
margin-right: 16px;
|
|
57
|
+
border-color: rgb(240, 240, 240);
|
|
58
|
+
padding: 5px 8px;
|
|
59
|
+
min-width: initial;
|
|
60
|
+
}
|
|
61
|
+
.filter-icon {
|
|
62
|
+
cursor: pointer;
|
|
63
|
+
color: ${(props) => props.theme.palette.grey[500]};
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
FilterIcon.propTypes = {};
|
|
68
|
+
FilterIcon.defaultProps = {};
|
|
69
|
+
export default FilterIcon;
|
|
@@ -81,7 +81,7 @@ export default function BlockletList({ blocklets, ...rest }) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
return (
|
|
84
|
-
<Grid container
|
|
84
|
+
<Grid container {...rest}>
|
|
85
85
|
{blocklets.map((blocklet) => (
|
|
86
86
|
<StyledGrid item lg={4} md={6} sm={6} xs={12} key={blocklet.did} data-blocklet-did={blocklet.did}>
|
|
87
87
|
{blockletRender({ blocklet, blocklets: blockletList })}
|
|
@@ -101,8 +101,13 @@ const StyledGrid = styled(Grid)`
|
|
|
101
101
|
@media (max-width: ${(props) => props.theme.breakpoints.values.sm}px) {
|
|
102
102
|
&.MuiGrid-item {
|
|
103
103
|
padding-bottom: 0px;
|
|
104
|
-
|
|
105
|
-
padding-right:
|
|
104
|
+
margin-left: ${(props) => props.theme.spacing(-2)};
|
|
105
|
+
padding-right: ${(props) => props.theme.spacing(0.5)};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
@media (min-width: ${(props) => props.theme.breakpoints.values.sm}px) {
|
|
109
|
+
&.MuiGrid-item {
|
|
110
|
+
margin-bottom: ${(props) => props.theme.spacing(2)};
|
|
106
111
|
}
|
|
107
112
|
}
|
|
108
113
|
`;
|
package/src/components/search.js
CHANGED
|
@@ -60,11 +60,10 @@ Search.defaultProps = {
|
|
|
60
60
|
};
|
|
61
61
|
const StyledSearch = styled(OutlinedInput)`
|
|
62
62
|
background-color: #fff;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
margin: 0 10px;
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
border-radius: 6px;
|
|
66
65
|
.MuiInputBase-input {
|
|
67
|
-
padding:
|
|
66
|
+
padding: 8px 0 8px 10px;
|
|
68
67
|
}
|
|
69
68
|
.MuiOutlinedInput-notchedOutline {
|
|
70
69
|
border: none;
|
|
@@ -75,13 +74,6 @@ const StyledSearch = styled(OutlinedInput)`
|
|
|
75
74
|
color: transparent;
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
|
-
@media (max-width: ${(props) => props.theme.breakpoints.values.md}px) {
|
|
79
|
-
font-size: 14px;
|
|
80
|
-
border-radius: 6px;
|
|
81
|
-
.MuiInputBase-input {
|
|
82
|
-
padding: 8px 0 8px 10px;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
77
|
`;
|
|
86
78
|
|
|
87
79
|
const StyledSearchIcon = styled(SearchIcon)`
|
package/src/contexts/filter.js
CHANGED
|
@@ -5,24 +5,14 @@ import orderBy from 'lodash/orderBy';
|
|
|
5
5
|
import axios from 'axios';
|
|
6
6
|
// import joinUrl from 'url-join';
|
|
7
7
|
|
|
8
|
-
import { getCategories, filterBlockletByPrice, replaceTranslate } from '../libs/utils';
|
|
8
|
+
import { getCategories, filterBlockletByPrice, replaceTranslate, getPrices, getCategoryOptions } from '../libs/utils';
|
|
9
9
|
import translations from '../assets/locale';
|
|
10
10
|
import { propTypes, defaultProps } from '../libs/prop-types';
|
|
11
11
|
|
|
12
12
|
const Filter = createContext({});
|
|
13
13
|
const { Provider, Consumer } = Filter;
|
|
14
14
|
|
|
15
|
-
function FilterProvider({
|
|
16
|
-
onSelectBlocklet,
|
|
17
|
-
selectedBlocklets,
|
|
18
|
-
filters,
|
|
19
|
-
children,
|
|
20
|
-
baseUrl,
|
|
21
|
-
endpoint,
|
|
22
|
-
locale,
|
|
23
|
-
blockletRender,
|
|
24
|
-
onFilterChange,
|
|
25
|
-
}) {
|
|
15
|
+
function FilterProvider({ filters, children, baseUrl, endpoint, locale, blockletRender, onFilterChange }) {
|
|
26
16
|
const storeApi = axios.create({
|
|
27
17
|
baseURL: endpoint,
|
|
28
18
|
});
|
|
@@ -105,6 +95,10 @@ function FilterProvider({
|
|
|
105
95
|
|
|
106
96
|
return replaceTranslate(translations[locale][key], data);
|
|
107
97
|
};
|
|
98
|
+
|
|
99
|
+
const categoryOptions = useMemo(() => getCategoryOptions(categoryList, locale), [categoryList, locale]);
|
|
100
|
+
const priceOptions = getPrices(translate);
|
|
101
|
+
|
|
108
102
|
const filterStore = {
|
|
109
103
|
errors: { fetchBlockletsError, fetchCategoriesError },
|
|
110
104
|
loadings: { fetchBlockletsLoading, fetchCategoriesLoading },
|
|
@@ -117,8 +111,8 @@ function FilterProvider({
|
|
|
117
111
|
baseUrl,
|
|
118
112
|
blockletRender,
|
|
119
113
|
locale,
|
|
120
|
-
|
|
121
|
-
|
|
114
|
+
categoryOptions,
|
|
115
|
+
priceOptions,
|
|
122
116
|
handleSort: (sort) => {
|
|
123
117
|
const changeData = {
|
|
124
118
|
...filters,
|
|
@@ -143,7 +137,7 @@ function FilterProvider({
|
|
|
143
137
|
const changeData = { ...filters, category: undefined };
|
|
144
138
|
onFilterChange(changeData);
|
|
145
139
|
} else {
|
|
146
|
-
const changeData = { ...filters, category };
|
|
140
|
+
const changeData = { ...filters, category: category === filters.category ? undefined : category };
|
|
147
141
|
onFilterChange(changeData);
|
|
148
142
|
}
|
|
149
143
|
},
|
package/src/libs/utils.js
CHANGED
|
@@ -35,6 +35,9 @@ const getPrices = (t) => {
|
|
|
35
35
|
{ name: t('blocklet.payment'), value: 'payment' },
|
|
36
36
|
];
|
|
37
37
|
};
|
|
38
|
+
const getCategoryOptions = (list = [], locale = 'en') => {
|
|
39
|
+
return list.map((item) => ({ name: item.locales[locale], value: item.name }));
|
|
40
|
+
};
|
|
38
41
|
/**
|
|
39
42
|
* 从开发者所属 blocklets 中的得到 Categories
|
|
40
43
|
* @param {*} list
|
|
@@ -114,4 +117,5 @@ export {
|
|
|
114
117
|
formatError,
|
|
115
118
|
removeUndefined,
|
|
116
119
|
urlStringify,
|
|
120
|
+
getCategoryOptions,
|
|
117
121
|
};
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
var _react = _interopRequireDefault(require("react"));
|
|
9
|
-
|
|
10
|
-
var _material = require("@mui/material");
|
|
11
|
-
|
|
12
|
-
var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
13
|
-
|
|
14
|
-
var _filter = require("../../contexts/filter");
|
|
15
|
-
|
|
16
|
-
var _utils = require("../../libs/utils");
|
|
17
|
-
|
|
18
|
-
var _search = _interopRequireDefault(require("../search"));
|
|
19
|
-
|
|
20
|
-
var _categoryLinkList = _interopRequireDefault(require("./category-link-list"));
|
|
21
|
-
|
|
22
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
-
|
|
24
|
-
const Aside = () => {
|
|
25
|
-
const {
|
|
26
|
-
filters,
|
|
27
|
-
handlePrice,
|
|
28
|
-
t
|
|
29
|
-
} = (0, _filter.useFilterContext)();
|
|
30
|
-
return /*#__PURE__*/_react.default.createElement(StyledAside, null, /*#__PURE__*/_react.default.createElement(_search.default, {
|
|
31
|
-
placeholder: t('common.searchStore')
|
|
32
|
-
}), /*#__PURE__*/_react.default.createElement(_material.Box, {
|
|
33
|
-
marginTop: "24px"
|
|
34
|
-
}, (0, _utils.getPrices)(t).map(item => /*#__PURE__*/_react.default.createElement(_material.FormControlLabel, {
|
|
35
|
-
className: "payments",
|
|
36
|
-
key: item.value,
|
|
37
|
-
control: /*#__PURE__*/_react.default.createElement(_material.Checkbox, {
|
|
38
|
-
onClick: () => {
|
|
39
|
-
handlePrice(item.value);
|
|
40
|
-
},
|
|
41
|
-
size: "small",
|
|
42
|
-
checked: item.value === filters.price
|
|
43
|
-
}),
|
|
44
|
-
label: item.name
|
|
45
|
-
}))), /*#__PURE__*/_react.default.createElement(_material.List, {
|
|
46
|
-
component: "nav",
|
|
47
|
-
color: "primary"
|
|
48
|
-
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
49
|
-
style: {
|
|
50
|
-
border: '1px solid #dadce0',
|
|
51
|
-
margin: '16px 16px'
|
|
52
|
-
}
|
|
53
|
-
}), /*#__PURE__*/_react.default.createElement(_categoryLinkList.default, null)));
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const StyledAside = _styledComponents.default.aside.withConfig({
|
|
57
|
-
displayName: "aside__StyledAside",
|
|
58
|
-
componentId: "sc-1vh5fc3-0"
|
|
59
|
-
})(["width:220px;margin-right:20px;background-color:", ";height:100%;padding:15px 0px;border-radius:8px;.MuiListItemText-root{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}.payments{display:flex;padding:0 16px;.MuiFormControlLabel-label{color:#5f6368;font-size:1rem;}}.MuiListItem-root{text-transform:capitalize;.category > span{font-weight:", ";}>:not(.category){.MuiListItemText-primary{color:#5f6368;}}&.Mui-selected{background-color:", "!important;border-radius:4px;.MuiListItemText-primary{color:#fff !important;}}}@media (max-width:", "px){.MuiListItemText-primary{font-size:16px;}}"], props => props.theme.palette.grey[50], props => props.theme.typography.fontWeightBold, props => props.theme.palette.primary.main, props => props.theme.breakpoints.values.md);
|
|
60
|
-
|
|
61
|
-
Aside.propTypes = {};
|
|
62
|
-
Aside.defaultProps = {};
|
|
63
|
-
var _default = Aside;
|
|
64
|
-
exports.default = _default;
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
var _react = _interopRequireDefault(require("react"));
|
|
9
|
-
|
|
10
|
-
var _material = require("@mui/material");
|
|
11
|
-
|
|
12
|
-
var _urlJoin = _interopRequireDefault(require("url-join"));
|
|
13
|
-
|
|
14
|
-
var _filter = require("../../contexts/filter");
|
|
15
|
-
|
|
16
|
-
var _utils = require("../../libs/utils");
|
|
17
|
-
|
|
18
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
-
|
|
20
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
21
|
-
|
|
22
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
23
|
-
|
|
24
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* 宽屏幕下的分类列表
|
|
28
|
-
* @returns
|
|
29
|
-
*/
|
|
30
|
-
const CategoryLinkList = () => {
|
|
31
|
-
const {
|
|
32
|
-
categoryList,
|
|
33
|
-
selectedCategory,
|
|
34
|
-
filters,
|
|
35
|
-
baseUrl,
|
|
36
|
-
handleCategory,
|
|
37
|
-
t,
|
|
38
|
-
locale
|
|
39
|
-
} = (0, _filter.useFilterContext)();
|
|
40
|
-
|
|
41
|
-
const handleClick = (e, name) => {
|
|
42
|
-
handleCategory(name);
|
|
43
|
-
e.preventDefault();
|
|
44
|
-
return false;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const content = /*#__PURE__*/_react.default.createElement("div", {
|
|
48
|
-
style: {
|
|
49
|
-
marginRight: '16px'
|
|
50
|
-
}
|
|
51
|
-
}, /*#__PURE__*/_react.default.createElement(_material.ListItem, {
|
|
52
|
-
selected: !selectedCategory,
|
|
53
|
-
button: true,
|
|
54
|
-
onClick: e => handleClick(e, 'all')
|
|
55
|
-
}, /*#__PURE__*/_react.default.createElement(_material.ListItemText, {
|
|
56
|
-
primary: t('category.all')
|
|
57
|
-
})), categoryList.map(item => /*#__PURE__*/_react.default.createElement(_material.ListItem, {
|
|
58
|
-
key: item._id,
|
|
59
|
-
title: item.locales[locale],
|
|
60
|
-
component: _material.Link,
|
|
61
|
-
to: "".concat((0, _urlJoin.default)(baseUrl, '/search'), "?").concat((0, _utils.urlStringify)(_objectSpread(_objectSpread({}, filters), {}, {
|
|
62
|
-
category: item.name
|
|
63
|
-
}))),
|
|
64
|
-
onClick: e => handleClick(e, item.name),
|
|
65
|
-
button: true,
|
|
66
|
-
selected: item.name === selectedCategory
|
|
67
|
-
}, /*#__PURE__*/_react.default.createElement(_material.ListItemText, {
|
|
68
|
-
primary: item.locales[locale]
|
|
69
|
-
}))));
|
|
70
|
-
|
|
71
|
-
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.ListItem, null, /*#__PURE__*/_react.default.createElement(_material.ListItemText, {
|
|
72
|
-
className: "category",
|
|
73
|
-
primary: t('common.category')
|
|
74
|
-
})), content);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
var _default = CategoryLinkList;
|
|
78
|
-
exports.default = _default;
|