@blocklet/list 0.8.6
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/README.md +0 -0
- package/lib/assets/locale.js +78 -0
- package/lib/base.js +131 -0
- package/lib/components/aside.js +65 -0
- package/lib/components/button.js +64 -0
- package/lib/components/categories.js +145 -0
- package/lib/components/custom-select.js +188 -0
- package/lib/components/empty.js +88 -0
- package/lib/components/filter-author.js +64 -0
- package/lib/components/list.js +132 -0
- package/lib/components/search.js +99 -0
- package/lib/contexts/store.js +333 -0
- package/lib/hooks/page-state.js +69 -0
- package/lib/index.js +33 -0
- package/lib/tools/utils.js +125 -0
- package/package.json +66 -0
- package/src/assets/locale.js +72 -0
- package/src/base.js +148 -0
- package/src/components/aside.js +91 -0
- package/src/components/button.js +35 -0
- package/src/components/categories.js +111 -0
- package/src/components/custom-select.js +207 -0
- package/src/components/empty.js +57 -0
- package/src/components/filter-author.js +39 -0
- package/src/components/list.js +117 -0
- package/src/components/search.js +93 -0
- package/src/contexts/store.js +250 -0
- package/src/hooks/page-state.js +53 -0
- package/src/index.js +27 -0
- package/src/tools/utils.js +97 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.SearchConsumer = void 0;
|
|
7
|
+
exports.SearchProvider = SearchProvider;
|
|
8
|
+
exports.useSearchContext = useSearchContext;
|
|
9
|
+
|
|
10
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
+
|
|
12
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
13
|
+
|
|
14
|
+
var _qs = _interopRequireDefault(require("qs"));
|
|
15
|
+
|
|
16
|
+
var _reactRouterDom = require("react-router-dom");
|
|
17
|
+
|
|
18
|
+
var _ahooks = require("ahooks");
|
|
19
|
+
|
|
20
|
+
var _orderBy = _interopRequireDefault(require("lodash-es/orderBy"));
|
|
21
|
+
|
|
22
|
+
var _axios = _interopRequireDefault(require("axios"));
|
|
23
|
+
|
|
24
|
+
var _urlJoin = _interopRequireDefault(require("url-join"));
|
|
25
|
+
|
|
26
|
+
var _pageState = _interopRequireDefault(require("../hooks/page-state"));
|
|
27
|
+
|
|
28
|
+
var _utils = require("../tools/utils");
|
|
29
|
+
|
|
30
|
+
var _locale = _interopRequireDefault(require("../assets/locale"));
|
|
31
|
+
|
|
32
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
33
|
+
|
|
34
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
35
|
+
|
|
36
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
37
|
+
|
|
38
|
+
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; }
|
|
39
|
+
|
|
40
|
+
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; }
|
|
41
|
+
|
|
42
|
+
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; }
|
|
43
|
+
|
|
44
|
+
const axiosInstance = _axios.default.create();
|
|
45
|
+
|
|
46
|
+
const Search = /*#__PURE__*/(0, _react.createContext)({});
|
|
47
|
+
const {
|
|
48
|
+
Provider,
|
|
49
|
+
Consumer
|
|
50
|
+
} = Search;
|
|
51
|
+
exports.SearchConsumer = Consumer;
|
|
52
|
+
|
|
53
|
+
function SearchProvider(_ref) {
|
|
54
|
+
let {
|
|
55
|
+
children,
|
|
56
|
+
baseUrl,
|
|
57
|
+
type,
|
|
58
|
+
endpoint,
|
|
59
|
+
locale,
|
|
60
|
+
blockletRender
|
|
61
|
+
} = _ref;
|
|
62
|
+
const location = (0, _reactRouterDom.useLocation)();
|
|
63
|
+
const history = (0, _reactRouterDom.useHistory)();
|
|
64
|
+
const pathParams = (0, _reactRouterDom.useParams)();
|
|
65
|
+
const isPageMode = type === 'page';
|
|
66
|
+
|
|
67
|
+
if (isPageMode && !baseUrl) {
|
|
68
|
+
throw new Error('baseUrl is required when type is page');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const {
|
|
72
|
+
data: allBlocklets,
|
|
73
|
+
error: fetchBlockletsError,
|
|
74
|
+
loading: fetchBlockletsLoading
|
|
75
|
+
} = (0, _ahooks.useRequest)(async () => {
|
|
76
|
+
const {
|
|
77
|
+
data: list
|
|
78
|
+
} = await axiosInstance.get((0, _urlJoin.default)(endpoint, '/api/blocklets.json'));
|
|
79
|
+
return list;
|
|
80
|
+
}, {
|
|
81
|
+
initialData: []
|
|
82
|
+
});
|
|
83
|
+
const {
|
|
84
|
+
data: allCategories,
|
|
85
|
+
error: fetchCategoriesError,
|
|
86
|
+
loading: fetchCategoriesLoading,
|
|
87
|
+
run: fetchCategories
|
|
88
|
+
} = (0, _ahooks.useRequest)(async () => {
|
|
89
|
+
const {
|
|
90
|
+
data: list
|
|
91
|
+
} = await axiosInstance.get("".concat((0, _urlJoin.default)(endpoint, '/api/blocklets/categories')));
|
|
92
|
+
return list;
|
|
93
|
+
}, {
|
|
94
|
+
initialData: [],
|
|
95
|
+
manual: true
|
|
96
|
+
});
|
|
97
|
+
const [memoryParams, setMemoryParams] = (0, _react.useState)({
|
|
98
|
+
sortBy: 'popularity',
|
|
99
|
+
sortDirection: 'desc'
|
|
100
|
+
});
|
|
101
|
+
const queryParams = (0, _react.useMemo)(() => {
|
|
102
|
+
return isPageMode ? _qs.default.parse(location.search, {
|
|
103
|
+
ignoreQueryPrefix: true
|
|
104
|
+
}) : memoryParams;
|
|
105
|
+
}, [memoryParams, location.search]);
|
|
106
|
+
let sortParams; // 当作页面使用时 sort 数据比较特殊, 默认取 localStorge 中的值,如果 url query 中有sort值则优先使用
|
|
107
|
+
|
|
108
|
+
if (isPageMode) {
|
|
109
|
+
const localSortParams = (0, _pageState.default)({
|
|
110
|
+
sort: 'popularity',
|
|
111
|
+
direction: 'desc'
|
|
112
|
+
}, baseUrl);
|
|
113
|
+
const urlSortParams = {
|
|
114
|
+
sort: queryParams.sortBy,
|
|
115
|
+
direction: queryParams.sortDirection
|
|
116
|
+
};
|
|
117
|
+
sortParams = urlSortParams.sortBy && urlSortParams.sortDirection ? urlSortParams : localSortParams;
|
|
118
|
+
} else {
|
|
119
|
+
sortParams = (0, _react.useMemo)(() => {
|
|
120
|
+
return {
|
|
121
|
+
sort: memoryParams.sortBy,
|
|
122
|
+
direction: memoryParams.sortDirection
|
|
123
|
+
};
|
|
124
|
+
}, [memoryParams]);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const isSearchPage = location.pathname === '/search';
|
|
128
|
+
const selectedCategory = (0, _react.useMemo)(() => {
|
|
129
|
+
let result = null;
|
|
130
|
+
|
|
131
|
+
if (isPageMode) {
|
|
132
|
+
result = !isSearchPage ? pathParams.category : queryParams.category;
|
|
133
|
+
} else {
|
|
134
|
+
result = queryParams.category;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return result;
|
|
138
|
+
}, [isPageMode, pathParams, queryParams]);
|
|
139
|
+
const hasDeveloperFilter = !!queryParams.developer;
|
|
140
|
+
const categoryState = !hasDeveloperFilter ? {
|
|
141
|
+
data: allCategories
|
|
142
|
+
} : (0, _utils.getCategories)(allBlocklets, queryParams.developer);
|
|
143
|
+
const blockletList = (0, _react.useMemo)(() => {
|
|
144
|
+
var _queryParams$search;
|
|
145
|
+
|
|
146
|
+
const sortByName = x => {
|
|
147
|
+
var _x$title, _x$name;
|
|
148
|
+
|
|
149
|
+
return (x === null || x === void 0 ? void 0 : (_x$title = x.title) === null || _x$title === void 0 ? void 0 : _x$title.toLocaleLowerCase()) || (x === null || x === void 0 ? void 0 : (_x$name = x.name) === null || _x$name === void 0 ? void 0 : _x$name.toLocaleLowerCase());
|
|
150
|
+
}; // 按名称排序
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
const sortByPopularity = x => x.stats.downloads; // 按下载量排序
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
const sortByPublish = x => x.lastPublishedAt; // 按发布时间
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
const sortMap = {
|
|
160
|
+
nameAsc: sortByName,
|
|
161
|
+
nameDesc: sortByName,
|
|
162
|
+
popularity: sortByPopularity,
|
|
163
|
+
publishAt: sortByPublish
|
|
164
|
+
};
|
|
165
|
+
let result = allBlocklets || []; // 按照付费/免费筛选
|
|
166
|
+
|
|
167
|
+
result = (0, _utils.filterBlockletByPrice)(result, queryParams.price); // 按照分类筛选
|
|
168
|
+
|
|
169
|
+
result = result.filter(item => {
|
|
170
|
+
var _item$category;
|
|
171
|
+
|
|
172
|
+
return selectedCategory ? (item === null || item === void 0 ? void 0 : (_item$category = item.category) === null || _item$category === void 0 ? void 0 : _item$category.name) === selectedCategory : true;
|
|
173
|
+
}); // 按照作者筛选
|
|
174
|
+
|
|
175
|
+
result = result.filter(item => queryParams !== null && queryParams !== void 0 && queryParams.developer ? item.owner.did === queryParams.developer : true);
|
|
176
|
+
const lowerSearch = (queryParams === null || queryParams === void 0 ? void 0 : (_queryParams$search = queryParams.search) === null || _queryParams$search === void 0 ? void 0 : _queryParams$search.toLocaleLowerCase()) || ''; // 按照搜索筛选
|
|
177
|
+
|
|
178
|
+
result = result.filter(item => {
|
|
179
|
+
var _ref2, _item$description, _item$version;
|
|
180
|
+
|
|
181
|
+
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));
|
|
182
|
+
}); // 排序
|
|
183
|
+
|
|
184
|
+
return (0, _orderBy.default)(result, [sortMap[sortParams.sort]], [sortParams.direction]);
|
|
185
|
+
}, [allBlocklets, queryParams, sortParams]);
|
|
186
|
+
const categoryList = (0, _react.useMemo)(() => {
|
|
187
|
+
const list = categoryState.data || []; // 分类按照名称排序
|
|
188
|
+
|
|
189
|
+
return (0, _orderBy.default)(list, [i => i.name], ['asc']);
|
|
190
|
+
}, [categoryState.data]);
|
|
191
|
+
|
|
192
|
+
const translate = (key, data) => {
|
|
193
|
+
if (!_locale.default[locale] || !_locale.default[locale][key]) {
|
|
194
|
+
console.warn("Warning: no ".concat(key, " translation of ").concat(locale));
|
|
195
|
+
return key;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return (0, _utils.replace)(_locale.default[locale][key], data);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const searchStore = {
|
|
202
|
+
errors: {
|
|
203
|
+
fetchBlockletsError,
|
|
204
|
+
fetchCategoriesError
|
|
205
|
+
},
|
|
206
|
+
loadings: {
|
|
207
|
+
fetchBlockletsLoading,
|
|
208
|
+
fetchCategoriesLoading
|
|
209
|
+
},
|
|
210
|
+
endpoint,
|
|
211
|
+
sortParams,
|
|
212
|
+
history,
|
|
213
|
+
blockletList,
|
|
214
|
+
t: translate,
|
|
215
|
+
queryParams,
|
|
216
|
+
selectedCategory,
|
|
217
|
+
isSearchPage,
|
|
218
|
+
categoryList,
|
|
219
|
+
isPageMode,
|
|
220
|
+
baseUrl,
|
|
221
|
+
blockletRender,
|
|
222
|
+
locale,
|
|
223
|
+
handleSort: value => {
|
|
224
|
+
const changData = _objectSpread(_objectSpread({}, queryParams), {}, {
|
|
225
|
+
sortBy: value,
|
|
226
|
+
sortDirection: value === 'nameAsc' ? 'asc' : 'desc'
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
if (isPageMode) {
|
|
230
|
+
sortParams.sort = changData.sortBy;
|
|
231
|
+
sortParams.direction = changData.sortDirection;
|
|
232
|
+
history.push("".concat(baseUrl, "search?").concat(_qs.default.stringify(changData)));
|
|
233
|
+
} else {
|
|
234
|
+
setMemoryParams(changData);
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
handleSearchKeyword: value => {
|
|
238
|
+
const changData = _objectSpread(_objectSpread({}, queryParams), {}, {
|
|
239
|
+
search: value || undefined
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
if (isPageMode) {
|
|
243
|
+
history.push("".concat(baseUrl, "search?").concat(_qs.default.stringify(changData)));
|
|
244
|
+
} else {
|
|
245
|
+
setMemoryParams(changData);
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
handlePriceFilter: value => {
|
|
249
|
+
const changData = _objectSpread(_objectSpread({}, queryParams), {}, {
|
|
250
|
+
price: value === queryParams.price ? undefined : value
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
if (isPageMode) {
|
|
254
|
+
history.push("".concat(baseUrl, "search?").concat(_qs.default.stringify(changData)));
|
|
255
|
+
} else {
|
|
256
|
+
setMemoryParams(changData);
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
getCategoryLocale: name => {
|
|
260
|
+
if (!name) return null;
|
|
261
|
+
let result = null;
|
|
262
|
+
const find = categoryState.data.find(item => item.name === name);
|
|
263
|
+
|
|
264
|
+
if (find) {
|
|
265
|
+
result = find.locales[locale];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return result;
|
|
269
|
+
},
|
|
270
|
+
handleCategorySelect: value => {
|
|
271
|
+
if (value === 'all') {
|
|
272
|
+
const changData = _objectSpread(_objectSpread({}, queryParams), {}, {
|
|
273
|
+
category: undefined
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
if (isPageMode) {
|
|
277
|
+
history.push(!isSearchPage ? baseUrl : "".concat(baseUrl, "search?").concat(_qs.default.stringify(changData)));
|
|
278
|
+
} else {
|
|
279
|
+
setMemoryParams(changData);
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
const changData = _objectSpread(_objectSpread({}, queryParams), {}, {
|
|
283
|
+
category: value
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
if (isPageMode) {
|
|
287
|
+
history.push(!isSearchPage ? "".concat(baseUrl, "category/").concat(value) : "".concat(baseUrl, "search?").concat(_qs.default.stringify(changData)));
|
|
288
|
+
} else {
|
|
289
|
+
setMemoryParams(changData);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
get developerName() {
|
|
295
|
+
var _allBlocklets$find, _allBlocklets$find$ow;
|
|
296
|
+
|
|
297
|
+
return ((_allBlocklets$find = allBlocklets.find(i => i.owner.did === queryParams.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) || '';
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
};
|
|
301
|
+
(0, _react.useEffect)(() => {
|
|
302
|
+
if (!hasDeveloperFilter) {
|
|
303
|
+
fetchCategories();
|
|
304
|
+
}
|
|
305
|
+
}, [!hasDeveloperFilter]);
|
|
306
|
+
return /*#__PURE__*/_react.default.createElement(Provider, {
|
|
307
|
+
value: searchStore
|
|
308
|
+
}, children);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
SearchProvider.propTypes = {
|
|
312
|
+
children: _propTypes.default.any.isRequired,
|
|
313
|
+
baseUrl: _propTypes.default.string,
|
|
314
|
+
endpoint: _propTypes.default.string.isRequired,
|
|
315
|
+
// 组件的类型: page 单独作为页面使用 持久化数据将存储在 url 和 localstorage,select 作为选择器组件使用 数据在存储在内存中
|
|
316
|
+
type: _propTypes.default.oneOf(['select', 'page']).isRequired,
|
|
317
|
+
locale: _propTypes.default.oneOf(['zh', 'en']),
|
|
318
|
+
blockletRender: _propTypes.default.func.isRequired
|
|
319
|
+
};
|
|
320
|
+
SearchProvider.defaultProps = {
|
|
321
|
+
baseUrl: null,
|
|
322
|
+
locale: 'zh'
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
function useSearchContext() {
|
|
326
|
+
const searchStore = (0, _react.useContext)(Search);
|
|
327
|
+
|
|
328
|
+
if (!searchStore) {
|
|
329
|
+
return {};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return searchStore;
|
|
333
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = usePageState;
|
|
7
|
+
|
|
8
|
+
var _ahooks = require("ahooks");
|
|
9
|
+
|
|
10
|
+
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; }
|
|
11
|
+
|
|
12
|
+
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; }
|
|
13
|
+
|
|
14
|
+
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; }
|
|
15
|
+
|
|
16
|
+
const PAGE_STATE_KEY = 'page-state';
|
|
17
|
+
|
|
18
|
+
function usePageState() {
|
|
19
|
+
let defaultValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
20
|
+
let persistence = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
21
|
+
let path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : window.location.pathname;
|
|
22
|
+
const [pageState, setPageState] = (0, _ahooks.useLocalStorageState)(PAGE_STATE_KEY, {});
|
|
23
|
+
const state = (0, _ahooks.useReactive)(pageState);
|
|
24
|
+
|
|
25
|
+
if (!(path in pageState) && persistence) {
|
|
26
|
+
state[path] = defaultValue;
|
|
27
|
+
syncState();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function syncState() {
|
|
31
|
+
setPageState(state);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return new Proxy({}, {
|
|
35
|
+
get: (target, prop) => {
|
|
36
|
+
try {
|
|
37
|
+
return state[path][prop];
|
|
38
|
+
} catch (_unused) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
set: (target, prop, value) => {
|
|
43
|
+
try {
|
|
44
|
+
const data = _objectSpread(_objectSpread({}, state[path] || {}), {}, {
|
|
45
|
+
[prop]: value
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
state[path] = data;
|
|
49
|
+
syncState();
|
|
50
|
+
return true;
|
|
51
|
+
} catch (_unused2) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
deleteProperty: (target, prop) => {
|
|
56
|
+
try {
|
|
57
|
+
const data = _objectSpread({}, state[path] || {});
|
|
58
|
+
|
|
59
|
+
delete data[prop];
|
|
60
|
+
delete state[path][prop];
|
|
61
|
+
syncState();
|
|
62
|
+
return true;
|
|
63
|
+
} catch (_unused3) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
ownKeys: () => Object.keys(state[path] || {})
|
|
68
|
+
});
|
|
69
|
+
}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = BlockletList;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
|
|
12
|
+
var _base = _interopRequireDefault(require("./base"));
|
|
13
|
+
|
|
14
|
+
var _store = require("./contexts/store");
|
|
15
|
+
|
|
16
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
|
+
|
|
18
|
+
function BlockletList(props) {
|
|
19
|
+
return /*#__PURE__*/_react.default.createElement(_store.SearchProvider, props, /*#__PURE__*/_react.default.createElement(_base.default, null));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
BlockletList.propTypes = {
|
|
23
|
+
baseUrl: _propTypes.default.string,
|
|
24
|
+
endpoint: _propTypes.default.string.isRequired,
|
|
25
|
+
// 组件的类型: page 单独作为页面使用 持久化数据将存储在 url 和 localstorage,select 作为选择器组件使用 数据在存储在内存中
|
|
26
|
+
type: _propTypes.default.oneOf(['select', 'page']).isRequired,
|
|
27
|
+
locale: _propTypes.default.oneOf(['zh', 'en']),
|
|
28
|
+
blockletRender: _propTypes.default.func.isRequired
|
|
29
|
+
};
|
|
30
|
+
BlockletList.defaultProps = {
|
|
31
|
+
baseUrl: null,
|
|
32
|
+
locale: 'zh'
|
|
33
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.replace = exports.getStoreDetail = exports.getSortOptions = exports.getPrices = exports.getCategories = exports.formatLogoPath = exports.formatError = exports.filterBlockletByPrice = void 0;
|
|
7
|
+
|
|
8
|
+
var _urlJoin = _interopRequireDefault(require("url-join"));
|
|
9
|
+
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
|
|
12
|
+
const isFreeBlocklet = meta => {
|
|
13
|
+
if (!meta.payment) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const priceList = (meta.payment.price || []).map(x => x.value || 0);
|
|
18
|
+
return priceList.every(x => x === 0);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const getSortOptions = t => {
|
|
22
|
+
return [{
|
|
23
|
+
name: t('sort.popularity'),
|
|
24
|
+
value: 'popularity'
|
|
25
|
+
}, {
|
|
26
|
+
name: t('sort.lastPublished'),
|
|
27
|
+
value: 'publishAt'
|
|
28
|
+
}, {
|
|
29
|
+
name: t('sort.nameAscend'),
|
|
30
|
+
value: 'nameAsc'
|
|
31
|
+
}, {
|
|
32
|
+
name: t('sort.nameDescend'),
|
|
33
|
+
value: 'nameDesc'
|
|
34
|
+
}];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
exports.getSortOptions = getSortOptions;
|
|
38
|
+
|
|
39
|
+
const getPrices = t => {
|
|
40
|
+
return [{
|
|
41
|
+
name: t('blocklet.free'),
|
|
42
|
+
value: 'free'
|
|
43
|
+
}, {
|
|
44
|
+
name: t('blocklet.payment'),
|
|
45
|
+
value: 'payment'
|
|
46
|
+
}];
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* 从开发者所属 blocklets 中的得到 Categories
|
|
50
|
+
* @param {*} list
|
|
51
|
+
* @param {*} developerDid
|
|
52
|
+
* @returns
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
exports.getPrices = getPrices;
|
|
57
|
+
|
|
58
|
+
const getCategories = (list, developerDid) => {
|
|
59
|
+
const filterList = list.filter(item => developerDid ? item.owner.did === developerDid : true);
|
|
60
|
+
const Categories = filterList.map(item => item.category);
|
|
61
|
+
const res = new Map();
|
|
62
|
+
const result = Categories.filter(i => !!i).filter(a => !res.has(a._id) && res.set(a._id, 1));
|
|
63
|
+
return {
|
|
64
|
+
data: result
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* 根据 是否付费 过滤 blocklet list
|
|
69
|
+
* @param {*} list
|
|
70
|
+
* @param {*} price
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
exports.getCategories = getCategories;
|
|
76
|
+
|
|
77
|
+
const filterBlockletByPrice = function filterBlockletByPrice() {
|
|
78
|
+
let list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
79
|
+
let price = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
|
|
80
|
+
let result = list;
|
|
81
|
+
if (!price) return result;
|
|
82
|
+
|
|
83
|
+
if (price === 'free') {
|
|
84
|
+
result = list.filter(blocklet => isFreeBlocklet(blocklet));
|
|
85
|
+
} else {
|
|
86
|
+
result = list.filter(blocklet => !isFreeBlocklet(blocklet));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return result;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
exports.filterBlockletByPrice = filterBlockletByPrice;
|
|
93
|
+
|
|
94
|
+
const formatError = error => {
|
|
95
|
+
if (Array.isArray(error.errors)) {
|
|
96
|
+
return error.errors.map(x => x.message).join('\n');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return error.message;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
exports.formatError = formatError;
|
|
103
|
+
|
|
104
|
+
const getStoreDetail = (storeUrl, blocklet) => {
|
|
105
|
+
return (0, _urlJoin.default)(storeUrl, "/blocklets/".concat(blocklet.did));
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
exports.getStoreDetail = getStoreDetail;
|
|
109
|
+
|
|
110
|
+
const formatLogoPath = function formatLogoPath(did, asset) {
|
|
111
|
+
let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'assets';
|
|
112
|
+
|
|
113
|
+
if (asset.startsWith(target)) {
|
|
114
|
+
return asset;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return "".concat(target, "/").concat(did, "/").concat(asset);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
exports.formatLogoPath = formatLogoPath;
|
|
121
|
+
|
|
122
|
+
const replace = (template, data) => // eslint-disable-next-line no-prototype-builtins
|
|
123
|
+
template.replace(/{(\w*)}/g, (m, key) => data.hasOwnProperty(key) ? data[key] : '');
|
|
124
|
+
|
|
125
|
+
exports.replace = replace;
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blocklet/list",
|
|
3
|
+
"version": "0.8.6",
|
|
4
|
+
"description": "Common ux components of blocklet",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"author": "machao <machao@arcblock.io>",
|
|
9
|
+
"homepage": "https://github.com/blocklet/blocklet-store#readme",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"main": "lib/index.js",
|
|
12
|
+
"files": [
|
|
13
|
+
"lib",
|
|
14
|
+
"src",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"package.json",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git@github.com:blocklet/blocklet-store.git"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"lint": "eslint src",
|
|
25
|
+
"build": "rm -rf lib && babel src --out-dir lib --copy-files",
|
|
26
|
+
"watch": "babel src --out-dir lib -w --copy-files",
|
|
27
|
+
"precommit": "CI=1 yarn test",
|
|
28
|
+
"prepush": "CI=1 yarn test",
|
|
29
|
+
"prepublish": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/blocklet/blocklet-store/issues"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": ">=16.12.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@arcblock/ux": "^2.1.1",
|
|
39
|
+
"@emotion/react": "^11.9.0",
|
|
40
|
+
"@emotion/styled": "^11.8.1",
|
|
41
|
+
"@mui/icons-material": "^5.6.2",
|
|
42
|
+
"@mui/material": "^5.7.0",
|
|
43
|
+
"@mui/styles": "^5.7.0",
|
|
44
|
+
"ahooks": "^2.10.12",
|
|
45
|
+
"axios": "^0.27.2",
|
|
46
|
+
"flat": "^5.0.2",
|
|
47
|
+
"lodash": "^4.17.21",
|
|
48
|
+
"lodash-es": "^4.17.21",
|
|
49
|
+
"mdi-material-ui": "^7.3.0",
|
|
50
|
+
"prop-types": "^15.7.2",
|
|
51
|
+
"qs": "^6.10.2",
|
|
52
|
+
"react-router-dom": "^5.3.0",
|
|
53
|
+
"styled-components": "5.3.5",
|
|
54
|
+
"url-join": "^4.0.1"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@babel/cli": "^7.8.4",
|
|
58
|
+
"@babel/core": "^7.8.4",
|
|
59
|
+
"@babel/preset-env": "^7.8.4",
|
|
60
|
+
"@babel/preset-react": "^7.8.3",
|
|
61
|
+
"@emotion/babel-plugin": "^11.9.2",
|
|
62
|
+
"babel-plugin-inline-react-svg": "^2.0.1",
|
|
63
|
+
"babel-plugin-styled-components": "^1.10.7"
|
|
64
|
+
},
|
|
65
|
+
"gitHead": "ef1d41695525f138255fe7f096c861395328a7f7"
|
|
66
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const flat = require('flat');
|
|
2
|
+
|
|
3
|
+
const en = {
|
|
4
|
+
common: {
|
|
5
|
+
searchStore: 'Search the store',
|
|
6
|
+
price: 'Price',
|
|
7
|
+
category: 'Category',
|
|
8
|
+
},
|
|
9
|
+
sort: {
|
|
10
|
+
sort: 'Sort',
|
|
11
|
+
nameDescend: 'Name Descending',
|
|
12
|
+
nameAscend: 'Name Ascending',
|
|
13
|
+
popularity: 'Most Popular',
|
|
14
|
+
lastPublished: 'Latest Published',
|
|
15
|
+
},
|
|
16
|
+
category: {
|
|
17
|
+
all: 'All',
|
|
18
|
+
placeholder: 'Category name',
|
|
19
|
+
helperText: 'Please select a category',
|
|
20
|
+
},
|
|
21
|
+
blocklet: {
|
|
22
|
+
noResults: 'No Blocklets',
|
|
23
|
+
payment: 'Paid Blocklets',
|
|
24
|
+
free: 'Fee Blocklets',
|
|
25
|
+
emptyTip: 'Tips:',
|
|
26
|
+
filterTip: 'Appropriately reduce the filter conditions',
|
|
27
|
+
keywordTip: 'Try other keywords',
|
|
28
|
+
owner: 'Blocklets from {name}',
|
|
29
|
+
noBlockletPart1: 'No Blocklets associated with"',
|
|
30
|
+
noBlockletPart2: '"were found',
|
|
31
|
+
noCategoryResults1: 'No "',
|
|
32
|
+
noCategoryResults2: '" Blocklets',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const zh = {
|
|
37
|
+
common: {
|
|
38
|
+
searchStore: '搜索商店内应用',
|
|
39
|
+
price: '价格',
|
|
40
|
+
category: '类别',
|
|
41
|
+
},
|
|
42
|
+
sort: {
|
|
43
|
+
sort: '排序',
|
|
44
|
+
nameDescend: '名称降序',
|
|
45
|
+
nameAscend: '名称升序',
|
|
46
|
+
popularity: '最热门',
|
|
47
|
+
lastPublished: '最新发布',
|
|
48
|
+
},
|
|
49
|
+
category: {
|
|
50
|
+
all: '全部',
|
|
51
|
+
placeholder: '分类名称',
|
|
52
|
+
helperText: '请选择分类',
|
|
53
|
+
},
|
|
54
|
+
blocklet: {
|
|
55
|
+
noResults: '暂无应用',
|
|
56
|
+
free: '免费应用',
|
|
57
|
+
payment: '付费应用',
|
|
58
|
+
emptyTip: '建议:',
|
|
59
|
+
filterTip: '适当减少筛选条件',
|
|
60
|
+
keywordTip: '尝试其他关键字',
|
|
61
|
+
owner: '来自 {name} 的 Blocklets',
|
|
62
|
+
noBlockletPart1: '没有找到与"',
|
|
63
|
+
noBlockletPart2: '"相关的 Blocklets',
|
|
64
|
+
noCategoryResults1: '无 "',
|
|
65
|
+
noCategoryResults2: '" 类别的 Blocklets',
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export default {
|
|
70
|
+
en: flat(en),
|
|
71
|
+
zh: flat(zh),
|
|
72
|
+
};
|