@arcblock/ux 1.16.62 → 1.16.63

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.
@@ -0,0 +1,379 @@
1
+ import React, { useRef } from 'react';
2
+ import styled from 'styled-components';
3
+ import PropTypes from 'prop-types';
4
+ import Portal from '@material-ui/core/Portal';
5
+ import Typography from '@material-ui/core/Typography';
6
+ import CircularProgress from '@material-ui/core/CircularProgress';
7
+ import useMediaQuery from '@material-ui/core/useMediaQuery';
8
+ import useTheme from '@material-ui/core/styles/useTheme';
9
+ import Avatar from '@arcblock/did-connect/lib/Avatar';
10
+
11
+ import Icon from '../Icon';
12
+ import Button from '../Button';
13
+ import Img from '../Img';
14
+
15
+ /**
16
+ * 美化数字 1000-->1k
17
+ * @param {*} _size
18
+ * @param {*} digits
19
+ * @returns
20
+ */
21
+ function prettySize(_size, digits = 1) {
22
+ let size = _size;
23
+ const list = ['', 'k', 'm', 'b'];
24
+ let index = 0;
25
+ while (size > 1000 && index < list.length - 1) {
26
+ size = (size / 1000).toFixed(digits);
27
+ index += 1;
28
+ }
29
+ return _size && `${size}${list[index]}`;
30
+ }
31
+
32
+ const Div = styled.div`
33
+ &.arcblock-blocklet {
34
+ padding: 0 16px;
35
+ background: ${props => props.theme.palette.common.white};
36
+ overflow: hidden;
37
+ box-shadow: 0px 0px 8px #f0f0f0;
38
+ &:hover {
39
+ box-shadow: 0px 2px 12px #f0f0f0;
40
+ }
41
+ }
42
+ .arcblock-blocklet__content {
43
+ padding: 16px 0 0 0;
44
+ }
45
+ .arcblock-blocklet__content--main {
46
+ display: flex;
47
+ align-items: center;
48
+ cursor: pointer;
49
+ }
50
+ .arcblock-blocklet__content--body {
51
+ overflow: hidden;
52
+ flex: 1;
53
+ display: flex;
54
+ align-items: flex-start;
55
+ }
56
+ .arcblock-blocklet__addons {
57
+ padding: 16px 0;
58
+ }
59
+ .arcblock-blocklet__cover {
60
+ width: 80px;
61
+ height: 80px;
62
+ margin-right: 12px;
63
+ overflow: hidden;
64
+ border-radius: 12px;
65
+ /* see: https://stackoverflow.com/questions/49066011/overflow-hidden-with-border-radius-not-working-on-safari */
66
+ transform: translateZ(0);
67
+ }
68
+ .arcblock-blocklet__button--hover {
69
+ &:not(.Mui-disabled) {
70
+ position: relative;
71
+ z-index: 1;
72
+ &::before {
73
+ content: '';
74
+ position: absolute;
75
+ height: 100%;
76
+ width: 100%;
77
+ left: 0;
78
+ top: 0;
79
+ transition: opacity 0.3s;
80
+ }
81
+ &:hover::before {
82
+ opacity: 0;
83
+ }
84
+ &::after {
85
+ content: '';
86
+ position: absolute;
87
+ height: 100%;
88
+ width: 100%;
89
+ background-color: ${props => props.theme.palette.primary.main};
90
+ transform: scale(0.1);
91
+ opacity: 0;
92
+ z-index: -1;
93
+ transition: transform 0.3s, opacity 0.3s, background-color 0.3s;
94
+ }
95
+ &:hover::after {
96
+ opacity: 1;
97
+ transform-origin: center;
98
+ transform: scale(1);
99
+ }
100
+ }
101
+
102
+ &:not(.Mui-disabled) {
103
+ background-color: transparent !important;
104
+ color: ${props => props.theme.palette.primary.main};
105
+ }
106
+ &:not(.Mui-disabled) {
107
+ &:hover {
108
+ color: ${props => props.theme.palette.common.white};
109
+ }
110
+ }
111
+ }
112
+ .arcblock-blocklet__info {
113
+ flex: 1;
114
+ overflow: hidden;
115
+ .arcblock-blocklet__button {
116
+ margin-top: 16px;
117
+ display: inline-block;
118
+ }
119
+ }
120
+ .arcblock-blocklet__title {
121
+ margin: 0;
122
+ font-size: 18px;
123
+ font-weight: 600;
124
+ overflow: hidden;
125
+ text-overflow: ellipsis;
126
+ white-space: nowrap;
127
+ }
128
+ .arcblock-blocklet__describe {
129
+ margin: 0 0 2px 0;
130
+ color: #999;
131
+ font-size: 14px;
132
+ overflow: hidden;
133
+ text-overflow: ellipsis;
134
+ white-space: nowrap;
135
+ }
136
+
137
+ .arcblock-blocklet__addons {
138
+ display: flex;
139
+ justify-content: space-between;
140
+ color: #999;
141
+ font-size: 14px;
142
+ position: relative;
143
+ }
144
+ .arcblock-blocklet__addons--item {
145
+ white-space: nowrap;
146
+ }
147
+ &.arcblock-blocklet--size-md {
148
+ &:hover {
149
+ position: relative;
150
+ }
151
+ .arcblock-blocklet__title {
152
+ height: 2.3em;
153
+ margin-bottom: 3px;
154
+ display: -webkit-box;
155
+ -webkit-box-orient: vertical;
156
+ -webkit-line-clamp: 2;
157
+ overflow: hidden;
158
+ text-overflow: initial;
159
+ white-space: initial;
160
+ word-break: break-all;
161
+ }
162
+ .arcblock-blocklet__describe {
163
+ white-space: normal;
164
+ height: 2.86em;
165
+ }
166
+ .arcblock-blocklet__button {
167
+ margin-top: 5px;
168
+ }
169
+ }
170
+ &.arcblock-blocklet--size-sm,
171
+ &.arcblock-blocklet--size-xs {
172
+ .arcblock-blocklet__cover {
173
+ width: 40px;
174
+ height: 40px;
175
+ border-radius: 6px;
176
+ }
177
+ .arcblock-blocklet__content {
178
+ padding: 16px 0;
179
+ }
180
+ .arcblock-blocklet__addons {
181
+ padding: 8px 0;
182
+ .arcblock-blocklet__addons--item {
183
+ font-size: 12px;
184
+ }
185
+ }
186
+ }
187
+ &.arcblock-blocklet--size-xs {
188
+ .arcblock-blocklet__addons {
189
+ display: none !important;
190
+ }
191
+ }
192
+ `;
193
+ function BlockletIcon({ name }) {
194
+ return <Icon name={name} color="inherit" size={15} style={{ marginRight: 8 }} />;
195
+ }
196
+ BlockletIcon.propTypes = {
197
+ name: PropTypes.string.isRequired,
198
+ };
199
+
200
+ export default function BlockletNFT({
201
+ title,
202
+ did,
203
+ description,
204
+ cover,
205
+ size,
206
+ addons,
207
+ button,
208
+ buttonText,
209
+ buttonDisabled,
210
+ buttonLoading,
211
+ isStickyButton,
212
+ onButtonClick,
213
+ onMainClick,
214
+ onTagClick,
215
+ className,
216
+ scaleClickZone,
217
+ ...rest
218
+ }) {
219
+ const wrapHandler =
220
+ (handler, stopFn = () => false) =>
221
+ (e, ...args) => {
222
+ if (stopFn()) {
223
+ e.preventDefault();
224
+ e.stopPropagation();
225
+ } else if (handler instanceof Function) {
226
+ e.preventDefault();
227
+ e.stopPropagation();
228
+ handler(...args);
229
+ }
230
+ };
231
+ const _onButtonClick = wrapHandler(onButtonClick, () => {
232
+ // stop click while custom button or buttonDisabled or buttondLoading
233
+ if (button || buttonDisabled || buttonLoading) {
234
+ return true;
235
+ }
236
+ return false;
237
+ });
238
+ const _onMainClick = wrapHandler(onMainClick);
239
+
240
+ const theme = useTheme();
241
+ const isDownSm = useMediaQuery(theme.breakpoints.down('sm'));
242
+ const isDownMd = useMediaQuery(theme.breakpoints.down('md'));
243
+ const isUpLg = useMediaQuery(theme.breakpoints.up('lg'));
244
+
245
+ // If size is auto, need calculate actual size according to screen size
246
+ // eslint-disable-next-line no-nested-ternary
247
+ const actualSize = size === 'auto' ? (isDownSm ? 'xs' : isDownMd ? 'sm' : 'md') : size;
248
+ // eslint-disable-next-line no-nested-ternary
249
+ const didAvatarSize = size === 'auto' ? (isUpLg ? 80 : 40) : size === 'md' ? 80 : 40;
250
+ const container = useRef(null);
251
+
252
+ return (
253
+ <Div
254
+ {...rest}
255
+ scaleClickZone={scaleClickZone}
256
+ className={`${className} arcblock-blocklet arcblock-blocklet--size-${actualSize}`}>
257
+ <div className="arcblock-blocklet__content">
258
+ <div className="arcblock-blocklet__content--main" onClick={_onMainClick} ref={container}>
259
+ <div className="arcblock-blocklet__content--body">
260
+ {cover ? (
261
+ <div className="arcblock-blocklet__cover">
262
+ <Img src={cover} />
263
+ </div>
264
+ ) : (
265
+ did && (
266
+ <div className="arcblock-blocklet__cover">
267
+ <Avatar did={did} size={didAvatarSize} />
268
+ </div>
269
+ )
270
+ )}
271
+ <div className="arcblock-blocklet__info">
272
+ <Typography
273
+ component="h3"
274
+ variant="h3"
275
+ className="arcblock-blocklet__title"
276
+ title={title}>
277
+ {title}
278
+ </Typography>
279
+ {description && (
280
+ <Typography
281
+ component="div"
282
+ variant="body2"
283
+ className="arcblock-blocklet__describe"
284
+ title={description}>
285
+ {description}
286
+ </Typography>
287
+ )}
288
+ {['md', 'sm', 'xs'].includes(actualSize) && (
289
+ <Portal container={container.current} disablePortal={actualSize === 'md'}>
290
+ <div
291
+ className="arcblock-blocklet__button"
292
+ onClick={_onButtonClick}
293
+ style={{ display: isStickyButton ? 'block' : '' }}>
294
+ {button ||
295
+ (onButtonClick && (
296
+ <Button
297
+ className="arcblock-blocklet__button--hover"
298
+ variant="outlined"
299
+ color="primary"
300
+ size="small"
301
+ disabled={buttonDisabled || buttonLoading}
302
+ style={
303
+ actualSize === 'md'
304
+ ? { padding: '3px 20px', fontSize: '14px' }
305
+ : { padding: '3px 15px', minWidth: '54px', fontSize: '13px' }
306
+ }>
307
+ {buttonLoading && (
308
+ <CircularProgress
309
+ size={actualSize === 'md' ? 15 : 13}
310
+ style={{ marginRight: 3, color: 'inherit' }}
311
+ />
312
+ )}
313
+ {buttonText}
314
+ </Button>
315
+ ))}
316
+ </div>
317
+ </Portal>
318
+ )}
319
+ </div>
320
+ </div>
321
+ </div>
322
+ </div>
323
+ <div className="arcblock-blocklet__addons">
324
+ {addons.map((item, index) => (
325
+ <Typography
326
+ component="span"
327
+ variant="caption"
328
+ className="arcblock-blocklet__addons--item"
329
+ // eslint-disable-next-line react/no-array-index-key
330
+ key={index}
331
+ title={item.title}>
332
+ {item.empty ? null : (
333
+ <>
334
+ <BlockletIcon name={item.icon} />
335
+ {item.pretty ? prettySize(item.value) : item.value}
336
+ </>
337
+ )}
338
+ </Typography>
339
+ ))}
340
+ </div>
341
+ </Div>
342
+ );
343
+ }
344
+ BlockletNFT.propTypes = {
345
+ title: PropTypes.string.isRequired,
346
+ did: PropTypes.string,
347
+ isStickyButton: PropTypes.bool,
348
+ description: PropTypes.string,
349
+ cover: PropTypes.string,
350
+ buttonText: PropTypes.string,
351
+ buttonDisabled: PropTypes.bool,
352
+ buttonLoading: PropTypes.bool,
353
+ button: PropTypes.element,
354
+ addons: PropTypes.arrayOf(PropTypes.object),
355
+ size: PropTypes.oneOf(['xs', 'sm', 'md', 'auto']),
356
+ onButtonClick: PropTypes.func,
357
+ onMainClick: PropTypes.func,
358
+ onTagClick: PropTypes.func,
359
+ className: PropTypes.string,
360
+ scaleClickZone: PropTypes.number,
361
+ };
362
+
363
+ BlockletNFT.defaultProps = {
364
+ description: null,
365
+ cover: null,
366
+ did: null,
367
+ isStickyButton: false,
368
+ buttonText: 'Install',
369
+ buttonDisabled: false,
370
+ buttonLoading: false,
371
+ button: null,
372
+ size: 'auto',
373
+ addons: [],
374
+ onButtonClick: null,
375
+ onMainClick: null,
376
+ onTagClick: null,
377
+ className: null,
378
+ scaleClickZone: 1.5,
379
+ };