@blocklet/list 0.8.31 → 0.8.34

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 CHANGED
@@ -13,6 +13,10 @@ var _material = require("@mui/material");
13
13
 
14
14
  var _Face = _interopRequireDefault(require("@mui/icons-material/Face"));
15
15
 
16
+ var _reactErrorBoundary = require("react-error-boundary");
17
+
18
+ var _ErrorBoundary = require("@arcblock/ux/lib/ErrorBoundary");
19
+
16
20
  var _filter = require("./contexts/filter");
17
21
 
18
22
  var _customSelect = _interopRequireDefault(require("./components/custom-select"));
@@ -104,8 +108,11 @@ function ListBase() {
104
108
  handlePrice(null);
105
109
  }
106
110
  })]
107
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_list.default, {
108
- blocklets: blockletList
111
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactErrorBoundary.ErrorBoundary, {
112
+ FallbackComponent: _ErrorBoundary.ErrorFallback,
113
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_list.default, {
114
+ blocklets: blockletList
115
+ })
109
116
  })]
110
117
  })]
111
118
  });
@@ -33,7 +33,7 @@ function Aside() {
33
33
  value: filters.price,
34
34
  onChange: handlePrice
35
35
  })
36
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
36
+ }), categoryOptions.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
37
37
  style: {
38
38
  marginTop: '16px'
39
39
  },
@@ -68,7 +68,7 @@ function FilterIcon() {
68
68
  onChange: v => {
69
69
  handelChange('price', v);
70
70
  }
71
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
71
+ }), categoryOptions.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
72
72
  style: {
73
73
  marginTop: '16px'
74
74
  },
@@ -3,11 +3,151 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.default = BlockletList;
7
7
 
8
- var _list = _interopRequireDefault(require("./list"));
8
+ var _propTypes = _interopRequireDefault(require("prop-types"));
9
+
10
+ var _styledComponents = _interopRequireDefault(require("styled-components"));
11
+
12
+ var _Empty = _interopRequireDefault(require("@arcblock/ux/lib/Empty"));
13
+
14
+ var _Box = _interopRequireDefault(require("@mui/material/Box"));
15
+
16
+ var _Grid = _interopRequireDefault(require("@mui/material/Grid"));
17
+
18
+ var _CircularProgress = _interopRequireDefault(require("@mui/material/CircularProgress"));
19
+
20
+ var _ErrorBoundary = require("@arcblock/ux/lib/ErrorBoundary");
21
+
22
+ var _empty = require("./empty");
23
+
24
+ var _filter = require("../../contexts/filter");
25
+
26
+ var _jsxRuntime = require("react/jsx-runtime");
27
+
28
+ const _excluded = ["blocklets"];
9
29
 
10
30
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
31
 
12
- var _default = _list.default;
13
- exports.default = _default;
32
+ 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; }
33
+
34
+ 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; }
35
+
36
+ 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; }
37
+
38
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
39
+
40
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
41
+
42
+ function BlockletList(_ref) {
43
+ let {
44
+ blocklets
45
+ } = _ref,
46
+ rest = _objectWithoutProperties(_ref, _excluded);
47
+
48
+ const {
49
+ blockletRender,
50
+ errors,
51
+ loadings,
52
+ selectedCategory,
53
+ blockletList,
54
+ getCategoryLocale,
55
+ filters,
56
+ t,
57
+ endpoint
58
+ } = (0, _filter.useFilterContext)();
59
+ const showFilterTip = !!selectedCategory || !!filters.price;
60
+
61
+ if (errors.fetchBlockletsError) {
62
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ErrorBoundary.ErrorFallback, {
63
+ error: new Error("Failed to fetch blocklets from ".concat(endpoint, ": ").concat(errors.fetchBlockletsError.message))
64
+ });
65
+ }
66
+
67
+ if (loadings.fetchBlockletsLoading) {
68
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
69
+ display: "flex",
70
+ alignItems: "center",
71
+ justifyContent: "center",
72
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CircularProgress.default, {})
73
+ });
74
+ }
75
+
76
+ if (filters.keyword && showFilterTip && blockletList.length === 0) {
77
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(CustomEmpty, {
78
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.EmptyTitle, {
79
+ primaryStart: t('blocklet.noBlockletPart1'),
80
+ primaryEnd: t('blocklet.noBlockletPart2'),
81
+ filter: filters.keyword
82
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResultsTips, {
83
+ keywordTip: true,
84
+ filterTip: true
85
+ })]
86
+ });
87
+ }
88
+
89
+ if (filters.keyword && blockletList.length === 0) {
90
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(CustomEmpty, {
91
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.EmptyTitle, {
92
+ primaryStart: t('blocklet.noBlockletPart1'),
93
+ primaryEnd: t('blocklet.noBlockletPart2'),
94
+ filter: filters.keyword
95
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResultsTips, {
96
+ keywordTip: true
97
+ })]
98
+ });
99
+ }
100
+
101
+ if (showFilterTip && blockletList.length === 0) {
102
+ const categoryLocale = getCategoryLocale(selectedCategory);
103
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(CustomEmpty, {
104
+ children: [categoryLocale ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.EmptyTitle, {
105
+ primaryStart: t('blocklet.noCategoryResults1'),
106
+ primaryEnd: t('blocklet.noCategoryResults2'),
107
+ filter: categoryLocale
108
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResults, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResultsTips, {
109
+ filterTip: true
110
+ })]
111
+ });
112
+ }
113
+
114
+ if (blockletList.length === 0) {
115
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(CustomEmpty, {
116
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResults, {})
117
+ });
118
+ }
119
+
120
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledGrid, _objectSpread(_objectSpread({
121
+ container: true
122
+ }, rest), {}, {
123
+ children: blocklets.map(blocklet => /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledGridItem, {
124
+ item: true,
125
+ lg: 4,
126
+ md: 6,
127
+ sm: 6,
128
+ xs: 12,
129
+ "data-blocklet-did": blocklet.did,
130
+ children: blockletRender({
131
+ blocklet,
132
+ blocklets: blockletList
133
+ })
134
+ }, blocklet.did))
135
+ }));
136
+ }
137
+
138
+ BlockletList.propTypes = {
139
+ blocklets: _propTypes.default.array.isRequired
140
+ };
141
+ BlockletList.defaultProps = {};
142
+ const StyledGrid = (0, _styledComponents.default)(_Grid.default).withConfig({
143
+ displayName: "list__StyledGrid",
144
+ componentId: "sc-1guvpon-0"
145
+ })(["&.MuiGrid-root{width:auto;margin:0 -16px;}"]);
146
+ const StyledGridItem = (0, _styledComponents.default)(_Grid.default).withConfig({
147
+ displayName: "list__StyledGridItem",
148
+ componentId: "sc-1guvpon-1"
149
+ })(["@media (max-width:", "px){&.MuiGrid-item{padding-bottom:0px;}}@media (min-width:", "px){&.MuiGrid-item{margin-bottom:", ";}}"], props => props.theme.breakpoints.values.sm, props => props.theme.breakpoints.values.sm, props => props.theme.spacing(2));
150
+ const CustomEmpty = (0, _styledComponents.default)(_Empty.default).withConfig({
151
+ displayName: "list__CustomEmpty",
152
+ componentId: "sc-1guvpon-2"
153
+ })(["text-align:center;.primary{color:", ";}.tips{margin-top:", ";}"], props => props.theme.palette.primary.main, props => props.theme.spacing(1));
@@ -17,6 +17,8 @@ var _orderBy = _interopRequireDefault(require("lodash/orderBy"));
17
17
 
18
18
  var _axios = _interopRequireDefault(require("axios"));
19
19
 
20
+ var _isArray = _interopRequireDefault(require("lodash/isArray"));
21
+
20
22
  var _utils = require("../libs/utils");
21
23
 
22
24
  var _locale = _interopRequireDefault(require("../assets/locale"));
@@ -44,11 +46,11 @@ function FilterProvider(_ref) {
44
46
  let {
45
47
  filters,
46
48
  children,
47
- baseUrl,
48
49
  endpoint,
49
50
  locale,
50
51
  blockletRender,
51
- onFilterChange
52
+ onFilterChange,
53
+ extraFilter
52
54
  } = _ref;
53
55
 
54
56
  const storeApi = _axios.default.create({
@@ -62,9 +64,14 @@ function FilterProvider(_ref) {
62
64
  run: fetchBlocklets
63
65
  } = (0, _ahooks.useRequest)(async () => {
64
66
  const {
65
- data: list
67
+ data
66
68
  } = await storeApi.get('/api/blocklets.json');
67
- return list;
69
+
70
+ if (!(0, _isArray.default)(data)) {
71
+ throw new Error('/api/blocklets.json response is not array');
72
+ }
73
+
74
+ return data;
68
75
  }, {
69
76
  initialData: [],
70
77
  manual: true
@@ -76,9 +83,14 @@ function FilterProvider(_ref) {
76
83
  run: fetchCategories
77
84
  } = (0, _ahooks.useRequest)(async () => {
78
85
  const {
79
- data: list
86
+ data
80
87
  } = await storeApi.get('/api/blocklets/categories');
81
- return list;
88
+
89
+ if (!(0, _isArray.default)(data)) {
90
+ throw new Error('/api/blocklets/categories response is not array');
91
+ }
92
+
93
+ return data;
82
94
  }, {
83
95
  initialData: [],
84
96
  manual: true
@@ -135,7 +147,9 @@ function FilterProvider(_ref) {
135
147
  var _ref2, _item$description, _item$version;
136
148
 
137
149
  return ((_ref2 = (item === null || item === void 0 ? void 0 : item.title) || (item === null || item === void 0 ? void 0 : item.name)) === null || _ref2 === void 0 ? void 0 : _ref2.toLocaleLowerCase().includes(lowerSearch)) || ((_item$description = item.description) === null || _item$description === void 0 ? void 0 : _item$description.toLocaleLowerCase().includes(lowerSearch)) || (item === null || item === void 0 ? void 0 : (_item$version = item.version) === null || _item$version === void 0 ? void 0 : _item$version.toLocaleLowerCase().includes(lowerSearch));
138
- }); // 排序
150
+ }); // 用户传入的过滤函数
151
+
152
+ blocklets = extraFilter(blocklets); // 排序
139
153
 
140
154
  return (0, _orderBy.default)(blocklets, [sortMap[finalFilters.sortBy]], [finalFilters.sortDirection]);
141
155
  }, [allBlocklets, finalFilters]);
@@ -171,7 +185,6 @@ function FilterProvider(_ref) {
171
185
  filters: finalFilters,
172
186
  selectedCategory,
173
187
  categoryList,
174
- baseUrl,
175
188
  blockletRender,
176
189
  locale,
177
190
  categoryOptions,
@@ -231,9 +244,10 @@ function FilterProvider(_ref) {
231
244
  },
232
245
 
233
246
  get developerName() {
234
- var _allBlocklets$find, _allBlocklets$find$ow;
247
+ var _blocklets$find, _blocklets$find$owner;
235
248
 
236
- return ((_allBlocklets$find = allBlocklets.find(blocklet => blocklet.owner.did === finalFilters.developer)) === null || _allBlocklets$find === void 0 ? void 0 : (_allBlocklets$find$ow = _allBlocklets$find.owner) === null || _allBlocklets$find$ow === void 0 ? void 0 : _allBlocklets$find$ow.name) || '';
249
+ const blocklets = allBlocklets || [];
250
+ return ((_blocklets$find = blocklets.find(blocklet => blocklet.owner.did === finalFilters.developer)) === null || _blocklets$find === void 0 ? void 0 : (_blocklets$find$owner = _blocklets$find.owner) === null || _blocklets$find$owner === void 0 ? void 0 : _blocklets$find$owner.name) || '';
237
251
  }
238
252
 
239
253
  };
@@ -18,17 +18,17 @@ const propTypes = {
18
18
  category: _propTypes.default.string,
19
19
  developer: _propTypes.default.string
20
20
  }),
21
+ extraFilter: _propTypes.default.func,
21
22
  endpoint: _propTypes.default.string.isRequired,
22
23
  blockletRender: _propTypes.default.func.isRequired,
23
24
  onFilterChange: _propTypes.default.func,
24
- baseUrl: _propTypes.default.string,
25
25
  locale: _propTypes.default.oneOf(['zh', 'en'])
26
26
  };
27
27
  exports.propTypes = propTypes;
28
28
  const defaultProps = {
29
- baseUrl: null,
30
29
  locale: 'zh',
31
30
  filters: {},
32
- onFilterChange: () => {}
31
+ onFilterChange: () => {},
32
+ extraFilter: list => list
33
33
  };
34
34
  exports.defaultProps = defaultProps;
package/lib/libs/utils.js CHANGED
@@ -68,7 +68,9 @@ const getCategoryOptions = function getCategoryOptions() {
68
68
 
69
69
  exports.getCategoryOptions = getCategoryOptions;
70
70
 
71
- const getCategories = (list, developerDid) => {
71
+ const getCategories = function getCategories() {
72
+ let list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
73
+ let developerDid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
72
74
  const filterList = list.filter(item => developerDid ? item.owner.did === developerDid : true);
73
75
  const Categories = filterList.map(item => item.category);
74
76
  const res = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/list",
3
- "version": "0.8.31",
3
+ "version": "0.8.34",
4
4
  "description": "Common ux components of blocklet",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -38,7 +38,7 @@
38
38
  "react": ">=18.1.0"
39
39
  },
40
40
  "dependencies": {
41
- "@arcblock/ux": "^2.1.16",
41
+ "@arcblock/ux": "^2.1.19",
42
42
  "@emotion/react": "^11.9.0",
43
43
  "@emotion/styled": "^11.8.1",
44
44
  "@mui/icons-material": "^5.6.2",
@@ -47,6 +47,7 @@
47
47
  "flat": "^5.0.2",
48
48
  "lodash": "^4.17.21",
49
49
  "prop-types": "^15.7.2",
50
+ "react-error-boundary": "^3.1.4",
50
51
  "styled-components": "5.3.5",
51
52
  "url-join": "^4.0.1"
52
53
  },
@@ -62,5 +63,5 @@
62
63
  "eslint": "^8.16.0",
63
64
  "prettier": "^2.6.2"
64
65
  },
65
- "gitHead": "cc9c1156de04b1e1277a34fdc55a35bc36748383"
66
+ "gitHead": "fed8918e15b5bd8cb3f4bac84b32434b58dda21b"
66
67
  }
package/src/base.js CHANGED
@@ -2,6 +2,8 @@ import styled from 'styled-components';
2
2
  import SortIcon from '@mui/icons-material/Sort';
3
3
  import { Box, Hidden } from '@mui/material';
4
4
  import FaceIcon from '@mui/icons-material/Face';
5
+ import { ErrorBoundary } from 'react-error-boundary';
6
+ import { ErrorFallback } from '@arcblock/ux/lib/ErrorBoundary';
5
7
 
6
8
  import { useFilterContext } from './contexts/filter';
7
9
  import CustomSelect from './components/custom-select';
@@ -76,7 +78,9 @@ function ListBase() {
76
78
  }}
77
79
  />
78
80
  </Box>
79
- <BlockletList blocklets={blockletList} />
81
+ <ErrorBoundary FallbackComponent={ErrorFallback}>
82
+ <BlockletList blocklets={blockletList} />
83
+ </ErrorBoundary>
80
84
  </StyledMin>
81
85
  </Box>
82
86
  );
@@ -12,14 +12,16 @@ function Aside() {
12
12
  <div>
13
13
  <FilterGroup title={t('common.price')} options={priceOptions} value={filters.price} onChange={handlePrice} />
14
14
  </div>
15
- <div style={{ marginTop: '16px' }}>
16
- <FilterGroup
17
- title={t('common.category')}
18
- options={categoryOptions}
19
- value={selectedCategory}
20
- onChange={handleCategory}
21
- />
22
- </div>
15
+ {categoryOptions.length > 0 && (
16
+ <div style={{ marginTop: '16px' }}>
17
+ <FilterGroup
18
+ title={t('common.category')}
19
+ options={categoryOptions}
20
+ value={selectedCategory}
21
+ onChange={handleCategory}
22
+ />
23
+ </div>
24
+ )}
23
25
  </StyledAside>
24
26
  );
25
27
  }
@@ -36,16 +36,18 @@ function FilterIcon() {
36
36
  handelChange('price', v);
37
37
  }}
38
38
  />
39
- <div style={{ marginTop: '16px' }}>
40
- <FilterGroup
41
- title={t('common.category')}
42
- options={categoryOptions}
43
- value={selectedCategory}
44
- onChange={(v) => {
45
- handelChange('category', v);
46
- }}
47
- />
48
- </div>
39
+ {categoryOptions.length > 0 && (
40
+ <div style={{ marginTop: '16px' }}>
41
+ <FilterGroup
42
+ title={t('common.category')}
43
+ options={categoryOptions}
44
+ value={selectedCategory}
45
+ onChange={(v) => {
46
+ handelChange('category', v);
47
+ }}
48
+ />
49
+ </div>
50
+ )}
49
51
  </Dialog>
50
52
  </StyledDiv>
51
53
  );
@@ -1,3 +1,125 @@
1
- import BlockletList from './list';
1
+ import PropTypes from 'prop-types';
2
+ import styled from 'styled-components';
3
+ import Empty from '@arcblock/ux/lib/Empty';
4
+ import Box from '@mui/material/Box';
5
+ import Grid from '@mui/material/Grid';
6
+ import CircularProgress from '@mui/material/CircularProgress';
7
+ import { ErrorFallback } from '@arcblock/ux/lib/ErrorBoundary';
2
8
 
3
- export default BlockletList;
9
+ import { NoResults, EmptyTitle, NoResultsTips } from './empty';
10
+ import { useFilterContext } from '../../contexts/filter';
11
+
12
+ export default function BlockletList({ blocklets, ...rest }) {
13
+ const { blockletRender, errors, loadings, selectedCategory, blockletList, getCategoryLocale, filters, t, endpoint } =
14
+ useFilterContext();
15
+
16
+ const showFilterTip = !!selectedCategory || !!filters.price;
17
+
18
+ if (errors.fetchBlockletsError) {
19
+ return (
20
+ <ErrorFallback
21
+ error={new Error(`Failed to fetch blocklets from ${endpoint}: ${errors.fetchBlockletsError.message}`)}
22
+ />
23
+ );
24
+ }
25
+ if (loadings.fetchBlockletsLoading) {
26
+ return (
27
+ <Box display="flex" alignItems="center" justifyContent="center">
28
+ <CircularProgress />
29
+ </Box>
30
+ );
31
+ }
32
+ if (filters.keyword && showFilterTip && blockletList.length === 0) {
33
+ return (
34
+ <CustomEmpty>
35
+ <EmptyTitle
36
+ primaryStart={t('blocklet.noBlockletPart1')}
37
+ primaryEnd={t('blocklet.noBlockletPart2')}
38
+ filter={filters.keyword}
39
+ />
40
+ <NoResultsTips keywordTip filterTip />
41
+ </CustomEmpty>
42
+ );
43
+ }
44
+ if (filters.keyword && blockletList.length === 0) {
45
+ return (
46
+ <CustomEmpty>
47
+ <EmptyTitle
48
+ primaryStart={t('blocklet.noBlockletPart1')}
49
+ primaryEnd={t('blocklet.noBlockletPart2')}
50
+ filter={filters.keyword}
51
+ />
52
+ <NoResultsTips keywordTip />
53
+ </CustomEmpty>
54
+ );
55
+ }
56
+ if (showFilterTip && blockletList.length === 0) {
57
+ const categoryLocale = getCategoryLocale(selectedCategory);
58
+ return (
59
+ <CustomEmpty>
60
+ {categoryLocale ? (
61
+ <EmptyTitle
62
+ primaryStart={t('blocklet.noCategoryResults1')}
63
+ primaryEnd={t('blocklet.noCategoryResults2')}
64
+ filter={categoryLocale}
65
+ />
66
+ ) : (
67
+ <NoResults />
68
+ )}
69
+ <NoResultsTips filterTip />
70
+ </CustomEmpty>
71
+ );
72
+ }
73
+ if (blockletList.length === 0) {
74
+ return (
75
+ <CustomEmpty>
76
+ <NoResults />
77
+ </CustomEmpty>
78
+ );
79
+ }
80
+
81
+ return (
82
+ <StyledGrid container {...rest}>
83
+ {blocklets.map((blocklet) => (
84
+ <StyledGridItem item lg={4} md={6} sm={6} xs={12} key={blocklet.did} data-blocklet-did={blocklet.did}>
85
+ {blockletRender({ blocklet, blocklets: blockletList })}
86
+ </StyledGridItem>
87
+ ))}
88
+ </StyledGrid>
89
+ );
90
+ }
91
+
92
+ BlockletList.propTypes = {
93
+ blocklets: PropTypes.array.isRequired,
94
+ };
95
+
96
+ BlockletList.defaultProps = {};
97
+
98
+ const StyledGrid = styled(Grid)`
99
+ &.MuiGrid-root {
100
+ width: auto;
101
+ margin: 0 -16px;
102
+ }
103
+ `;
104
+
105
+ const StyledGridItem = styled(Grid)`
106
+ @media (max-width: ${(props) => props.theme.breakpoints.values.sm}px) {
107
+ &.MuiGrid-item {
108
+ padding-bottom: 0px;
109
+ }
110
+ }
111
+ @media (min-width: ${(props) => props.theme.breakpoints.values.sm}px) {
112
+ &.MuiGrid-item {
113
+ margin-bottom: ${(props) => props.theme.spacing(2)};
114
+ }
115
+ }
116
+ `;
117
+ const CustomEmpty = styled(Empty)`
118
+ text-align: center;
119
+ .primary {
120
+ color: ${(props) => props.theme.palette.primary.main};
121
+ }
122
+ .tips {
123
+ margin-top: ${(props) => props.theme.spacing(1)};
124
+ }
125
+ `;
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import { useRequest } from 'ahooks';
4
4
  import orderBy from 'lodash/orderBy';
5
5
  import axios from 'axios';
6
- // import joinUrl from 'url-join';
6
+ import isArray from 'lodash/isArray';
7
7
 
8
8
  import { getCategories, filterBlockletByPrice, replaceTranslate, getPrices, getCategoryOptions } from '../libs/utils';
9
9
  import translations from '../assets/locale';
@@ -12,7 +12,7 @@ import { propTypes, defaultProps } from '../libs/prop-types';
12
12
  const Filter = createContext({});
13
13
  const { Provider, Consumer } = Filter;
14
14
 
15
- function FilterProvider({ filters, children, baseUrl, endpoint, locale, blockletRender, onFilterChange }) {
15
+ function FilterProvider({ filters, children, endpoint, locale, blockletRender, onFilterChange, extraFilter }) {
16
16
  const storeApi = axios.create({
17
17
  baseURL: endpoint,
18
18
  });
@@ -23,8 +23,11 @@ function FilterProvider({ filters, children, baseUrl, endpoint, locale, blocklet
23
23
  run: fetchBlocklets,
24
24
  } = useRequest(
25
25
  async () => {
26
- const { data: list } = await storeApi.get('/api/blocklets.json');
27
- return list;
26
+ const { data } = await storeApi.get('/api/blocklets.json');
27
+ if (!isArray(data)) {
28
+ throw new Error('/api/blocklets.json response is not array');
29
+ }
30
+ return data;
28
31
  },
29
32
  { initialData: [], manual: true }
30
33
  );
@@ -36,8 +39,11 @@ function FilterProvider({ filters, children, baseUrl, endpoint, locale, blocklet
36
39
  run: fetchCategories,
37
40
  } = useRequest(
38
41
  async () => {
39
- const { data: list } = await storeApi.get('/api/blocklets/categories');
40
- return list;
42
+ const { data } = await storeApi.get('/api/blocklets/categories');
43
+ if (!isArray(data)) {
44
+ throw new Error('/api/blocklets/categories response is not array');
45
+ }
46
+ return data;
41
47
  },
42
48
  { initialData: [], manual: true }
43
49
  );
@@ -59,7 +65,6 @@ function FilterProvider({ filters, children, baseUrl, endpoint, locale, blocklet
59
65
  popularity: sortByPopularity,
60
66
  publishAt: sortByPublish,
61
67
  };
62
-
63
68
  let blocklets = allBlocklets || [];
64
69
  // 按照付费/免费筛选
65
70
  blocklets = filterBlockletByPrice(blocklets, finalFilters.price);
@@ -78,6 +83,8 @@ function FilterProvider({ filters, children, baseUrl, endpoint, locale, blocklet
78
83
  item?.version?.toLocaleLowerCase().includes(lowerSearch)
79
84
  );
80
85
  });
86
+ // 用户传入的过滤函数
87
+ blocklets = extraFilter(blocklets);
81
88
  // 排序
82
89
  return orderBy(blocklets, [sortMap[finalFilters.sortBy]], [finalFilters.sortDirection]);
83
90
  }, [allBlocklets, finalFilters]);
@@ -96,10 +103,8 @@ function FilterProvider({ filters, children, baseUrl, endpoint, locale, blocklet
96
103
 
97
104
  return replaceTranslate(translations[locale][key], data);
98
105
  };
99
-
100
106
  const categoryOptions = useMemo(() => getCategoryOptions(categoryList, locale), [categoryList, locale]);
101
107
  const priceOptions = getPrices(translate);
102
-
103
108
  const filterStore = {
104
109
  errors: { fetchBlockletsError, fetchCategoriesError },
105
110
  loadings: { fetchBlockletsLoading, fetchCategoriesLoading },
@@ -109,7 +114,6 @@ function FilterProvider({ filters, children, baseUrl, endpoint, locale, blocklet
109
114
  filters: finalFilters,
110
115
  selectedCategory,
111
116
  categoryList,
112
- baseUrl,
113
117
  blockletRender,
114
118
  locale,
115
119
  categoryOptions,
@@ -155,7 +159,8 @@ function FilterProvider({ filters, children, baseUrl, endpoint, locale, blocklet
155
159
  return result;
156
160
  },
157
161
  get developerName() {
158
- return allBlocklets.find((blocklet) => blocklet.owner.did === finalFilters.developer)?.owner?.name || '';
162
+ const blocklets = allBlocklets || [];
163
+ return blocklets.find((blocklet) => blocklet.owner.did === finalFilters.developer)?.owner?.name || '';
159
164
  },
160
165
  };
161
166
 
@@ -9,18 +9,18 @@ const propTypes = {
9
9
  category: PropTypes.string,
10
10
  developer: PropTypes.string,
11
11
  }),
12
+ extraFilter: PropTypes.func,
12
13
  endpoint: PropTypes.string.isRequired,
13
14
  blockletRender: PropTypes.func.isRequired,
14
15
  onFilterChange: PropTypes.func,
15
- baseUrl: PropTypes.string,
16
16
  locale: PropTypes.oneOf(['zh', 'en']),
17
17
  };
18
18
 
19
19
  const defaultProps = {
20
- baseUrl: null,
21
20
  locale: 'zh',
22
21
  filters: {},
23
22
  onFilterChange: () => {},
23
+ extraFilter: (list) => list,
24
24
  };
25
25
 
26
26
  export { propTypes, defaultProps };
package/src/libs/utils.js CHANGED
@@ -44,7 +44,7 @@ const getCategoryOptions = (list = [], locale = 'en') => {
44
44
  * @param {*} developerDid
45
45
  * @returns
46
46
  */
47
- const getCategories = (list, developerDid) => {
47
+ const getCategories = (list = [], developerDid = null) => {
48
48
  const filterList = list.filter((item) => (developerDid ? item.owner.did === developerDid : true));
49
49
  const Categories = filterList.map((item) => item.category);
50
50
  const res = new Map();
@@ -1,158 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = BlockletList;
7
-
8
- var _propTypes = _interopRequireDefault(require("prop-types"));
9
-
10
- var _styledComponents = _interopRequireDefault(require("styled-components"));
11
-
12
- var _Empty = _interopRequireDefault(require("@arcblock/ux/lib/Empty"));
13
-
14
- var _Alert = _interopRequireDefault(require("@arcblock/ux/lib/Alert"));
15
-
16
- var _Box = _interopRequireDefault(require("@mui/material/Box"));
17
-
18
- var _Grid = _interopRequireDefault(require("@mui/material/Grid"));
19
-
20
- var _CircularProgress = _interopRequireDefault(require("@mui/material/CircularProgress"));
21
-
22
- var _empty = require("./empty");
23
-
24
- var _filter = require("../../contexts/filter");
25
-
26
- var _utils = require("../../libs/utils");
27
-
28
- var _jsxRuntime = require("react/jsx-runtime");
29
-
30
- const _excluded = ["blocklets"];
31
-
32
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
-
34
- 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; }
35
-
36
- 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; }
37
-
38
- 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; }
39
-
40
- function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
41
-
42
- function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
43
-
44
- function BlockletList(_ref) {
45
- let {
46
- blocklets
47
- } = _ref,
48
- rest = _objectWithoutProperties(_ref, _excluded);
49
-
50
- const {
51
- blockletRender,
52
- errors,
53
- loadings,
54
- selectedCategory,
55
- blockletList,
56
- getCategoryLocale,
57
- filters,
58
- t
59
- } = (0, _filter.useFilterContext)();
60
- const showFilterTip = !!selectedCategory || !!filters.price;
61
-
62
- if (errors.fetchBlockletsError) {
63
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Alert.default, {
64
- type: "error",
65
- variant: "icon",
66
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
67
- children: (0, _utils.formatError)(errors.fetchBlockletsError)
68
- })
69
- });
70
- }
71
-
72
- if (loadings.fetchBlockletsLoading) {
73
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
74
- display: "flex",
75
- alignItems: "center",
76
- justifyContent: "center",
77
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CircularProgress.default, {})
78
- });
79
- }
80
-
81
- if (filters.keyword && showFilterTip && blockletList.length === 0) {
82
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(CustomEmpty, {
83
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.EmptyTitle, {
84
- primaryStart: t('blocklet.noBlockletPart1'),
85
- primaryEnd: t('blocklet.noBlockletPart2'),
86
- filter: filters.keyword
87
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResultsTips, {
88
- keywordTip: true,
89
- filterTip: true
90
- })]
91
- });
92
- }
93
-
94
- if (filters.keyword && blockletList.length === 0) {
95
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(CustomEmpty, {
96
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.EmptyTitle, {
97
- primaryStart: t('blocklet.noBlockletPart1'),
98
- primaryEnd: t('blocklet.noBlockletPart2'),
99
- filter: filters.keyword
100
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResultsTips, {
101
- keywordTip: true
102
- })]
103
- });
104
- }
105
-
106
- if (showFilterTip && blockletList.length === 0) {
107
- const categoryLocale = getCategoryLocale(selectedCategory);
108
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(CustomEmpty, {
109
- children: [categoryLocale ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.EmptyTitle, {
110
- primaryStart: t('blocklet.noCategoryResults1'),
111
- primaryEnd: t('blocklet.noCategoryResults2'),
112
- filter: categoryLocale
113
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResults, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResultsTips, {
114
- filterTip: true
115
- })]
116
- });
117
- }
118
-
119
- if (blockletList.length === 0) {
120
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(CustomEmpty, {
121
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_empty.NoResults, {})
122
- });
123
- }
124
-
125
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledGrid, _objectSpread(_objectSpread({
126
- container: true
127
- }, rest), {}, {
128
- children: blocklets.map(blocklet => /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledGridItem, {
129
- item: true,
130
- lg: 4,
131
- md: 6,
132
- sm: 6,
133
- xs: 12,
134
- "data-blocklet-did": blocklet.did,
135
- children: blockletRender({
136
- blocklet,
137
- blocklets: blockletList
138
- })
139
- }, blocklet.did))
140
- }));
141
- }
142
-
143
- BlockletList.propTypes = {
144
- blocklets: _propTypes.default.array.isRequired
145
- };
146
- BlockletList.defaultProps = {};
147
- const StyledGrid = (0, _styledComponents.default)(_Grid.default).withConfig({
148
- displayName: "list__StyledGrid",
149
- componentId: "sc-jzgpev-0"
150
- })(["&.MuiGrid-root{width:auto;margin:0 -16px;}"]);
151
- const StyledGridItem = (0, _styledComponents.default)(_Grid.default).withConfig({
152
- displayName: "list__StyledGridItem",
153
- componentId: "sc-jzgpev-1"
154
- })(["@media (max-width:", "px){&.MuiGrid-item{padding-bottom:0px;}}@media (min-width:", "px){&.MuiGrid-item{margin-bottom:", ";}}"], props => props.theme.breakpoints.values.sm, props => props.theme.breakpoints.values.sm, props => props.theme.spacing(2));
155
- const CustomEmpty = (0, _styledComponents.default)(_Empty.default).withConfig({
156
- displayName: "list__CustomEmpty",
157
- componentId: "sc-jzgpev-2"
158
- })(["text-align:center;.primary{color:", ";}.tips{margin-top:", ";}"], props => props.theme.palette.primary.main, props => props.theme.spacing(1));
@@ -1,126 +0,0 @@
1
- import PropTypes from 'prop-types';
2
- import styled from 'styled-components';
3
- import Empty from '@arcblock/ux/lib/Empty';
4
- import Alert from '@arcblock/ux/lib/Alert';
5
- import Box from '@mui/material/Box';
6
- import Grid from '@mui/material/Grid';
7
- import CircularProgress from '@mui/material/CircularProgress';
8
-
9
- import { NoResults, EmptyTitle, NoResultsTips } from './empty';
10
- import { useFilterContext } from '../../contexts/filter';
11
- import { formatError } from '../../libs/utils';
12
-
13
- export default function BlockletList({ blocklets, ...rest }) {
14
- const { blockletRender, errors, loadings, selectedCategory, blockletList, getCategoryLocale, filters, t } =
15
- useFilterContext();
16
-
17
- const showFilterTip = !!selectedCategory || !!filters.price;
18
-
19
- if (errors.fetchBlockletsError) {
20
- return (
21
- <Alert type="error" variant="icon">
22
- <div>{formatError(errors.fetchBlockletsError)}</div>
23
- </Alert>
24
- );
25
- }
26
- if (loadings.fetchBlockletsLoading) {
27
- return (
28
- <Box display="flex" alignItems="center" justifyContent="center">
29
- <CircularProgress />
30
- </Box>
31
- );
32
- }
33
- if (filters.keyword && showFilterTip && blockletList.length === 0) {
34
- return (
35
- <CustomEmpty>
36
- <EmptyTitle
37
- primaryStart={t('blocklet.noBlockletPart1')}
38
- primaryEnd={t('blocklet.noBlockletPart2')}
39
- filter={filters.keyword}
40
- />
41
- <NoResultsTips keywordTip filterTip />
42
- </CustomEmpty>
43
- );
44
- }
45
- if (filters.keyword && blockletList.length === 0) {
46
- return (
47
- <CustomEmpty>
48
- <EmptyTitle
49
- primaryStart={t('blocklet.noBlockletPart1')}
50
- primaryEnd={t('blocklet.noBlockletPart2')}
51
- filter={filters.keyword}
52
- />
53
- <NoResultsTips keywordTip />
54
- </CustomEmpty>
55
- );
56
- }
57
- if (showFilterTip && blockletList.length === 0) {
58
- const categoryLocale = getCategoryLocale(selectedCategory);
59
- return (
60
- <CustomEmpty>
61
- {categoryLocale ? (
62
- <EmptyTitle
63
- primaryStart={t('blocklet.noCategoryResults1')}
64
- primaryEnd={t('blocklet.noCategoryResults2')}
65
- filter={categoryLocale}
66
- />
67
- ) : (
68
- <NoResults />
69
- )}
70
- <NoResultsTips filterTip />
71
- </CustomEmpty>
72
- );
73
- }
74
- if (blockletList.length === 0) {
75
- return (
76
- <CustomEmpty>
77
- <NoResults />
78
- </CustomEmpty>
79
- );
80
- }
81
-
82
- return (
83
- <StyledGrid container {...rest}>
84
- {blocklets.map((blocklet) => (
85
- <StyledGridItem item lg={4} md={6} sm={6} xs={12} key={blocklet.did} data-blocklet-did={blocklet.did}>
86
- {blockletRender({ blocklet, blocklets: blockletList })}
87
- </StyledGridItem>
88
- ))}
89
- </StyledGrid>
90
- );
91
- }
92
-
93
- BlockletList.propTypes = {
94
- blocklets: PropTypes.array.isRequired,
95
- };
96
-
97
- BlockletList.defaultProps = {};
98
-
99
- const StyledGrid = styled(Grid)`
100
- &.MuiGrid-root {
101
- width: auto;
102
- margin: 0 -16px;
103
- }
104
- `;
105
-
106
- const StyledGridItem = styled(Grid)`
107
- @media (max-width: ${(props) => props.theme.breakpoints.values.sm}px) {
108
- &.MuiGrid-item {
109
- padding-bottom: 0px;
110
- }
111
- }
112
- @media (min-width: ${(props) => props.theme.breakpoints.values.sm}px) {
113
- &.MuiGrid-item {
114
- margin-bottom: ${(props) => props.theme.spacing(2)};
115
- }
116
- }
117
- `;
118
- const CustomEmpty = styled(Empty)`
119
- text-align: center;
120
- .primary {
121
- color: ${(props) => props.theme.palette.primary.main};
122
- }
123
- .tips {
124
- margin-top: ${(props) => props.theme.spacing(1)};
125
- }
126
- `;