@arcblock/ux 2.13.8 → 2.13.10
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/lib/UserCard/Cards/basic-info.js +2 -4
- package/lib/UserCard/Content/basic.js +114 -55
- package/lib/UserCard/Content/clock.js +18 -5
- package/lib/UserCard/Content/minimal.js +4 -2
- package/package.json +6 -6
- package/src/UserCard/Cards/basic-info.tsx +1 -1
- package/src/UserCard/Content/basic.tsx +103 -52
- package/src/UserCard/Content/clock.tsx +22 -11
- package/src/UserCard/Content/minimal.tsx +2 -0
- package/lib/UserCard/Content/left-layout.d.ts +0 -16
- package/lib/UserCard/Content/left-layout.js +0 -33
- package/src/UserCard/Content/left-layout.tsx +0 -40
@@ -20,10 +20,8 @@ function BasicCard(props) {
|
|
20
20
|
display: "flex",
|
21
21
|
flexDirection: "column",
|
22
22
|
width: "100%",
|
23
|
-
|
24
|
-
|
25
|
-
minWidth: 0
|
26
|
-
},
|
23
|
+
flex: 1,
|
24
|
+
height: "100%",
|
27
25
|
children: [/*#__PURE__*/_jsx(MinimalContent, {
|
28
26
|
user: user,
|
29
27
|
avatarSize: avatarSize,
|
@@ -1,6 +1,6 @@
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
2
|
import { Typography, Box, Grid } from '@mui/material';
|
3
|
-
import { useCreation } from 'ahooks';
|
3
|
+
import { useCreation, useMemoizedFn } from 'ahooks';
|
4
4
|
import styled from '@emotion/styled';
|
5
5
|
import isArray from 'lodash/isArray';
|
6
6
|
import { Icon as IconifyIcon } from '@iconify/react';
|
@@ -11,7 +11,7 @@ import LocationIcon from '@arcblock/icons/lib/Location';
|
|
11
11
|
import EmailIcon from '@arcblock/icons/lib/Email';
|
12
12
|
import TimezoneIcon from '@arcblock/icons/lib/Timezone';
|
13
13
|
import { joinURL, withoutProtocol } from 'ufo';
|
14
|
-
import {
|
14
|
+
import { useState, useMemo, useCallback } from 'react';
|
15
15
|
import Clock from './clock';
|
16
16
|
const IconMap = {
|
17
17
|
timezone: TimezoneIcon,
|
@@ -32,6 +32,9 @@ const iconSize = {
|
|
32
32
|
width: 16,
|
33
33
|
height: 16
|
34
34
|
};
|
35
|
+
|
36
|
+
// 定义渲染项的类型
|
37
|
+
|
35
38
|
function TimeZoneField({
|
36
39
|
value
|
37
40
|
}) {
|
@@ -42,14 +45,10 @@ function TimeZoneField({
|
|
42
45
|
className: "user-card__timezone-field",
|
43
46
|
children: [/*#__PURE__*/_jsx(TimezoneIcon, {
|
44
47
|
...iconSize
|
45
|
-
}), /*#__PURE__*/_jsx(
|
48
|
+
}), /*#__PURE__*/_jsx(Clock, {
|
49
|
+
value: value,
|
46
50
|
variant: "body2",
|
47
|
-
color: "grey.800"
|
48
|
-
children: /*#__PURE__*/_jsx(Clock, {
|
49
|
-
value: value,
|
50
|
-
variant: "body2",
|
51
|
-
color: "grey.800"
|
52
|
-
})
|
51
|
+
color: "grey.800"
|
53
52
|
})]
|
54
53
|
});
|
55
54
|
}
|
@@ -72,23 +71,28 @@ function LinkField({
|
|
72
71
|
display: "flex",
|
73
72
|
alignItems: "center",
|
74
73
|
gap: 1,
|
74
|
+
className: "user-card__link-field",
|
75
75
|
children: [faviconUrl && !useFallback ? /*#__PURE__*/_jsx("img", {
|
76
76
|
src: faviconUrl,
|
77
77
|
alt: "site icon",
|
78
78
|
style: {
|
79
|
-
width:
|
80
|
-
height:
|
79
|
+
width: 16,
|
80
|
+
height: 16,
|
81
81
|
objectFit: 'contain'
|
82
82
|
},
|
83
83
|
onError: handleImageError
|
84
84
|
}) : /*#__PURE__*/_jsx(LinkIcon, {
|
85
85
|
...iconSize
|
86
86
|
}), /*#__PURE__*/_jsx(LineText, {
|
87
|
+
variant: "body2",
|
88
|
+
color: "grey.800",
|
87
89
|
children: /*#__PURE__*/_jsx(Typography, {
|
88
90
|
component: "a",
|
89
91
|
href: value,
|
90
92
|
style: {
|
91
|
-
textDecoration: 'none'
|
93
|
+
textDecoration: 'none',
|
94
|
+
color: 'inherit',
|
95
|
+
fontSize: 'inherit'
|
92
96
|
},
|
93
97
|
target: "_blank",
|
94
98
|
variant: "body2",
|
@@ -101,7 +105,8 @@ function LinkField({
|
|
101
105
|
}
|
102
106
|
function BasicField({
|
103
107
|
field,
|
104
|
-
value
|
108
|
+
value,
|
109
|
+
children
|
105
110
|
}) {
|
106
111
|
const Icon = IconMap[field];
|
107
112
|
return /*#__PURE__*/_jsxs(Box, {
|
@@ -117,7 +122,7 @@ function BasicField({
|
|
117
122
|
}), /*#__PURE__*/_jsx(LineText, {
|
118
123
|
variant: "body2",
|
119
124
|
color: "grey.800",
|
120
|
-
children: value
|
125
|
+
children: children ?? value
|
121
126
|
})]
|
122
127
|
}, field);
|
123
128
|
}
|
@@ -165,9 +170,11 @@ function BasicContent({
|
|
165
170
|
}
|
166
171
|
}, [user, metadata, address]);
|
167
172
|
|
168
|
-
//
|
169
|
-
const
|
170
|
-
|
173
|
+
// 计算实际可见的字段数量和渲染元素数量
|
174
|
+
const {
|
175
|
+
effectiveRenderCount
|
176
|
+
} = useMemo(() => {
|
177
|
+
const visible = fields.filter(field => {
|
171
178
|
if (field === 'bio') return false; // bio field is handled separately
|
172
179
|
const value = getFieldValue(field);
|
173
180
|
if (value === undefined || value === null || value === '') return false;
|
@@ -176,41 +183,96 @@ function BasicContent({
|
|
176
183
|
}
|
177
184
|
return String(value).trim().length > 0;
|
178
185
|
});
|
186
|
+
|
187
|
+
// 计算实际渲染数量
|
188
|
+
const renderCount = visible.reduce((count, field) => {
|
189
|
+
const value = getFieldValue(field);
|
190
|
+
return count + (Array.isArray(value) ? value.filter(item => item && String(item).trim()).length : 1);
|
191
|
+
}, 0);
|
192
|
+
return {
|
193
|
+
visibleFields: visible,
|
194
|
+
effectiveRenderCount: renderCount
|
195
|
+
};
|
179
196
|
}, [fields, getFieldValue]);
|
180
197
|
|
181
198
|
// 判断是否需要使用两列布局
|
182
|
-
const useDoubleColumn =
|
199
|
+
const useDoubleColumn = effectiveRenderCount > 4;
|
200
|
+
const isValidValue = useMemoizedFn(value => value !== undefined && value !== null && String(value).trim().length > 0);
|
201
|
+
|
202
|
+
// 准备要渲染的所有元素项
|
203
|
+
const renderItems = useMemo(() => {
|
204
|
+
const items = [];
|
205
|
+
|
206
|
+
// 遍历有效字段,展开数组字段为单独的渲染项
|
207
|
+
fields.forEach(field => {
|
208
|
+
if (field === 'bio') return; // bio field is handled separately
|
209
|
+
const value = getFieldValue(field);
|
210
|
+
if (!value) return;
|
211
|
+
if (isArray(value)) {
|
212
|
+
// 数组类型字段,每个有效项生成一个渲染元素
|
213
|
+
value.forEach((item, index) => {
|
214
|
+
if (isValidValue(item)) {
|
215
|
+
items.push({
|
216
|
+
field,
|
217
|
+
value: item,
|
218
|
+
key: `${field}-${index}`
|
219
|
+
});
|
220
|
+
}
|
221
|
+
});
|
222
|
+
} else if (isValidValue(value)) {
|
223
|
+
// 非数组类型字段,生成一个渲染元素
|
224
|
+
items.push({
|
225
|
+
field,
|
226
|
+
value,
|
227
|
+
key: field
|
228
|
+
});
|
229
|
+
}
|
230
|
+
});
|
231
|
+
return items;
|
232
|
+
}, [fields, getFieldValue, isValidValue]);
|
183
233
|
if (fields.length === 0) {
|
184
234
|
return null;
|
185
235
|
}
|
186
|
-
const
|
187
|
-
const
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
236
|
+
const renderItem = item => {
|
237
|
+
const {
|
238
|
+
field,
|
239
|
+
value,
|
240
|
+
key
|
241
|
+
} = item;
|
242
|
+
switch (field) {
|
243
|
+
case 'link':
|
244
|
+
return /*#__PURE__*/_jsx(LinkField, {
|
245
|
+
value: value
|
246
|
+
}, key);
|
247
|
+
case 'timezone':
|
248
|
+
return /*#__PURE__*/_jsx(TimeZoneField, {
|
249
|
+
value: value
|
250
|
+
}, key);
|
251
|
+
case 'email':
|
252
|
+
return /*#__PURE__*/_jsx(BasicField, {
|
253
|
+
field: field,
|
254
|
+
value: value
|
255
|
+
// eslint-disable-next-line react/no-children-prop
|
256
|
+
,
|
257
|
+
children: /*#__PURE__*/_jsx(Typography, {
|
258
|
+
component: "a",
|
259
|
+
href: `mailto:${value}`,
|
260
|
+
rel: "noopener noreferrer",
|
261
|
+
referrerPolicy: "no-referrer",
|
262
|
+
style: {
|
263
|
+
color: 'inherit',
|
264
|
+
textDecoration: 'none',
|
265
|
+
fontSize: 'inherit'
|
266
|
+
},
|
267
|
+
children: value
|
268
|
+
})
|
269
|
+
});
|
270
|
+
default:
|
271
|
+
return /*#__PURE__*/_jsx(BasicField, {
|
272
|
+
field: field,
|
273
|
+
value: value
|
274
|
+
}, key);
|
209
275
|
}
|
210
|
-
return /*#__PURE__*/_jsx(BasicField, {
|
211
|
-
field: field,
|
212
|
-
value: value
|
213
|
-
}, field);
|
214
276
|
};
|
215
277
|
return /*#__PURE__*/_jsxs(Box, {
|
216
278
|
mt: 1,
|
@@ -226,19 +288,16 @@ function BasicContent({
|
|
226
288
|
}), useDoubleColumn ? /*#__PURE__*/_jsx(Grid, {
|
227
289
|
container: true,
|
228
290
|
spacing: 0.5,
|
229
|
-
children:
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
children: renderField(field)
|
235
|
-
}, field);
|
236
|
-
})
|
291
|
+
children: renderItems.map(item => /*#__PURE__*/_jsx(Grid, {
|
292
|
+
item: true,
|
293
|
+
xs: 6,
|
294
|
+
children: renderItem(item)
|
295
|
+
}, item.key))
|
237
296
|
}) : /*#__PURE__*/_jsx(Box, {
|
238
297
|
display: "flex",
|
239
298
|
flexDirection: "column",
|
240
299
|
gap: 0.5,
|
241
|
-
children:
|
300
|
+
children: renderItems.map(item => renderItem(item))
|
242
301
|
})]
|
243
302
|
});
|
244
303
|
}
|
@@ -40,16 +40,21 @@ export default function Clock({
|
|
40
40
|
});
|
41
41
|
const timeInfo = useClock(value, locale);
|
42
42
|
return /*#__PURE__*/_jsxs(Box, {
|
43
|
-
sx: {
|
44
|
-
whiteSpace: 'nowrap',
|
45
|
-
overflow: 'hidden',
|
46
|
-
textOverflow: 'ellipsis'
|
47
|
-
},
|
48
43
|
display: "flex",
|
49
44
|
alignItems: "center",
|
50
45
|
gap: 1,
|
46
|
+
flex: 1,
|
47
|
+
justifyContent: "flex-start",
|
48
|
+
overflow: "hidden",
|
49
|
+
width: "100%",
|
51
50
|
children: [/*#__PURE__*/_jsx(Typography, {
|
52
51
|
...props,
|
52
|
+
noWrap: true,
|
53
|
+
sx: {
|
54
|
+
flex: '0 1 auto',
|
55
|
+
minWidth: 0,
|
56
|
+
...props.sx
|
57
|
+
},
|
53
58
|
children: value
|
54
59
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
55
60
|
enterDelay: 200,
|
@@ -61,6 +66,14 @@ export default function Clock({
|
|
61
66
|
children: /*#__PURE__*/_jsxs(Typography, {
|
62
67
|
component: "span",
|
63
68
|
fontSize: 14,
|
69
|
+
noWrap: true,
|
70
|
+
sx: {
|
71
|
+
whiteSpace: 'nowrap',
|
72
|
+
overflow: 'hidden',
|
73
|
+
textOverflow: 'ellipsis',
|
74
|
+
flex: '0 0 auto',
|
75
|
+
maxWidth: '100%'
|
76
|
+
},
|
64
77
|
children: ["(", locale === 'zh' ? `${t(`timezonePhase.${timeInfo.phase}`)} ` : '', timeInfo.formattedTime, ")"]
|
65
78
|
})
|
66
79
|
})]
|
@@ -16,7 +16,8 @@ function MinimalContent(props) {
|
|
16
16
|
renderTopRightContent,
|
17
17
|
topRightMaxWidth,
|
18
18
|
avatarProps,
|
19
|
-
shortenLabelProps
|
19
|
+
shortenLabelProps,
|
20
|
+
...rest
|
20
21
|
} = props;
|
21
22
|
return /*#__PURE__*/_jsxs(Box, {
|
22
23
|
display: "flex",
|
@@ -35,7 +36,8 @@ function MinimalContent(props) {
|
|
35
36
|
avatarSize: avatarSize,
|
36
37
|
shouldShowHoverCard: shouldShowHoverCard,
|
37
38
|
renderCardContent: renderCardContent,
|
38
|
-
avatarProps: avatarProps
|
39
|
+
avatarProps: avatarProps,
|
40
|
+
...rest
|
39
41
|
}), /*#__PURE__*/_jsxs(Box, {
|
40
42
|
children: [/*#__PURE__*/_jsx(Typography, {
|
41
43
|
variant: "subtitle1",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@arcblock/ux",
|
3
|
-
"version": "2.13.
|
3
|
+
"version": "2.13.10",
|
4
4
|
"description": "Common used react components for arcblock products",
|
5
5
|
"keywords": [
|
6
6
|
"react",
|
@@ -70,14 +70,14 @@
|
|
70
70
|
"react": ">=18.2.0",
|
71
71
|
"react-router-dom": ">=6.22.3"
|
72
72
|
},
|
73
|
-
"gitHead": "
|
73
|
+
"gitHead": "164845889eb29a84f9da191b79f66c43554f9fa1",
|
74
74
|
"dependencies": {
|
75
75
|
"@arcblock/did-motif": "^1.1.13",
|
76
|
-
"@arcblock/icons": "^2.13.
|
77
|
-
"@arcblock/nft-display": "^2.13.
|
78
|
-
"@arcblock/react-hooks": "^2.13.
|
76
|
+
"@arcblock/icons": "^2.13.10",
|
77
|
+
"@arcblock/nft-display": "^2.13.10",
|
78
|
+
"@arcblock/react-hooks": "^2.13.10",
|
79
79
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
80
|
-
"@blocklet/theme": "^2.13.
|
80
|
+
"@blocklet/theme": "^2.13.10",
|
81
81
|
"@fontsource/roboto": "~5.1.1",
|
82
82
|
"@fontsource/ubuntu-mono": "^5.0.18",
|
83
83
|
"@iconify-icons/logos": "^1.2.36",
|
@@ -25,7 +25,7 @@ function BasicCard(props: BasicCardProps) {
|
|
25
25
|
} = props;
|
26
26
|
|
27
27
|
return (
|
28
|
-
<Box display="flex" flexDirection="column" width="100%"
|
28
|
+
<Box display="flex" flexDirection="column" width="100%" flex={1} height="100%">
|
29
29
|
<MinimalContent user={user} avatarSize={avatarSize} {...rest} />
|
30
30
|
|
31
31
|
{infoType === InfoType.Basic && <BasicContent user={user} isFull={isFull} renderFields={renderFields} />}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Typography, Box, Grid } from '@mui/material';
|
2
|
-
import { useCreation } from 'ahooks';
|
2
|
+
import { useCreation, useMemoizedFn } from 'ahooks';
|
3
3
|
import styled from '@emotion/styled';
|
4
4
|
import isArray from 'lodash/isArray';
|
5
5
|
import { Icon as IconifyIcon } from '@iconify/react';
|
@@ -41,13 +41,18 @@ interface BasicContentProps {
|
|
41
41
|
renderFields?: string[];
|
42
42
|
}
|
43
43
|
|
44
|
+
// 定义渲染项的类型
|
45
|
+
interface RenderItem {
|
46
|
+
field: string;
|
47
|
+
value: string | any;
|
48
|
+
key: string;
|
49
|
+
}
|
50
|
+
|
44
51
|
function TimeZoneField({ value }: { value: string }) {
|
45
52
|
return (
|
46
53
|
<Box display="flex" alignItems="center" gap={1} className="user-card__timezone-field">
|
47
54
|
<TimezoneIcon {...iconSize} />
|
48
|
-
<
|
49
|
-
<Clock value={value} variant="body2" color="grey.800" />
|
50
|
-
</LineText>
|
55
|
+
<Clock value={value} variant="body2" color="grey.800" />
|
51
56
|
</Box>
|
52
57
|
);
|
53
58
|
}
|
@@ -68,22 +73,22 @@ function LinkField({ value }: { value: string }) {
|
|
68
73
|
};
|
69
74
|
|
70
75
|
return (
|
71
|
-
<Box display="flex" alignItems="center" gap={1}>
|
76
|
+
<Box display="flex" alignItems="center" gap={1} className="user-card__link-field">
|
72
77
|
{faviconUrl && !useFallback ? (
|
73
78
|
<img
|
74
79
|
src={faviconUrl}
|
75
80
|
alt="site icon"
|
76
|
-
style={{ width:
|
81
|
+
style={{ width: 16, height: 16, objectFit: 'contain' }}
|
77
82
|
onError={handleImageError}
|
78
83
|
/>
|
79
84
|
) : (
|
80
85
|
<LinkIcon {...iconSize} />
|
81
86
|
)}
|
82
|
-
<LineText>
|
87
|
+
<LineText variant="body2" color="grey.800">
|
83
88
|
<Typography
|
84
89
|
component="a"
|
85
90
|
href={value}
|
86
|
-
style={{ textDecoration: 'none' }}
|
91
|
+
style={{ textDecoration: 'none', color: 'inherit', fontSize: 'inherit' }}
|
87
92
|
target="_blank"
|
88
93
|
variant="body2"
|
89
94
|
color="grey.800"
|
@@ -95,13 +100,13 @@ function LinkField({ value }: { value: string }) {
|
|
95
100
|
);
|
96
101
|
}
|
97
102
|
|
98
|
-
function BasicField({ field, value }: { field: string; value: string }) {
|
103
|
+
function BasicField({ field, value, children }: { field: string; value: string; children?: React.ReactNode }) {
|
99
104
|
const Icon = IconMap[field as keyof typeof IconMap];
|
100
105
|
return (
|
101
106
|
<Box key={field} display="flex" alignItems="center" gap={1} className={`user-card__${field}-field`}>
|
102
107
|
{Icon ? <Icon {...iconSize} /> : <IconifyIcon icon={infoCircleIcon} {...iconSize} />}
|
103
108
|
<LineText variant="body2" color="grey.800">
|
104
|
-
{value}
|
109
|
+
{children ?? value}
|
105
110
|
</LineText>
|
106
111
|
</Box>
|
107
112
|
);
|
@@ -156,9 +161,9 @@ function BasicContent({ user, isFull = false, renderFields }: BasicContentProps)
|
|
156
161
|
[user, metadata, address]
|
157
162
|
);
|
158
163
|
|
159
|
-
//
|
160
|
-
const
|
161
|
-
|
164
|
+
// 计算实际可见的字段数量和渲染元素数量
|
165
|
+
const { effectiveRenderCount } = useMemo(() => {
|
166
|
+
const visible = fields.filter((field) => {
|
162
167
|
if (field === 'bio') return false; // bio field is handled separately
|
163
168
|
const value = getFieldValue(field);
|
164
169
|
|
@@ -170,46 +175,95 @@ function BasicContent({ user, isFull = false, renderFields }: BasicContentProps)
|
|
170
175
|
|
171
176
|
return String(value).trim().length > 0;
|
172
177
|
});
|
178
|
+
|
179
|
+
// 计算实际渲染数量
|
180
|
+
const renderCount = visible.reduce((count, field) => {
|
181
|
+
const value = getFieldValue(field);
|
182
|
+
return count + (Array.isArray(value) ? value.filter((item) => item && String(item).trim()).length : 1);
|
183
|
+
}, 0);
|
184
|
+
|
185
|
+
return { visibleFields: visible, effectiveRenderCount: renderCount };
|
173
186
|
}, [fields, getFieldValue]);
|
174
187
|
|
175
188
|
// 判断是否需要使用两列布局
|
176
|
-
const useDoubleColumn =
|
189
|
+
const useDoubleColumn = effectiveRenderCount > 4;
|
190
|
+
|
191
|
+
const isValidValue = useMemoizedFn(
|
192
|
+
(value: any) => value !== undefined && value !== null && String(value).trim().length > 0
|
193
|
+
);
|
194
|
+
|
195
|
+
// 准备要渲染的所有元素项
|
196
|
+
const renderItems = useMemo(() => {
|
197
|
+
const items: RenderItem[] = [];
|
198
|
+
|
199
|
+
// 遍历有效字段,展开数组字段为单独的渲染项
|
200
|
+
fields.forEach((field) => {
|
201
|
+
if (field === 'bio') return; // bio field is handled separately
|
202
|
+
const value = getFieldValue(field);
|
203
|
+
|
204
|
+
if (!value) return;
|
205
|
+
|
206
|
+
if (isArray(value)) {
|
207
|
+
// 数组类型字段,每个有效项生成一个渲染元素
|
208
|
+
value.forEach((item, index) => {
|
209
|
+
if (isValidValue(item)) {
|
210
|
+
items.push({
|
211
|
+
field,
|
212
|
+
value: item,
|
213
|
+
key: `${field}-${index}`,
|
214
|
+
});
|
215
|
+
}
|
216
|
+
});
|
217
|
+
} else if (isValidValue(value)) {
|
218
|
+
// 非数组类型字段,生成一个渲染元素
|
219
|
+
items.push({
|
220
|
+
field,
|
221
|
+
value,
|
222
|
+
key: field,
|
223
|
+
});
|
224
|
+
}
|
225
|
+
});
|
226
|
+
|
227
|
+
return items;
|
228
|
+
}, [fields, getFieldValue, isValidValue]);
|
177
229
|
|
178
230
|
if (fields.length === 0) {
|
179
231
|
return null;
|
180
232
|
}
|
181
233
|
|
182
|
-
const
|
183
|
-
const value =
|
184
|
-
if (!value || field === 'bio') {
|
185
|
-
return null;
|
186
|
-
}
|
234
|
+
const renderItem = (item: RenderItem) => {
|
235
|
+
const { field, value, key } = item;
|
187
236
|
|
188
|
-
|
189
|
-
|
190
|
-
<
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
237
|
+
switch (field) {
|
238
|
+
case 'link':
|
239
|
+
return <LinkField key={key} value={value as string} />;
|
240
|
+
case 'timezone':
|
241
|
+
return <TimeZoneField key={key} value={value as string} />;
|
242
|
+
case 'email':
|
243
|
+
return (
|
244
|
+
<BasicField
|
245
|
+
field={field}
|
246
|
+
value={value as string}
|
247
|
+
// eslint-disable-next-line react/no-children-prop
|
248
|
+
children={
|
249
|
+
<Typography
|
250
|
+
component="a"
|
251
|
+
href={`mailto:${value}`}
|
252
|
+
rel="noopener noreferrer"
|
253
|
+
referrerPolicy="no-referrer"
|
254
|
+
style={{
|
255
|
+
color: 'inherit',
|
256
|
+
textDecoration: 'none',
|
257
|
+
fontSize: 'inherit',
|
258
|
+
}}>
|
259
|
+
{value}
|
260
|
+
</Typography>
|
261
|
+
}
|
262
|
+
/>
|
263
|
+
);
|
264
|
+
default:
|
265
|
+
return <BasicField key={key} field={field} value={value as string} />;
|
206
266
|
}
|
207
|
-
|
208
|
-
if (field === 'timezone') {
|
209
|
-
return <TimeZoneField key={field} value={value as string} />;
|
210
|
-
}
|
211
|
-
|
212
|
-
return <BasicField key={field} field={field} value={value as string} />;
|
213
267
|
};
|
214
268
|
|
215
269
|
return (
|
@@ -222,18 +276,15 @@ function BasicContent({ user, isFull = false, renderFields }: BasicContentProps)
|
|
222
276
|
{/* 其他字段 */}
|
223
277
|
{useDoubleColumn ? (
|
224
278
|
<Grid container spacing={0.5}>
|
225
|
-
{
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
</Grid>
|
231
|
-
);
|
232
|
-
})}
|
279
|
+
{renderItems.map((item) => (
|
280
|
+
<Grid item xs={6} key={item.key}>
|
281
|
+
{renderItem(item)}
|
282
|
+
</Grid>
|
283
|
+
))}
|
233
284
|
</Grid>
|
234
285
|
) : (
|
235
286
|
<Box display="flex" flexDirection="column" gap={0.5}>
|
236
|
-
{
|
287
|
+
{renderItems.map((item) => renderItem(item))}
|
237
288
|
</Box>
|
238
289
|
)}
|
239
290
|
</Box>
|
@@ -34,16 +34,17 @@ export default function Clock({ value, ...props }: { value: string; [key: string
|
|
34
34
|
const timeInfo = useClock(value, locale);
|
35
35
|
|
36
36
|
return (
|
37
|
-
<Box
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
<Box display="flex" alignItems="center" gap={1} flex={1} justifyContent="flex-start" overflow="hidden" width="100%">
|
38
|
+
<Typography
|
39
|
+
{...props}
|
40
|
+
noWrap
|
41
|
+
sx={{
|
42
|
+
flex: '0 1 auto',
|
43
|
+
minWidth: 0,
|
44
|
+
...props.sx,
|
45
|
+
}}>
|
46
|
+
{value}
|
47
|
+
</Typography>
|
47
48
|
<Tooltip
|
48
49
|
enterDelay={200}
|
49
50
|
title={
|
@@ -53,7 +54,17 @@ export default function Clock({ value, ...props }: { value: string; [key: string
|
|
53
54
|
}
|
54
55
|
placement="top"
|
55
56
|
arrow>
|
56
|
-
<Typography
|
57
|
+
<Typography
|
58
|
+
component="span"
|
59
|
+
fontSize={14}
|
60
|
+
noWrap
|
61
|
+
sx={{
|
62
|
+
whiteSpace: 'nowrap',
|
63
|
+
overflow: 'hidden',
|
64
|
+
textOverflow: 'ellipsis',
|
65
|
+
flex: '0 0 auto',
|
66
|
+
maxWidth: '100%',
|
67
|
+
}}>
|
57
68
|
({locale === 'zh' ? `${t(`timezonePhase.${timeInfo.phase}`)} ` : ''}
|
58
69
|
{timeInfo.formattedTime})
|
59
70
|
</Typography>
|
@@ -27,6 +27,7 @@ function MinimalContent(props: MinimalContentProps) {
|
|
27
27
|
topRightMaxWidth,
|
28
28
|
avatarProps,
|
29
29
|
shortenLabelProps,
|
30
|
+
...rest
|
30
31
|
} = props;
|
31
32
|
|
32
33
|
return (
|
@@ -38,6 +39,7 @@ function MinimalContent(props: MinimalContentProps) {
|
|
38
39
|
shouldShowHoverCard={shouldShowHoverCard}
|
39
40
|
renderCardContent={renderCardContent}
|
40
41
|
avatarProps={avatarProps}
|
42
|
+
{...rest}
|
41
43
|
/>
|
42
44
|
<Box>
|
43
45
|
<Typography
|
@@ -1,16 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { User } from '../types';
|
3
|
-
interface LeftColumnLayoutProps {
|
4
|
-
user: User;
|
5
|
-
avatarSize: number;
|
6
|
-
shouldShowHoverCard: boolean;
|
7
|
-
renderCardContent: () => React.ReactNode;
|
8
|
-
followButtonStyle: string;
|
9
|
-
isFollowed: boolean;
|
10
|
-
followLoading: boolean;
|
11
|
-
}
|
12
|
-
/**
|
13
|
-
* 统一左侧列布局组件,包含头像和关注按钮
|
14
|
-
*/
|
15
|
-
declare function LeftColumnLayout({ user, avatarSize, shouldShowHoverCard, renderCardContent, followButtonStyle, isFollowed, followLoading, }: LeftColumnLayoutProps): import("react/jsx-runtime").JSX.Element;
|
16
|
-
export default LeftColumnLayout;
|
@@ -1,33 +0,0 @@
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
import React from 'react';
|
3
|
-
import { Box } from '@mui/material';
|
4
|
-
import TooltipAvatar from './tooltip-avatar';
|
5
|
-
/**
|
6
|
-
* 统一左侧列布局组件,包含头像和关注按钮
|
7
|
-
*/
|
8
|
-
function LeftColumnLayout({
|
9
|
-
user,
|
10
|
-
avatarSize,
|
11
|
-
shouldShowHoverCard,
|
12
|
-
renderCardContent,
|
13
|
-
followButtonStyle,
|
14
|
-
isFollowed,
|
15
|
-
followLoading
|
16
|
-
}) {
|
17
|
-
return /*#__PURE__*/_jsx(Box, {
|
18
|
-
sx: {
|
19
|
-
mr: 2,
|
20
|
-
display: 'flex',
|
21
|
-
flexDirection: 'column',
|
22
|
-
alignItems: 'center',
|
23
|
-
gap: 1
|
24
|
-
},
|
25
|
-
children: /*#__PURE__*/_jsx(TooltipAvatar, {
|
26
|
-
user: user,
|
27
|
-
avatarSize: avatarSize,
|
28
|
-
shouldShowHoverCard: shouldShowHoverCard,
|
29
|
-
renderCardContent: renderCardContent
|
30
|
-
})
|
31
|
-
});
|
32
|
-
}
|
33
|
-
export default LeftColumnLayout;
|
@@ -1,40 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { Box } from '@mui/material';
|
3
|
-
import { User } from '../types';
|
4
|
-
import TooltipAvatar from './tooltip-avatar';
|
5
|
-
|
6
|
-
interface LeftColumnLayoutProps {
|
7
|
-
user: User;
|
8
|
-
avatarSize: number;
|
9
|
-
shouldShowHoverCard: boolean;
|
10
|
-
renderCardContent: () => React.ReactNode;
|
11
|
-
followButtonStyle: string;
|
12
|
-
isFollowed: boolean;
|
13
|
-
followLoading: boolean;
|
14
|
-
}
|
15
|
-
|
16
|
-
/**
|
17
|
-
* 统一左侧列布局组件,包含头像和关注按钮
|
18
|
-
*/
|
19
|
-
function LeftColumnLayout({
|
20
|
-
user,
|
21
|
-
avatarSize,
|
22
|
-
shouldShowHoverCard,
|
23
|
-
renderCardContent,
|
24
|
-
followButtonStyle,
|
25
|
-
isFollowed,
|
26
|
-
followLoading,
|
27
|
-
}: LeftColumnLayoutProps) {
|
28
|
-
return (
|
29
|
-
<Box sx={{ mr: 2, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 }}>
|
30
|
-
<TooltipAvatar
|
31
|
-
user={user}
|
32
|
-
avatarSize={avatarSize}
|
33
|
-
shouldShowHoverCard={shouldShowHoverCard}
|
34
|
-
renderCardContent={renderCardContent}
|
35
|
-
/>
|
36
|
-
</Box>
|
37
|
-
);
|
38
|
-
}
|
39
|
-
|
40
|
-
export default LeftColumnLayout;
|