@blocklet/ui-react 2.12.8 → 2.12.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.
Files changed (54) hide show
  1. package/lib/@types/index.d.ts +34 -0
  2. package/lib/@types/index.js +16 -0
  3. package/lib/@types/shims.d.ts +1 -0
  4. package/lib/UserCenter/components/config-profile.js +23 -1
  5. package/lib/UserCenter/components/editable-field.d.ts +22 -0
  6. package/lib/UserCenter/components/editable-field.js +159 -0
  7. package/lib/UserCenter/components/nft.d.ts +4 -0
  8. package/lib/UserCenter/components/nft.js +93 -0
  9. package/lib/UserCenter/components/settings.js +32 -15
  10. package/lib/UserCenter/components/status-selector/duration-menu.d.ts +9 -0
  11. package/lib/UserCenter/components/status-selector/duration-menu.js +75 -0
  12. package/lib/UserCenter/components/status-selector/index.d.ts +9 -0
  13. package/lib/UserCenter/components/status-selector/index.js +39 -0
  14. package/lib/UserCenter/components/status-selector/menu-item.d.ts +24 -0
  15. package/lib/UserCenter/components/status-selector/menu-item.js +24 -0
  16. package/lib/UserCenter/components/user-center.js +119 -122
  17. package/lib/UserCenter/components/user-info/clock.d.ts +4 -0
  18. package/lib/UserCenter/components/user-info/clock.js +23 -0
  19. package/lib/UserCenter/components/user-info/link-preview-input.d.ts +5 -0
  20. package/lib/UserCenter/components/user-info/link-preview-input.js +181 -0
  21. package/lib/UserCenter/components/user-info/metadata.d.ts +7 -0
  22. package/lib/UserCenter/components/user-info/metadata.js +458 -0
  23. package/lib/UserCenter/components/user-info/switch-role.js +2 -3
  24. package/lib/UserCenter/components/user-info/user-basic-info.d.ts +2 -0
  25. package/lib/UserCenter/components/user-info/user-basic-info.js +159 -90
  26. package/lib/UserCenter/components/user-info/user-info.js +2 -16
  27. package/lib/UserCenter/components/user-info/user-status.d.ts +8 -0
  28. package/lib/UserCenter/components/user-info/user-status.js +153 -0
  29. package/lib/UserCenter/components/user-info/utils.d.ts +19 -0
  30. package/lib/UserCenter/components/user-info/utils.js +86 -0
  31. package/lib/UserCenter/libs/locales.d.ts +65 -0
  32. package/lib/UserCenter/libs/locales.js +67 -2
  33. package/lib/UserSessions/components/user-sessions.js +48 -14
  34. package/package.json +8 -5
  35. package/src/@types/index.ts +39 -0
  36. package/src/@types/shims.d.ts +1 -0
  37. package/src/UserCenter/components/config-profile.tsx +20 -1
  38. package/src/UserCenter/components/editable-field.tsx +180 -0
  39. package/src/UserCenter/components/nft.tsx +122 -0
  40. package/src/UserCenter/components/settings.tsx +16 -4
  41. package/src/UserCenter/components/status-selector/duration-menu.tsx +87 -0
  42. package/src/UserCenter/components/status-selector/index.tsx +52 -0
  43. package/src/UserCenter/components/status-selector/menu-item.tsx +52 -0
  44. package/src/UserCenter/components/user-center.tsx +104 -103
  45. package/src/UserCenter/components/user-info/clock.tsx +29 -0
  46. package/src/UserCenter/components/user-info/link-preview-input.tsx +227 -0
  47. package/src/UserCenter/components/user-info/metadata.tsx +465 -0
  48. package/src/UserCenter/components/user-info/switch-role.tsx +3 -3
  49. package/src/UserCenter/components/user-info/user-basic-info.tsx +150 -87
  50. package/src/UserCenter/components/user-info/user-info.tsx +6 -16
  51. package/src/UserCenter/components/user-info/user-status.tsx +182 -0
  52. package/src/UserCenter/components/user-info/utils.ts +114 -0
  53. package/src/UserCenter/libs/locales.ts +65 -0
  54. package/src/UserSessions/components/user-sessions.tsx +68 -18
@@ -20,7 +20,7 @@ import { PROFILE_URL } from "@arcblock/ux/lib/Util/constant";
20
20
  import Footer from "../../Footer/index.js";
21
21
  import Header from "../../Header/index.js";
22
22
  import { translations } from "../libs/locales.js";
23
- import { UserInfo, UserBasicInfo, SwitchRole } from "./user-info/index.js";
23
+ import { UserBasicInfo } from "./user-info/index.js";
24
24
  import { formatBlockletInfo, getLink, getLocalizedNavigation } from "../../blocklets.js";
25
25
  import Passport from "./passport.js";
26
26
  import Settings from "./settings.js";
@@ -28,15 +28,16 @@ import { client } from "../../libs/client.js";
28
28
  import useMobile from "../../hooks/use-mobile.js";
29
29
  import { ConfigUserSpaceProvider } from "../../contexts/config-user-space.js";
30
30
  import DidSpace from "./storage/index.js";
31
- const profileLink = joinURL(PROFILE_URL, "/profile");
31
+ import Nft from "./nft.js";
32
+ const nftsLink = joinURL(PROFILE_URL, "/nfts");
32
33
  const settingsLink = joinURL(PROFILE_URL, "/settings");
33
34
  const didSpacesLink = joinURL(PROFILE_URL, "/did-spaces");
34
35
  const Main = styled(Box)(({ theme }) => ({
35
36
  flex: 1,
36
37
  boxSizing: "border-box",
37
- padding: theme.spacing(3),
38
+ padding: "0 16px",
38
39
  width: "100%",
39
- maxWidth: 1200,
40
+ maxWidth: 1600,
40
41
  margin: "0 auto",
41
42
  display: "flex",
42
43
  alignItems: "stretch",
@@ -152,29 +153,32 @@ export default function UserCenter({
152
153
  }
153
154
  }, []);
154
155
  const defaultTabs = useCreation(() => {
155
- const tabs = [
156
- {
157
- label: t("common.profile"),
158
- protected: false,
159
- value: profileLink,
160
- url: getLink(profileLink, locale)
161
- }
162
- ];
156
+ let tabs = [];
163
157
  if (isMyself) {
164
- tabs.push({
165
- label: t("common.setting"),
166
- protected: true,
167
- isPrivate: true,
168
- value: settingsLink,
169
- url: getLink(settingsLink, locale)
170
- });
171
- tabs.push({
172
- label: t("storageManagement"),
173
- protected: true,
174
- isPrivate: true,
175
- value: didSpacesLink,
176
- url: getLink(didSpacesLink, locale)
177
- });
158
+ tabs = [
159
+ {
160
+ label: t("common.nft"),
161
+ protected: true,
162
+ isPrivate: true,
163
+ // 隐私数据,仅自己可见
164
+ value: nftsLink,
165
+ url: getLink(nftsLink, locale)
166
+ },
167
+ {
168
+ label: t("common.setting"),
169
+ protected: true,
170
+ isPrivate: true,
171
+ value: settingsLink,
172
+ url: getLink(settingsLink, locale)
173
+ },
174
+ {
175
+ label: t("storageManagement"),
176
+ protected: true,
177
+ isPrivate: true,
178
+ value: didSpacesLink,
179
+ url: getLink(didSpacesLink, locale)
180
+ }
181
+ ];
178
182
  }
179
183
  return tabs;
180
184
  }, [isMyself, locale]);
@@ -189,7 +193,8 @@ export default function UserCenter({
189
193
  label: x.title || x.label,
190
194
  url: x.link || x.url,
191
195
  protected: privacyState?.data?.[value] ?? false,
192
- isPrivate: x.isPrivate
196
+ isPrivate: x.isPrivate || x._rawLink === "/payment-kit/customer"
197
+ // FIXME: HACK: 隐藏 payment-kit/customer 菜单, 需要一个通用的解决方案,在嵌入的时候就决定是否是私有的
193
198
  // icon: x.icon,
194
199
  };
195
200
  }).filter((x) => isMyself || !x.isPrivate);
@@ -227,8 +232,8 @@ export default function UserCenter({
227
232
  const isSettingTab = useCreation(() => {
228
233
  return currentActiveTab && currentActiveTab?.value === joinURL(PROFILE_URL, "/settings");
229
234
  }, [currentActiveTab]);
230
- const isProfileTab = useCreation(() => {
231
- return currentActiveTab && currentActiveTab?.value === joinURL(PROFILE_URL, "/profile");
235
+ const isNftsTab = useCreation(() => {
236
+ return currentActiveTab && currentActiveTab?.value === joinURL(PROFILE_URL, "/profile") || currentActiveTab?.value === joinURL(PROFILE_URL, "/nfts");
232
237
  }, [currentActiveTab]);
233
238
  const isDidSpaceTab = useCreation(() => {
234
239
  return currentActiveTab && currentActiveTab?.value === joinURL(PROFILE_URL, "/did-spaces");
@@ -245,53 +250,32 @@ export default function UserCenter({
245
250
  }
246
251
  });
247
252
  const renderDefaultTab = useCreation(() => {
248
- if (isProfileTab) {
249
- return /* @__PURE__ */ jsx(
253
+ if (isNftsTab && isMyself) {
254
+ return /* @__PURE__ */ jsxs(
250
255
  Box,
251
256
  {
252
257
  sx: {
253
- maxWidth: "100%",
254
- position: "relative"
258
+ display: "flex",
259
+ flexDirection: "column",
260
+ gap: 2.5
255
261
  },
256
- children: /* @__PURE__ */ jsxs(
257
- Box,
258
- {
259
- sx: {
260
- display: "flex",
261
- flexDirection: "column",
262
- gap: 2.5,
263
- position: {
264
- xs: "static",
265
- md: stickySidebar ? "sticky" : "static"
266
- },
267
- top: (theme) => stickySidebar ? theme.spacing(3) : "unset"
268
- },
269
- children: [
270
- /* @__PURE__ */ jsxs(
271
- Box,
272
- {
273
- sx: {
274
- width: {
275
- sx: "100%",
276
- md: 420
277
- }
278
- },
279
- children: [
280
- /* @__PURE__ */ jsxs(Box, { display: "flex", justifyContent: "space-between", children: [
281
- /* @__PURE__ */ jsx(Typography, { sx: { fontWeight: 600, mb: 1.5 }, children: isMyself ? t("myInfo") : t("hisInfo") }),
282
- isMyself ? /* @__PURE__ */ jsx(SwitchRole, { user: userState.data, switchPassport: handleSwitchPassport }) : null
283
- ] }),
284
- /* @__PURE__ */ jsx(UserInfo, { user: userState.data, isMySelf: isMyself })
285
- ]
286
- }
287
- ),
288
- isMyself ? /* @__PURE__ */ jsxs(Box, { children: [
289
- /* @__PURE__ */ jsx(Typography, { sx: { fontWeight: 600, mb: 1.5 }, children: t("passport") }),
290
- /* @__PURE__ */ jsx(Passport, { user: userState.data })
291
- ] }) : null
292
- ]
293
- }
294
- )
262
+ children: [
263
+ /* @__PURE__ */ jsxs(Box, { sx: { border: `1px solid ${colors.dividerColor}`, borderRadius: 2, p: 2 }, children: [
264
+ /* @__PURE__ */ jsx(
265
+ Typography,
266
+ {
267
+ sx: {
268
+ color: colors.foregroundsFgBase,
269
+ fontWeight: 600,
270
+ mb: 2.5
271
+ },
272
+ children: t("passport")
273
+ }
274
+ ),
275
+ /* @__PURE__ */ jsx(Passport, { user: userState.data })
276
+ ] }),
277
+ /* @__PURE__ */ jsx(Nft, { user: userState.data })
278
+ ]
295
279
  }
296
280
  );
297
281
  }
@@ -302,7 +286,7 @@ export default function UserCenter({
302
286
  return /* @__PURE__ */ jsx(ConfigUserSpaceProvider, { children: /* @__PURE__ */ jsx(DidSpace, {}) });
303
287
  }
304
288
  return null;
305
- }, [isSettingTab, isProfileTab, userState, isMyself, stickySidebar, settingContent]);
289
+ }, [isSettingTab, isNftsTab, userState, isMyself, stickySidebar, settingContent]);
306
290
  const emptyContent = useCreation(() => {
307
291
  return /* @__PURE__ */ jsx(
308
292
  Box,
@@ -397,66 +381,79 @@ export default function UserCenter({
397
381
  userCenterTabs.length === 0 && emptyContent
398
382
  ] });
399
383
  }
400
- return /* @__PURE__ */ jsxs(ContentWrapper, { children: [
384
+ return /* @__PURE__ */ jsxs(ContentWrapper, { display: "flex", flexDirection: isMobile ? "column" : "row", children: [
385
+ /* @__PURE__ */ jsxs(Box, { flex: "1", order: isMobile ? 2 : "unset", children: [
386
+ userCenterTabs.length > 0 && currentTab ? /* @__PURE__ */ jsxs(
387
+ Box,
388
+ {
389
+ display: "flex",
390
+ flexDirection: "column",
391
+ sx: {
392
+ height: "100%",
393
+ overflow: "auto",
394
+ padding: "1px"
395
+ },
396
+ children: [
397
+ /* @__PURE__ */ jsx(
398
+ Tabs,
399
+ {
400
+ orientation: "horizontal",
401
+ variant: "line",
402
+ tabs: userCenterTabs,
403
+ current: currentActiveTab?.value ?? currentTab,
404
+ onChange: handleChangeTab,
405
+ sx: {
406
+ mb: 2,
407
+ ".MuiTabs-flexContainer": {
408
+ gap: 3,
409
+ ".MuiButtonBase-root": {
410
+ padding: "40px 4px 32px 4px",
411
+ fontSize: 16
412
+ },
413
+ ".MuiTab-root": {
414
+ display: "block",
415
+ textAlign: "left",
416
+ alignItems: "flex-start",
417
+ justifyContent: "flex-start",
418
+ fontWeight: 400
419
+ }
420
+ },
421
+ ".MuiTabs-scroller": {
422
+ "&:after": {
423
+ content: '""',
424
+ display: "block",
425
+ width: "100%",
426
+ height: "1px",
427
+ backgroundColor: `${colors.dividerColor} !important`
428
+ }
429
+ }
430
+ }
431
+ }
432
+ ),
433
+ tabContent
434
+ ]
435
+ }
436
+ ) : null,
437
+ userCenterTabs.length === 0 && emptyContent
438
+ ] }),
439
+ !isMobile && /* @__PURE__ */ jsx(Divider, { orientation: "vertical", sx: { borderColor: colors.dividerColor, ml: 5 } }),
401
440
  /* @__PURE__ */ jsx(
402
441
  UserBasicInfo,
403
442
  {
443
+ isMobile,
444
+ order: isMobile ? 1 : "unset",
404
445
  isMyself,
405
446
  switchPassport: handleSwitchPassport,
406
447
  switchProfile: session.switchProfile,
407
448
  user: userState.data,
408
449
  showFullDid: false,
409
450
  sx: {
410
- display: "flex",
411
- gap: 3,
412
- mt: 2
451
+ padding: !isMobile ? "40px 24px 24px 40px" : "24px 0",
452
+ ...!isMobile ? { width: 320, maxWidth: 320, flexShrink: 0 } : {},
453
+ boxSizing: "content-box"
413
454
  }
414
455
  }
415
- ),
416
- /* @__PURE__ */ jsx(Divider, { sx: { mt: 3, mb: 3, borderColor: colors.dividerColor } }),
417
- userCenterTabs.length > 0 && currentTab ? /* @__PURE__ */ jsxs(
418
- Box,
419
- {
420
- display: isMobile ? "block" : "flex",
421
- sx: {
422
- height: "100%",
423
- overflow: "auto",
424
- padding: "1px"
425
- },
426
- children: [
427
- /* @__PURE__ */ jsx(
428
- Tabs,
429
- {
430
- orientation: isMobile ? "horizontal" : "vertical",
431
- variant: "line",
432
- tabs: userCenterTabs,
433
- current: currentActiveTab?.value ?? currentTab,
434
- onChange: handleChangeTab,
435
- sx: {
436
- width: isMobile ? "100%" : 160,
437
- marginBottom: isMobile ? "8px" : 0,
438
- flexShrink: 0,
439
- ".MuiTabs-flexContainer": {
440
- gap: 1.5,
441
- ".MuiButtonBase-root": {
442
- fontSize: 16
443
- },
444
- ".MuiTab-root": {
445
- display: "block",
446
- textAlign: "left",
447
- alignItems: "flex-start",
448
- justifyContent: "flex-start"
449
- }
450
- }
451
- }
452
- }
453
- ),
454
- /* @__PURE__ */ jsx(Divider, { orientation: "vertical", sx: { height: "100%", mr: 3, borderColor: colors.dividerColor } }),
455
- tabContent
456
- ]
457
- }
458
- ) : null,
459
- userCenterTabs.length === 0 && emptyContent
456
+ )
460
457
  ] });
461
458
  }, [
462
459
  userState,
@@ -0,0 +1,4 @@
1
+ export default function Clock({ timezone, locale }: {
2
+ timezone?: string;
3
+ locale?: string;
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useState, useEffect } from "react";
3
+ import dayjs from "dayjs";
4
+ import utc from "dayjs/plugin/utc";
5
+ import timezonePlugin from "dayjs/plugin/timezone";
6
+ import { formatToDatetime } from "@arcblock/ux/lib/Util";
7
+ import { useCreation } from "ahooks";
8
+ dayjs.extend(utc);
9
+ dayjs.extend(timezonePlugin);
10
+ export default function Clock({ timezone = "utc", locale = "zh" }) {
11
+ const [time, setTime] = useState(dayjs().tz(timezone));
12
+ useEffect(() => {
13
+ const timerId = setInterval(() => {
14
+ setTime(dayjs().tz(timezone));
15
+ }, 6e3);
16
+ return () => clearInterval(timerId);
17
+ }, [timezone]);
18
+ const formatTime = useCreation(() => {
19
+ const localeOption = locale === "zh" ? "zh-cn" : "en-us";
20
+ return formatToDatetime(time.toDate(), { tz: timezone, locale: localeOption });
21
+ }, [time, timezone, locale]);
22
+ return /* @__PURE__ */ jsx("div", { children: formatTime });
23
+ }
@@ -0,0 +1,5 @@
1
+ export declare function LinkPreviewInput({ editable, links, onChange, }: {
2
+ editable?: boolean;
3
+ links: string[];
4
+ onChange: (links: string[]) => void;
5
+ }): import("react").JSX.Element;
@@ -0,0 +1,181 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Box, Button, FormControl, IconButton, TextField, Typography } from "@mui/material";
3
+ import styled from "@emotion/styled";
4
+ import RemoveIcon from "@arcblock/icons/lib/Subtract";
5
+ import AddIcon from "@mui/icons-material/Add";
6
+ import { temp as colors } from "@arcblock/ux/lib/Colors";
7
+ import { useEffect, useMemo, useState } from "react";
8
+ import { translate } from "@arcblock/ux/lib/Locale/util";
9
+ import { useMemoizedFn } from "ahooks";
10
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
11
+ import LinkIcon from "@arcblock/icons/lib/Link";
12
+ import { joinURL } from "ufo";
13
+ import { isValidUrl } from "./utils.js";
14
+ import { translations } from "../../libs/locales.js";
15
+ function LinkInput({ value, onChange, error }) {
16
+ const handleUrlChange = (event) => {
17
+ const inputValue = event.target.value;
18
+ onChange(inputValue);
19
+ };
20
+ return /* @__PURE__ */ jsx(FormControl, { fullWidth: true, children: /* @__PURE__ */ jsx(
21
+ TextField,
22
+ {
23
+ variant: "outlined",
24
+ value,
25
+ onChange: handleUrlChange,
26
+ fullWidth: true,
27
+ error,
28
+ helperText: error ? "Invalid URL" : "",
29
+ sx: {
30
+ fieldset: {
31
+ borderColor: colors.dividerColor
32
+ }
33
+ }
34
+ }
35
+ ) });
36
+ }
37
+ function DynamicLinkForm({ links = [], onChange }) {
38
+ const { locale } = useLocaleContext();
39
+ const t = useMemoizedFn((key, data = {}) => {
40
+ return translate(translations, key, locale, "en", data);
41
+ });
42
+ const [errors, setErrors] = useState([false]);
43
+ const isLastError = useMemo(() => {
44
+ const lastLink = links[links.length - 1];
45
+ return !isValidUrl(lastLink) || errors.length > 0 && errors[errors.length - 1];
46
+ }, [errors, links]);
47
+ const handleAddLink = () => {
48
+ if (links.length < 5 || !isLastError) {
49
+ onChange([...links, ""]);
50
+ }
51
+ };
52
+ const handleRemoveLink = (index) => {
53
+ const updatedLinks = links.filter((_, i) => i !== index);
54
+ const updatedErrors = errors.filter((_, i) => i !== index);
55
+ setErrors(updatedErrors);
56
+ onChange(updatedLinks);
57
+ };
58
+ const handleInputChange = (index, value) => {
59
+ const updatedLinks = [...links];
60
+ updatedLinks[index] = value;
61
+ const updatedErrors = [...errors];
62
+ updatedErrors[index] = !!(value && !isValidUrl(value));
63
+ setErrors(updatedErrors);
64
+ onChange(updatedLinks);
65
+ };
66
+ return /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
67
+ /* @__PURE__ */ jsx(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", gap: 1, children: /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", gutterBottom: true, sx: { mb: 0, fontSize: "12px", color: "#4B5563" }, children: "Social Media" }) }),
68
+ links.map((link, index) => (
69
+ // eslint-disable-next-line react/no-array-index-key
70
+ /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "flex-start", mb: 1, children: [
71
+ /* @__PURE__ */ jsx(LinkInput, { value: link, onChange: (value) => handleInputChange(index, value), error: errors[index] }),
72
+ /* @__PURE__ */ jsx(IconButton, { sx: { color: colors.foregroundsFgMuted }, onClick: () => handleRemoveLink(index), children: /* @__PURE__ */ jsx(RemoveIcon, {}) })
73
+ ] }, index)
74
+ )),
75
+ links.length < 5 && /* @__PURE__ */ jsxs(
76
+ Button,
77
+ {
78
+ fullWidth: true,
79
+ variant: "outlined",
80
+ disabled: isLastError,
81
+ onClick: handleAddLink,
82
+ size: "small",
83
+ sx: {
84
+ height: "40px",
85
+ border: `1px dashed ${colors.dividerColor}`,
86
+ color: colors.textBase,
87
+ "&:hover": {
88
+ border: `1px dashed ${colors.backgroundsBgSubtileHover}`,
89
+ backgroundColor: colors.backgroundsBgSubtileHover
90
+ },
91
+ "&.Mui-disabled": {
92
+ borderStyle: "dashed"
93
+ }
94
+ },
95
+ children: [
96
+ /* @__PURE__ */ jsx(AddIcon, {}),
97
+ " ",
98
+ /* @__PURE__ */ jsx("span", { children: t("profile.addLink") })
99
+ ]
100
+ }
101
+ )
102
+ ] });
103
+ }
104
+ function FaviconPreview({ link }) {
105
+ const [favicon, setFavicon] = useState("");
106
+ const [iconError, setIconError] = useState(false);
107
+ useEffect(() => {
108
+ try {
109
+ if (link) {
110
+ const url = new URL(link);
111
+ const faviconUrl = joinURL(url.origin, "favicon.ico");
112
+ const img = new Image();
113
+ img.src = faviconUrl;
114
+ img.onload = () => {
115
+ setFavicon(faviconUrl);
116
+ setIconError(false);
117
+ };
118
+ img.onerror = () => {
119
+ setIconError(true);
120
+ setFavicon("");
121
+ };
122
+ } else {
123
+ setIconError(true);
124
+ setFavicon("");
125
+ }
126
+ } catch (error) {
127
+ setIconError(true);
128
+ }
129
+ }, [link]);
130
+ if (!link) {
131
+ return null;
132
+ }
133
+ if (iconError || !favicon) {
134
+ return /* @__PURE__ */ jsx(LinkIcon, { width: 20, height: 20 });
135
+ }
136
+ return /* @__PURE__ */ jsx("img", { src: favicon, alt: "Favicon", width: 20, height: 20 });
137
+ }
138
+ export function LinkPreviewInput({
139
+ editable = false,
140
+ links = [],
141
+ onChange
142
+ }) {
143
+ if (editable) {
144
+ return /* @__PURE__ */ jsx(DynamicLinkForm, { links, onChange });
145
+ }
146
+ return /* @__PURE__ */ jsx(Box, { width: "100%", display: "flex", flexDirection: "column", gap: 2, children: links.map((link) => /* @__PURE__ */ jsxs(
147
+ Box,
148
+ {
149
+ display: "flex",
150
+ alignItems: "center",
151
+ gap: 1,
152
+ sx: {
153
+ overflow: "hidden",
154
+ width: "100%"
155
+ },
156
+ children: [
157
+ /* @__PURE__ */ jsx(FaviconPreview, { link }),
158
+ /* @__PURE__ */ jsx(LinkDiv, { children: /* @__PURE__ */ jsx(Box, { component: "a", href: link, style: { textDecoration: "none" }, target: "_blank", rel: "noopener noreferrer", children: link }) })
159
+ ]
160
+ },
161
+ link
162
+ )) });
163
+ }
164
+ const LinkDiv = styled.span`
165
+ flex: 1;
166
+ white-space: nowrap;
167
+ overflow: hidden;
168
+ text-overflow: ellipsis;
169
+ &,
170
+ & > * {
171
+ color: #222;
172
+ }
173
+
174
+ & > * {
175
+ word-break: break-all;
176
+ }
177
+
178
+ .status {
179
+ margin-left: 8px;
180
+ }
181
+ `;
@@ -0,0 +1,7 @@
1
+ import type { User, UserMetadata } from '../../../@types';
2
+ export default function UserMetadataComponent({ isMyself, user, onSave, }: {
3
+ isMyself: boolean;
4
+ user: User;
5
+ onSave: (v: UserMetadata) => void;
6
+ isMobile?: boolean;
7
+ }): import("react").JSX.Element;