@blocklet/ui-react 2.12.63 → 2.12.70

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.
@@ -1,13 +1,12 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { useMemo } from "react";
3
3
  import PropTypes from "prop-types";
4
- import { styled } from "@arcblock/ux/lib/Theme";
4
+ import { styled, useTheme, deepmerge, ThemeProvider } from "@arcblock/ux/lib/Theme";
5
5
  import { withErrorBoundary } from "react-error-boundary";
6
6
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
7
7
  import { ErrorFallback } from "@arcblock/ux/lib/ErrorBoundary";
8
8
  import { temp as colors } from "@arcblock/ux/lib/Colors";
9
9
  import omit from "lodash/omit";
10
- import OverridableThemeProvider from "../common/overridable-theme-provider.js";
11
10
  import InternalFooter from "./internal-footer.js";
12
11
  import { mapRecursive } from "../utils.js";
13
12
  import { formatBlockletInfo, getLocalizedNavigation } from "../blocklets.js";
@@ -15,6 +14,7 @@ import { BlockletMetaProps } from "../types.js";
15
14
  import withHideWhenEmbed from "../libs/with-hide-when-embed.js";
16
15
  function Footer({ meta, theme: themeOverrides, ...rest }) {
17
16
  const { locale } = useLocaleContext() || {};
17
+ const parentTheme = useTheme();
18
18
  const formattedBlocklet = useMemo(() => {
19
19
  const blocklet = Object.assign({}, window.blocklet, meta);
20
20
  try {
@@ -24,10 +24,12 @@ function Footer({ meta, theme: themeOverrides, ...rest }) {
24
24
  return blocklet;
25
25
  }
26
26
  }, [meta]);
27
+ const mergeTheme = useMemo(() => deepmerge(parentTheme, themeOverrides), [parentTheme, themeOverrides]);
27
28
  if (!formattedBlocklet.appName) {
28
29
  return null;
29
30
  }
30
- const { appLogo, appLogoRect, appName, appDescription, description, theme, copyright } = formattedBlocklet;
31
+ const { appLogo, appLogoRect, appName, appDescription, description, copyright } = formattedBlocklet;
32
+ const $bgColor = mergeTheme.palette.background.default;
31
33
  const localized = {
32
34
  footerNav: getLocalizedNavigation(formattedBlocklet?.navigation?.footer, locale) || [],
33
35
  socialMedia: getLocalizedNavigation(formattedBlocklet?.navigation?.social, locale) || [],
@@ -52,15 +54,7 @@ function Footer({ meta, theme: themeOverrides, ...rest }) {
52
54
  socialMedia: localized.socialMedia,
53
55
  links: localized.links.map((item) => ({ ...item, label: item.title }))
54
56
  };
55
- return /* @__PURE__ */ jsx(OverridableThemeProvider, { theme: themeOverrides, children: /* @__PURE__ */ jsx(
56
- StyledInternalFooter,
57
- {
58
- ...props,
59
- ...omit(rest, ["bordered"]),
60
- $bordered: rest?.bordered,
61
- $bgcolor: theme?.background?.footer
62
- }
63
- ) });
57
+ return /* @__PURE__ */ jsx(ThemeProvider, { theme: mergeTheme, children: /* @__PURE__ */ jsx(StyledInternalFooter, { ...props, ...omit(rest, ["bordered"]), $bordered: rest?.bordered, $bgcolor: $bgColor }) });
64
58
  }
65
59
  Footer.propTypes = {
66
60
  meta: BlockletMetaProps,
@@ -75,8 +69,6 @@ const StyledInternalFooter = styled(InternalFooter)`
75
69
  ${({ $bordered }) => `border-top: 1px solid ${$bordered ? colors.strokeSep : "#eee"};`}
76
70
  color: ${(props) => props.theme.palette.grey[600]};
77
71
  ${({ $bgcolor }) => $bgcolor && `background-color: ${$bgcolor};`}
78
- font-family: Inter, Avenir, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
79
- 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
80
72
  `;
81
73
  export default withErrorBoundary(withHideWhenEmbed(Footer), {
82
74
  FallbackComponent: ErrorFallback
@@ -128,7 +128,7 @@ Links.defaultProps = {
128
128
  };
129
129
  const Root = styled("div")`
130
130
  overflow: hidden;
131
- color: #9397a1;
131
+ color: ${({ theme }) => theme.palette.grey[500]};
132
132
  .footer-links-inner {
133
133
  display: flex;
134
134
  justify-content: space-between;
@@ -159,8 +159,8 @@ const Root = styled("div")`
159
159
  font-size: 14px;
160
160
  &--new::after {
161
161
  content: 'New';
162
- color: #4672ea;
163
- background-color: #e1e8fb;
162
+ color: ${({ theme }) => theme.palette.info.main};
163
+ background-color: ${({ theme }) => theme.palette.info.light};
164
164
  padding: 1px 8px;
165
165
  border-radius: 10px/50%;
166
166
  margin-left: 8px;
@@ -170,7 +170,7 @@ const Root = styled("div")`
170
170
  .footer-links-group {
171
171
  > .footer-links-item {
172
172
  font-weight: 600;
173
- color: #25292f;
173
+ color: ${({ theme }) => theme.palette.text.primary};
174
174
  }
175
175
  .footer-links-sub {
176
176
  margin-top: 8px;
@@ -184,7 +184,7 @@ const Root = styled("div")`
184
184
  text-decoration: none;
185
185
  transition: color 0.2s ease-in-out;
186
186
  &:hover {
187
- color: #25292f;
187
+ color: ${({ theme }) => theme.palette.text.primary};
188
188
  }
189
189
  }
190
190
  /* columns 布局 */
@@ -48,11 +48,11 @@ const Root = styled("div")`
48
48
  justify-content: center;
49
49
  gap: 20px;
50
50
  a {
51
- color: ${(props) => props.theme.palette.grey[400]};
51
+ color: ${(props) => props.theme.palette.grey[500]};
52
52
  text-decoration: none;
53
53
  transition: color 0.2s ease-in-out;
54
54
  &:hover {
55
- color: #25292f;
55
+ color: ${({ theme }) => theme.palette.text.primary};
56
56
  }
57
57
  }
58
58
  ${(props) => props.theme.breakpoints.down("md")} {
@@ -3,7 +3,7 @@ import { useMemo } from "react";
3
3
  import { useMemoizedFn } from "ahooks";
4
4
  import { withErrorBoundary } from "react-error-boundary";
5
5
  import { ErrorFallback } from "@arcblock/ux/lib/ErrorBoundary";
6
- import { styled } from "@arcblock/ux/lib/Theme";
6
+ import { styled, useTheme, deepmerge, ThemeProvider } from "@arcblock/ux/lib/Theme";
7
7
  import { ResponsiveHeader } from "@arcblock/ux/lib/Header";
8
8
  import NavMenu, { Products } from "@arcblock/ux/lib/NavMenu";
9
9
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
@@ -13,7 +13,6 @@ import omit from "lodash/omit";
13
13
  import isFinite from "lodash/isFinite";
14
14
  import clsx from "clsx";
15
15
  import Icon from "../Icon/index.js";
16
- import OverridableThemeProvider from "../common/overridable-theme-provider.js";
17
16
  import { mapRecursive, flatRecursive, matchPaths } from "../utils.js";
18
17
  import { publicPath, formatBlockletInfo, getLocalizedNavigation } from "../blocklets.js";
19
18
  import HeaderAddons from "../common/header-addons.js";
@@ -76,6 +75,7 @@ function Header({
76
75
  ...rest
77
76
  }) {
78
77
  useWalletHiddenTopbar();
78
+ const parentTheme = useTheme();
79
79
  const { locale } = useLocaleContext() || {};
80
80
  const t = useMemoizedFn((key, data = {}) => {
81
81
  return translate(translations, key, locale, "en", data);
@@ -90,10 +90,11 @@ function Header({
90
90
  }
91
91
  }, [meta]);
92
92
  const isMobileDevice = useMobile();
93
+ const mergeTheme = useMemo(() => deepmerge(parentTheme, themeOverrides), [parentTheme, themeOverrides]);
93
94
  if (!formattedBlocklet.appName) {
94
95
  return null;
95
96
  }
96
- const { appLogo, appLogoRect, theme } = formattedBlocklet;
97
+ const { appLogo, appLogoRect } = formattedBlocklet;
97
98
  const navigation = getLocalizedNavigation(formattedBlocklet?.navigation?.header, locale);
98
99
  const parsedNavigation = parseNavigation(navigation);
99
100
  const { navItems, activeId } = parsedNavigation;
@@ -118,7 +119,7 @@ function Header({
118
119
  }
119
120
  )
120
121
  );
121
- return /* @__PURE__ */ jsx(OverridableThemeProvider, { theme: themeOverrides, children: /* @__PURE__ */ jsx(
122
+ return /* @__PURE__ */ jsx(ThemeProvider, { theme: mergeTheme, children: /* @__PURE__ */ jsx(
122
123
  StyledUxHeader,
123
124
  {
124
125
  homeLink,
@@ -126,7 +127,7 @@ function Header({
126
127
  addons: headerAddons,
127
128
  ...omit(rest, ["bordered"]),
128
129
  $bordered: rest?.bordered,
129
- $bgcolor: theme?.background?.header,
130
+ $bgcolor: mergeTheme.palette.background.default,
130
131
  className: clsx("blocklet__header", rest.className),
131
132
  children: hideNavMenu || !navItems?.length ? null : ({ isMobile }) => (
132
133
  // @ts-ignore
@@ -138,7 +139,8 @@ function Header({
138
139
  items: navItems,
139
140
  className: "header-nav",
140
141
  bgColor: "transparent",
141
- textColor: "#777"
142
+ textColor: mergeTheme.palette.grey[500],
143
+ activeTextColor: mergeTheme.palette.text.primary
142
144
  }
143
145
  )
144
146
  )
@@ -147,8 +149,6 @@ function Header({
147
149
  }
148
150
  const StyledUxHeader = styled(ResponsiveHeader)`
149
151
  ${({ $bgcolor }) => `background-color: ${$bgcolor || "#fff"};`}
150
- font-family: Inter, Avenir, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
151
- 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
152
152
  .header-logo {
153
153
  min-width: 44px;
154
154
  }
@@ -19,6 +19,7 @@ interface EditableFieldProps {
19
19
  verified?: boolean;
20
20
  errorMsg?: string;
21
21
  canEdit?: boolean;
22
+ hidePreview?: boolean;
22
23
  renderValue?: (value: string) => React.ReactNode;
23
24
  }
24
25
  export declare const commonInputStyle: {
@@ -47,5 +48,5 @@ export declare const inputFieldStyle: {
47
48
  borderColor: string;
48
49
  };
49
50
  };
50
- declare function EditableField({ value, onChange, onValueValidate, errorMsg, editable, component, placeholder, rows, maxLength, icon, label, children, tooltip, inline, style, verified, canEdit, renderValue, disabled, }: EditableFieldProps): JSX.Element | null;
51
+ declare function EditableField({ value, onChange, onValueValidate, errorMsg, editable, component, placeholder, rows, maxLength, icon, label, children, tooltip, inline, style, verified, canEdit, renderValue, disabled, hidePreview, }: EditableFieldProps): JSX.Element | null;
51
52
  export default EditableField;
@@ -55,7 +55,8 @@ function EditableField({
55
55
  verified = false,
56
56
  canEdit = true,
57
57
  renderValue,
58
- disabled = false
58
+ disabled = false,
59
+ hidePreview = false
59
60
  }) {
60
61
  const { locale } = useLocaleContext();
61
62
  const t = useMemoizedFn((key, data = {}) => {
@@ -145,7 +146,7 @@ function EditableField({
145
146
  return null;
146
147
  }
147
148
  if (!editable) {
148
- return value ? /* @__PURE__ */ jsx(
149
+ return value && !hidePreview ? /* @__PURE__ */ jsx(
149
150
  Tooltip,
150
151
  {
151
152
  open: Boolean(mousePosition),
@@ -22,12 +22,12 @@ import isEmail from "validator/lib/isEmail";
22
22
  import isPostalCode from "validator/lib/isPostalCode";
23
23
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
24
24
  import { useBrowser } from "@arcblock/react-hooks";
25
+ import Clock from "@arcblock/ux/lib/UserCard/Content/clock";
25
26
  import { translations } from "../../libs/locales.js";
26
27
  import EditableField, { commonInputStyle, inputFieldStyle } from "../editable-field.js";
27
28
  import { LinkPreviewInput } from "./link-preview-input.js";
28
29
  import { currentTimezone, defaultButtonStyle, primaryButtonStyle } from "./utils.js";
29
30
  import { TimezoneSelect } from "./timezone-select.js";
30
- import Clock from "./clock.js";
31
31
  import AddressEditor from "./address.js";
32
32
  const LocationIcon = lazy(() => import("@arcblock/icons/lib/Location"));
33
33
  const TimezoneIcon = lazy(() => import("@arcblock/icons/lib/Timezone"));
@@ -363,6 +363,7 @@ export default function UserMetadataComponent({
363
363
  {
364
364
  value: metadata.email ?? user?.email ?? "",
365
365
  editable: editing,
366
+ hidePreview: !isMyself,
366
367
  disabled: user?.sourceProvider === LOGIN_PROVIDER.EMAIL,
367
368
  canEdit: !emailVerified,
368
369
  verified: emailVerified,
@@ -384,7 +385,7 @@ export default function UserMetadataComponent({
384
385
  ] }),
385
386
  onChange: (value) => onChange(value, "email"),
386
387
  errorMsg: validateMsg.email,
387
- renderValue: (value) => /* @__PURE__ */ jsx(
388
+ renderValue: (value) => isMyself ? /* @__PURE__ */ jsx(
388
389
  "a",
389
390
  {
390
391
  href: `mailto:${value}`,
@@ -394,7 +395,7 @@ export default function UserMetadataComponent({
394
395
  },
395
396
  children: value
396
397
  }
397
- ),
398
+ ) : null,
398
399
  onValueValidate: (value) => {
399
400
  let msg = "";
400
401
  if (!!value && !isEmail(value)) {
@@ -409,6 +410,7 @@ export default function UserMetadataComponent({
409
410
  {
410
411
  value: phoneValue.phone,
411
412
  editable: editing,
413
+ hidePreview: !isMyself,
412
414
  canEdit: !phoneVerified,
413
415
  verified: phoneVerified,
414
416
  placeholder: "Phone",
@@ -416,7 +418,7 @@ export default function UserMetadataComponent({
416
418
  onChange: (value) => onChange(value, "phone"),
417
419
  label: t("profile.phone"),
418
420
  renderValue: () => {
419
- return /* @__PURE__ */ jsx(PhoneInput, { value: phoneValue, preview: true });
421
+ return isMyself ? /* @__PURE__ */ jsx(PhoneInput, { value: phoneValue, preview: true }) : null;
420
422
  },
421
423
  children: /* @__PURE__ */ jsx(
422
424
  PhoneInput,
@@ -2,7 +2,6 @@ import { jsx } from "react/jsx-runtime";
2
2
  import Badge from "@mui/material/Badge";
3
3
  import PropTypes from "prop-types";
4
4
  import { useCallback, useEffect } from "react";
5
- import { temp as colors } from "@arcblock/ux/lib/Colors";
6
5
  import { IconButton } from "@mui/material";
7
6
  import { useSnackbar } from "notistack";
8
7
  import NotificationsOutlinedIcon from "@arcblock/icons/lib/Notification";
@@ -89,7 +88,6 @@ export default function NotificationAddon({ session = {} }) {
89
88
  variant: "outlined",
90
89
  href: viewAllUrl,
91
90
  sx: {
92
- borderColor: colors.lineBorderStrong,
93
91
  "&:hover": {
94
92
  borderRadius: "50%"
95
93
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/ui-react",
3
- "version": "2.12.63",
3
+ "version": "2.12.70",
4
4
  "description": "Some useful front-end web components that can be used in Blocklets.",
5
5
  "keywords": [
6
6
  "react",
@@ -34,8 +34,8 @@
34
34
  "dependencies": {
35
35
  "@abtnode/constant": "^1.16.41",
36
36
  "@abtnode/util": "^1.16.41",
37
- "@arcblock/bridge": "^2.12.63",
38
- "@arcblock/react-hooks": "^2.12.63",
37
+ "@arcblock/bridge": "^2.12.70",
38
+ "@arcblock/react-hooks": "^2.12.70",
39
39
  "@arcblock/ws": "^1.19.19",
40
40
  "@blocklet/constant": "^1.16.42-beta-20250408-072924-4b6a877a",
41
41
  "@blocklet/did-space-react": "^1.0.43",
@@ -94,5 +94,5 @@
94
94
  "jest": "^29.7.0",
95
95
  "unbuild": "^2.0.0"
96
96
  },
97
- "gitHead": "47f8ac34d544cb600e084266ceb722989476f287"
97
+ "gitHead": "89e31e2599d8ab7462307771239849a6edd19d7f"
98
98
  }
@@ -1,13 +1,12 @@
1
1
  import { useMemo } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { styled } from '@arcblock/ux/lib/Theme';
3
+ import { styled, useTheme, deepmerge, ThemeProvider } from '@arcblock/ux/lib/Theme';
4
4
  import { withErrorBoundary } from 'react-error-boundary';
5
5
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
6
6
  import { ErrorFallback } from '@arcblock/ux/lib/ErrorBoundary';
7
7
  import { temp as colors } from '@arcblock/ux/lib/Colors';
8
8
  import omit from 'lodash/omit';
9
9
 
10
- import OverridableThemeProvider from '../common/overridable-theme-provider';
11
10
  import InternalFooter from './internal-footer';
12
11
  import { mapRecursive } from '../utils';
13
12
  import { formatBlockletInfo, getLocalizedNavigation } from '../blocklets';
@@ -19,6 +18,7 @@ import withHideWhenEmbed from '../libs/with-hide-when-embed';
19
18
  */
20
19
  function Footer({ meta, theme: themeOverrides, ...rest }) {
21
20
  const { locale } = useLocaleContext() || {};
21
+ const parentTheme = useTheme();
22
22
  const formattedBlocklet = useMemo(() => {
23
23
  const blocklet = Object.assign({}, window.blocklet, meta);
24
24
  try {
@@ -28,12 +28,14 @@ function Footer({ meta, theme: themeOverrides, ...rest }) {
28
28
  return blocklet;
29
29
  }
30
30
  }, [meta]);
31
+ const mergeTheme = useMemo(() => deepmerge(parentTheme, themeOverrides), [parentTheme, themeOverrides]);
31
32
 
32
33
  if (!formattedBlocklet.appName) {
33
34
  return null;
34
35
  }
35
36
 
36
- const { appLogo, appLogoRect, appName, appDescription, description, theme, copyright } = formattedBlocklet;
37
+ const { appLogo, appLogoRect, appName, appDescription, description, copyright } = formattedBlocklet;
38
+ const $bgColor = mergeTheme.palette.background.default;
37
39
 
38
40
  const localized = {
39
41
  footerNav: getLocalizedNavigation(formattedBlocklet?.navigation?.footer, locale) || [],
@@ -62,14 +64,9 @@ function Footer({ meta, theme: themeOverrides, ...rest }) {
62
64
  };
63
65
 
64
66
  return (
65
- <OverridableThemeProvider theme={themeOverrides}>
66
- <StyledInternalFooter
67
- {...props}
68
- {...omit(rest, ['bordered'])}
69
- $bordered={rest?.bordered}
70
- $bgcolor={theme?.background?.footer}
71
- />
72
- </OverridableThemeProvider>
67
+ <ThemeProvider theme={mergeTheme}>
68
+ <StyledInternalFooter {...props} {...omit(rest, ['bordered'])} $bordered={rest?.bordered} $bgcolor={$bgColor} />
69
+ </ThemeProvider>
73
70
  );
74
71
  }
75
72
 
@@ -88,8 +85,6 @@ const StyledInternalFooter = styled(InternalFooter)`
88
85
  ${({ $bordered }) => `border-top: 1px solid ${$bordered ? colors.strokeSep : '#eee'};`}
89
86
  color: ${(props) => props.theme.palette.grey[600]};
90
87
  ${({ $bgcolor }) => $bgcolor && `background-color: ${$bgcolor};`}
91
- font-family: Inter, Avenir, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
92
- 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
93
88
  `;
94
89
 
95
90
  export default withErrorBoundary(withHideWhenEmbed(Footer), {
@@ -167,7 +167,7 @@ Links.defaultProps = {
167
167
 
168
168
  const Root = styled('div')`
169
169
  overflow: hidden;
170
- color: #9397a1;
170
+ color: ${({ theme }) => theme.palette.grey[500]};
171
171
  .footer-links-inner {
172
172
  display: flex;
173
173
  justify-content: space-between;
@@ -198,8 +198,8 @@ const Root = styled('div')`
198
198
  font-size: 14px;
199
199
  &--new::after {
200
200
  content: 'New';
201
- color: #4672ea;
202
- background-color: #e1e8fb;
201
+ color: ${({ theme }) => theme.palette.info.main};
202
+ background-color: ${({ theme }) => theme.palette.info.light};
203
203
  padding: 1px 8px;
204
204
  border-radius: 10px/50%;
205
205
  margin-left: 8px;
@@ -209,7 +209,7 @@ const Root = styled('div')`
209
209
  .footer-links-group {
210
210
  > .footer-links-item {
211
211
  font-weight: 600;
212
- color: #25292f;
212
+ color: ${({ theme }) => theme.palette.text.primary};
213
213
  }
214
214
  .footer-links-sub {
215
215
  margin-top: 8px;
@@ -223,7 +223,7 @@ const Root = styled('div')`
223
223
  text-decoration: none;
224
224
  transition: color 0.2s ease-in-out;
225
225
  &:hover {
226
- color: #25292f;
226
+ color: ${({ theme }) => theme.palette.text.primary};
227
227
  }
228
228
  }
229
229
  /* columns 布局 */
@@ -52,11 +52,11 @@ const Root = styled('div')`
52
52
  justify-content: center;
53
53
  gap: 20px;
54
54
  a {
55
- color: ${(props) => props.theme.palette.grey[400]};
55
+ color: ${(props) => props.theme.palette.grey[500]};
56
56
  text-decoration: none;
57
57
  transition: color 0.2s ease-in-out;
58
58
  &:hover {
59
- color: #25292f;
59
+ color: ${({ theme }) => theme.palette.text.primary};
60
60
  }
61
61
  }
62
62
  ${(props) => props.theme.breakpoints.down('md')} {
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
2
2
  import { useMemoizedFn } from 'ahooks';
3
3
  import { withErrorBoundary } from 'react-error-boundary';
4
4
  import { ErrorFallback } from '@arcblock/ux/lib/ErrorBoundary';
5
- import { styled } from '@arcblock/ux/lib/Theme';
5
+ import { styled, useTheme, deepmerge, ThemeProvider } from '@arcblock/ux/lib/Theme';
6
6
  import { ResponsiveHeader } from '@arcblock/ux/lib/Header';
7
7
  import NavMenu, { Products } from '@arcblock/ux/lib/NavMenu';
8
8
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
@@ -14,7 +14,6 @@ import type { BoxProps, Breakpoint } from '@mui/material';
14
14
  import clsx from 'clsx';
15
15
 
16
16
  import Icon from '../Icon';
17
- import OverridableThemeProvider from '../common/overridable-theme-provider';
18
17
  import { mapRecursive, flatRecursive, matchPaths } from '../utils';
19
18
  import { publicPath, formatBlockletInfo, getLocalizedNavigation } from '../blocklets';
20
19
  import HeaderAddons from '../common/header-addons';
@@ -115,6 +114,7 @@ function Header({
115
114
  ...rest
116
115
  }: HeaderProps & Omit<BoxProps, keyof HeaderProps>) {
117
116
  useWalletHiddenTopbar();
117
+ const parentTheme = useTheme();
118
118
  const { locale } = useLocaleContext() || {};
119
119
  const t = useMemoizedFn((key, data = {}) => {
120
120
  return translate(translations, key, locale, 'en', data);
@@ -129,11 +129,12 @@ function Header({
129
129
  }
130
130
  }, [meta]);
131
131
  const isMobileDevice = useMobile();
132
+ const mergeTheme = useMemo(() => deepmerge(parentTheme, themeOverrides), [parentTheme, themeOverrides]);
132
133
 
133
134
  if (!formattedBlocklet.appName) {
134
135
  return null;
135
136
  }
136
- const { appLogo, appLogoRect, theme } = formattedBlocklet;
137
+ const { appLogo, appLogoRect } = formattedBlocklet;
137
138
  const navigation = getLocalizedNavigation(formattedBlocklet?.navigation?.header, locale);
138
139
  const parsedNavigation = parseNavigation(navigation);
139
140
  const { navItems, activeId } = parsedNavigation;
@@ -164,7 +165,7 @@ function Header({
164
165
  );
165
166
 
166
167
  return (
167
- <OverridableThemeProvider theme={themeOverrides}>
168
+ <ThemeProvider theme={mergeTheme}>
168
169
  <StyledUxHeader
169
170
  // @ts-ignore
170
171
  homeLink={homeLink}
@@ -172,7 +173,7 @@ function Header({
172
173
  addons={headerAddons}
173
174
  {...omit(rest, ['bordered'])}
174
175
  $bordered={rest?.bordered}
175
- $bgcolor={theme?.background?.header}
176
+ $bgcolor={mergeTheme.palette.background.default}
176
177
  className={clsx('blocklet__header', rest.className)}>
177
178
  {/* blocklet.yml 没有配置 navigation 时, 则为 children 传入 null, 此时 ResponsiveHeader 会渲染普通的不带 menu 的 Header */}
178
179
  {hideNavMenu || !navItems?.length
@@ -185,11 +186,12 @@ function Header({
185
186
  items={navItems}
186
187
  className="header-nav"
187
188
  bgColor="transparent"
188
- textColor="#777"
189
+ textColor={mergeTheme.palette.grey[500]}
190
+ activeTextColor={mergeTheme.palette.text.primary}
189
191
  />
190
192
  )}
191
193
  </StyledUxHeader>
192
- </OverridableThemeProvider>
194
+ </ThemeProvider>
193
195
  );
194
196
  }
195
197
 
@@ -200,8 +202,6 @@ type StyledUxHeaderProps = {
200
202
 
201
203
  const StyledUxHeader = styled(ResponsiveHeader)<StyledUxHeaderProps>`
202
204
  ${({ $bgcolor }) => `background-color: ${$bgcolor || '#fff'};`}
203
- font-family: Inter, Avenir, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
204
- 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
205
205
  .header-logo {
206
206
  min-width: 44px;
207
207
  }
@@ -27,6 +27,7 @@ interface EditableFieldProps {
27
27
  verified?: boolean;
28
28
  errorMsg?: string;
29
29
  canEdit?: boolean;
30
+ hidePreview?: boolean;
30
31
  renderValue?: (value: string) => React.ReactNode;
31
32
  }
32
33
 
@@ -78,6 +79,7 @@ function EditableField({
78
79
  canEdit = true,
79
80
  renderValue,
80
81
  disabled = false,
82
+ hidePreview = false,
81
83
  }: EditableFieldProps) {
82
84
  const { locale } = useLocaleContext();
83
85
  const t = useMemoizedFn((key, data = {}) => {
@@ -174,7 +176,7 @@ function EditableField({
174
176
  }
175
177
 
176
178
  if (!editable) {
177
- return value ? (
179
+ return value && !hidePreview ? (
178
180
  <Tooltip
179
181
  open={Boolean(mousePosition)}
180
182
  title={tooltip}
@@ -25,6 +25,7 @@ import isEmail from 'validator/lib/isEmail';
25
25
  import isPostalCode from 'validator/lib/isPostalCode';
26
26
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
27
27
  import { useBrowser } from '@arcblock/react-hooks';
28
+ import Clock from '@arcblock/ux/lib/UserCard/Content/clock';
28
29
 
29
30
  import { translations } from '../../libs/locales';
30
31
  import type { User, UserAddress, UserMetadata, UserPhoneProps } from '../../../@types';
@@ -32,7 +33,6 @@ import EditableField, { commonInputStyle, inputFieldStyle } from '../editable-fi
32
33
  import { LinkPreviewInput } from './link-preview-input';
33
34
  import { currentTimezone, defaultButtonStyle, primaryButtonStyle } from './utils';
34
35
  import { TimezoneSelect } from './timezone-select';
35
- import Clock from './clock';
36
36
  import AddressEditor from './address';
37
37
 
38
38
  const LocationIcon = lazy(() => import('@arcblock/icons/lib/Location'));
@@ -429,6 +429,7 @@ export default function UserMetadataComponent({
429
429
  <EditableField
430
430
  value={metadata.email ?? user?.email ?? ''}
431
431
  editable={editing}
432
+ hidePreview={!isMyself}
432
433
  disabled={user?.sourceProvider === LOGIN_PROVIDER.EMAIL}
433
434
  canEdit={!emailVerified}
434
435
  verified={emailVerified}
@@ -453,16 +454,18 @@ export default function UserMetadataComponent({
453
454
  }
454
455
  onChange={(value) => onChange(value, 'email')}
455
456
  errorMsg={validateMsg.email}
456
- renderValue={(value) => (
457
- <a
458
- href={`mailto:${value}`}
459
- style={{
460
- color: 'inherit',
461
- textDecoration: 'none',
462
- }}>
463
- {value}
464
- </a>
465
- )}
457
+ renderValue={(value) =>
458
+ isMyself ? (
459
+ <a
460
+ href={`mailto:${value}`}
461
+ style={{
462
+ color: 'inherit',
463
+ textDecoration: 'none',
464
+ }}>
465
+ {value}
466
+ </a>
467
+ ) : null
468
+ }
466
469
  onValueValidate={(value) => {
467
470
  let msg = '';
468
471
  if (!!value && !isEmail(value)) {
@@ -475,6 +478,7 @@ export default function UserMetadataComponent({
475
478
  <EditableField
476
479
  value={phoneValue.phone}
477
480
  editable={editing}
481
+ hidePreview={!isMyself}
478
482
  canEdit={!phoneVerified}
479
483
  verified={phoneVerified}
480
484
  placeholder="Phone"
@@ -482,7 +486,7 @@ export default function UserMetadataComponent({
482
486
  onChange={(value) => onChange(value, 'phone')}
483
487
  label={t('profile.phone')}
484
488
  renderValue={() => {
485
- return <PhoneInput value={phoneValue} preview />;
489
+ return isMyself ? <PhoneInput value={phoneValue} preview /> : null;
486
490
  }}>
487
491
  <PhoneInput
488
492
  variant="outlined"
@@ -1,7 +1,6 @@
1
1
  import Badge from '@mui/material/Badge';
2
2
  import PropTypes from 'prop-types';
3
3
  import { useCallback, useEffect } from 'react';
4
- import { temp as colors } from '@arcblock/ux/lib/Colors';
5
4
  import { IconButton } from '@mui/material';
6
5
  import { useSnackbar } from 'notistack';
7
6
  // eslint-disable-next-line import/no-extraneous-dependencies
@@ -105,7 +104,6 @@ export default function NotificationAddon({ session = {} }) {
105
104
  variant="outlined"
106
105
  href={viewAllUrl}
107
106
  sx={{
108
- borderColor: colors.lineBorderStrong,
109
107
  '&:hover': {
110
108
  borderRadius: '50%',
111
109
  },
@@ -1,3 +0,0 @@
1
- export default function Clock({ value }: {
2
- value: string;
3
- }): import("react").JSX.Element;
@@ -1,50 +0,0 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
2
- import Tooltip from "@mui/material/Tooltip";
3
- import Typography from "@mui/material/Typography";
4
- import Box from "@mui/material/Box";
5
- import { translate } from "@arcblock/ux/lib/Locale/util";
6
- import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
7
- import { useMemoizedFn } from "ahooks";
8
- import { translations } from "../../libs/locales.js";
9
- import { useClock } from "../../../hooks/use-clock.js";
10
- export default function Clock({ value }) {
11
- const { locale } = useLocaleContext();
12
- const t = useMemoizedFn((key, data = {}) => {
13
- return translate(translations, key, locale, "en", data);
14
- });
15
- const timeInfo = useClock(value, locale);
16
- return /* @__PURE__ */ jsxs(
17
- Box,
18
- {
19
- sx: {
20
- whiteSpace: "nowrap",
21
- overflow: "hidden",
22
- textOverflow: "ellipsis"
23
- },
24
- display: "flex",
25
- alignItems: "center",
26
- gap: 1,
27
- children: [
28
- /* @__PURE__ */ jsx(Typography, { children: value }),
29
- /* @__PURE__ */ jsx(
30
- Tooltip,
31
- {
32
- title: /* @__PURE__ */ jsxs("span", { children: [
33
- t("profile.localTime"),
34
- " ",
35
- timeInfo.fullDateTime
36
- ] }),
37
- placement: "top",
38
- arrow: true,
39
- children: /* @__PURE__ */ jsxs(Typography, { component: "span", fontSize: 14, children: [
40
- "(",
41
- locale === "zh" ? `${t(`profile.timezonePhase.${timeInfo.phase}`)} ` : "",
42
- timeInfo.formattedTime,
43
- ")"
44
- ] })
45
- }
46
- )
47
- ]
48
- }
49
- );
50
- }
@@ -1,9 +0,0 @@
1
- import 'dayjs/locale/zh-cn';
2
- import 'dayjs/locale/en';
3
- export declare function useClock(timezone?: any, locale?: string): {
4
- formattedTime: any;
5
- fullDateTime: any;
6
- phase: string;
7
- icon: string;
8
- rawTime: any;
9
- };
@@ -1,49 +0,0 @@
1
- import { useState, useEffect, useCallback } from "react";
2
- import dayjs from "dayjs";
3
- import utc from "dayjs/plugin/utc";
4
- import timezonePlugin from "dayjs/plugin/timezone";
5
- import localizedFormat from "dayjs/plugin/localizedFormat";
6
- import { formatToDatetime } from "@arcblock/ux/lib/Util";
7
- import "dayjs/locale/zh-cn";
8
- import "dayjs/locale/en";
9
- dayjs.extend(utc);
10
- dayjs.extend(timezonePlugin);
11
- dayjs.extend(localizedFormat);
12
- const currentTimezone = dayjs.tz.guess();
13
- const getTimePhase = (hour) => {
14
- if (hour >= 0 && hour < 6)
15
- return { phase: "dawn", icon: "\u{1F312}" };
16
- if (hour >= 6 && hour < 12)
17
- return { phase: "morning", icon: "\u{1F31E}" };
18
- if (hour >= 12 && hour < 18)
19
- return { phase: "afternoon", icon: "\u{1F31E}" };
20
- return { phase: "night", icon: "\u{1F312}" };
21
- };
22
- export function useClock(timezone = currentTimezone, locale = "zh") {
23
- const getLatestTimeInfo = useCallback(() => {
24
- const currentLocale = locale === "zh" ? "zh-cn" : "en";
25
- const localeOption = locale === "zh" ? "zh-cn" : "en-us";
26
- dayjs.locale(currentLocale);
27
- const now = dayjs().tz(timezone);
28
- const hour = now.hour();
29
- const { phase, icon } = getTimePhase(hour);
30
- return {
31
- formattedTime: now.format("LT"),
32
- fullDateTime: formatToDatetime(now.toDate(), { tz: timezone, locale: localeOption }),
33
- phase,
34
- icon,
35
- rawTime: now
36
- };
37
- }, [timezone, locale]);
38
- const [timeInfo, setTimeInfo] = useState(getLatestTimeInfo());
39
- useEffect(() => {
40
- setTimeInfo(getLatestTimeInfo());
41
- const timerId = setInterval(() => {
42
- setTimeInfo(getLatestTimeInfo());
43
- }, 6e3);
44
- return () => {
45
- clearInterval(timerId);
46
- };
47
- }, [timezone, locale, getLatestTimeInfo]);
48
- return timeInfo;
49
- }
@@ -1,43 +0,0 @@
1
- import Tooltip from '@mui/material/Tooltip';
2
- import Typography from '@mui/material/Typography';
3
- import Box from '@mui/material/Box';
4
- import { translate } from '@arcblock/ux/lib/Locale/util';
5
- import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
6
- import { useMemoizedFn } from 'ahooks';
7
- import { translations } from '../../libs/locales';
8
- import { useClock } from '../../../hooks/use-clock';
9
-
10
- export default function Clock({ value }: { value: string }) {
11
- const { locale } = useLocaleContext();
12
- const t = useMemoizedFn((key, data = {}) => {
13
- return translate(translations, key, locale, 'en', data);
14
- });
15
- const timeInfo = useClock(value, locale);
16
-
17
- return (
18
- <Box
19
- sx={{
20
- whiteSpace: 'nowrap',
21
- overflow: 'hidden',
22
- textOverflow: 'ellipsis',
23
- }}
24
- display="flex"
25
- alignItems="center"
26
- gap={1}>
27
- <Typography>{value}</Typography>
28
- <Tooltip
29
- title={
30
- <span>
31
- {t('profile.localTime')} {timeInfo.fullDateTime}
32
- </span>
33
- }
34
- placement="top"
35
- arrow>
36
- <Typography component="span" fontSize={14}>
37
- ({locale === 'zh' ? `${t(`profile.timezonePhase.${timeInfo.phase}`)} ` : ''}
38
- {timeInfo.formattedTime})
39
- </Typography>
40
- </Tooltip>
41
- </Box>
42
- );
43
- }
@@ -1,61 +0,0 @@
1
- import { useState, useEffect, useCallback } from 'react';
2
- import dayjs from 'dayjs';
3
- import utc from 'dayjs/plugin/utc';
4
- import timezonePlugin from 'dayjs/plugin/timezone';
5
- import localizedFormat from 'dayjs/plugin/localizedFormat';
6
- import { formatToDatetime } from '@arcblock/ux/lib/Util';
7
- import 'dayjs/locale/zh-cn';
8
- import 'dayjs/locale/en';
9
-
10
- dayjs.extend(utc);
11
- dayjs.extend(timezonePlugin);
12
- dayjs.extend(localizedFormat);
13
-
14
- const currentTimezone = dayjs.tz.guess();
15
-
16
- // 获取时间段
17
- const getTimePhase = (hour: number) => {
18
- if (hour >= 0 && hour < 6) return { phase: 'dawn', icon: '🌒' }; // 凌晨 00:00-05:59
19
- if (hour >= 6 && hour < 12) return { phase: 'morning', icon: '🌞' }; // 上午 06:00-11:59
20
- if (hour >= 12 && hour < 18) return { phase: 'afternoon', icon: '🌞' }; // 下午 12:00-17:59
21
- return { phase: 'night', icon: '🌒' }; // 晚上 18:00-23:59
22
- };
23
-
24
- export function useClock(timezone = currentTimezone, locale = 'zh') {
25
- const getLatestTimeInfo = useCallback(() => {
26
- const currentLocale = locale === 'zh' ? 'zh-cn' : 'en';
27
- const localeOption = locale === 'zh' ? 'zh-cn' : 'en-us';
28
- dayjs.locale(currentLocale);
29
-
30
- const now = dayjs().tz(timezone);
31
- const hour = now.hour();
32
- const { phase, icon } = getTimePhase(hour);
33
-
34
- return {
35
- formattedTime: now.format('LT'),
36
- fullDateTime: formatToDatetime(now.toDate(), { tz: timezone, locale: localeOption }),
37
- phase,
38
- icon,
39
- rawTime: now,
40
- };
41
- }, [timezone, locale]);
42
-
43
- const [timeInfo, setTimeInfo] = useState(getLatestTimeInfo());
44
-
45
- useEffect(() => {
46
- // 立即更新一次,确保初始状态是最新的
47
- setTimeInfo(getLatestTimeInfo());
48
-
49
- // 设置定时器
50
- const timerId = setInterval(() => {
51
- setTimeInfo(getLatestTimeInfo());
52
- }, 6000);
53
-
54
- // 清理函数
55
- return () => {
56
- clearInterval(timerId);
57
- };
58
- }, [timezone, locale, getLatestTimeInfo]);
59
-
60
- return timeInfo;
61
- }