From bcee0bbf3a8fcbc6c513671cb6b4d1cca38548e6 Mon Sep 17 00:00:00 2001 From: boojack Date: Sat, 18 Feb 2023 10:00:46 +0800 Subject: [PATCH] feat: add avatar to user in frontend (#1108) --- .../components/Settings/MyAccountSection.tsx | 8 ++- web/src/components/UpdateAccountDialog.tsx | 59 ++++++++++++++++--- web/src/components/UserAvatar.tsx | 17 ++++++ web/src/components/UserBanner.tsx | 52 +++++++++------- web/src/components/common/Dropdown.tsx | 4 +- web/src/helpers/consts.ts | 2 + web/src/helpers/utils.ts | 9 +++ web/src/less/toast.less | 3 +- web/src/less/user-banner.less | 43 -------------- web/src/locales/en.json | 1 + web/src/types/modules/user.d.ts | 2 + 11 files changed, 120 insertions(+), 80 deletions(-) create mode 100644 web/src/components/UserAvatar.tsx delete mode 100644 web/src/less/user-banner.less diff --git a/web/src/components/Settings/MyAccountSection.tsx b/web/src/components/Settings/MyAccountSection.tsx index bed7870c..487c310f 100644 --- a/web/src/components/Settings/MyAccountSection.tsx +++ b/web/src/components/Settings/MyAccountSection.tsx @@ -3,6 +3,7 @@ import { useUserStore } from "../../store/module"; import { showCommonDialog } from "../Dialog/CommonDialog"; import showChangePasswordDialog from "../ChangePasswordDialog"; import showUpdateAccountDialog from "../UpdateAccountDialog"; +import UserAvatar from "../UserAvatar"; import "../../less/settings/my-account-section.less"; const MyAccountSection = () => { @@ -30,14 +31,15 @@ const MyAccountSection = () => { <>

{t("setting.account-section.title")}

-
+
+ {user.nickname} - ({user.username}) + ({user.username})
{user.email}
-
-

- {t("common.nickname")} - (Display in the banner) -

- -

+

+
+ {t("common.avatar")} + +
+

{t("common.username")} (Using to sign in)

-

+

+ {t("common.nickname")} + (Display in the banner) +

+ +

{t("common.email")} (Optional)

-
+
{t("common.cancel")} diff --git a/web/src/components/UserAvatar.tsx b/web/src/components/UserAvatar.tsx new file mode 100644 index 00000000..f38114ae --- /dev/null +++ b/web/src/components/UserAvatar.tsx @@ -0,0 +1,17 @@ +import { MEMOS_LOGO_URL } from "../helpers/consts"; + +interface Props { + avatarUrl?: string; + className?: string; +} + +const UserAvatar = (props: Props) => { + const { avatarUrl, className } = props; + return ( +
+ +
+ ); +}; + +export default UserAvatar; diff --git a/web/src/components/UserBanner.tsx b/web/src/components/UserBanner.tsx index 74dac9a7..c4fd83c4 100644 --- a/web/src/components/UserBanner.tsx +++ b/web/src/components/UserBanner.tsx @@ -3,11 +3,10 @@ import { useTranslation } from "react-i18next"; import { useLocationStore, useMemoStore, useTagStore, useUserStore } from "../store/module"; import { getMemoStats } from "../helpers/api"; import * as utils from "../helpers/utils"; -import Icon from "./Icon"; import Dropdown from "./common/Dropdown"; import showArchivedMemoDialog from "./ArchivedMemoDialog"; import showAboutSiteDialog from "./AboutSiteDialog"; -import "../less/user-banner.less"; +import UserAvatar from "./UserAvatar"; const UserBanner = () => { const { t } = useTranslation(); @@ -65,20 +64,29 @@ const UserBanner = () => { return ( <> -
-
- {username} - {!isVisitorMode && user?.role === "HOST" ? MOD : null} -
+
} - actionsClassName="min-w-36" + className="w-full" + trigger={ +
+ + {username} + {!isVisitorMode && user?.role === "HOST" ? ( + MOD + ) : null} +
+ } + actionsClassName="min-w-[128px] max-w-full" + positionClassName="top-full mt-2" actions={ <> {!userStore.isVisitorMode() && ( <> {!userStore.isVisitorMode() && (
-
-
- {memoAmount} - {t("amount-text.memo", { count: memoAmount })} +
+
+ {memoAmount} + {t("amount-text.memo", { count: memoAmount })}
-
- {tags.length} - {t("amount-text.tag", { count: tags.length })} +
+ {tags.length} + {t("amount-text.tag", { count: tags.length })}
-
- {createdDays} - {t("amount-text.day", { count: createdDays })} +
+ {createdDays} + {t("amount-text.day", { count: createdDays })}
diff --git a/web/src/components/common/Dropdown.tsx b/web/src/components/common/Dropdown.tsx index ff5bcee7..2fbeafdb 100644 --- a/web/src/components/common/Dropdown.tsx +++ b/web/src/components/common/Dropdown.tsx @@ -44,8 +44,8 @@ const Dropdown: React.FC = (props: Props) => { )}
{actions}
diff --git a/web/src/helpers/consts.ts b/web/src/helpers/consts.ts index 21829eef..ca772065 100644 --- a/web/src/helpers/consts.ts +++ b/web/src/helpers/consts.ts @@ -23,3 +23,5 @@ export const TAB_SPACE_WIDTH = 2; // default fetch memo amount export const DEFAULT_MEMO_LIMIT = 30; + +export const MEMOS_LOGO_URL = "https://usememos.com/logo.png"; diff --git a/web/src/helpers/utils.ts b/web/src/helpers/utils.ts index 0316d774..67f7d107 100644 --- a/web/src/helpers/utils.ts +++ b/web/src/helpers/utils.ts @@ -148,3 +148,12 @@ export function getSystemColorScheme() { return "light"; } } + +export function convertFileToBase64(file: File): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result?.toString() || ""); + reader.onerror = (error) => reject(error); + }); +} diff --git a/web/src/less/toast.less b/web/src/less/toast.less index 62120100..0d8b9ae1 100644 --- a/web/src/less/toast.less +++ b/web/src/less/toast.less @@ -1,5 +1,6 @@ .toast-list-container { - @apply flex flex-col justify-start items-end fixed top-2 right-4 z-1000 max-h-full; + @apply flex flex-col justify-start items-end fixed top-2 right-4 max-h-full; + z-index: 9999; > .toast-wrapper { @apply flex flex-col justify-start items-start relative left-full invisible text-base cursor-pointer shadow-lg rounded bg-white mt-6 py-2 px-4; diff --git a/web/src/less/user-banner.less b/web/src/less/user-banner.less deleted file mode 100644 index 02aee6b9..00000000 --- a/web/src/less/user-banner.less +++ /dev/null @@ -1,43 +0,0 @@ -.user-banner-container { - @apply flex flex-row justify-between items-center relative w-full h-10 px-6 flex-nowrap mb-1 shrink-0; - - > .username-container { - @apply shrink flex flex-row justify-start items-center flex-nowrap truncate; - - > .username-text { - @apply font-bold text-lg pr-1 text-slate-800 dark:text-gray-200 cursor-pointer shrink truncate; - } - - > .tag { - @apply text-xs px-1 bg-blue-600 dark:bg-blue-800 rounded text-white dark:text-gray-200 shadow; - } - } - - > .action-btn { - @apply shrink-0 select-none border-none; - - &.menu-popup-btn { - @apply flex flex-col justify-center items-center w-9 h-10 -mr-2 cursor-pointer; - - > .icon-img { - @apply w-5 h-auto; - } - } - } -} - -.amount-text-container { - @apply flex flex-row justify-between items-start w-full px-6 select-none shrink-0 pb-4; - - > .status-text { - @apply flex flex-col justify-start items-start; - - > .amount-text { - @apply font-bold text-2xl opacity-80 leading-10 text-slate-600 dark:text-gray-300; - } - - > .type-text { - @apply text-gray-400 text-xs font-mono; - } - } -} diff --git a/web/src/locales/en.json b/web/src/locales/en.json index fd24ae78..0415fb89 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -7,6 +7,7 @@ "repeat-password": "Repeat the password", "new-password": "New password", "repeat-new-password": "Repeat the new password", + "avatar": "Avatar", "username": "Username", "nickname": "Nickname", "save": "Save", diff --git a/web/src/types/modules/user.d.ts b/web/src/types/modules/user.d.ts index 7adee787..8b273958 100644 --- a/web/src/types/modules/user.d.ts +++ b/web/src/types/modules/user.d.ts @@ -13,6 +13,7 @@ interface User { email: string; nickname: string; openId: string; + avatarUrl: string; userSettingList: UserSetting[]; setting: Setting; @@ -31,6 +32,7 @@ interface UserPatch { username?: string; email?: string; nickname?: string; + avatarUrl?: string; password?: string; resetOpenId?: boolean; }