@arcblock/ux 0.78.26 → 1.6.60

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 (174) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +0 -56
  3. package/lib/ActionButton/index.js +6 -4
  4. package/lib/ActivityIndicator/index.js +75 -23
  5. package/lib/Alert/index.js +15 -11
  6. package/lib/Async/index.js +1 -1
  7. package/lib/Badge/index.js +17 -15
  8. package/lib/Blocklet/index.js +261 -0
  9. package/lib/Button/wrap.js +96 -43
  10. package/lib/ButtonGroup/index.js +3 -16
  11. package/lib/Center/index.js +30 -4
  12. package/lib/ClickToCopy/index.js +10 -8
  13. package/lib/CodeBlock/index.js +40 -13
  14. package/lib/Colors/index.js +15 -0
  15. package/lib/Colors/themes/default.js +85 -0
  16. package/lib/ContactForm/index.js +9 -10
  17. package/lib/CookieConsent/index.js +98 -0
  18. package/lib/CountDown/index.js +18 -14
  19. package/lib/Dialog/confirm.js +84 -0
  20. package/lib/Dialog/dialog.js +137 -0
  21. package/lib/Dialog/index.js +23 -0
  22. package/lib/Earth/index.js +33 -33
  23. package/lib/Empty/index.js +61 -0
  24. package/lib/Footer/index.js +16 -18
  25. package/lib/Icon/image.js +10 -13
  26. package/lib/Icon/index.js +10 -8
  27. package/lib/Img/index.js +212 -0
  28. package/lib/InfoRow/index.js +7 -6
  29. package/lib/Layout/dashboard/header.js +60 -42
  30. package/lib/Layout/dashboard/index.js +72 -60
  31. package/lib/Layout/dashboard/sidebar.js +41 -25
  32. package/lib/Layout/index.js +113 -51
  33. package/lib/Locale/browser-lang.js +0 -2
  34. package/lib/Locale/context.js +85 -61
  35. package/lib/Locale/selector.js +33 -20
  36. package/lib/Logo/index.js +15 -13
  37. package/lib/Metric/index.js +5 -6
  38. package/lib/NFTDisplay/README.md +59 -0
  39. package/lib/NFTDisplay/aspect-ratio-container.js +52 -0
  40. package/lib/NFTDisplay/broken.js +25 -0
  41. package/lib/NFTDisplay/index.js +317 -0
  42. package/lib/NFTDisplay/loading.js +23 -0
  43. package/lib/NFTDisplay/svg-embedder/img.js +68 -0
  44. package/lib/NFTDisplay/svg-embedder/inline-svg.js +54 -0
  45. package/lib/PageScroller/index.js +10 -11
  46. package/lib/PageScroller/usePrevValue.js +2 -2
  47. package/lib/PricingTable/PricingPlan.js +12 -15
  48. package/lib/PricingTable/index.js +5 -5
  49. package/lib/QRCode/index.js +89 -0
  50. package/lib/Result/common.js +176 -0
  51. package/lib/Result/index.js +61 -0
  52. package/lib/Result/result.js +69 -0
  53. package/lib/Result/translations.js +61 -0
  54. package/lib/Screenshot/index.js +14 -13
  55. package/lib/Spinner/index.js +37 -0
  56. package/lib/SplitButton/index.js +126 -0
  57. package/lib/Switch/index.js +107 -0
  58. package/lib/Tabs/index.js +24 -47
  59. package/lib/Tag/index.js +15 -13
  60. package/lib/Terminal/Player.js +43 -45
  61. package/lib/Terminal/index.js +3 -1
  62. package/lib/Terminal/util.js +2 -3
  63. package/lib/TextCollapse/index.js +21 -14
  64. package/lib/Theme/index.js +79 -63
  65. package/lib/Theme/responsiveFontSizes.js +8 -8
  66. package/lib/Toast/index.js +12 -11
  67. package/lib/Util/index.js +197 -26
  68. package/lib/Video/index.js +8 -11
  69. package/lib/Wallet/Action.js +15 -13
  70. package/lib/Wallet/Download.js +60 -58
  71. package/lib/Wallet/Open.js +2 -2
  72. package/lib/WechatPrompt/index.js +10 -10
  73. package/lib/index.js +6 -6
  74. package/lib/withTheme/index.js +5 -17
  75. package/lib/withTracker/error_boundary.js +3 -3
  76. package/lib/withTracker/index.js +6 -7
  77. package/package.json +23 -17
  78. package/src/ActionButton/index.js +65 -0
  79. package/src/ActivityIndicator/index.js +141 -0
  80. package/src/Alert/index.js +104 -0
  81. package/src/Async/index.js +39 -0
  82. package/src/Badge/index.js +71 -0
  83. package/src/Blocklet/index.js +424 -0
  84. package/src/Button/index.js +4 -0
  85. package/src/Button/wrap.js +101 -0
  86. package/src/ButtonGroup/index.js +6 -0
  87. package/src/Center/index.js +40 -0
  88. package/src/ClickToCopy/index.js +90 -0
  89. package/src/CodeBlock/index.js +160 -0
  90. package/src/Colors/index.js +1 -0
  91. package/src/Colors/themes/default.js +54 -0
  92. package/src/ContactForm/index.js +240 -0
  93. package/src/CookieConsent/index.js +90 -0
  94. package/src/CountDown/index.js +151 -0
  95. package/src/Dialog/confirm.js +76 -0
  96. package/src/Dialog/dialog.js +162 -0
  97. package/src/Dialog/index.js +2 -0
  98. package/src/DriftBot/index.js +81 -0
  99. package/src/Earth/countries.json +8057 -0
  100. package/src/Earth/index.js +511 -0
  101. package/src/Earth/util.js +69 -0
  102. package/src/Empty/index.js +41 -0
  103. package/src/Footer/index.js +110 -0
  104. package/src/Icon/image.js +55 -0
  105. package/src/Icon/index.js +69 -0
  106. package/src/Img/index.js +172 -0
  107. package/src/InfoRow/index.js +83 -0
  108. package/src/Layout/dashboard/header.js +157 -0
  109. package/src/Layout/dashboard/index.js +150 -0
  110. package/src/Layout/dashboard/sidebar.js +122 -0
  111. package/src/Layout/index.js +318 -0
  112. package/src/Locale/browser-lang.js +63 -0
  113. package/src/Locale/context.js +94 -0
  114. package/src/Locale/images/globe-dark.png +0 -0
  115. package/src/Locale/images/globe-light.png +0 -0
  116. package/src/Locale/selector.js +135 -0
  117. package/src/Logo/images/logo-dark-text.svg +3 -0
  118. package/src/Logo/images/logo-dark-top.svg +6 -0
  119. package/src/Logo/images/logo-light-text.svg +3 -0
  120. package/src/Logo/images/logo-light-top.svg +6 -0
  121. package/src/Logo/index.js +47 -0
  122. package/src/Metric/index.js +115 -0
  123. package/src/NFTDisplay/README.md +59 -0
  124. package/src/NFTDisplay/aspect-ratio-container.js +34 -0
  125. package/src/NFTDisplay/broken.js +18 -0
  126. package/src/NFTDisplay/index.js +257 -0
  127. package/src/NFTDisplay/loading.js +17 -0
  128. package/src/NFTDisplay/svg-embedder/img.js +36 -0
  129. package/src/NFTDisplay/svg-embedder/inline-svg.js +37 -0
  130. package/src/PageScroller/index.js +342 -0
  131. package/src/PageScroller/usePrevValue.js +12 -0
  132. package/src/PricingTable/PricingPlan.js +112 -0
  133. package/src/PricingTable/index.js +43 -0
  134. package/src/QRCode/index.js +56 -0
  135. package/src/Result/common.js +116 -0
  136. package/src/Result/index.js +31 -0
  137. package/src/Result/result.js +57 -0
  138. package/src/Result/translations.js +56 -0
  139. package/src/Screenshot/devices.css +1366 -0
  140. package/src/Screenshot/index.js +181 -0
  141. package/src/Spinner/index.js +19 -0
  142. package/src/SplitButton/index.js +112 -0
  143. package/src/Switch/index.js +78 -0
  144. package/src/Tabs/index.js +46 -0
  145. package/src/Tag/index.js +73 -0
  146. package/src/Terminal/Player.js +364 -0
  147. package/src/Terminal/index.js +150 -0
  148. package/src/Terminal/player.css +378 -0
  149. package/src/Terminal/util.js +167 -0
  150. package/src/Terminal/xterm.css +171 -0
  151. package/src/TextCollapse/index.js +92 -0
  152. package/src/Theme/index.js +184 -0
  153. package/src/Theme/responsiveFontSizes.js +94 -0
  154. package/src/Toast/index.js +118 -0
  155. package/src/Util/index.js +281 -0
  156. package/src/Video/index.js +72 -0
  157. package/src/Wallet/Action.js +105 -0
  158. package/src/Wallet/Download.js +130 -0
  159. package/src/Wallet/Open.js +50 -0
  160. package/src/Wallet/images/abtwallet.png +0 -0
  161. package/src/Wallet/images/android_download.svg +23 -0
  162. package/src/Wallet/images/app-store.svg +20 -0
  163. package/src/Wallet/images/google-play.svg +70 -0
  164. package/src/WechatPrompt/images/android.png +0 -0
  165. package/src/WechatPrompt/images/ios.png +0 -0
  166. package/src/WechatPrompt/index.js +81 -0
  167. package/src/index.js +63 -0
  168. package/src/withTheme/index.js +72 -0
  169. package/src/withTracker/README.md +34 -0
  170. package/src/withTracker/error_boundary.js +34 -0
  171. package/src/withTracker/index.js +70 -0
  172. package/lib/GraphQLPlayground/graphiql.css +0 -1850
  173. package/lib/GraphQLPlayground/index.js +0 -302
  174. package/lib/GraphQLPlayground/util.js +0 -55
@@ -0,0 +1,160 @@
1
+ /* eslint-disable react/no-danger */
2
+ import React, { useState } from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import styled from 'styled-components';
5
+ import Copy from 'copy-to-clipboard';
6
+ import Button from '@material-ui/core/IconButton';
7
+ import useMountedState from 'react-use/lib/useMountedState';
8
+
9
+ import hljs from 'highlight.js/lib/highlight';
10
+ import javascript from 'highlight.js/lib/languages/javascript';
11
+ import json from 'highlight.js/lib/languages/json';
12
+ import elixir from 'highlight.js/lib/languages/elixir';
13
+ import java from 'highlight.js/lib/languages/java';
14
+ import swift from 'highlight.js/lib/languages/swift';
15
+ import objectivec from 'highlight.js/lib/languages/objectivec';
16
+ import kotlin from 'highlight.js/lib/languages/kotlin';
17
+ import protobuf from 'highlight.js/lib/languages/protobuf';
18
+ import python from 'highlight.js/lib/languages/python';
19
+ import yaml from 'highlight.js/lib/languages/yaml';
20
+ import shell from 'highlight.js/lib/languages/shell';
21
+ import diff from 'highlight.js/lib/languages/diff';
22
+ import plaintext from 'highlight.js/lib/languages/plaintext';
23
+
24
+ import 'highlight.js/styles/atom-one-dark.css';
25
+
26
+ import CopyIcon from '@material-ui/icons/FileCopy';
27
+ import CheckIcon from '@material-ui/icons/Check';
28
+ import colors from '../Colors';
29
+
30
+ hljs.registerLanguage('javascript', javascript);
31
+ hljs.registerLanguage('js', javascript);
32
+ hljs.registerLanguage('json', json);
33
+ hljs.registerLanguage('elixir', elixir);
34
+ hljs.registerLanguage('java', java);
35
+ hljs.registerLanguage('kotlin', kotlin);
36
+ hljs.registerLanguage('kt', kotlin);
37
+ hljs.registerLanguage('protobuf', protobuf);
38
+ hljs.registerLanguage('protobuffer', protobuf);
39
+ hljs.registerLanguage('python', python);
40
+ hljs.registerLanguage('py', python);
41
+ hljs.registerLanguage('yaml', yaml);
42
+ hljs.registerLanguage('yml', yaml);
43
+ hljs.registerLanguage('shell', shell);
44
+ hljs.registerLanguage('sh', shell);
45
+ hljs.registerLanguage('plaintext', plaintext);
46
+ hljs.registerLanguage('text', plaintext);
47
+ hljs.registerLanguage('patch', diff);
48
+ hljs.registerLanguage('diff', diff);
49
+ hljs.registerLanguage('swift', swift);
50
+ hljs.registerLanguage('objectivec', objectivec);
51
+ hljs.registerLanguage('oc', objectivec);
52
+
53
+ export default function CodeBlock({ code, language, children, ...rest }) {
54
+ const [copied, setCopied] = useState(false);
55
+ const isMounted = useMountedState();
56
+ const source = code || children;
57
+
58
+ const onCopy = () => {
59
+ Copy(source);
60
+ setCopied(true);
61
+ // 恢复 copied 状态
62
+ setTimeout(() => {
63
+ if (isMounted()) {
64
+ setCopied(false);
65
+ }
66
+ }, 1500);
67
+ };
68
+
69
+ return (
70
+ <Pre {...rest}>
71
+ <span className="codeblock__inner">
72
+ <code
73
+ className={`hljs ${language}`}
74
+ dangerouslySetInnerHTML={{ __html: hljs.highlightAuto(source, [language]).value }}
75
+ />
76
+ </span>
77
+ <Button
78
+ className="copy-button"
79
+ onClick={onCopy}
80
+ tabIndex="-1"
81
+ color="primary"
82
+ disabled={copied}>
83
+ {!copied && <CopyIcon style={{ color: '#fff', fontSize: 16 }} />}
84
+ {copied && <CheckIcon style={{ color: '#fff', fontSize: 16 }} />}
85
+ </Button>
86
+ </Pre>
87
+ );
88
+ }
89
+
90
+ CodeBlock.propTypes = {
91
+ code: PropTypes.string,
92
+ language: PropTypes.string,
93
+ children: PropTypes.any,
94
+ };
95
+
96
+ CodeBlock.defaultProps = {
97
+ code: '',
98
+ language: 'text',
99
+ children: null,
100
+ };
101
+
102
+ const fontFamily = 'source-code-pro, Menlo, Monaco, Consolas, Courier New, monospace !important';
103
+ const Pre = styled.pre`
104
+ font-family: ${fontFamily};
105
+ display: block;
106
+ font-size: 14px;
107
+ line-height: 1.42857143;
108
+ margin: 0 0 32px;
109
+ word-break: break-word;
110
+ word-wrap: break-word;
111
+ text-align: left;
112
+ border-radius: 5px;
113
+ border: 1px solid #dedede;
114
+ background: #222;
115
+ color: #fff;
116
+ position: relative;
117
+
118
+ .codeblock__inner {
119
+ display: block;
120
+ width: 100%;
121
+ max-height: 46.25rem;
122
+ overflow: scroll;
123
+ }
124
+
125
+ .copy-button {
126
+ display: none;
127
+ position: absolute;
128
+ top: 8px;
129
+ right: 24px;
130
+ padding: 4px;
131
+ border-radius: 4px;
132
+
133
+ &,
134
+ &:hover,
135
+ &.Mui-disabled {
136
+ background: ${colors.primary.main};
137
+ }
138
+ }
139
+
140
+ &:hover {
141
+ .copy-button {
142
+ display: block;
143
+ }
144
+ }
145
+
146
+ code {
147
+ counter-reset: line;
148
+ counter-increment: line;
149
+ padding: 16px;
150
+ font-family: ${fontFamily};
151
+ color: #fff;
152
+ * {
153
+ font-family: ${fontFamily};
154
+ }
155
+ }
156
+
157
+ .hljs * {
158
+ white-space: normal; // autowrap
159
+ }
160
+ `;
@@ -0,0 +1 @@
1
+ export { default } from './themes/default';
@@ -0,0 +1,54 @@
1
+ /**
2
+ * 默认 colors, ABT 系列
3
+ *
4
+ * - colors object 结构是在 mui theme#palette object 基础上调整后的结构
5
+ * - 色值在 mui default theme 基础上将 figma 中常用的 colors 进行覆盖
6
+ * - 扩展一些常用色值 (如 DID 系列)
7
+ * - figma: https://www.figma.com/file/1qHyMF137EXOQpSFVByszG/UX-Library?node-id=295%3A1518
8
+ */
9
+ const colors = {
10
+ common: {
11
+ black: '#000',
12
+ white: '#fff',
13
+ },
14
+ primary: { main: '#3773F2', contrastText: '#fff' }, // override
15
+ secondary: { main: '#16CED1', contrastText: '#fff' }, // override
16
+ error: { main: '#F16E6E', contrastText: '#fff' }, // override
17
+ warning: { main: '#DE9E37', contrastText: '#fff' }, // override
18
+ info: { main: '#0775F8', contrastText: '#fff' }, // override
19
+ success: { main: '#34BE74', contrastText: '#fff' }, // override
20
+ grey: {
21
+ 50: '#fafafa',
22
+ 100: '#f5f5f5',
23
+ 200: '#eeeeee',
24
+ 300: '#e0e0e0',
25
+ 400: '#bdbdbd',
26
+ 500: '#9e9e9e',
27
+ 600: '#757575',
28
+ 700: '#616161',
29
+ 800: '#424242',
30
+ 900: '#212121',
31
+ A100: '#d5d5d5',
32
+ A200: '#aaaaaa',
33
+ A400: '#303030',
34
+ A700: '#616161',
35
+ },
36
+ text: {
37
+ primary: 'rgba(0, 0, 0, 0.87)',
38
+ secondary: 'rgba(0, 0, 0, 0.54)',
39
+ disabled: 'rgba(0, 0, 0, 0.38)',
40
+ hint: 'rgba(0, 0, 0, 0.38)',
41
+ },
42
+ divider: 'rgba(0, 0, 0, 0.12)',
43
+ background: {
44
+ default: '#fff',
45
+ },
46
+ // 扩展色值, 适用于 did 相关的组件, 如果某些产品整体风格是 did 系列, 可以扩展出一个 did 系列的 theme
47
+ did: {
48
+ primary: '#4598FA',
49
+ secondary: '#49C3AD',
50
+ },
51
+ // TODO: 等设计规范稳定后, 考虑扩展 trade 相关的常用颜色 (send/receive/exchange/transfer)
52
+ };
53
+
54
+ export default colors;
@@ -0,0 +1,240 @@
1
+ /* eslint-disable react/no-unused-prop-types */
2
+ /* eslint-disable react/static-property-placement */
3
+ import React from 'react';
4
+ import PropTypes from 'prop-types';
5
+ import styled from 'styled-components';
6
+ import axios from 'axios';
7
+
8
+ import Typography from '@material-ui/core/Typography';
9
+ import CircularProgress from '@material-ui/core/CircularProgress';
10
+
11
+ import { mergeProps } from '../Util';
12
+ import Button from '../Button';
13
+
14
+ export async function submitContactForm({ formId, portalId }, fields, context) {
15
+ const url = `https://api.hsforms.com/submissions/v3/integration/submit/${portalId}/${formId}`;
16
+ return axios
17
+ .post(url, {
18
+ submittedAt: Date.now(),
19
+ fields: Object.keys(fields).map(x => ({
20
+ name: x.replace(/\s+/, '').toLowerCase(),
21
+ value: fields[x],
22
+ })),
23
+ context,
24
+ skipValidation: false,
25
+ })
26
+ .then(res => res.data.inlineMessage)
27
+ .catch(res => (res.data ? res.data.message : 'Form Submit Failed'));
28
+ }
29
+
30
+ export default class ContactForm extends React.Component {
31
+ static propTypes = {
32
+ style: PropTypes.object,
33
+ className: PropTypes.string,
34
+ portalId: PropTypes.string,
35
+ formId: PropTypes.string,
36
+ title: PropTypes.string,
37
+ button: PropTypes.string,
38
+ successMessage: PropTypes.string,
39
+ layout: PropTypes.oneOf(['horizontal', 'vertical']),
40
+ fields: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
41
+ };
42
+
43
+ static defaultProps = {
44
+ style: {},
45
+ className: '',
46
+ portalId: '4796488',
47
+ formId: '929a510f-34f4-4251-98b3-34175200aebd',
48
+ title: undefined,
49
+ button: '',
50
+ layout: 'vertical',
51
+ successMessage: 'Form Submit Success',
52
+ fields: ['Email', 'First Name', 'Last Name'],
53
+ };
54
+
55
+ constructor(props) {
56
+ super(props);
57
+
58
+ if (typeof props.fields === 'string') {
59
+ this.fields = props.fields.split(',').map(x => x.trim());
60
+ } else {
61
+ this.fields = props.fields;
62
+ }
63
+
64
+ this.state = {
65
+ loading: false,
66
+ errorMessage: '',
67
+ successMessage: '',
68
+ };
69
+
70
+ this.fields.forEach(x => {
71
+ this.state[x] = '';
72
+ });
73
+ }
74
+
75
+ deriveProps() {
76
+ const newProps = mergeProps(this.props, ContactForm);
77
+
78
+ if (typeof newProps.title === 'undefined') {
79
+ newProps.title = 'Signup for our news letter';
80
+ }
81
+ if (!newProps.button) {
82
+ newProps.button = 'Subscribe';
83
+ }
84
+
85
+ return newProps;
86
+ }
87
+
88
+ render() {
89
+ const { className, style, title, button, layout } = this.deriveProps();
90
+ const { loading, errorMessage, successMessage } = this.state;
91
+ return (
92
+ <Form
93
+ onSubmit={this.onSubmit}
94
+ className={className}
95
+ style={style}
96
+ layout={layout}
97
+ fieldCount={this.fields.length}
98
+ name="subscribe">
99
+ {!!title && (
100
+ <Typography component="p" className="title">
101
+ {title}
102
+ </Typography>
103
+ )}
104
+ <div className="form-controls">
105
+ {this.fields.map(x => (
106
+ <input
107
+ required
108
+ key={x}
109
+ type="text"
110
+ value={this.state[x]}
111
+ onChange={this.getInputHandler(x)}
112
+ className="input"
113
+ placeholder={x}
114
+ />
115
+ ))}
116
+ <Button
117
+ variant="outlined"
118
+ type="submit"
119
+ color="default"
120
+ size="large"
121
+ disabled={loading}
122
+ className="subscribe-btn-empty">
123
+ {loading ? <CircularProgress size={28} /> : button}
124
+ </Button>
125
+ </div>
126
+ {!!errorMessage && (
127
+ <Typography
128
+ component="p"
129
+ variant="body1"
130
+ className="error"
131
+ color="secondary"
132
+ dangerouslySetInnerHTML={{ __html: errorMessage }}
133
+ />
134
+ )}
135
+ {!!successMessage && (
136
+ <Typography
137
+ component="p"
138
+ variant="body1"
139
+ className="success"
140
+ color="primary"
141
+ dangerouslySetInnerHTML={{ __html: successMessage }}
142
+ />
143
+ )}
144
+ </Form>
145
+ );
146
+ }
147
+
148
+ onSubmit = async e => {
149
+ e.preventDefault();
150
+ this.setState({ loading: true });
151
+
152
+ try {
153
+ const message = await submitContactForm(
154
+ { formId: this.props.formId, portalId: this.props.portalId },
155
+ this.fields.reduce((obj, x) => {
156
+ obj[x] = this.state[x];
157
+ return obj;
158
+ }, {}),
159
+ {
160
+ pageUri: window.location.href,
161
+ pageName: window.location.title,
162
+ }
163
+ );
164
+
165
+ this.setState({
166
+ loading: false,
167
+ successMessage: message || this.props.successMessage,
168
+ });
169
+ } catch (err) {
170
+ this.setState({
171
+ loading: false,
172
+ errorMessage: err ? err.message : 'Form submit failed',
173
+ });
174
+ }
175
+ };
176
+
177
+ getInputHandler =
178
+ (name, state = {}) =>
179
+ e => {
180
+ this.setState(
181
+ Object.assign(state, {
182
+ [name]: e.target.value,
183
+ })
184
+ );
185
+ };
186
+ }
187
+
188
+ // prettier-ignore
189
+ const getInputWidth = props => (props.layout === 'vertical' ? '100%' : `${Math.max(95 / (props.fieldCount + 1), 20)}%`);
190
+
191
+ const Form = styled.form`
192
+ display: flex;
193
+ flex-direction: column;
194
+ justify-content: center;
195
+ align-items: center;
196
+ @media (max-width: ${props => props.theme.breakpoints.values.sm}px) {
197
+ width: 100% !important;
198
+ }
199
+ max-width: 800px;
200
+ margin: 0px auto;
201
+
202
+ .title {
203
+ font-size: 30px;
204
+ text-align: center;
205
+ color: ${props => props.theme.typography.color.main};
206
+ }
207
+
208
+ .form-controls {
209
+ width: 100%;
210
+ flex-direction: ${props => (props.layout === 'vertical' ? 'column' : 'row')};
211
+ justify-content: space-between;
212
+ align-items: center;
213
+
214
+ .input {
215
+ width: ${props => getInputWidth(props)};
216
+ height: 50px;
217
+ border: none;
218
+ border-bottom: 1px solid ${props => props.theme.typography.color.main};
219
+ font-size: 16px;
220
+ letter-spacing: 1.8px;
221
+ outline: none;
222
+ margin: ${props => (props.layout === 'vertical' ? '12px 0' : '12px')};
223
+ background: transparent;
224
+
225
+ &:first-of-type {
226
+ margin-top: 40px;
227
+ }
228
+ }
229
+
230
+ .subscribe-btn-empty {
231
+ margin-top: ${props => (props.layout === 'vertical' ? '40px' : '0')};
232
+ width: ${props => (props.layout === 'vertical' ? '100%' : 'auto')};
233
+ }
234
+ }
235
+
236
+ .error,
237
+ .success {
238
+ margin-top: 20px;
239
+ }
240
+ `;
@@ -0,0 +1,90 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import styled from 'styled-components';
4
+ import Button from '@material-ui/core/Button';
5
+ import CookieConsent, { resetCookieConsentValue } from 'react-cookie-consent';
6
+
7
+ export { resetCookieConsentValue };
8
+
9
+ const translations = {
10
+ en: {
11
+ content:
12
+ 'We use cookies and other tracking technologies to improve your browsing experience on our website, to show you personalized content, to analyze our website traffic, and to understand where our visitors are coming from.',
13
+ agree: 'I Understand',
14
+ },
15
+ zh: {
16
+ content:
17
+ '我们使用 cookies 和其他跟踪技术来改善您在我们网站上的浏览体验,向您展示个性化的内容,分析我们的网站流量,并了解我们的访问者来自哪里。',
18
+ agree: '我知道了',
19
+ },
20
+ };
21
+
22
+ /**
23
+ * DefaultCookieConsent, 对 react-cookie-consent package 封装, 以便 arcblock 内部产品可以快速使用
24
+ * - 默认内容
25
+ * - 默认配置/样式
26
+ */
27
+ export default function DefaultCookieConsent({ children, locale, style, ...rest }) {
28
+ if (locale && !translations[locale]) {
29
+ // eslint-disable-next-line no-param-reassign
30
+ locale = 'en';
31
+ }
32
+ return (
33
+ <Wrapper style={style}>
34
+ <CookieConsent
35
+ disableStyles
36
+ disableButtonStyles
37
+ ButtonComponent={Button}
38
+ buttonText={translations[locale].agree}
39
+ buttonClasses="MuiButton-contained MuiButton-containedPrimary"
40
+ buttonStyle={{ marginTop: 16, padding: '6px 16px' }}
41
+ {...rest}>
42
+ {children || <p style={{ margin: 0 }}>{translations[locale].content}</p>}
43
+ </CookieConsent>
44
+ </Wrapper>
45
+ );
46
+ }
47
+
48
+ DefaultCookieConsent.propTypes = {
49
+ children: PropTypes.any,
50
+ style: PropTypes.object,
51
+ locale: PropTypes.string,
52
+ };
53
+
54
+ DefaultCookieConsent.defaultProps = {
55
+ children: null,
56
+ style: {},
57
+ locale: 'en',
58
+ };
59
+
60
+ const Wrapper = styled.div`
61
+ box-sizing: border-box;
62
+ position: fixed;
63
+ right: 20px;
64
+ bottom: 20px;
65
+ z-index: 999;
66
+ max-width: 440px;
67
+ padding: 16px 24px;
68
+ font-size: 16px;
69
+ color: #666;
70
+ background: #fff;
71
+ border-radius: 6px;
72
+ box-shadow: 0 0 18px rgba(0, 0, 0, 0.2);
73
+ &:empty {
74
+ display: none;
75
+ }
76
+ button {
77
+ min-width: 200px;
78
+ }
79
+
80
+ @media screen and (max-width: 480px) {
81
+ left: 16px;
82
+ right: 16px;
83
+ bottom: 16px;
84
+ width: auto;
85
+ button {
86
+ display: block;
87
+ width: 100%;
88
+ }
89
+ }
90
+ `;
@@ -0,0 +1,151 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import styled from 'styled-components';
4
+
5
+ import { getColor, mergeProps } from '../Util';
6
+
7
+ const SECONDS_OF_MINUTE = 60;
8
+ const SECONDS_OF_HOUR = 60 * SECONDS_OF_MINUTE;
9
+ const SECONDS_OF_DAY = 24 * SECONDS_OF_HOUR;
10
+
11
+ function getRemaining(endTime) {
12
+ const now = new Date().getTime();
13
+ const diff = Math.round((endTime - now) / 1000);
14
+ const days = Math.floor(diff / SECONDS_OF_DAY);
15
+ const hours = Math.floor((diff % SECONDS_OF_DAY) / SECONDS_OF_HOUR);
16
+ const minutes = Math.floor(((diff % SECONDS_OF_DAY) % SECONDS_OF_HOUR) / SECONDS_OF_MINUTE);
17
+ const seconds = Math.round(((diff % SECONDS_OF_DAY) % SECONDS_OF_HOUR) % SECONDS_OF_MINUTE);
18
+ return { days, hours, minutes, seconds, done: diff <= 0 };
19
+ }
20
+
21
+ // eslint-disable-next-line react/prop-types
22
+ function FixWidthNumber({ number, label, length = 2 }) {
23
+ let str = number.toString();
24
+ while (str.length < length) {
25
+ str = `0${str}`;
26
+ }
27
+
28
+ const numbers = str.split('');
29
+ return (
30
+ <span className="num-group">
31
+ <span className="num-items">
32
+ {numbers.map((x, i) => (
33
+ // eslint-disable-next-line react/no-array-index-key
34
+ <strong key={`num-${i}`} className="num-item">
35
+ {x}
36
+ </strong>
37
+ ))}
38
+ </span>
39
+ <span className="num-label">{label}</span>
40
+ </span>
41
+ );
42
+ }
43
+
44
+ export default class CountDown extends React.Component {
45
+ constructor(props) {
46
+ const newProps = mergeProps(props, CountDown, ['dark', 'endTime', 'style']);
47
+ super(newProps);
48
+ this.state = getRemaining(newProps.endTime);
49
+ this.timer = null;
50
+ }
51
+
52
+ componentDidMount() {
53
+ this.timer = setInterval(() => {
54
+ const remaining = getRemaining(this.props.endTime);
55
+ if (remaining.done) {
56
+ clearInterval(this.timer);
57
+ this.timer = null;
58
+ }
59
+
60
+ this.setState(remaining);
61
+ }, 1000);
62
+ }
63
+
64
+ componentWillUnmount() {
65
+ if (this.timer) {
66
+ clearInterval(this.timer);
67
+ this.timer = null;
68
+ }
69
+ }
70
+
71
+ render() {
72
+ const { dark, endTime, ...rest } = this.props;
73
+ const { days, hours, minutes, seconds } = this.state;
74
+ return (
75
+ <Container dark={dark} {...rest}>
76
+ <FixWidthNumber number={days} label="D" />
77
+ <span className="num-sep">:</span>
78
+ <FixWidthNumber number={hours} label="H" />
79
+ <span className="num-sep">:</span>
80
+ <FixWidthNumber number={minutes} label="M" />
81
+ <span className="num-sep">:</span>
82
+ <FixWidthNumber number={seconds} label="S" />
83
+ </Container>
84
+ );
85
+ }
86
+ }
87
+
88
+ CountDown.propTypes = {
89
+ endTime: PropTypes.number.isRequired, // endTime should be UTC
90
+ dark: PropTypes.bool,
91
+ style: PropTypes.object,
92
+ };
93
+
94
+ CountDown.defaultProps = {
95
+ dark: true,
96
+ style: {},
97
+ };
98
+
99
+ const textBackground = `linear-gradient(to bottom, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4)),
100
+ linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.5) 77%, rgba(0, 0, 0, 0.5))`;
101
+
102
+ const Container = styled.div`
103
+ color: ${props => getColor(props)};
104
+ font-size: 50px;
105
+ display: flex;
106
+ flex-direction: row;
107
+ justify-content: center;
108
+ align-items: flex-start;
109
+
110
+ .num-group {
111
+ display: flex;
112
+ flex-direction: column;
113
+ justify-content: center;
114
+ align-items: center;
115
+ margin: 0 60px;
116
+
117
+ @media (max-width: ${props => props.theme.breakpoints.values.md}px) {
118
+ margin: 0 20px;
119
+ }
120
+ @media (max-width: ${props => props.theme.breakpoints.values.sm}px) {
121
+ margin: 0;
122
+ }
123
+
124
+ .num-items {
125
+ display: flex;
126
+ flex-direction: row;
127
+ }
128
+
129
+ .num-item {
130
+ display: inline-block;
131
+ width: 40px;
132
+ height: 60px;
133
+ line-height: 60px;
134
+ background-image: ${props => (props.dark ? textBackground : 'none')};
135
+ text-align: center;
136
+
137
+ &:first-of-type {
138
+ margin-right: 10px;
139
+ @media (max-width: ${props => props.theme.breakpoints.values.sm}px) {
140
+ margin: 0;
141
+ }
142
+ }
143
+ }
144
+
145
+ .num-label {
146
+ margin-top: 20px;
147
+ font-size: 24px;
148
+ color: ${props => getColor(props)};
149
+ }
150
+ }
151
+ `;