@arcblock/ux 2.9.13 → 2.9.14

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 (149) hide show
  1. package/es/Address/did-address.js +18 -13
  2. package/es/Colors/themes/default.js +0 -1
  3. package/es/Colors/themes/temp.js +10 -1
  4. package/es/ContactForm/index.js +2 -2
  5. package/es/DID/index.js +0 -1
  6. package/es/Dialog/confirm.js +1 -99
  7. package/es/Dialog/dialog.js +4 -7
  8. package/es/Dialog/index.js +1 -1
  9. package/es/Dialog/use-confirm.js +105 -0
  10. package/es/Locale/util.js +10 -5
  11. package/es/NFTDisplay/index.js +0 -1
  12. package/es/Passport/index.js +2 -0
  13. package/es/Passport/passport.js +103 -0
  14. package/es/SessionUser/components/logged-in.js +1 -1
  15. package/es/SessionUser/components/user-info.js +1 -1
  16. package/es/SessionUser/index.js +2 -2
  17. package/es/Tabs/index.js +88 -2
  18. package/es/Util/passport.js +62 -0
  19. package/lib/ActionButton/index.js +6 -7
  20. package/lib/ActivityIndicator/index.js +4 -4
  21. package/lib/Address/compact-text.js +6 -6
  22. package/lib/Address/did-address.js +25 -21
  23. package/lib/Address/index.js +4 -4
  24. package/lib/Address/responsive-did-address.js +4 -4
  25. package/lib/Alert/index.js +5 -6
  26. package/lib/AnimationWaiter/index.js +4 -4
  27. package/lib/Async/index.js +6 -6
  28. package/lib/Avatar/did-motif.js +5 -6
  29. package/lib/Avatar/etherscan-blockies.js +2 -3
  30. package/lib/Avatar/index.js +4 -4
  31. package/lib/Badge/index.js +5 -6
  32. package/lib/Blocklet/blocklet.js +4 -4
  33. package/lib/Blocklet/index.js +3 -4
  34. package/lib/Blocklet/utils.js +3 -5
  35. package/lib/BlockletContext/index.js +1 -2
  36. package/lib/BlockletNFT/index.js +4 -4
  37. package/lib/Button/index.js +1 -2
  38. package/lib/Button/wrap.js +4 -4
  39. package/lib/ButtonGroup/index.js +1 -2
  40. package/lib/ClickToCopy/copy-button.js +4 -4
  41. package/lib/ClickToCopy/index.js +6 -6
  42. package/lib/CodeBlock/LightBox.js +1 -2
  43. package/lib/CodeBlock/index.js +4 -4
  44. package/lib/Colors/themes/default.js +1 -2
  45. package/lib/Colors/themes/temp.js +11 -3
  46. package/lib/ContactForm/index.js +2 -2
  47. package/lib/CookieConsent/index.js +6 -6
  48. package/lib/CountDown/index.js +4 -4
  49. package/lib/DID/index.js +7 -9
  50. package/lib/Datatable/CustomToolbar.js +2 -2
  51. package/lib/Datatable/index.js +49 -49
  52. package/lib/Datatable/utils.js +2 -3
  53. package/lib/Dialog/confirm.js +5 -113
  54. package/lib/Dialog/dialog.js +14 -18
  55. package/lib/Dialog/index.js +3 -4
  56. package/lib/Dialog/use-confirm.js +126 -0
  57. package/lib/Earth/index.js +7 -8
  58. package/lib/Empty/index.js +5 -6
  59. package/lib/Header/auto-hidden.js +5 -6
  60. package/lib/Header/header.js +5 -6
  61. package/lib/Header/responsive-header.js +5 -6
  62. package/lib/Icon/image.js +4 -4
  63. package/lib/Icon/index.js +6 -7
  64. package/lib/Img/index.js +5 -6
  65. package/lib/InfoRow/index.js +5 -6
  66. package/lib/Layout/dashboard/external-link.js +4 -4
  67. package/lib/Layout/dashboard/full-page.js +5 -6
  68. package/lib/Layout/dashboard/index.js +4 -4
  69. package/lib/Layout/dashboard/sidebar.js +5 -6
  70. package/lib/Layout/dashboard-legacy/header.js +4 -4
  71. package/lib/Layout/dashboard-legacy/index.js +4 -4
  72. package/lib/Layout/dashboard-legacy/sidebar.js +4 -4
  73. package/lib/Layout/index.js +4 -4
  74. package/lib/Locale/browser-lang.js +1 -2
  75. package/lib/Locale/context.js +6 -8
  76. package/lib/Locale/languages.js +7 -9
  77. package/lib/Locale/selector.js +4 -4
  78. package/lib/Locale/util.js +12 -11
  79. package/lib/Logo/index.js +4 -4
  80. package/lib/NFTDisplay/aspect-ratio-container.js +5 -6
  81. package/lib/NFTDisplay/broken.js +4 -4
  82. package/lib/NFTDisplay/index.js +5 -7
  83. package/lib/NFTDisplay/svg-embedder/img.js +5 -6
  84. package/lib/NFTDisplay/svg-embedder/inline-svg.js +5 -6
  85. package/lib/NavMenu/nav-menu.js +5 -6
  86. package/lib/NavMenu/style.js +2 -4
  87. package/lib/PageScroller/index.js +6 -7
  88. package/lib/Passport/index.js +9 -0
  89. package/lib/Passport/passport.js +116 -0
  90. package/lib/PoweredByArcBlock/index.js +4 -4
  91. package/lib/PricingTable/PricingPlan.js +1 -2
  92. package/lib/PricingTable/index.js +1 -2
  93. package/lib/QRCode/index.js +5 -6
  94. package/lib/RelativeTime/index.js +4 -4
  95. package/lib/Result/common.js +4 -4
  96. package/lib/Result/index.js +7 -8
  97. package/lib/Result/result.js +5 -6
  98. package/lib/Result/translations.js +2 -3
  99. package/lib/Screenshot/BaseScreenshot/index.js +5 -6
  100. package/lib/Screenshot/BaseScreenshot/shells/Macbook.js +10 -15
  101. package/lib/Screenshot/BaseScreenshot/shells/Phone.js +10 -15
  102. package/lib/Screenshot/index.js +5 -6
  103. package/lib/SessionBlocklet/index.js +4 -4
  104. package/lib/SessionManager/index.js +1 -2
  105. package/lib/SessionUser/components/logged-in.js +5 -5
  106. package/lib/SessionUser/components/session-user-item.js +5 -6
  107. package/lib/SessionUser/components/session-user-switch.js +4 -4
  108. package/lib/SessionUser/components/user-info.js +1 -1
  109. package/lib/SessionUser/index.js +2 -2
  110. package/lib/SessionUser/libs/translation.js +2 -3
  111. package/lib/Spinner/index.js +13 -14
  112. package/lib/SplitButton/index.js +4 -4
  113. package/lib/Switch/index.js +5 -6
  114. package/lib/Tabs/index.js +98 -11
  115. package/lib/Tag/index.js +5 -6
  116. package/lib/TextCollapse/index.js +5 -6
  117. package/lib/Theme/index.js +6 -7
  118. package/lib/Theme/theme.js +6 -8
  119. package/lib/Toast/index.js +12 -13
  120. package/lib/Typography/index.js +4 -4
  121. package/lib/Util/constant.js +10 -20
  122. package/lib/Util/deprecate.js +4 -4
  123. package/lib/Util/index.js +2 -4
  124. package/lib/Util/passport.js +72 -0
  125. package/lib/Util/wallet.js +1 -2
  126. package/lib/Video/index.js +4 -4
  127. package/lib/Wallet/Action.js +4 -4
  128. package/lib/Wallet/Download.js +4 -4
  129. package/lib/WebWalletSWKeeper/index.js +5 -6
  130. package/lib/withTheme/index.js +5 -6
  131. package/lib/withTracker/error_boundary.js +2 -2
  132. package/lib/withTracker/index.js +8 -9
  133. package/package.json +9 -4
  134. package/src/Address/did-address.jsx +15 -12
  135. package/src/Colors/themes/temp.js +9 -0
  136. package/src/Dialog/confirm.jsx +94 -0
  137. package/src/Dialog/{dialog.js → dialog.jsx} +14 -7
  138. package/src/Dialog/index.js +1 -1
  139. package/src/Dialog/use-confirm.jsx +114 -0
  140. package/src/Locale/util.js +12 -5
  141. package/src/Passport/index.jsx +3 -0
  142. package/src/Passport/passport.jsx +99 -0
  143. package/src/SessionUser/components/logged-in.jsx +1 -1
  144. package/src/SessionUser/components/user-info.jsx +1 -1
  145. package/src/SessionUser/index.jsx +1 -1
  146. package/src/Tabs/index.jsx +124 -0
  147. package/src/Util/passport.js +75 -0
  148. package/src/Dialog/confirm.js +0 -201
  149. package/src/Tabs/index.js +0 -45
@@ -92,20 +92,12 @@ const DidAddress = forwardRef(
92
92
  return (
93
93
  <Root as={component} size={size} {...rest} ref={ref}>
94
94
  {prepend}
95
+ <Box sx={{ display: 'none' }} ref={textRef}>
96
+ {children}
97
+ </Box>
95
98
  {/* 注意: 该元素必须渲染(可以隐藏), 以便 compact 模式下复制的文本是完整的 */}
96
99
  <Tooltip title={copyable ? '' : translations[locale].copied} placement="bottom" arrow open={copied}>
97
- <Box
98
- ref={textRef}
99
- component="span"
100
- className="did-address-text did-address-truncate"
101
- sx={{
102
- display: compact ? 'none' : 'inline',
103
- cursor: copyable ? 'text' : 'pointer',
104
- }}
105
- onDoubleClick={copyable ? noop : onCopy}>
106
- {children}
107
- </Box>
108
- {compact && (
100
+ {compact ? (
109
101
  <Box
110
102
  component="span"
111
103
  className="did-address-text"
@@ -120,6 +112,17 @@ const DidAddress = forwardRef(
120
112
  {children}
121
113
  </CompactText>
122
114
  </Box>
115
+ ) : (
116
+ <Box
117
+ component="span"
118
+ className="did-address-text did-address-truncate"
119
+ sx={{
120
+ display: compact ? 'none' : 'inline',
121
+ cursor: copyable ? 'text' : 'pointer',
122
+ }}
123
+ onDoubleClick={copyable ? noop : onCopy}>
124
+ {children}
125
+ </Box>
123
126
  )}
124
127
  </Tooltip>
125
128
  {copyElement}
@@ -13,6 +13,15 @@ const colors = {
13
13
  primaryBase: 'rgba(19, 125, 250, 1)',
14
14
  primary100: 'rgba(19, 125, 250, 1)',
15
15
  gray6: 'rgba(17, 22, 24, 0.06)',
16
+ backgroundsBgSubtitle: 'rgba(249, 250, 251, 1)',
17
+ backgroundsBgComponent: 'rgba(241, 243, 245, 1)',
18
+ backgroundsBgField: 'rgba(249, 250, 251, 1)',
19
+ foregroundsFgBase: 'rgba(3, 7, 18, 1)',
20
+ foregroundsFgSubtile: 'rgba(75, 85, 99, 1)',
21
+ strokeBorderBase: 'rgba(229, 231, 235, 1)',
22
+ strokeBorderStrong: 'rgba(209, 213, 219, 1)',
23
+ buttonsButtonNeutral: 'rgba(255, 255, 255, 1)',
24
+ buttonsButtonNeutralHover: 'rgba(243, 244, 246, 1)',
16
25
  };
17
26
 
18
27
  export default colors;
@@ -0,0 +1,94 @@
1
+ import PropTypes from 'prop-types';
2
+
3
+ import Button from '../Button';
4
+ import Dialog from './dialog';
5
+
6
+ /**
7
+ @typedef {Object} ConfirmProps
8
+ @property {boolean} open
9
+ @property {React.ReactNode} title
10
+ @property {React.ReactNode} children
11
+ @property {() => void | Promise<void>} onConfirm
12
+ @property {() => void | Promise<void>} onCancel
13
+ @property {boolean} [showCancelButton=true]
14
+ @property {{text: string, props?: import('../Button/wrap').ButtonProps}} [confirmButton={text: 'Confirm'}]
15
+ @property {{text: string, props?: import('../Button/wrap').ButtonProps}} [cancelButton={text: 'Cancel'}]
16
+ @property {import('@mui/material').PaperProps} [PaperProps={}]
17
+ */
18
+
19
+ // 注意排在 {...rest} 之后的 props 优先级更高
20
+ /**
21
+ *
22
+ * @param {ConfirmProps} props
23
+ * @returns {import('react').ReactComponentElement}
24
+ */
25
+ export default function Confirm({
26
+ title,
27
+ children,
28
+ onConfirm,
29
+ onCancel,
30
+ showCancelButton,
31
+ confirmButton,
32
+ cancelButton,
33
+ PaperProps,
34
+ ...rest
35
+ }) {
36
+ // 去除 dialog 默认的 300 最小高度
37
+ PaperProps.style = Object.assign(
38
+ {
39
+ minHeight: 0,
40
+ },
41
+ PaperProps.style
42
+ );
43
+
44
+ return (
45
+ <Dialog
46
+ title={title}
47
+ PaperProps={PaperProps}
48
+ {...rest}
49
+ onClose={() => onCancel()}
50
+ actions={
51
+ <>
52
+ {showCancelButton && (
53
+ <Button onClick={() => onCancel()} color="primary" {...cancelButton.props}>
54
+ {cancelButton.text}
55
+ </Button>
56
+ )}
57
+ <Button onClick={() => onConfirm()} color="primary" autoFocus {...confirmButton.props}>
58
+ {confirmButton.text}
59
+ </Button>
60
+ </>
61
+ }>
62
+ {children}
63
+ </Dialog>
64
+ );
65
+ }
66
+
67
+ Confirm.propTypes = {
68
+ title: PropTypes.node.isRequired,
69
+ children: PropTypes.node.isRequired,
70
+ onConfirm: PropTypes.func.isRequired,
71
+ onCancel: PropTypes.func.isRequired,
72
+ showCancelButton: PropTypes.bool,
73
+ // 可以传入 {text: ..., props: ...}
74
+ confirmButton: PropTypes.shape({
75
+ text: PropTypes.string.isRequired,
76
+ props: PropTypes.object,
77
+ }),
78
+ cancelButton: PropTypes.shape({
79
+ text: PropTypes.string.isRequired,
80
+ props: PropTypes.object,
81
+ }),
82
+ PaperProps: PropTypes.object,
83
+ };
84
+
85
+ Confirm.defaultProps = {
86
+ showCancelButton: true,
87
+ confirmButton: {
88
+ text: 'Confirm',
89
+ },
90
+ cancelButton: {
91
+ text: 'Cancel',
92
+ },
93
+ PaperProps: {},
94
+ };
@@ -1,10 +1,13 @@
1
1
  import PropTypes from 'prop-types';
2
- import MuiDialog from '@mui/material/Dialog';
3
- import MuiDialogContent from '@mui/material/DialogContent';
4
- import DialogActions from '@mui/material/DialogActions';
5
- import IconButton from '@mui/material/IconButton';
6
- import useMediaQuery from '@mui/material/useMediaQuery';
7
2
  import CloseIcon from '@mui/icons-material/Close';
3
+ import {
4
+ Typography,
5
+ Dialog as MuiDialog,
6
+ DialogContent as MuiDialogContent,
7
+ DialogActions,
8
+ IconButton,
9
+ useMediaQuery,
10
+ } from '@mui/material';
8
11
 
9
12
  import { styled, useTheme } from '../Theme';
10
13
 
@@ -25,7 +28,7 @@ import { styled, useTheme } from '../Theme';
25
28
  @property {boolean} [showCloseButton=true] - Whether or not to show the close button.
26
29
  @property {'left'|'center'|'right'} [actionsPosition='right'] - The position of the actions toolbar.
27
30
  @property {PaperStyle} [PaperProps] - Props to be passed down to the dialog paper.
28
- @property {(event: React.SyntheticEvent, reason: string) => void} [onClose] - Callback function fired when the dialog is closed.
31
+ @property {(event: React.SyntheticEvent, reason: string) => void} [onClose] - Callback function fired when the dialog is closed.
29
32
  */
30
33
 
31
34
  /**
@@ -74,7 +77,11 @@ function Dialog({ children, title, prepend, toolbar, actions, showCloseButton, a
74
77
  <div className="ux-dialog_left">
75
78
  {showCloseButton && isMobile && closeButton}
76
79
  {prepend && <div className="ux-dialog_prepend">{prepend}</div>}
77
- {title && <h6 className="ux-dialog_title">{title}</h6>}
80
+ {title && (
81
+ <Typography variant="h6" className="ux-dialog_title">
82
+ {title}
83
+ </Typography>
84
+ )}
78
85
  </div>
79
86
 
80
87
  <div className="ux-dialog_right">
@@ -1,4 +1,4 @@
1
1
  // eslint-disable-next-line no-restricted-exports
2
2
  export { default } from './dialog';
3
3
  export { default as Confirm } from './confirm';
4
- export { useConfirm } from './confirm';
4
+ export { default as useConfirm } from './use-confirm';
@@ -0,0 +1,114 @@
1
+ import { forwardRef, useImperativeHandle, useRef, useState } from 'react';
2
+ import { useMemoizedFn, useReactive } from 'ahooks';
3
+ import noop from 'lodash/noop';
4
+
5
+ import Confirm from './confirm';
6
+
7
+ const ConfirmHolder = forwardRef((props, ref) => {
8
+ // HACK: 这里默认值不使用 null,来避免开发环境中的字段必填警告
9
+ const [title, setTitle] = useState('');
10
+ const [content, setContent] = useState('');
11
+ const state = useReactive({
12
+ show: false,
13
+ onConfirm: noop,
14
+ onCancel: noop,
15
+ loading: false,
16
+ confirmButtonText: 'Confirm',
17
+ cancelButtonText: 'Cancel',
18
+ });
19
+ const open = useMemoizedFn((params = {}) => {
20
+ setTitle(params.title);
21
+ setContent(params.content);
22
+ state.onConfirm = params.onConfirm || noop;
23
+ state.onCancel = params.onCancel || noop;
24
+ state.showCancelButton = params.showCancelButton ?? true;
25
+ if (params.confirmButtonText) state.confirmButtonText = params.confirmButtonText;
26
+ if (params.cancelButtonText) state.cancelButtonText = params.cancelButtonText;
27
+
28
+ state.loading = false;
29
+ state.show = true;
30
+ });
31
+ const reset = useMemoizedFn(() => {
32
+ setTitle('');
33
+ setContent('');
34
+ state.onConfirm = noop;
35
+ state.onCancel = noop;
36
+ state.confirmButtonText = 'Confirm';
37
+ state.cancelButtonText = 'Cancel';
38
+ });
39
+ const close = useMemoizedFn(() => {
40
+ state.show = false;
41
+ setTimeout(() => {
42
+ reset();
43
+ }, 300);
44
+ });
45
+ const onCancel = useMemoizedFn(() => {
46
+ close();
47
+ state?.onCancel();
48
+ }, []);
49
+ const onConfirm = useMemoizedFn(async () => {
50
+ state.loading = true;
51
+ try {
52
+ await state?.onConfirm(close);
53
+ } finally {
54
+ state.loading = false;
55
+ }
56
+ }, []);
57
+ useImperativeHandle(
58
+ ref,
59
+ () => {
60
+ return {
61
+ open,
62
+ close,
63
+ };
64
+ },
65
+ [open, close]
66
+ );
67
+
68
+ return (
69
+ <Confirm
70
+ {...props}
71
+ open={state.show}
72
+ title={title}
73
+ onConfirm={onConfirm}
74
+ onCancel={onCancel}
75
+ confirmButton={{
76
+ text: state.confirmButtonText,
77
+ props: {
78
+ variant: 'contained',
79
+ color: 'primary',
80
+ loading: state.loading,
81
+ },
82
+ }}
83
+ showCancelButton={state.showCancelButton}
84
+ cancelButton={{
85
+ text: state.cancelButtonText,
86
+ props: {
87
+ variant: 'outlined',
88
+ color: 'primary',
89
+ },
90
+ }}>
91
+ {content}
92
+ </Confirm>
93
+ );
94
+ });
95
+
96
+ export default function useConfirm(props = {}) {
97
+ const confirmRef = useRef(null);
98
+
99
+ const open = useMemoizedFn((...args) => {
100
+ confirmRef.current?.open(...args);
101
+ });
102
+ const close = useMemoizedFn((...args) => {
103
+ confirmRef.current?.close(...args);
104
+ });
105
+ const confirmApi = {
106
+ open,
107
+ close,
108
+ };
109
+
110
+ return {
111
+ confirmHolder: <ConfirmHolder {...props} ref={confirmRef} />,
112
+ confirmApi,
113
+ };
114
+ }
@@ -1,19 +1,26 @@
1
+ import get from 'lodash/get';
2
+
1
3
  /* eslint-disable no-prototype-builtins */
2
4
  export const replace = (template, data) =>
3
5
  template.replace(/{(\w*)}/g, (m, key) => (data.hasOwnProperty(key) ? data[key] : ''));
4
6
 
5
7
  export const translate = (translations, key, locale, fallbackLocale = 'en', data = {}) => {
6
- if (!translations[locale] || !translations[locale][key]) {
8
+ const translation = translations[locale];
9
+ const translationValue = get(translation, key);
10
+ const fallbackValue = get(translations[fallbackLocale], key);
11
+
12
+ if (!translation || !translationValue) {
7
13
  console.warn(`Warning: no ${key} translation of ${locale}`);
8
- if (fallbackLocale && translations[fallbackLocale]?.[key]) {
9
- return replace(translations[fallbackLocale]?.[key], data);
14
+ if (fallbackLocale && fallbackValue) {
15
+ return replace(fallbackValue, data);
10
16
  }
11
17
  return key;
12
18
  }
19
+
13
20
  if (typeof translations[locale] === 'function' || translations[locale].then) {
14
- return replace(translations[fallbackLocale][key], data);
21
+ return replace(fallbackValue, data);
15
22
  }
16
- return replace(translations[locale][key], data);
23
+ return replace(translationValue, data);
17
24
  };
18
25
 
19
26
  export const t = translate;
@@ -0,0 +1,3 @@
1
+ import PassportItem from './passport';
2
+
3
+ export default PassportItem;
@@ -0,0 +1,99 @@
1
+ import PropTypes from 'prop-types';
2
+ import upperFirst from 'lodash/upperFirst';
3
+ import { Box } from '@mui/material';
4
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
5
+ import RevokeIcon from '@arcblock/icons/lib/RevokeIcon';
6
+
7
+ export default function Passport({ passport, user, color, width, icon, children, createPassportSvg, ...rest }) {
8
+ const { t } = useLocaleContext();
9
+ return (
10
+ <Box
11
+ {...rest}
12
+ sx={{
13
+ display: 'flex',
14
+ alignItems: 'center',
15
+ ...rest?.sx,
16
+ }}>
17
+ <Box
18
+ className="passport-item__display"
19
+ // eslint-disable-next-line react/no-danger
20
+ dangerouslySetInnerHTML={{
21
+ __html: createPassportSvg({
22
+ title: passport.title || passport.name,
23
+ issuer: passport.issuer && passport.issuer.name,
24
+ issuerDid: passport.issuer && passport.issuer.id,
25
+ ownerName: user.fullName,
26
+ ownerDid: user.did,
27
+ ownerAvatarUrl: user.avatar,
28
+ revoked: passport.revoked,
29
+ preferredColor: color,
30
+ width,
31
+ }),
32
+ }}
33
+ />
34
+ <Box
35
+ className="passport-item__body"
36
+ sx={{
37
+ p: 0,
38
+ ml: 3,
39
+ mt: 0,
40
+ }}>
41
+ <Box
42
+ className="passport-item__title"
43
+ sx={{
44
+ display: 'flex',
45
+ alignItems: 'center',
46
+ fontWeight: 400,
47
+ fontSize: '16px',
48
+ lineHeight: 1.1875,
49
+ color: '#222222',
50
+ }}>
51
+ {upperFirst(passport.title)}
52
+ <Box
53
+ className="passport-item__status-icon"
54
+ sx={{
55
+ svg: {
56
+ fill: '#bfbfbf',
57
+ height: '1.2em',
58
+ marginLeft: '0.4em',
59
+ },
60
+ }}>
61
+ {icon}
62
+ {passport.revoked && <RevokeIcon />}
63
+ </Box>
64
+ </Box>
65
+ {passport.expirationDate && (
66
+ <Box
67
+ className="passport-item__title"
68
+ sx={{
69
+ display: 'flex',
70
+ alignItems: 'center',
71
+ fontWeight: 400,
72
+ fontSize: '16px',
73
+ lineHeight: 1.1875,
74
+ color: '#222222',
75
+ }}>
76
+ {t('team.passport.validUntil', { date: passport.expirationDate })}
77
+ </Box>
78
+ )}
79
+ {children}
80
+ </Box>
81
+ </Box>
82
+ );
83
+ }
84
+
85
+ Passport.propTypes = {
86
+ passport: PropTypes.any.isRequired,
87
+ user: PropTypes.any.isRequired,
88
+ color: PropTypes.string.isRequired,
89
+ createPassportSvg: PropTypes.func.isRequired,
90
+ icon: PropTypes.any,
91
+ children: PropTypes.any,
92
+ width: PropTypes.number,
93
+ };
94
+
95
+ Passport.defaultProps = {
96
+ icon: null,
97
+ children: null,
98
+ width: 150,
99
+ };
@@ -189,6 +189,6 @@ function SessionMenuItem({ icon, title, ...rest }) {
189
189
  }
190
190
 
191
191
  SessionMenuItem.propTypes = {
192
- icon: PropTypes.string.isRequired,
192
+ icon: PropTypes.any.isRequired,
193
193
  title: PropTypes.string.isRequired,
194
194
  };
@@ -98,7 +98,7 @@ export default function UserInfo({
98
98
  />
99
99
  </Box>
100
100
 
101
- <Typography variant="h6" sx={{ wordBreak: 'break-all' }}>
101
+ <Typography variant="h6" sx={{ wordBreak: 'break-word' }}>
102
102
  {session.user.fullName}
103
103
  </Typography>
104
104
  </Box>
@@ -22,8 +22,8 @@ SessionUser.propTypes = {
22
22
  user: PropTypes.shape({
23
23
  did: PropTypes.string.isRequired,
24
24
  fullName: PropTypes.string.isRequired,
25
- email: PropTypes.string.isRequired,
26
25
  avatar: PropTypes.string.isRequired,
26
+ email: PropTypes.string,
27
27
  }),
28
28
  }).isRequired,
29
29
  onBindWallet: PropTypes.func,
@@ -0,0 +1,124 @@
1
+ import PropTypes from 'prop-types';
2
+ import { Tabs as MuiTabs, Tab as MuiTab } from '@mui/material';
3
+
4
+ import { temp as colors } from '../Colors';
5
+ import { styled } from '../Theme';
6
+
7
+ const PREFIX = 'index';
8
+
9
+ const classes = {
10
+ tabs: `${PREFIX}-tabs`,
11
+ tab: `${PREFIX}-tab`,
12
+ };
13
+
14
+ const StyledMuiTabs = styled(MuiTabs)(({ theme }) => ({
15
+ [`& .${classes.tabs}`]: {},
16
+
17
+ [`& .${classes.tab}`]: {
18
+ fontSize: '0.875rem',
19
+ [theme.breakpoints.up('md')]: {
20
+ fontSize: '1rem',
21
+ },
22
+ },
23
+ }));
24
+
25
+ function CardTabs({ tabs, current, onChange, ...rest }) {
26
+ return (
27
+ <MuiTabs
28
+ scrollButtons="auto"
29
+ value={current}
30
+ onChange={(_, newValue) => onChange(newValue)}
31
+ {...rest}
32
+ variant="scrollable"
33
+ sx={{
34
+ minHeight: 'auto',
35
+ '.MuiTabs-scrollButtons.Mui-disabled': {
36
+ opacity: 0.3,
37
+ cursor: 'not-allowed',
38
+ pointerEvents: 'auto',
39
+ },
40
+ '.MuiTabs-scroller': {
41
+ borderRadius: '100vw',
42
+ },
43
+ '.MuiTabs-flexContainer': {
44
+ borderRadius: '100vw',
45
+ backgroundColor: colors.backgroundsBgComponent,
46
+ padding: 0.5,
47
+ display: 'inline-flex',
48
+ columnGap: 0.25,
49
+ },
50
+ '.MuiTab-root': {
51
+ borderRadius: '100vw',
52
+ border: '1px solid transparent',
53
+ minHeight: 'auto',
54
+ lineHeight: 1,
55
+ py: 1,
56
+ color: colors.foregroundsFgSubtile,
57
+ fontSize: '13px',
58
+ fontWeight: 'normal',
59
+ textTransform: 'capitalize',
60
+ transition: 'background-color 0.2s ease',
61
+ '&.Mui-selected, &:hover': {
62
+ backgroundColor: 'white',
63
+ borderColor: colors.lineBorderBase,
64
+ color: colors.foregroundsFgBase,
65
+ },
66
+ },
67
+ '.MuiTabs-indicator': {
68
+ display: 'none',
69
+ },
70
+ ...rest.sx,
71
+ }}>
72
+ {tabs.map((x) => (
73
+ <MuiTab className={classes.tab} key={x.value} value={x.value} label={x.label} icon={x.icon || null} />
74
+ ))}
75
+ </MuiTabs>
76
+ );
77
+ }
78
+
79
+ CardTabs.propTypes = {
80
+ tabs: PropTypes.array.isRequired,
81
+ current: PropTypes.string.isRequired,
82
+ onChange: PropTypes.func.isRequired,
83
+ };
84
+
85
+ /**
86
+ * @typedef {import('@mui/material').TabsProps & {
87
+ * tabs: string[];
88
+ * onChange: (value) => {};
89
+ * variant: 'card' | 'fullWidth' | 'scrollable' | 'standard'
90
+ * }} TabsProps
91
+ */
92
+
93
+ /**
94
+ * @description
95
+ * @param { TabsProps} props
96
+ * @return {import('react').ReactNode}
97
+ */
98
+
99
+ export default function Tabs({ tabs, current, onChange, ...rest }) {
100
+ if (rest.variant === 'card') {
101
+ return <CardTabs tabs={tabs} current={current} onChange={onChange} />;
102
+ }
103
+
104
+ return (
105
+ <StyledMuiTabs
106
+ scrollButtons="auto"
107
+ variant="scrollable"
108
+ value={current}
109
+ onChange={(_, newValue) => onChange(newValue)}
110
+ indicatorColor="primary"
111
+ {...rest}
112
+ className={[classes.tabs, rest.className || ''].join(' ')}>
113
+ {tabs.map((x) => (
114
+ <MuiTab className={classes.tab} key={x.value} value={x.value} label={x.label} icon={x.icon || null} />
115
+ ))}
116
+ </StyledMuiTabs>
117
+ );
118
+ }
119
+
120
+ Tabs.propTypes = {
121
+ tabs: PropTypes.array.isRequired,
122
+ current: PropTypes.string.isRequired,
123
+ onChange: PropTypes.func.isRequired,
124
+ };
@@ -0,0 +1,75 @@
1
+ import { getNftBGColor, DEFAULT_COLORS, getNftBGColorFromDid, getSvg } from '@arcblock/nft-display';
2
+
3
+ export const getPassportColor = (preferredColor, did) => {
4
+ let color;
5
+ if (preferredColor === 'default') {
6
+ color = DEFAULT_COLORS['app-passport'];
7
+ } else if (preferredColor === 'auto') {
8
+ color = getNftBGColorFromDid(did);
9
+ } else {
10
+ color = getNftBGColor(preferredColor);
11
+ }
12
+
13
+ return color;
14
+ };
15
+
16
+ export const getTextColor = (background) => {
17
+ const r = parseInt(background.slice(1, 3), 16);
18
+ const g = parseInt(background.slice(3, 5), 16);
19
+ const b = parseInt(background.slice(5, 7), 16);
20
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
21
+ return luminance > 0.5 ? '#111' : '#EEE';
22
+ };
23
+
24
+ export const createPassportSvg = ({
25
+ issuer = '',
26
+ title = '',
27
+ issuerDid = '',
28
+ issuerAvatarUrl = '',
29
+ ownerDid = '',
30
+ ownerName = '',
31
+ ownerAvatarUrl = '',
32
+ preferredColor = 'default',
33
+ revoked = false,
34
+ isDataUrl = false,
35
+ width = '100%',
36
+ height = '100%',
37
+ }) => {
38
+ const color = getPassportColor(preferredColor, issuerDid);
39
+
40
+ const svgXML = getSvg({
41
+ width,
42
+ height,
43
+
44
+ tag: revoked ? 'revoked' : '',
45
+ tagVariant: revoked ? 'error' : 'info',
46
+
47
+ color,
48
+
49
+ did: ownerDid,
50
+ variant: 'app-passport' || ownerName,
51
+ verifiable: true,
52
+
53
+ issuer: {
54
+ name: issuer,
55
+ icon: issuerAvatarUrl,
56
+ },
57
+
58
+ header: {
59
+ name: title,
60
+ icon: ownerAvatarUrl,
61
+ },
62
+
63
+ // FIXME: @wangshijun this should be dynamic
64
+ extra: {
65
+ key: 'Exp',
66
+ value: '2123-01-01',
67
+ },
68
+ });
69
+
70
+ if (isDataUrl) {
71
+ return `data:image/svg+xml;utf8,${encodeURIComponent(svgXML)}`;
72
+ }
73
+
74
+ return svgXML;
75
+ };