feat(client): bio editor

Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
2026-01-20 22:08:10 +08:00
parent 4e45a9b6d0
commit 96d76b3657
4 changed files with 538 additions and 5 deletions

View File

@@ -1,12 +1,22 @@
import { Mail } from 'lucide-react';
import MDEditor from '@uiw/react-md-editor';
import { isNil } from 'lodash-es';
import { Mail, Pencil } from 'lucide-react';
import { useState } from 'react';
import Markdown from 'react-markdown';
import { toast } from 'sonner';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { useUpdateUser } from '@/hooks/data/useUpdateUser';
import { useUserInfo } from '@/hooks/data/useUserInfo';
import { base64ToUtf8 } from '@/lib/utils';
import { base64ToUtf8, utf8ToBase64 } from '@/lib/utils';
import { Button } from '../ui/button';
import { EditProfileDialog } from './edit-profile-dialog';
export function MainProfile() {
const { data: user } = useUserInfo();
const [bio, setBio] = useState<string | undefined>(() => base64ToUtf8(user.bio));
const [enableBioEdit, setEnableBioEdit] = useState(false);
const { mutateAsync } = useUpdateUser();
return (
<div className="flex flex-col justify-center w-full lg:w-auto h-full lg:h-auto lg:flex-row lg:gap-8">
<div className="flex w-full flex-row mt-2 lg:mt-0 lg:flex-col lg:w-max">
@@ -30,9 +40,42 @@ export function MainProfile() {
<EditProfileDialog />
</div>
</div>
<section className="rounded-md border border-muted w-full flex-1 lg:flex-auto min-h-72 lg:h-full mt-4 lg:mt-0 p-6 prose dark:prose-invert max-w-[1012px] self-center">
<section className="relative rounded-md border border-muted w-full flex-1 lg:flex-auto min-h-72 lg:h-full mt-4 lg:mt-0 prose dark:prose-invert max-w-[1012px] self-center">
{/* Bio */}
<Markdown>{base64ToUtf8(user.bio)}</Markdown>
{enableBioEdit
? (
<MDEditor
value={bio}
onChange={setBio}
height="100%"
/>
)
: <div className="p-6 prose dark:prose-invert"><Markdown>{bio}</Markdown></div>}
<Button
className="absolute bottom-4 right-4"
// eslint-disable-next-line ts/no-misused-promises
onClick={async () => {
if (!enableBioEdit) {
setEnableBioEdit(true);
}
else {
if (!isNil(bio)) {
try {
await mutateAsync({ bio: utf8ToBase64(bio) });
setEnableBioEdit(false);
}
catch (error) {
console.error(error);
toast.error('个人简介更新失败');
}
}
}
}}
size="icon-sm"
variant={enableBioEdit ? 'default' : 'outline'}
>
<Pencil />
</Button>
</section>
</div>
);