@arcblock/ux 1.16.0 → 1.16.4

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.
Files changed (90) hide show
  1. package/lib/CodeBlock/index.js +3 -1
  2. package/package.json +6 -5
  3. package/src/ActionButton/index.js +65 -0
  4. package/src/ActivityIndicator/index.js +186 -0
  5. package/src/Alert/index.js +104 -0
  6. package/src/Async/index.js +39 -0
  7. package/src/Badge/index.js +71 -0
  8. package/src/Blocklet/index.js +335 -0
  9. package/src/Button/index.js +4 -0
  10. package/src/Button/wrap.js +88 -0
  11. package/src/ButtonGroup/index.js +19 -0
  12. package/src/Center/index.js +17 -0
  13. package/src/ClickToCopy/index.js +90 -0
  14. package/src/CodeBlock/index.js +160 -0
  15. package/src/Colors/index.js +1 -0
  16. package/src/Colors/themes/default.js +53 -0
  17. package/src/ContactForm/index.js +240 -0
  18. package/src/CookieConsent/index.js +90 -0
  19. package/src/CountDown/index.js +151 -0
  20. package/src/Dialog/confirm.js +76 -0
  21. package/src/Dialog/dialog.js +162 -0
  22. package/src/Dialog/index.js +2 -0
  23. package/src/DriftBot/index.js +81 -0
  24. package/src/Earth/countries.json +8057 -0
  25. package/src/Earth/index.js +511 -0
  26. package/src/Earth/util.js +69 -0
  27. package/src/Empty/index.js +41 -0
  28. package/src/Footer/index.js +84 -0
  29. package/src/Icon/image.js +55 -0
  30. package/src/Icon/index.js +69 -0
  31. package/src/Img/index.js +172 -0
  32. package/src/InfoRow/index.js +83 -0
  33. package/src/Layout/dashboard/header.js +145 -0
  34. package/src/Layout/dashboard/index.js +140 -0
  35. package/src/Layout/dashboard/sidebar.js +120 -0
  36. package/src/Layout/index.js +318 -0
  37. package/src/Locale/browser-lang.js +63 -0
  38. package/src/Locale/context.js +88 -0
  39. package/src/Locale/images/globe-dark.png +0 -0
  40. package/src/Locale/images/globe-light.png +0 -0
  41. package/src/Locale/selector.js +138 -0
  42. package/src/Logo/images/logo-dark-text.svg +3 -0
  43. package/src/Logo/images/logo-dark-top.svg +6 -0
  44. package/src/Logo/images/logo-light-text.svg +3 -0
  45. package/src/Logo/images/logo-light-top.svg +6 -0
  46. package/src/Logo/index.js +47 -0
  47. package/src/Metric/index.js +115 -0
  48. package/src/NFTDisplay/README.md +59 -0
  49. package/src/NFTDisplay/aspect-ratio-container.js +34 -0
  50. package/src/NFTDisplay/broken.js +18 -0
  51. package/src/NFTDisplay/index.js +230 -0
  52. package/src/NFTDisplay/loading.js +17 -0
  53. package/src/NFTDisplay/svg-embedder/img.js +36 -0
  54. package/src/NFTDisplay/svg-embedder/inline-svg.js +37 -0
  55. package/src/PageScroller/index.js +342 -0
  56. package/src/PageScroller/usePrevValue.js +12 -0
  57. package/src/PricingTable/PricingPlan.js +112 -0
  58. package/src/PricingTable/index.js +43 -0
  59. package/src/Screenshot/devices.css +1366 -0
  60. package/src/Screenshot/index.js +181 -0
  61. package/src/Spinner/index.js +33 -0
  62. package/src/Switch/index.js +78 -0
  63. package/src/Tabs/index.js +46 -0
  64. package/src/Tag/index.js +73 -0
  65. package/src/Terminal/Player.js +364 -0
  66. package/src/Terminal/index.js +150 -0
  67. package/src/Terminal/player.css +378 -0
  68. package/src/Terminal/util.js +167 -0
  69. package/src/Terminal/xterm.css +171 -0
  70. package/src/TextCollapse/index.js +92 -0
  71. package/src/Theme/index.js +169 -0
  72. package/src/Theme/responsiveFontSizes.js +94 -0
  73. package/src/Toast/index.js +118 -0
  74. package/src/Util/index.js +264 -0
  75. package/src/Video/index.js +72 -0
  76. package/src/Wallet/Action.js +105 -0
  77. package/src/Wallet/Download.js +130 -0
  78. package/src/Wallet/Open.js +50 -0
  79. package/src/Wallet/images/abtwallet.png +0 -0
  80. package/src/Wallet/images/android_download.svg +23 -0
  81. package/src/Wallet/images/app-store.svg +20 -0
  82. package/src/Wallet/images/google-play.svg +70 -0
  83. package/src/WechatPrompt/images/android.png +0 -0
  84. package/src/WechatPrompt/images/ios.png +0 -0
  85. package/src/WechatPrompt/index.js +81 -0
  86. package/src/index.js +63 -0
  87. package/src/withTheme/index.js +72 -0
  88. package/src/withTracker/README.md +34 -0
  89. package/src/withTracker/error_boundary.js +34 -0
  90. package/src/withTracker/index.js +70 -0
@@ -0,0 +1,511 @@
1
+ /* eslint-disable consistent-return */
2
+ import React, { useReducer, useRef, useEffect } from 'react';
3
+ import useSpring from 'react-use/lib/useSpring';
4
+ import PropTypes from 'prop-types';
5
+ import styled from 'styled-components';
6
+ import * as d3 from 'd3-geo';
7
+ import * as topojson from 'topojson-client';
8
+ import versor from 'versor';
9
+
10
+ import json from './countries.json';
11
+ import util from './util';
12
+
13
+ const geoJson = topojson.feature(json, json.objects.ne_110m_admin_0_countries);
14
+ const themes = {
15
+ light: {
16
+ ocean: '#EDF4F4',
17
+ graticule: '#EDF4F4',
18
+ land: '#CCEAEA',
19
+ activeLand: '#AFD3D3',
20
+ border: '#AFD3D3',
21
+ marker: '#4E6AF6',
22
+ activeMarker: '#4E6AF6',
23
+ },
24
+ dark: {
25
+ ocean: '#09233B',
26
+ graticule: '#09233B',
27
+ land: '#0D2344',
28
+ activeLand: '#173159',
29
+ border: '#89DDD9',
30
+ marker: '#ffffff',
31
+ activeMarker: '#FFD159',
32
+ },
33
+ };
34
+
35
+ function stateReducer(state, action) {
36
+ switch (action.type) {
37
+ case 'dragEnd':
38
+ return { ...state, isDragging: false };
39
+ case 'dragStart':
40
+ return {
41
+ ...state,
42
+ isDragging: true,
43
+ animationDuration: 1,
44
+ mousePosition: action.payload.mousePosition,
45
+ };
46
+ case 'tooltip':
47
+ case 'rotate':
48
+ return Object.assign({}, state, action.payload);
49
+ default:
50
+ return state;
51
+ }
52
+ }
53
+
54
+ export default function Earth({
55
+ theme,
56
+ width,
57
+ height,
58
+ enableRotation,
59
+ rotationSpeed,
60
+ markers,
61
+ activeMarkerId,
62
+ colors,
63
+ }) {
64
+ Object.assign(colors, themes[theme]);
65
+ const [state, dispatch] = useReducer(stateReducer, {
66
+ rotation: [0, 0, 0],
67
+ isDragging: false,
68
+ animateDuration: 1,
69
+ mousePosition: null,
70
+ tooltipIndex: -1,
71
+ });
72
+
73
+ const svgRef = useRef(null);
74
+
75
+ // variables used to track drag and rotate
76
+ const dragRef = useRef({
77
+ v0: undefined,
78
+ r0: undefined,
79
+ q0: undefined,
80
+ });
81
+
82
+ // variables used to track start and end position when there is active marker
83
+ const rotateRef = useRef({
84
+ p1: null,
85
+ p2: [0, 0],
86
+ r1: null,
87
+ r2: [0, 0, 0],
88
+ step: 0,
89
+ markerId: null,
90
+ iv: null,
91
+ });
92
+
93
+ // console.log('renderGlobe', state, dragRef.current, rotateRef.current, geoJson);
94
+ const t = useSpring(state.animateDuration, 170, 26);
95
+
96
+ const isValid =
97
+ activeMarkerId &&
98
+ rotateRef.current.markerId !== activeMarkerId &&
99
+ markers.some(x => x.id === activeMarkerId);
100
+
101
+ // Setup path for globe
102
+ const projection = d3
103
+ .geoOrthographic()
104
+ .fitExtent(
105
+ [
106
+ [30, 30],
107
+ [width - 30, height - 30],
108
+ ],
109
+ geoJson
110
+ )
111
+ .rotate(
112
+ t <= 1 || state.isDragging || !activeMarkerId
113
+ ? state.rotation
114
+ : rotateRef.current.iv(t / state.animateDuration)
115
+ );
116
+
117
+ const pathGenerator = d3.geoPath().projection(projection).pointRadius(2);
118
+
119
+ useEffect(() => {
120
+ // Rotate to active marker
121
+ if (isValid) {
122
+ // eslint-disable-next-line prefer-const
123
+ let { p1, p2, r1, r2, markerId } = rotateRef.current;
124
+ // We should only start new animation if the marker has changed
125
+ if (markerId !== activeMarkerId && !state.isDragging) {
126
+ const marker = markers.find(x => x.id === activeMarkerId);
127
+ p1 = p2;
128
+ p2 = [marker.longitude, marker.latitude];
129
+ r1 = r2;
130
+ r2 = [-p2[0], 20 - p2[1], projection.rotate()[2]];
131
+ const iv = util.interpolateAngles(r1, r2);
132
+
133
+ Object.assign(rotateRef.current, {
134
+ p1,
135
+ p2,
136
+ r1,
137
+ r2,
138
+ iv,
139
+ markerId: activeMarkerId,
140
+ });
141
+ const duration = state.animateDuration * 2;
142
+
143
+ dispatch({
144
+ type: 'rotate',
145
+ payload: {
146
+ animateDuration: duration > 1e3 ? 2 : duration,
147
+ },
148
+ });
149
+ }
150
+
151
+ // Enable auto rotation
152
+ } else if (enableRotation) {
153
+ const handler = window.requestAnimationFrame(() => {
154
+ const newRotation = [
155
+ state.rotation[0] + 2 / rotationSpeed,
156
+ state.rotation[1],
157
+ state.rotation[2],
158
+ ];
159
+ dispatch({ type: 'rotate', payload: { rotation: newRotation } });
160
+ });
161
+
162
+ return function cleanup() {
163
+ window.cancelAnimationFrame(handler);
164
+ };
165
+ }
166
+ });
167
+
168
+ const getMousePosition = event => {
169
+ const node = svgRef.current;
170
+ const rect = node.getBoundingClientRect();
171
+ const mousePosition = [
172
+ event.clientX - rect.left - node.clientLeft,
173
+ event.clientY - rect.top - node.clientTop,
174
+ ];
175
+
176
+ return mousePosition;
177
+ };
178
+
179
+ const onDragStart = event => {
180
+ const mousePosition = getMousePosition(event);
181
+
182
+ if (!mousePosition[0]) {
183
+ return;
184
+ }
185
+
186
+ dragRef.current.v0 = versor.cartesian(projection.invert(mousePosition));
187
+ dragRef.current.r0 = projection.rotate();
188
+ dragRef.current.q0 = versor(dragRef.current.r0);
189
+
190
+ dispatch({ type: 'dragStart', payload: { mousePosition } });
191
+ };
192
+
193
+ const onDrag = event => {
194
+ if (state.isDragging === false) {
195
+ return;
196
+ }
197
+
198
+ const mousePosition = getMousePosition(event);
199
+ const { r0, v0, q0 } = dragRef.current;
200
+
201
+ const v1 = versor.cartesian(projection.rotate(r0).invert(mousePosition));
202
+ const q1 = versor.multiply(q0, versor.delta(v0, v1));
203
+ const r1 = versor.rotation(q1);
204
+
205
+ dispatch({ type: 'rotate', payload: { rotation: r1, mousePosition } });
206
+ };
207
+
208
+ const onDragEnd = () => {
209
+ setTimeout(() => {
210
+ dispatch({ type: 'dragEnd', payload: {} });
211
+ }, 200);
212
+ };
213
+
214
+ const onShowTooltip = (event, i) =>
215
+ dispatch({
216
+ type: 'tooltip',
217
+ payload: { tooltipIndex: i, mousePosition: getMousePosition(event) },
218
+ });
219
+
220
+ const onHideTooltip = () =>
221
+ dispatch({ type: 'tooltip', payload: { tooltipIndex: -1, mousePosition: null } });
222
+
223
+ const renderMarkers = () =>
224
+ markers.map((x, i) => {
225
+ const areaCoords = [x.longitude, x.latitude];
226
+ const distance = d3.geoDistance(areaCoords, projection.invert([width / 2, height / 2]));
227
+ const sphereCoords = projection(areaCoords);
228
+ const isActive = activeMarkerId === x.id;
229
+ // eslint-disable-next-line no-nested-ternary
230
+ const fill = distance > 1.57 ? 'none' : isActive ? colors.activeMarker : colors.marker;
231
+ const radius = isActive ? 9 : 6;
232
+ return (
233
+ <g
234
+ key={x.id}
235
+ className={`marker ${isActive ? 'marker--active' : ''}`}
236
+ onFocus={event => onShowTooltip(event, i)}
237
+ onBlur={onHideTooltip}
238
+ onMouseOver={event => onShowTooltip(event, i)}
239
+ onMouseOut={onHideTooltip}>
240
+ <circle
241
+ key="marker-inner"
242
+ className="marker__inner"
243
+ r={radius}
244
+ cx={sphereCoords[0]}
245
+ cy={sphereCoords[1]}
246
+ fill={fill}
247
+ style={{ fillOpacity: isActive ? 1 : 0.5 }}
248
+ />
249
+ <circle
250
+ key="marker-outer"
251
+ className="marker__outer"
252
+ r={radius * 2}
253
+ cx={sphereCoords[0]}
254
+ cy={sphereCoords[1]}
255
+ fill={fill}
256
+ style={{
257
+ animationDuration: isActive ? '800ms' : '1600ms',
258
+ animationDelay: `${i * 0.2}s`,
259
+ transformOrigin: `${sphereCoords[0]}px ${sphereCoords[1]}px`,
260
+ }}
261
+ />
262
+ </g>
263
+ );
264
+ });
265
+
266
+ const renderTooltip = () => {
267
+ if (state.tooltipIndex >= 0) {
268
+ const marker = markers[state.tooltipIndex];
269
+ return (
270
+ <Tooltip style={{ left: state.mousePosition[0], top: state.mousePosition[1] }}>
271
+ <p className="title">{marker.title}</p>
272
+ <p className="description">{marker.description}</p>
273
+ <p className="description">ID: {marker.id}</p>
274
+ </Tooltip>
275
+ );
276
+ }
277
+ };
278
+
279
+ let activeCountry = null;
280
+ if (activeMarkerId && markers.some(x => x.id === activeMarkerId)) {
281
+ const activeMarker = markers.find(x => x.id === activeMarkerId);
282
+ activeCountry = geoJson.features.findIndex(
283
+ x => x.properties && x.properties.name && x.properties.name === activeMarker.country
284
+ );
285
+ }
286
+
287
+ return (
288
+ <Container width={width} height={height} theme={theme} colors={colors} onMouseLeave={onDragEnd}>
289
+ {renderTooltip()}
290
+ <svg
291
+ className="earth"
292
+ width={width}
293
+ height={height}
294
+ onMouseDown={onDragStart}
295
+ onMouseMove={onDrag}
296
+ onMouseUp={onDragEnd}
297
+ ref={svgRef}>
298
+ <rect className="frame" width={width} height={height} />
299
+ <circle
300
+ cx={width / 2}
301
+ cy={height / 2}
302
+ r={projection.scale()}
303
+ className="globe"
304
+ filter="url(#glow)"
305
+ />
306
+ <path className="graticule" d={pathGenerator(d3.geoGraticule().step([10, 10])())} />
307
+ <g className="features">
308
+ {geoJson.features.map((x, i) => (
309
+ <path
310
+ key={x.properties.name}
311
+ className={`country ${activeCountry === i ? 'country--active' : ''}`}
312
+ d={pathGenerator(x)}
313
+ />
314
+ ))}
315
+ </g>
316
+ <g className="markers">{renderMarkers()}</g>
317
+ {state.isDragging && state.mousePosition && (
318
+ <path
319
+ className="point point-mouse"
320
+ d={pathGenerator({
321
+ type: 'Point',
322
+ coordinates: projection.invert(state.mousePosition),
323
+ })}
324
+ />
325
+ )}
326
+ </svg>
327
+ <svg className="defs">
328
+ <defs>
329
+ <linearGradient id="gradBlue" x1="0%" y1="0%" x2="100%" y2="0%">
330
+ <stop offset="0%" style={{ stopColor: '#005C99', stopOpacity: 1 }} />
331
+ <stop offset="100%" style={{ stopColor: '#0099FF', stopOpacity: 1 }} />
332
+ </linearGradient>
333
+ <filter id="glow">
334
+ <feColorMatrix
335
+ type="matrix"
336
+ values="0 0 0 0 0
337
+ 0 0 0 0.9 0
338
+ 0 0 0 0.9 0
339
+ 0 0 0 1 0"
340
+ />
341
+ <feGaussianBlur stdDeviation="5.5" result="coloredBlur" />
342
+ <feMerge>
343
+ <feMergeNode in="coloredBlur" />
344
+ <feMergeNode in="SourceGraphic" />
345
+ </feMerge>
346
+ </filter>
347
+ </defs>
348
+ </svg>
349
+ </Container>
350
+ );
351
+ }
352
+
353
+ Earth.propTypes = {
354
+ theme: PropTypes.oneOf(['light', 'dark']),
355
+ width: PropTypes.number,
356
+ height: PropTypes.number,
357
+ enableRotation: PropTypes.bool,
358
+ rotationSpeed: PropTypes.number,
359
+ activeMarkerId: PropTypes.string,
360
+ markers: PropTypes.arrayOf(
361
+ PropTypes.shape({
362
+ id: PropTypes.string.isRequired,
363
+ title: PropTypes.string.isRequired,
364
+ description: PropTypes.string.isRequired,
365
+ country: PropTypes.string.isRequired,
366
+ latitude: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
367
+ longitude: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
368
+ })
369
+ ),
370
+ colors: PropTypes.shape({
371
+ ocean: PropTypes.string,
372
+ graticule: PropTypes.string,
373
+ land: PropTypes.string,
374
+ activeLand: PropTypes.string,
375
+ border: PropTypes.string,
376
+ marker: PropTypes.string,
377
+ activeMarker: PropTypes.string,
378
+ }),
379
+ };
380
+
381
+ Earth.defaultProps = {
382
+ theme: 'dark',
383
+ width: 1200,
384
+ height: 600,
385
+ enableRotation: false,
386
+ rotationSpeed: 5,
387
+ markers: [],
388
+ activeMarkerId: undefined,
389
+ colors: {},
390
+ };
391
+
392
+ const Container = styled.div`
393
+ background-color: ${props => (props.theme === 'light' ? '#f7f7f7' : '#222')};
394
+ width: ${props => props.width}px;
395
+ height: ${props => props.height}px;
396
+ position: relative;
397
+ animation-name: zoomIn;
398
+ animation-duration: 1s;
399
+ animation-iteration-count: 1;
400
+ animation-timing-function: ease;
401
+ user-select: none;
402
+
403
+ .defs {
404
+ height: 0;
405
+ width: 0;
406
+ }
407
+
408
+ .frame {
409
+ fill: none;
410
+ pointer-events: all;
411
+ }
412
+
413
+ .country {
414
+ fill: ${props => props.colors.land};
415
+ stroke: ${props => props.colors.border};
416
+ stroke-width: 0.5px;
417
+ transition: fill 300ms ease;
418
+
419
+ &:hover {
420
+ fill: ${props => props.colors.activeLand};
421
+ }
422
+ }
423
+
424
+ .country--active {
425
+ fill: ${props => props.colors.activeLand};
426
+ }
427
+
428
+ .globe {
429
+ fill: ${props => props.colors.ocean};
430
+ stroke: rgba(255, 255, 255, 0.5);
431
+ stroke-width: 0.25px;
432
+ }
433
+
434
+ .graticule {
435
+ fill: none;
436
+ stroke: ${props => props.colors.graticule};
437
+ }
438
+
439
+ .star {
440
+ fill: #fff;
441
+ stroke: rgba(255, 255, 255, 0.5);
442
+ stroke-width: 0.25px;
443
+ }
444
+
445
+ .marker {
446
+ .marker__outer {
447
+ fill-opacity: 0;
448
+ animation: scaleIn 2s infinite ease-in-out;
449
+ }
450
+ }
451
+
452
+ @keyframes zoomIn {
453
+ from {
454
+ opacity: 0;
455
+ transform: scale3d(0.1, 0.1, 0.1);
456
+ }
457
+
458
+ 50% {
459
+ opacity: 1;
460
+ }
461
+ }
462
+
463
+ @keyframes scaleIn {
464
+ from {
465
+ fill-opacity: 0.3;
466
+ transform: scale3d(0.5, 0.5, 0.5);
467
+ }
468
+ to {
469
+ fill-opacity: 0;
470
+ transform: scale3d(1.5, 1.5, 1.5);
471
+ }
472
+ }
473
+ `;
474
+
475
+ const Tooltip = styled.div`
476
+ position: absolute;
477
+ width: auto;
478
+ min-width: 90px;
479
+ max-width: 320px;
480
+ padding: 8px 12px;
481
+ font-size: 14px;
482
+ background-color: #4a4a4a;
483
+ border-radius: 2px;
484
+ animation-name: fadeIn;
485
+ animation-duration: 250ms;
486
+ animation-iteration-count: 1;
487
+ animation-timing-function: ease;
488
+
489
+ .title,
490
+ .description {
491
+ margin: 0;
492
+ font-size: 16px;
493
+ color: #fff;
494
+ }
495
+
496
+ .description {
497
+ margin-top: ${props => props.theme.spacing(1)}px;
498
+ color: #fff;
499
+ font-size: 12px;
500
+ }
501
+
502
+ @keyframes fadeIn {
503
+ from {
504
+ opacity: 0;
505
+ }
506
+
507
+ to {
508
+ opacity: 1;
509
+ }
510
+ }
511
+ `;
@@ -0,0 +1,69 @@
1
+ /* eslint-disable */
2
+ // Code from: https://observablehq.com/@d3/world-tour
3
+ export default class Util {
4
+ static fromAngles([l, p, g]) {
5
+ l *= Math.PI / 360;
6
+ p *= Math.PI / 360;
7
+ g *= Math.PI / 360;
8
+ const sl = Math.sin(l);
9
+ const cl = Math.cos(l);
10
+ const sp = Math.sin(p);
11
+ const cp = Math.cos(p);
12
+ const sg = Math.sin(g);
13
+ const cg = Math.cos(g);
14
+ return [
15
+ cl * cp * cg + sl * sp * sg,
16
+ sl * cp * cg - cl * sp * sg,
17
+ cl * sp * cg + sl * cp * sg,
18
+ cl * cp * sg - sl * sp * cg,
19
+ ];
20
+ }
21
+
22
+ static toAngles([a, b, c, d]) {
23
+ return [
24
+ (Math.atan2(2 * (a * b + c * d), 1 - 2 * (b * b + c * c)) * 180) / Math.PI,
25
+ (Math.asin(Math.max(-1, Math.min(1, 2 * (a * c - d * b)))) * 180) / Math.PI,
26
+ (Math.atan2(2 * (a * d + b * c), 1 - 2 * (c * c + d * d)) * 180) / Math.PI,
27
+ ];
28
+ }
29
+
30
+ static interpolateAngles(a, b) {
31
+ const i = Util.interpolate(Util.fromAngles(a), Util.fromAngles(b));
32
+ return t => Util.toAngles(i(t));
33
+ }
34
+
35
+ static interpolateLinear([a1, b1, c1, d1], [a2, b2, c2, d2]) {
36
+ (a2 -= a1), (b2 -= b1), (c2 -= c1), (d2 -= d1);
37
+ const x = new Array(4);
38
+ return t => {
39
+ const l = Math.hypot(
40
+ (x[0] = a1 + a2 * t),
41
+ (x[1] = b1 + b2 * t),
42
+ (x[2] = c1 + c2 * t),
43
+ (x[3] = d1 + d2 * t)
44
+ );
45
+ (x[0] /= l), (x[1] /= l), (x[2] /= l), (x[3] /= l);
46
+ return x;
47
+ };
48
+ }
49
+
50
+ static interpolate([a1, b1, c1, d1], [a2, b2, c2, d2]) {
51
+ let dot = a1 * a2 + b1 * b2 + c1 * c2 + d1 * d2;
52
+ if (dot < 0) (a2 = -a2), (b2 = -b2), (c2 = -c2), (d2 = -d2), (dot = -dot);
53
+ if (dot > 0.9995) return Util.interpolateLinear([a1, b1, c1, d1], [a2, b2, c2, d2]);
54
+ const theta0 = Math.acos(Math.max(-1, Math.min(1, dot)));
55
+ const x = new Array(4);
56
+ const l = Math.hypot((a2 -= a1 * dot), (b2 -= b1 * dot), (c2 -= c1 * dot), (d2 -= d1 * dot));
57
+ (a2 /= l), (b2 /= l), (c2 /= l), (d2 /= l);
58
+ return t => {
59
+ const theta = theta0 * t;
60
+ const s = Math.sin(theta);
61
+ const c = Math.cos(theta);
62
+ x[0] = a1 * c + a2 * s;
63
+ x[1] = b1 * c + b2 * s;
64
+ x[2] = c1 * c + c2 * s;
65
+ x[3] = d1 * c + d2 * s;
66
+ return x;
67
+ };
68
+ }
69
+ }
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import styled from 'styled-components';
4
+ import Icon from '../Icon';
5
+
6
+ const Wrapper = styled.div`
7
+ display: flex;
8
+ justify-content: center;
9
+ align-items: center;
10
+ flex-direction: column;
11
+ height: 100%;
12
+ min-height: 100px;
13
+ color: #999;
14
+ .empty-icon {
15
+ margin: 10px 0;
16
+ }
17
+ `;
18
+
19
+ function Empty({ name, color, size, children, ...rest }) {
20
+ return (
21
+ <Wrapper {...rest}>
22
+ <Icon name={name} size={size} className="empty-icon" color={color} />
23
+ <div className="empty-content">{children}</div>
24
+ </Wrapper>
25
+ );
26
+ }
27
+
28
+ Empty.propTypes = {
29
+ color: PropTypes.string,
30
+ name: PropTypes.string,
31
+ size: PropTypes.number,
32
+ children: PropTypes.any,
33
+ };
34
+ Empty.defaultProps = {
35
+ color: 'inherit',
36
+ name: 'inbox',
37
+ size: 36,
38
+ children: null,
39
+ };
40
+
41
+ export default Empty;
@@ -0,0 +1,84 @@
1
+ /* eslint-disable react/no-unused-prop-types */
2
+ import React from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import styled from 'styled-components';
5
+ import Typography from '@material-ui/core/Typography';
6
+
7
+ import { mergeProps } from '../Util';
8
+ import Logo from '../Logo';
9
+
10
+ export default function Footer(props) {
11
+ const newProps = mergeProps(props, Footer, ['dark', 'style']);
12
+ const { className, copyStart, style, brand, dark } = newProps;
13
+
14
+ const endYear = new Date().getFullYear();
15
+ const copyYear = endYear === copyStart ? endYear : `${copyStart}-${endYear}`;
16
+
17
+ return (
18
+ <Container className={className} style={style} dark={dark}>
19
+ <Typography component="div" className="footer">
20
+ <Typography component="p" className="footer-item">
21
+ <span className="footer-copy">&copy; Copyright {copyYear} </span>
22
+ <span className="footer-brand">{brand}</span>
23
+ </Typography>
24
+ <Typography component="p" className="footer-item">
25
+ Powered by
26
+ <Logo
27
+ mode={dark ? 'light' : 'dark'}
28
+ layout="horizontal"
29
+ style={{ transform: 'scale(0.6)', opacity: 0.5 }}
30
+ />
31
+ </Typography>
32
+ </Typography>
33
+ </Container>
34
+ );
35
+ }
36
+
37
+ Footer.propTypes = {
38
+ dark: PropTypes.bool,
39
+ className: PropTypes.string,
40
+ copyStart: PropTypes.string,
41
+ brand: PropTypes.string,
42
+ style: PropTypes.object,
43
+ };
44
+
45
+ Footer.defaultProps = {
46
+ dark: false,
47
+ brand: 'ArcBlock Inc.',
48
+ copyStart: '2017',
49
+ className: '',
50
+ style: {},
51
+ };
52
+
53
+ const Container = styled.div`
54
+ margin-top: 64px;
55
+ padding: 24px 0 32px;
56
+ border-top: 1px solid ${props => (props.dark ? props.theme.palette.grey[900] : '#dee2e7')};
57
+ box-sizing: border-box;
58
+ width: 100%;
59
+
60
+ .footer {
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: space-between;
64
+
65
+ @media (max-width: 540px) {
66
+ flex-direction: column;
67
+ align-items: flex-start;
68
+ justify-content: flex-start;
69
+ }
70
+
71
+ .footer-item {
72
+ color: ${props => props.theme.palette.grey[900]};
73
+ display: flex;
74
+ align-items: center;
75
+ flex-wrap: wrap;
76
+ font-size: 0.9rem;
77
+ }
78
+
79
+ .footer-brand {
80
+ margin-left: 8px;
81
+ margin-right: 8px;
82
+ }
83
+ }
84
+ `;