@arcblock/ux 0.78.25 → 1.6.59
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/LICENSE +1 -1
- package/README.md +0 -56
- package/lib/ActionButton/index.js +6 -4
- package/lib/ActivityIndicator/index.js +75 -23
- package/lib/Alert/index.js +15 -11
- package/lib/Async/index.js +1 -1
- package/lib/Badge/index.js +17 -15
- package/lib/Blocklet/index.js +261 -0
- package/lib/Button/wrap.js +96 -43
- package/lib/ButtonGroup/index.js +3 -16
- package/lib/Center/index.js +30 -4
- package/lib/ClickToCopy/index.js +10 -8
- package/lib/CodeBlock/index.js +40 -13
- package/lib/Colors/index.js +15 -0
- package/lib/Colors/themes/default.js +85 -0
- package/lib/ContactForm/index.js +9 -10
- package/lib/CookieConsent/index.js +98 -0
- package/lib/CountDown/index.js +18 -14
- package/lib/Dialog/confirm.js +84 -0
- package/lib/Dialog/dialog.js +137 -0
- package/lib/Dialog/index.js +23 -0
- package/lib/Earth/index.js +33 -33
- package/lib/Empty/index.js +61 -0
- package/lib/Footer/index.js +16 -18
- package/lib/Icon/image.js +10 -13
- package/lib/Icon/index.js +10 -8
- package/lib/Img/index.js +212 -0
- package/lib/InfoRow/index.js +7 -6
- package/lib/Layout/dashboard/header.js +60 -42
- package/lib/Layout/dashboard/index.js +72 -60
- package/lib/Layout/dashboard/sidebar.js +41 -25
- package/lib/Layout/index.js +113 -51
- package/lib/Locale/browser-lang.js +0 -2
- package/lib/Locale/context.js +85 -61
- package/lib/Locale/selector.js +33 -20
- package/lib/Logo/index.js +15 -13
- package/lib/Metric/index.js +5 -6
- package/lib/NFTDisplay/README.md +59 -0
- package/lib/NFTDisplay/aspect-ratio-container.js +52 -0
- package/lib/NFTDisplay/broken.js +25 -0
- package/lib/NFTDisplay/index.js +317 -0
- package/lib/NFTDisplay/loading.js +23 -0
- package/lib/NFTDisplay/svg-embedder/img.js +68 -0
- package/lib/NFTDisplay/svg-embedder/inline-svg.js +54 -0
- package/lib/PageScroller/index.js +10 -11
- package/lib/PageScroller/usePrevValue.js +2 -2
- package/lib/PricingTable/PricingPlan.js +12 -15
- package/lib/PricingTable/index.js +5 -5
- package/lib/Result/common.js +176 -0
- package/lib/Result/index.js +61 -0
- package/lib/Result/result.js +69 -0
- package/lib/Result/translations.js +61 -0
- package/lib/Screenshot/index.js +14 -13
- package/lib/Spinner/index.js +37 -0
- package/lib/SplitButton/index.js +126 -0
- package/lib/Switch/index.js +107 -0
- package/lib/Tabs/index.js +24 -47
- package/lib/Tag/index.js +15 -13
- package/lib/Terminal/Player.js +43 -45
- package/lib/Terminal/index.js +3 -1
- package/lib/Terminal/util.js +2 -3
- package/lib/TextCollapse/index.js +21 -14
- package/lib/Theme/index.js +79 -63
- package/lib/Theme/responsiveFontSizes.js +8 -8
- package/lib/Toast/index.js +12 -11
- package/lib/Util/index.js +197 -26
- package/lib/Video/index.js +8 -11
- package/lib/Wallet/Action.js +15 -13
- package/lib/Wallet/Download.js +60 -58
- package/lib/Wallet/Open.js +2 -2
- package/lib/WechatPrompt/index.js +10 -10
- package/lib/index.js +6 -6
- package/lib/withTheme/index.js +5 -17
- package/lib/withTracker/error_boundary.js +3 -3
- package/lib/withTracker/index.js +6 -7
- package/package.json +22 -17
- package/src/ActionButton/index.js +65 -0
- package/src/ActivityIndicator/index.js +141 -0
- package/src/Alert/index.js +104 -0
- package/src/Async/index.js +39 -0
- package/src/Badge/index.js +71 -0
- package/src/Blocklet/index.js +424 -0
- package/src/Button/index.js +4 -0
- package/src/Button/wrap.js +101 -0
- package/src/ButtonGroup/index.js +6 -0
- package/src/Center/index.js +40 -0
- package/src/ClickToCopy/index.js +90 -0
- package/src/CodeBlock/index.js +160 -0
- package/src/Colors/index.js +1 -0
- package/src/Colors/themes/default.js +54 -0
- package/src/ContactForm/index.js +240 -0
- package/src/CookieConsent/index.js +90 -0
- package/src/CountDown/index.js +151 -0
- package/src/Dialog/confirm.js +76 -0
- package/src/Dialog/dialog.js +162 -0
- package/src/Dialog/index.js +2 -0
- package/src/DriftBot/index.js +81 -0
- package/src/Earth/countries.json +8057 -0
- package/src/Earth/index.js +511 -0
- package/src/Earth/util.js +69 -0
- package/src/Empty/index.js +41 -0
- package/src/Footer/index.js +110 -0
- package/src/Icon/image.js +55 -0
- package/src/Icon/index.js +69 -0
- package/src/Img/index.js +172 -0
- package/src/InfoRow/index.js +83 -0
- package/src/Layout/dashboard/header.js +157 -0
- package/src/Layout/dashboard/index.js +150 -0
- package/src/Layout/dashboard/sidebar.js +122 -0
- package/src/Layout/index.js +318 -0
- package/src/Locale/browser-lang.js +63 -0
- package/src/Locale/context.js +94 -0
- package/src/Locale/images/globe-dark.png +0 -0
- package/src/Locale/images/globe-light.png +0 -0
- package/src/Locale/selector.js +135 -0
- package/src/Logo/images/logo-dark-text.svg +3 -0
- package/src/Logo/images/logo-dark-top.svg +6 -0
- package/src/Logo/images/logo-light-text.svg +3 -0
- package/src/Logo/images/logo-light-top.svg +6 -0
- package/src/Logo/index.js +47 -0
- package/src/Metric/index.js +115 -0
- package/src/NFTDisplay/README.md +59 -0
- package/src/NFTDisplay/aspect-ratio-container.js +34 -0
- package/src/NFTDisplay/broken.js +18 -0
- package/src/NFTDisplay/index.js +257 -0
- package/src/NFTDisplay/loading.js +17 -0
- package/src/NFTDisplay/svg-embedder/img.js +36 -0
- package/src/NFTDisplay/svg-embedder/inline-svg.js +37 -0
- package/src/PageScroller/index.js +342 -0
- package/src/PageScroller/usePrevValue.js +12 -0
- package/src/PricingTable/PricingPlan.js +112 -0
- package/src/PricingTable/index.js +43 -0
- package/src/Result/common.js +116 -0
- package/src/Result/index.js +31 -0
- package/src/Result/result.js +57 -0
- package/src/Result/translations.js +56 -0
- package/src/Screenshot/devices.css +1366 -0
- package/src/Screenshot/index.js +181 -0
- package/src/Spinner/index.js +19 -0
- package/src/SplitButton/index.js +112 -0
- package/src/Switch/index.js +78 -0
- package/src/Tabs/index.js +46 -0
- package/src/Tag/index.js +73 -0
- package/src/Terminal/Player.js +364 -0
- package/src/Terminal/index.js +150 -0
- package/src/Terminal/player.css +378 -0
- package/src/Terminal/util.js +167 -0
- package/src/Terminal/xterm.css +171 -0
- package/src/TextCollapse/index.js +92 -0
- package/src/Theme/index.js +184 -0
- package/src/Theme/responsiveFontSizes.js +94 -0
- package/src/Toast/index.js +118 -0
- package/src/Util/index.js +281 -0
- package/src/Video/index.js +72 -0
- package/src/Wallet/Action.js +105 -0
- package/src/Wallet/Download.js +130 -0
- package/src/Wallet/Open.js +50 -0
- package/src/Wallet/images/abtwallet.png +0 -0
- package/src/Wallet/images/android_download.svg +23 -0
- package/src/Wallet/images/app-store.svg +20 -0
- package/src/Wallet/images/google-play.svg +70 -0
- package/src/WechatPrompt/images/android.png +0 -0
- package/src/WechatPrompt/images/ios.png +0 -0
- package/src/WechatPrompt/index.js +81 -0
- package/src/index.js +63 -0
- package/src/withTheme/index.js +72 -0
- package/src/withTracker/README.md +34 -0
- package/src/withTracker/error_boundary.js +34 -0
- package/src/withTracker/index.js +70 -0
- package/lib/GraphQLPlayground/graphiql.css +0 -1850
- package/lib/GraphQLPlayground/index.js +0 -302
- package/lib/GraphQLPlayground/util.js +0 -55
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* eslint-disable no-prototype-builtins */
|
|
2
|
+
import React, { useState, useEffect, useContext } from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import Cookie from 'js-cookie';
|
|
5
|
+
|
|
6
|
+
import browserLang from './browser-lang';
|
|
7
|
+
import { getCookieOptions } from '../Util';
|
|
8
|
+
|
|
9
|
+
const cookieName = 'nf_lang';
|
|
10
|
+
const languages = [
|
|
11
|
+
{ value: 'en', text: 'English' },
|
|
12
|
+
{ value: 'zh', text: '简体中文' },
|
|
13
|
+
];
|
|
14
|
+
const langParams = {
|
|
15
|
+
languages: ['zh', 'en'],
|
|
16
|
+
fallback: 'en',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// 跨应用传递多语言选择的方式是在 query string 中添加 locale 参数,LocaleSelector 要高优先级遵守这个参数
|
|
20
|
+
const getLocaleFromSearchParams = (url = window.location.href) => {
|
|
21
|
+
const locale = new URL(url).searchParams.get('locale');
|
|
22
|
+
if (languages.find(x => x.value === locale)) {
|
|
23
|
+
return locale;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const getLocale = locale =>
|
|
29
|
+
locale || getLocaleFromSearchParams() || Cookie.get(cookieName) || browserLang(langParams);
|
|
30
|
+
const setLocale = locale => Cookie.set(cookieName, locale, getCookieOptions());
|
|
31
|
+
|
|
32
|
+
const replace = (template, data) =>
|
|
33
|
+
template.replace(/{(\w*)}/g, (m, key) => (data.hasOwnProperty(key) ? data[key] : ''));
|
|
34
|
+
|
|
35
|
+
const create = () => {
|
|
36
|
+
const LocaleContext = React.createContext();
|
|
37
|
+
const { Provider, Consumer } = LocaleContext;
|
|
38
|
+
function LocaleProvider({ children, locale, translations, ...rest }) {
|
|
39
|
+
const [currentLocale, setCurrentLocale] = useState(getLocale(locale));
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
setLocale(currentLocale);
|
|
43
|
+
}, [currentLocale]);
|
|
44
|
+
|
|
45
|
+
const changeLocale = newLocale => {
|
|
46
|
+
setCurrentLocale(newLocale);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const translate = (key, data) => {
|
|
50
|
+
if (!translations[currentLocale] || !translations[currentLocale][key]) {
|
|
51
|
+
console.warn(`Warning: no ${key} translation of ${currentLocale}`);
|
|
52
|
+
return key;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return replace(translations[currentLocale][key], data);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Provider value={{ locale: currentLocale, changeLocale, t: translate, ...rest }}>
|
|
60
|
+
{children}
|
|
61
|
+
</Provider>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function useLocaleContext() {
|
|
66
|
+
const context = useContext(LocaleContext);
|
|
67
|
+
return context;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
LocaleProvider.propTypes = {
|
|
71
|
+
children: PropTypes.any.isRequired,
|
|
72
|
+
translations: PropTypes.object.isRequired,
|
|
73
|
+
locale: PropTypes.string,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
LocaleProvider.defaultProps = {
|
|
77
|
+
locale: '',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return { Consumer, LocaleProvider, LocaleContext, useLocaleContext };
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const { Consumer, LocaleProvider, LocaleContext, useLocaleContext } = create();
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
LocaleProvider,
|
|
87
|
+
Consumer as LocaleConsumer,
|
|
88
|
+
LocaleContext,
|
|
89
|
+
useLocaleContext,
|
|
90
|
+
setLocale,
|
|
91
|
+
getLocale,
|
|
92
|
+
languages,
|
|
93
|
+
create,
|
|
94
|
+
};
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import React, { useState, useContext, useRef } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
import { useTheme } from '@material-ui/core/styles';
|
|
6
|
+
import Button from '@material-ui/core/Button';
|
|
7
|
+
import Typography from '@material-ui/core/Typography';
|
|
8
|
+
import IconButton from '@material-ui/core/IconButton';
|
|
9
|
+
import ClickAwayListener from '@material-ui/core/ClickAwayListener';
|
|
10
|
+
import Popper from '@material-ui/core/Popper';
|
|
11
|
+
import MenuItem from '@material-ui/core/MenuItem';
|
|
12
|
+
import MenuList from '@material-ui/core/MenuList';
|
|
13
|
+
import CheckIcon from '@material-ui/icons/Check';
|
|
14
|
+
|
|
15
|
+
import { getColor, getBackground } from '../Util';
|
|
16
|
+
|
|
17
|
+
import { LocaleContext, languages } from './context';
|
|
18
|
+
|
|
19
|
+
import globeDark from './images/globe-dark.png';
|
|
20
|
+
import globeLight from './images/globe-light.png';
|
|
21
|
+
|
|
22
|
+
function LocaleSelector(props) {
|
|
23
|
+
const { dark, showText, popperProps, ...rest } = props;
|
|
24
|
+
const { locale, changeLocale } = useContext(LocaleContext);
|
|
25
|
+
const anchorEl = useRef(null);
|
|
26
|
+
const [open, setOpen] = useState(false);
|
|
27
|
+
const theme = useTheme();
|
|
28
|
+
|
|
29
|
+
const onSelect = newLocale => {
|
|
30
|
+
changeLocale(newLocale);
|
|
31
|
+
setOpen(false);
|
|
32
|
+
if (typeof props.onChange === 'function') {
|
|
33
|
+
props.onChange(newLocale);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function onClose(e) {
|
|
38
|
+
if (anchorEl.current?.contains(e.target)) return;
|
|
39
|
+
setOpen(false);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const ButtonComponent = showText ? Button : IconButton;
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Div component="div" dark={dark} theme={theme} {...rest}>
|
|
46
|
+
<ButtonComponent ref={anchorEl} className="trigger" onClick={() => setOpen(!open)}>
|
|
47
|
+
<img src={dark ? globeDark : globeLight} className="trigger-image" alt="globe" />
|
|
48
|
+
{showText ? (
|
|
49
|
+
<Typography component="strong" className="trigger-text">
|
|
50
|
+
{languages.find(x => x.value === locale).text}
|
|
51
|
+
</Typography>
|
|
52
|
+
) : (
|
|
53
|
+
''
|
|
54
|
+
)}
|
|
55
|
+
</ButtonComponent>
|
|
56
|
+
<Popper open={open} anchorEl={anchorEl.current} {...popperProps} disablePortal>
|
|
57
|
+
<div className="locales">
|
|
58
|
+
<ClickAwayListener onClickAway={onClose}>
|
|
59
|
+
<MenuList>
|
|
60
|
+
{languages.map(({ value, text }) => (
|
|
61
|
+
<MenuItem key={value} className="locale-item" onClick={() => onSelect(value, text)}>
|
|
62
|
+
<CheckIcon
|
|
63
|
+
className={value === locale ? 'check-icon check-icon-visible' : 'check-icon'}
|
|
64
|
+
fontSize="small"
|
|
65
|
+
/>
|
|
66
|
+
{text}
|
|
67
|
+
</MenuItem>
|
|
68
|
+
))}
|
|
69
|
+
</MenuList>
|
|
70
|
+
</ClickAwayListener>
|
|
71
|
+
</div>
|
|
72
|
+
</Popper>
|
|
73
|
+
</Div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
LocaleSelector.propTypes = {
|
|
78
|
+
dark: PropTypes.bool,
|
|
79
|
+
size: PropTypes.number,
|
|
80
|
+
showText: PropTypes.bool,
|
|
81
|
+
popperProps: PropTypes.object,
|
|
82
|
+
onChange: PropTypes.func,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
LocaleSelector.defaultProps = {
|
|
86
|
+
dark: false,
|
|
87
|
+
showText: true,
|
|
88
|
+
size: 24,
|
|
89
|
+
popperProps: {},
|
|
90
|
+
onChange: () => {},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export default LocaleSelector;
|
|
94
|
+
|
|
95
|
+
const Div = styled.div`
|
|
96
|
+
.trigger {
|
|
97
|
+
display: flex;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
font-size: 14px;
|
|
101
|
+
.trigger-image {
|
|
102
|
+
width: ${props => props.size}px;
|
|
103
|
+
height: ${props => props.size}px;
|
|
104
|
+
}
|
|
105
|
+
.trigger-text {
|
|
106
|
+
margin-left: 5px;
|
|
107
|
+
font-size: 14px;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.locales {
|
|
112
|
+
background: ${props => getBackground(props)};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.locale-item {
|
|
116
|
+
font-size: 16px;
|
|
117
|
+
font-style: normal;
|
|
118
|
+
font-stretch: normal;
|
|
119
|
+
line-height: normal;
|
|
120
|
+
letter-spacing: 2px;
|
|
121
|
+
text-align: center;
|
|
122
|
+
color: ${props => getColor(props)};
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
display: flex;
|
|
125
|
+
padding: 16px;
|
|
126
|
+
align-items: center;
|
|
127
|
+
.check-icon {
|
|
128
|
+
visibility: hidden;
|
|
129
|
+
margin-right: 4px;
|
|
130
|
+
}
|
|
131
|
+
.check-icon-visible {
|
|
132
|
+
visibility: visible;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
`;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="99" height="18" viewBox="0 0 99 18">
|
|
2
|
+
<path fill="#000" fill-rule="evenodd" d="M6.5.053h2.864L16.028 18h-2.114l-1.391-3.795H3.504L2.14 18H0L6.5.053zm1.474 1.481L4.04 12.563h7.895L7.975 1.534zm14.44 3.542c1.27 0 2.198.296 2.78.892.58.597.871 1.52.871 2.765v.36c0 .117-.008.245-.026.385h-1.826c.018-.14.027-.292.027-.452v-.48c0-.766-.186-1.283-.551-1.55-.367-.266-.916-.4-1.65-.4-.968 0-1.698.24-2.189.723-.493.48-.738 1.208-.738 2.187v8.308h-1.88V5.341h1.824l-.079 1.443c.376-.614.863-1.053 1.463-1.316a4.868 4.868 0 0 1 1.974-.392zM35.95 15.903c.501-.328.752-1.205.752-2.63h1.852c0 1.924-.403 3.178-1.208 3.765-.806.589-2.158.882-4.055.882-2.65 0-4.24-.538-4.766-1.616-.529-1.076-.793-2.781-.793-5.114 0-2.118.367-3.645 1.102-4.581.732-.934 2.209-1.401 4.43-1.401 1.378 0 2.569.221 3.572.665 1.002.446 1.503 1.497 1.503 3.153v.188a.234.234 0 0 0-.027.106v.106h-1.826c0-1.12-.228-1.851-.685-2.188-.455-.34-1.23-.507-2.322-.507-1.665 0-2.713.259-3.142.782-.43.524-.646 1.67-.646 3.44V12.2c0 1.4.161 2.448.485 3.15.322.7 1.297 1.048 2.926 1.048 1.397 0 2.346-.165 2.848-.495zm15.87-.318c.606-.328.912-1.263.912-2.805 0-.924-.147-1.69-.444-2.302-.294-.611-1.007-.917-2.133-.917H43.065v6.516h5.528c1.543 0 2.617-.165 3.226-.492zm-8.754-13.85v6.036h5.665c1.325 0 2.239-.214 2.737-.643.503-.428.755-1.288.755-2.575 0-1.09-.192-1.834-.577-2.226-.385-.394-1.116-.591-2.19-.591h-6.39zM52 8.466c1.185.322 1.956.816 2.314 1.482.359.67.54 1.581.54 2.739 0 1.6-.325 2.858-.97 3.764-.647.909-1.874 1.363-3.686 1.363H41.05V0h8.62c1.592 0 2.759.312 3.503.934.744.624 1.115 1.78 1.115 3.473 0 1.014-.129 1.855-.386 2.522-.258.669-.89 1.181-1.903 1.536zm5.43 9.348V.001h1.907v17.812H57.43zm13.374-6.168v-.708c0-1.539-.141-2.636-.426-3.297-.284-.658-1.191-.99-2.718-.99h-.401c-1.617 0-2.625.25-3.025.75-.399.5-.599 1.632-.599 3.4V12.822c0 .206.008.407.024.602a9.48 9.48 0 0 0 .216 1.474c.106.465.275.822.505 1.072.196.179.435.302.72.373.283.072.586.116.905.135h1.254c1.083 0 1.914-.151 2.492-.456.577-.302.9-1.043.972-2.22a18.338 18.338 0 0 0 .054-1.447c.015-.233.027-.47.027-.71zm-3.786-6.518c2.399 0 3.956.414 4.672 1.243.717.828 1.074 2.418 1.074 4.766 0 2.048-.219 3.704-.657 4.966C71.668 17.367 70.16 18 67.581 18c-2.237 0-3.782-.347-4.632-1.042-.85-.694-1.275-2.205-1.275-4.54v-1.174c0-2.12.318-3.669.954-4.646.635-.98 2.099-1.471 4.39-1.471zm16.434 10.776c.501-.328.752-1.205.752-2.63h1.853c0 1.924-.403 3.178-1.209 3.765-.804.589-2.157.882-4.054.882-2.648 0-4.24-.538-4.767-1.616-.528-1.076-.79-2.781-.79-5.114 0-2.118.365-3.645 1.1-4.581.732-.934 2.21-1.401 4.43-1.401 1.377 0 2.568.221 3.571.665 1.003.446 1.504 1.497 1.504 3.153v.188a.232.232 0 0 0-.026.106v.106H83.99c0-1.12-.229-1.851-.686-2.188-.455-.34-1.23-.507-2.323-.507-1.665 0-2.712.259-3.142.782-.43.524-.643 1.67-.643 3.44V12.2c0 1.4.16 2.448.482 3.15.324.7 1.298 1.048 2.927 1.048 1.397 0 2.346-.165 2.847-.495zm9.236-4.82L99 17.813h-2.47l-5.317-6.01h-.752v6.01h-1.907V0h1.907v10.362h.752l4.512-5.02h2.309l-5.346 5.741z"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="45" height="52" viewBox="0 0 45 52">
|
|
2
|
+
<g fill="none" fill-rule="evenodd" stroke="#000">
|
|
3
|
+
<path d="M.5 13.077L22.15.577l21.651 12.5v25l-21.65 12.5L.5 38.077zM22.15.577v50M.5 13.077l43.301 25M.5 38.077l43.301-25"/>
|
|
4
|
+
<path d="M22.15 38.077l10.826-6.25-10.825-18.75-10.825 18.75z"/>
|
|
5
|
+
</g>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="99" height="18" viewBox="0 0 99 18">
|
|
2
|
+
<path fill="#FFF" fill-rule="evenodd" d="M6.5.053h2.864L16.028 18h-2.114l-1.391-3.795H3.504L2.14 18H0L6.5.053zm1.474 1.481L4.04 12.563h7.895L7.975 1.534zm14.44 3.542c1.27 0 2.198.296 2.78.892.58.597.871 1.52.871 2.765v.36c0 .117-.008.245-.026.385h-1.826c.018-.14.027-.292.027-.452v-.48c0-.766-.186-1.283-.551-1.55-.367-.266-.916-.4-1.65-.4-.968 0-1.698.24-2.189.723-.493.48-.738 1.208-.738 2.187v8.308h-1.88V5.341h1.824l-.079 1.443c.376-.614.863-1.053 1.463-1.316a4.868 4.868 0 0 1 1.974-.392zM35.95 15.903c.501-.328.752-1.205.752-2.63h1.852c0 1.924-.403 3.178-1.208 3.765-.806.589-2.158.882-4.055.882-2.65 0-4.24-.538-4.766-1.616-.529-1.076-.793-2.781-.793-5.114 0-2.118.367-3.645 1.102-4.581.732-.934 2.209-1.401 4.43-1.401 1.378 0 2.569.221 3.572.665 1.002.446 1.503 1.497 1.503 3.153v.188a.234.234 0 0 0-.027.106v.106h-1.826c0-1.12-.228-1.851-.685-2.188-.455-.34-1.23-.507-2.322-.507-1.665 0-2.713.259-3.142.782-.43.524-.646 1.67-.646 3.44V12.2c0 1.4.161 2.448.485 3.15.322.7 1.297 1.048 2.926 1.048 1.397 0 2.346-.165 2.848-.495zm15.87-.318c.606-.328.912-1.263.912-2.805 0-.924-.147-1.69-.444-2.302-.294-.611-1.007-.917-2.133-.917H43.065v6.516h5.528c1.543 0 2.617-.165 3.226-.492zm-8.754-13.85v6.036h5.665c1.325 0 2.239-.214 2.737-.643.503-.428.755-1.288.755-2.575 0-1.09-.192-1.834-.577-2.226-.385-.394-1.116-.591-2.19-.591h-6.39zM52 8.466c1.185.322 1.956.816 2.314 1.482.359.67.54 1.581.54 2.739 0 1.6-.325 2.858-.97 3.764-.647.909-1.874 1.363-3.686 1.363H41.05V0h8.62c1.592 0 2.759.312 3.503.934.744.624 1.115 1.78 1.115 3.473 0 1.014-.129 1.855-.386 2.522-.258.669-.89 1.181-1.903 1.536zm5.43 9.348V.001h1.907v17.812H57.43zm13.374-6.168v-.708c0-1.539-.141-2.636-.426-3.297-.284-.658-1.191-.99-2.718-.99h-.401c-1.617 0-2.625.25-3.025.75-.399.5-.599 1.632-.599 3.4V12.822c0 .206.008.407.024.602a9.48 9.48 0 0 0 .216 1.474c.106.465.275.822.505 1.072.196.179.435.302.72.373.283.072.586.116.905.135h1.254c1.083 0 1.914-.151 2.492-.456.577-.302.9-1.043.972-2.22a18.338 18.338 0 0 0 .054-1.447c.015-.233.027-.47.027-.71zm-3.786-6.518c2.399 0 3.956.414 4.672 1.243.717.828 1.074 2.418 1.074 4.766 0 2.048-.219 3.704-.657 4.966C71.668 17.367 70.16 18 67.581 18c-2.237 0-3.782-.347-4.632-1.042-.85-.694-1.275-2.205-1.275-4.54v-1.174c0-2.12.318-3.669.954-4.646.635-.98 2.099-1.471 4.39-1.471zm16.434 10.776c.501-.328.752-1.205.752-2.63h1.853c0 1.924-.403 3.178-1.209 3.765-.804.589-2.157.882-4.054.882-2.648 0-4.24-.538-4.767-1.616-.528-1.076-.79-2.781-.79-5.114 0-2.118.365-3.645 1.1-4.581.732-.934 2.21-1.401 4.43-1.401 1.377 0 2.568.221 3.571.665 1.003.446 1.504 1.497 1.504 3.153v.188a.232.232 0 0 0-.026.106v.106H83.99c0-1.12-.229-1.851-.686-2.188-.455-.34-1.23-.507-2.323-.507-1.665 0-2.712.259-3.142.782-.43.524-.643 1.67-.643 3.44V12.2c0 1.4.16 2.448.482 3.15.324.7 1.298 1.048 2.927 1.048 1.397 0 2.346-.165 2.847-.495zm9.236-4.82L99 17.813h-2.47l-5.317-6.01h-.752v6.01h-1.907V0h1.907v10.362h.752l4.512-5.02h2.309l-5.346 5.741z"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="45" height="52" viewBox="0 0 45 52">
|
|
2
|
+
<g fill="none" fill-rule="evenodd" stroke="#FFF">
|
|
3
|
+
<path d="M.5 13.077L22.15.577l21.651 12.5v25l-21.65 12.5L.5 38.077zM22.15.577v50M.5 13.077l43.301 25M.5 38.077l43.301-25"/>
|
|
4
|
+
<path d="M22.15 38.077l10.826-6.25-10.825-18.75-10.825 18.75z"/>
|
|
5
|
+
</g>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
import { ReactComponent as LightLogo } from './images/logo-light-top.svg';
|
|
6
|
+
import { ReactComponent as LightText } from './images/logo-light-text.svg';
|
|
7
|
+
import { ReactComponent as DarkLogo } from './images/logo-dark-top.svg';
|
|
8
|
+
import { ReactComponent as DarkText } from './images/logo-dark-text.svg';
|
|
9
|
+
|
|
10
|
+
export default function Logo({ showText, showLogo, mode, layout, ...rest }) {
|
|
11
|
+
const logo = mode === 'light' ? <LightLogo /> : <DarkLogo />;
|
|
12
|
+
const text =
|
|
13
|
+
mode === 'light' ? <LightText className="logo-text" /> : <DarkText className="logo-text" />;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Container layout={layout} {...rest}>
|
|
17
|
+
{showLogo && logo}
|
|
18
|
+
{showText && text}
|
|
19
|
+
</Container>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
Logo.propTypes = {
|
|
24
|
+
mode: PropTypes.oneOf(['light', 'dark']),
|
|
25
|
+
layout: PropTypes.oneOf(['vertical', 'horizontal']),
|
|
26
|
+
showText: PropTypes.bool,
|
|
27
|
+
showLogo: PropTypes.bool,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
Logo.defaultProps = {
|
|
31
|
+
mode: 'dark',
|
|
32
|
+
layout: 'vertical',
|
|
33
|
+
showText: true,
|
|
34
|
+
showLogo: true,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const Container = styled.span`
|
|
38
|
+
display: inline-flex;
|
|
39
|
+
flex-direction: ${props => (props.layout === 'horizontal' ? 'row' : 'column')};
|
|
40
|
+
justify-content: center;
|
|
41
|
+
align-items: center;
|
|
42
|
+
|
|
43
|
+
.logo-text {
|
|
44
|
+
${props => (props.layout === 'vertical' ? 'margin-top: 8px;' : '')}
|
|
45
|
+
${props => (props.layout === 'vertical' ? '' : 'margin-left: 8px;')};
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* eslint-disable react/no-danger */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import styled from 'styled-components';
|
|
5
|
+
|
|
6
|
+
import ImageIcon from '../Icon/image';
|
|
7
|
+
|
|
8
|
+
export default function Metric({ icon, value, name, url, animated, LinkComponent, prefix }) {
|
|
9
|
+
const metric = (
|
|
10
|
+
<>
|
|
11
|
+
<div className="metric__image">
|
|
12
|
+
<ImageIcon name={icon} alt={name} size={30} prefix={prefix} color="#222222" />
|
|
13
|
+
</div>
|
|
14
|
+
<div>
|
|
15
|
+
<div
|
|
16
|
+
className={`metric__number ${animated ? 'metric__number--animated' : ''}`}
|
|
17
|
+
dangerouslySetInnerHTML={{ __html: value }}
|
|
18
|
+
/>
|
|
19
|
+
<div className="metric__name">{name}</div>
|
|
20
|
+
</div>
|
|
21
|
+
</>
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return <Container>{url ? <LinkComponent to={url}>{metric}</LinkComponent> : metric}</Container>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Metric.propTypes = {
|
|
28
|
+
icon: PropTypes.string.isRequired,
|
|
29
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
30
|
+
name: PropTypes.string.isRequired,
|
|
31
|
+
animated: PropTypes.bool,
|
|
32
|
+
url: PropTypes.string,
|
|
33
|
+
LinkComponent: PropTypes.any,
|
|
34
|
+
prefix: PropTypes.string,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
Metric.defaultProps = {
|
|
38
|
+
animated: false,
|
|
39
|
+
url: '',
|
|
40
|
+
LinkComponent: null,
|
|
41
|
+
prefix: '/images',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const Container = styled.div`
|
|
45
|
+
border-left: 1px solid ${props => props.theme.typography.color.main};
|
|
46
|
+
padding: 10px 0 10px 16px;
|
|
47
|
+
@media (max-width: ${props => props.theme.breakpoints.values.sm}px) {
|
|
48
|
+
padding: 0 0 0 8px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
display: flex;
|
|
52
|
+
justify-items: center;
|
|
53
|
+
align-items: flex-start;
|
|
54
|
+
|
|
55
|
+
a {
|
|
56
|
+
display: flex;
|
|
57
|
+
justify-items: center;
|
|
58
|
+
align-items: flex-start;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.metric__image {
|
|
62
|
+
margin-right: 8px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.metric__number {
|
|
66
|
+
margin-bottom: 8px;
|
|
67
|
+
font-size: ${props => (props.size === 'small' ? 32 : 36)}px;
|
|
68
|
+
font-weight: 600;
|
|
69
|
+
line-height: 36px;
|
|
70
|
+
color: ${props => props.theme.typography.color.main};
|
|
71
|
+
|
|
72
|
+
small {
|
|
73
|
+
font-size: 12px;
|
|
74
|
+
line-height: 12px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@media (max-width: ${props => props.theme.breakpoints.values.sm}px) {
|
|
78
|
+
font-size: ${props => (props.size === 'small' ? 24 : 28)}px;
|
|
79
|
+
line-height: ${props => (props.size === 'small' ? 24 : 28)}px;
|
|
80
|
+
margin-bottom: 2px;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.metric__number--animated {
|
|
85
|
+
animation-name: blink-opacity;
|
|
86
|
+
animation-duration: 250ms;
|
|
87
|
+
animation-timing-function: linear;
|
|
88
|
+
animation-iteration-count: 1;
|
|
89
|
+
background-color: transparent !important;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.metric__name {
|
|
93
|
+
font-size: 14px;
|
|
94
|
+
text-transform: capitalize;
|
|
95
|
+
line-height: 1.2;
|
|
96
|
+
font-weight: 500;
|
|
97
|
+
color: ${props => props.theme.typography.color.main};
|
|
98
|
+
@media (max-width: ${props => props.theme.breakpoints.values.sm}px) {
|
|
99
|
+
font-size: 10px;
|
|
100
|
+
line-height: 1;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@keyframes blink-opacity {
|
|
105
|
+
0% {
|
|
106
|
+
opacity: 1;
|
|
107
|
+
}
|
|
108
|
+
50% {
|
|
109
|
+
opacity: 0.3;
|
|
110
|
+
}
|
|
111
|
+
100% {
|
|
112
|
+
opacity: 1;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
`;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# NFTDisplay
|
|
2
|
+
|
|
3
|
+
## 01 使用
|
|
4
|
+
|
|
5
|
+
### 01.01 默认样式
|
|
6
|
+
|
|
7
|
+
NFTDisplay 组件默认尺寸为 *150x150*, 可以通过 css 设置 width/height. 固定尺寸的使用场景感觉比较少, 多数情况应该都需要将 NFTDisplay 应用于响应式布局中.
|
|
8
|
+
|
|
9
|
+
### 01.02 aspect ratio
|
|
10
|
+
|
|
11
|
+
可以使用 aspect prop 设置 NFTDisplay 的宽高比, NFTDisplay 包裹一两层 div/span 标签 (用来控制布局, 没有直接把 img 标签渲染出来), 所以这里说的长宽比指的不是 img 的长宽比, 图片的尺寸大小不一, 长宽比也是既定的, aspect prop 控制的是包裹 img 容器的长宽比.
|
|
12
|
+
|
|
13
|
+
NFTDisplay 宽高比的计算是根据父容器的 width 来确定的 (NFTDisplay 会填充整个宽度), 所以可以通过控制父容器的 width 来控制 NFTDisplay 的大小.
|
|
14
|
+
|
|
15
|
+
### 01.03 inset
|
|
16
|
+
|
|
17
|
+
inset 设置为 true 时 NFTDisplay 会镶嵌/填满父容器 (并垂直+水平居中显示图片), 所以父容器必须有明确的宽高 (尤其是高度). 响应式布局中应该会比较常用.
|
|
18
|
+
|
|
19
|
+
注: inset 比 aspect ratio 优先级高, 如果同时设置了 inset 和 aspect, 则后者不生效.
|
|
20
|
+
|
|
21
|
+
### 01.04 asset data (prop)
|
|
22
|
+
|
|
23
|
+
可以为 asset data prop 传入 raw data 或 parsed data, 避免多次解析 asset data.
|
|
24
|
+
|
|
25
|
+
### 01.05 broken image & error handling
|
|
26
|
+
|
|
27
|
+
* display 加载失败时会显示一个 broken-image, 可以从外部覆盖 `.nft-display--broken` 的样式来调整尺寸/颜色等样式
|
|
28
|
+
* error handling, 这部分感觉出错原因可能性会很多, 有 json 解析错误、某字段缺失、某 object 指定路径的值缺失、nft type 不支持等等, 暂时没想到如何更合理的捕获和处理这些错误.
|
|
29
|
+
|
|
30
|
+
### 02 svg 加载
|
|
31
|
+
|
|
32
|
+
基于 `img` 标签加载 NFT Display. 几种 nft type 的加载:
|
|
33
|
+
|
|
34
|
+
- url
|
|
35
|
+
直接使用 `<img>`
|
|
36
|
+
- svg_gzipped
|
|
37
|
+
content => ungzip => svgToImgUrl => `<img>`
|
|
38
|
+
- svg (未测试, 需要测试数据)
|
|
39
|
+
content => svgToImgUrl => `<img>`
|
|
40
|
+
- html (TODO)
|
|
41
|
+
基于 `<img>` 的加载方式不适用, 目前没有发现这种 nft type 的测试数据
|
|
42
|
+
|
|
43
|
+
基于 `<img>` 标签的加载方式没有样式污染问题, 加载、尺寸控制也比较方便, 不过据说有些情况下 svg 可能无法正确显示 (比如 svg 加载了 font|image 资源), 目前没有发现问题, 还需要更多的观察
|
|
44
|
+
|
|
45
|
+
## 03 iframe 第三方嵌入 (TODO)
|
|
46
|
+
|
|
47
|
+
需要设计 iframe 的 API (iframe#src 查询参数), 目前想到的参数:
|
|
48
|
+
|
|
49
|
+
- address : asset address
|
|
50
|
+
调用 getAssetState 接口获取 display 数据进行展示
|
|
51
|
+
- 样式控制相关的参数 ?
|
|
52
|
+
|
|
53
|
+
## 04 参考
|
|
54
|
+
|
|
55
|
+
* [提供一个 NFT display 组件 · Issue #199 · ArcBlock/ux](https://github.com/ArcBlock/ux/issues/199)
|
|
56
|
+
* [2021徽章出现奇怪的渲染 · Issue #230 · blocklet/nft-marketplace](https://github.com/blocklet/nft-marketplace/issues/230)
|
|
57
|
+
* [Adding vector graphics to the Web - Learn web development | MDN](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web)
|
|
58
|
+
* [The Best Way to Embed SVG on HTML (2021)](https://vecta.io/blog/best-way-to-embed-svg)
|
|
59
|
+
* [javascript - Do I always need to call URL.revokeObjectURL() explicitly? - Stack Overflow](https://stackoverflow.com/questions/49209756/do-i-always-need-to-call-url-revokeobjecturl-explicitly)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
function AspectRatioContainer({ aspect, children, ...rest }) {
|
|
6
|
+
return (
|
|
7
|
+
<Root aspect={aspect} {...rest}>
|
|
8
|
+
<span className="aspect-ratio-container__inner">{children}</span>
|
|
9
|
+
</Root>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
AspectRatioContainer.propTypes = {
|
|
14
|
+
aspect: PropTypes.number.isRequired,
|
|
15
|
+
children: PropTypes.node.isRequired,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const Root = styled.span`
|
|
19
|
+
display: block;
|
|
20
|
+
position: relative;
|
|
21
|
+
width: 100%;
|
|
22
|
+
height: 0;
|
|
23
|
+
padding-bottom: ${({ aspect }) => (1 / aspect) * 100}%;
|
|
24
|
+
|
|
25
|
+
.aspect-ratio-container__inner {
|
|
26
|
+
position: absolute;
|
|
27
|
+
top: 0;
|
|
28
|
+
bottom: 0;
|
|
29
|
+
left: 0;
|
|
30
|
+
right: 0;
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
export default AspectRatioContainer;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import BrokenImage from '@material-ui/icons/BrokenImage';
|
|
4
|
+
|
|
5
|
+
export default function Broken() {
|
|
6
|
+
return <Root className="nft-display__broken" />;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const Root = styled(BrokenImage)`
|
|
10
|
+
&& {
|
|
11
|
+
width: 100%;
|
|
12
|
+
max-width: 200px;
|
|
13
|
+
height: auto;
|
|
14
|
+
max-width: 100%;
|
|
15
|
+
max-height: 100%;
|
|
16
|
+
fill: #ddd;
|
|
17
|
+
}
|
|
18
|
+
`;
|