mirror of
https://github.com/docmost/docmost.git
synced 2025-11-10 06:42:06 +10:00
Update custom avatar
This commit is contained in:
@ -11,7 +11,7 @@ import { currentUserAtom } from "@/features/user/atoms/current-user-atom.ts";
|
||||
import { Link } from "react-router-dom";
|
||||
import APP_ROUTE from "@/lib/app-route.ts";
|
||||
import useAuth from "@/features/auth/hooks/use-auth.ts";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar.tsx";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
|
||||
export default function TopMenu() {
|
||||
const [currentUser] = useAtom(currentUserAtom);
|
||||
@ -29,12 +29,11 @@ export default function TopMenu() {
|
||||
<Menu.Target>
|
||||
<UnstyledButton>
|
||||
<Group gap={7} wrap={"nowrap"}>
|
||||
<UserAvatar
|
||||
<CustomAvatar
|
||||
avatarUrl={workspace.logo}
|
||||
name={workspace.name}
|
||||
radius="xl"
|
||||
color="blue"
|
||||
size={20}
|
||||
variant="filled"
|
||||
size="sm"
|
||||
/>
|
||||
<Text fw={500} size="sm" lh={1} mr={3}>
|
||||
{workspace.name}
|
||||
@ -80,8 +79,7 @@ export default function TopMenu() {
|
||||
<Menu.Label>Account</Menu.Label>
|
||||
<Menu.Item component={Link} to={APP_ROUTE.SETTINGS.ACCOUNT.PROFILE}>
|
||||
<Group wrap={"nowrap"}>
|
||||
<UserAvatar
|
||||
radius="xl"
|
||||
<CustomAvatar
|
||||
size={"sm"}
|
||||
avatarUrl={user.avatarUrl}
|
||||
name={user.name}
|
||||
|
||||
32
apps/client/src/components/ui/custom-avatar.tsx
Normal file
32
apps/client/src/components/ui/custom-avatar.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import React from "react";
|
||||
import { Avatar } from "@mantine/core";
|
||||
import { getAvatarUrl } from "@/lib/config.ts";
|
||||
|
||||
interface CustomAvatarProps {
|
||||
avatarUrl: string;
|
||||
name: string;
|
||||
color?: string;
|
||||
size?: string | number;
|
||||
radius?: string | number;
|
||||
variant?: string;
|
||||
style?: any;
|
||||
component?: any;
|
||||
}
|
||||
|
||||
export const CustomAvatar = React.forwardRef<
|
||||
HTMLInputElement,
|
||||
CustomAvatarProps
|
||||
>(({ avatarUrl, name, ...props }: CustomAvatarProps, ref) => {
|
||||
const avatarLink = getAvatarUrl(avatarUrl);
|
||||
|
||||
return (
|
||||
<Avatar
|
||||
ref={ref}
|
||||
src={avatarLink}
|
||||
name={name}
|
||||
alt={name}
|
||||
color="initials"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@ -1,35 +0,0 @@
|
||||
import React, { useRef } from "react";
|
||||
import { Avatar } from "@mantine/core";
|
||||
import { getAvatarUrl } from "@/lib/config.ts";
|
||||
|
||||
interface UserAvatarProps {
|
||||
avatarUrl: string;
|
||||
name: string;
|
||||
color?: string;
|
||||
size?: string | number;
|
||||
radius?: string | number;
|
||||
style?: any;
|
||||
component?: any;
|
||||
}
|
||||
|
||||
export const UserAvatar = React.forwardRef<HTMLInputElement, UserAvatarProps>(
|
||||
({ avatarUrl, name, ...props }: UserAvatarProps, ref) => {
|
||||
const avatar = getAvatarUrl(avatarUrl);
|
||||
|
||||
const getInitials = (name: string) => {
|
||||
const names = name?.split(" ");
|
||||
return names
|
||||
?.slice(0, 2)
|
||||
.map((n) => n[0])
|
||||
.join("");
|
||||
};
|
||||
|
||||
return avatar ? (
|
||||
<Avatar ref={ref} src={avatar} alt={name} radius="xl" {...props} />
|
||||
) : (
|
||||
<Avatar ref={ref} {...props}>
|
||||
{getInitials(name)}
|
||||
</Avatar>
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -13,7 +13,7 @@ import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
|
||||
import { useCreateCommentMutation } from "@/features/comment/queries/comment-query";
|
||||
import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom";
|
||||
import { useEditor } from "@tiptap/react";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar.tsx";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
|
||||
interface CommentDialogProps {
|
||||
editor: ReturnType<typeof useEditor>;
|
||||
@ -94,8 +94,7 @@ function CommentDialog({ editor, pageId }: CommentDialogProps) {
|
||||
>
|
||||
<Stack gap={2}>
|
||||
<Group>
|
||||
<UserAvatar
|
||||
color="blue"
|
||||
<CustomAvatar
|
||||
size="sm"
|
||||
avatarUrl={currentUser.user.avatarUrl}
|
||||
name={currentUser.user.name}
|
||||
|
||||
@ -13,7 +13,7 @@ import {
|
||||
useUpdateCommentMutation,
|
||||
} from "@/features/comment/queries/comment-query";
|
||||
import { IComment } from "@/features/comment/types/comment.types";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
import { currentUserAtom } from "@/features/user/atoms/current-user-atom.ts";
|
||||
|
||||
interface CommentListItemProps {
|
||||
@ -63,8 +63,7 @@ function CommentListItem({ comment }: CommentListItemProps) {
|
||||
return (
|
||||
<Box ref={ref} pb="xs">
|
||||
<Group>
|
||||
<UserAvatar
|
||||
color="blue"
|
||||
<CustomAvatar
|
||||
size="sm"
|
||||
avatarUrl={comment.creator.avatarUrl}
|
||||
name={comment.creator.name}
|
||||
|
||||
@ -7,7 +7,7 @@ import { useParams } from "react-router-dom";
|
||||
import React from "react";
|
||||
import { IconDots } from "@tabler/icons-react";
|
||||
import { modals } from "@mantine/modals";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar.tsx";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
import useUserRole from "@/hooks/use-user-role.tsx";
|
||||
|
||||
export default function GroupMembersList() {
|
||||
@ -56,7 +56,7 @@ export default function GroupMembersList() {
|
||||
<Table.Tr key={index}>
|
||||
<Table.Td>
|
||||
<Group gap="sm">
|
||||
<UserAvatar avatarUrl={user.avatarUrl} name={user.name} />
|
||||
<CustomAvatar avatarUrl={user.avatarUrl} name={user.name} />
|
||||
<div>
|
||||
<Text fz="sm" fw={500}>
|
||||
{user.name}
|
||||
|
||||
@ -3,7 +3,7 @@ import { useDebouncedValue } from "@mantine/hooks";
|
||||
import { useWorkspaceMembersQuery } from "@/features/workspace/queries/workspace-query.ts";
|
||||
import { IUser } from "@/features/user/types/user.types.ts";
|
||||
import { Group, MultiSelect, MultiSelectProps, Text } from "@mantine/core";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar.tsx";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
|
||||
interface MultiUserSelectProps {
|
||||
onChange: (value: string[]) => void;
|
||||
@ -14,11 +14,10 @@ const renderMultiSelectOption: MultiSelectProps["renderOption"] = ({
|
||||
option,
|
||||
}) => (
|
||||
<Group gap="sm">
|
||||
<UserAvatar
|
||||
<CustomAvatar
|
||||
avatarUrl={option?.["avatarUrl"]}
|
||||
name={option.label}
|
||||
size={36}
|
||||
radius="xl"
|
||||
/>
|
||||
<div>
|
||||
<Text size="sm">{option.label}</Text>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Text, Group, UnstyledButton } from "@mantine/core";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
import { formattedDate } from "@/lib/time";
|
||||
import classes from "./history.module.css";
|
||||
import clsx from "clsx";
|
||||
@ -25,8 +25,7 @@ function HistoryItem({ historyItem, onSelect, isActive }: HistoryItemProps) {
|
||||
|
||||
<div style={{ flex: 1 }}>
|
||||
<Group gap={4} wrap="nowrap">
|
||||
<UserAvatar
|
||||
color="blue"
|
||||
<CustomAvatar
|
||||
size="sm"
|
||||
avatarUrl={historyItem.lastUpdatedBy.avatarUrl}
|
||||
name={historyItem.lastUpdatedBy.name}
|
||||
|
||||
@ -3,7 +3,7 @@ import { useDebouncedValue } from "@mantine/hooks";
|
||||
import { Group, MultiSelect, MultiSelectProps, Text } from "@mantine/core";
|
||||
import { IGroup } from "@/features/group/types/group.types.ts";
|
||||
import { useSearchSuggestionsQuery } from "@/features/search/queries/search-query.ts";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar.tsx";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
import { IUser } from "@/features/user/types/user.types.ts";
|
||||
import { IconGroupCircle } from "@/components/icons/icon-people-circle.tsx";
|
||||
|
||||
@ -16,7 +16,7 @@ const renderMultiSelectOption: MultiSelectProps["renderOption"] = ({
|
||||
}) => (
|
||||
<Group gap="sm">
|
||||
{option["type"] === "user" && (
|
||||
<UserAvatar
|
||||
<CustomAvatar
|
||||
avatarUrl={option["avatarUrl"]}
|
||||
size={20}
|
||||
name={option.label}
|
||||
|
||||
@ -20,9 +20,13 @@ export default function SpaceGrid() {
|
||||
withBorder
|
||||
>
|
||||
<Card.Section className={classes.cardSection} h={40}></Card.Section>
|
||||
<Avatar variant="filled" size="md" mt={rem(-20)}>
|
||||
{space.name.charAt(0).toUpperCase()}
|
||||
</Avatar>
|
||||
<Avatar
|
||||
name={space.name}
|
||||
color="initials"
|
||||
variant="filled"
|
||||
size="md"
|
||||
mt={rem(-20)}
|
||||
/>
|
||||
|
||||
<Text fz="md" fw={500} mt="xs" className={classes.title}>
|
||||
{space.name}
|
||||
|
||||
@ -34,9 +34,11 @@ export default function SpaceList() {
|
||||
>
|
||||
<Table.Td>
|
||||
<Group gap="sm">
|
||||
<Avatar color="gray" radius="xl">
|
||||
{space.name.charAt(0).toUpperCase()}
|
||||
</Avatar>
|
||||
<Avatar
|
||||
color="initials"
|
||||
variant="filled"
|
||||
name={space.name}
|
||||
/>
|
||||
<div>
|
||||
<Text fz="sm" fw={500}>
|
||||
{space.name}
|
||||
|
||||
@ -3,7 +3,7 @@ import { useParams } from "react-router-dom";
|
||||
import React from "react";
|
||||
import { IconDots } from "@tabler/icons-react";
|
||||
import { modals } from "@mantine/modals";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar.tsx";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
import {
|
||||
useChangeSpaceMemberRoleMutation,
|
||||
useRemoveSpaceMemberMutation,
|
||||
@ -109,7 +109,7 @@ export default function SpaceMembersList({
|
||||
<Table.Td>
|
||||
<Group gap="sm">
|
||||
{member.type === "user" && (
|
||||
<UserAvatar
|
||||
<CustomAvatar
|
||||
avatarUrl={member?.avatarUrl}
|
||||
name={member.name}
|
||||
/>
|
||||
|
||||
@ -2,7 +2,7 @@ import { focusAtom } from "jotai-optics";
|
||||
import { currentUserAtom } from "@/features/user/atoms/current-user-atom.ts";
|
||||
import { useState } from "react";
|
||||
import { useAtom } from "jotai";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar.tsx";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
import { FileButton, Tooltip } from "@mantine/core";
|
||||
import { uploadAvatar } from "@/features/user/services/user-service.ts";
|
||||
|
||||
@ -37,10 +37,9 @@ export default function AccountAvatar() {
|
||||
<FileButton onChange={handleFileChange} accept="image/png,image/jpeg">
|
||||
{(props) => (
|
||||
<Tooltip label="Change photo" position="bottom">
|
||||
<UserAvatar
|
||||
<CustomAvatar
|
||||
{...props}
|
||||
component="button"
|
||||
radius="xl"
|
||||
size="60px"
|
||||
avatarUrl={currentUser?.user.avatarUrl}
|
||||
name={currentUser?.user.name}
|
||||
|
||||
@ -35,7 +35,7 @@ export default function WorkspaceInvitesTable() {
|
||||
<Table.Tr key={index}>
|
||||
<Table.Td>
|
||||
<Group gap="sm">
|
||||
<Avatar src={invitation.email} />
|
||||
<Avatar name={invitation.email} color="initials" />
|
||||
<div>
|
||||
<Text fz="sm" fw={500}>
|
||||
{invitation.email}
|
||||
|
||||
@ -3,7 +3,7 @@ import {
|
||||
useChangeMemberRoleMutation,
|
||||
useWorkspaceMembersQuery,
|
||||
} from "@/features/workspace/queries/workspace-query.ts";
|
||||
import { UserAvatar } from "@/components/ui/user-avatar.tsx";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
import React from "react";
|
||||
import RoleSelectMenu from "@/components/ui/role-select-menu.tsx";
|
||||
import {
|
||||
@ -51,7 +51,7 @@ export default function WorkspaceMembersTable() {
|
||||
<Table.Tr key={index}>
|
||||
<Table.Td>
|
||||
<Group gap="sm">
|
||||
<UserAvatar avatarUrl={user.avatarUrl} name={user.name} />
|
||||
<CustomAvatar avatarUrl={user.avatarUrl} name={user.name} />
|
||||
<div>
|
||||
<Text fz="sm" fw={500}>
|
||||
{user.name}
|
||||
|
||||
Reference in New Issue
Block a user