import { useStorage } from "@tensamin/storage/context"; import { Avatar, AvatarFallback, AvatarImage, Button, cn, Input, useIsMobile, } from "@tensamin/ui"; import { useUser, type User } from "@tensamin/user/context"; import { useEffect, useRef, useState } from "react"; import MDInput from "@tensamin/markdown/input"; import { mtp } from "@tensamin/shared/data"; import { useMTP } from "@tensamin/mtp"; import { Check } from "lucide-react"; async function prepImage( file: File, size = 300, quality = 0.8, ): Promise { const bitmap = await createImageBitmap(file); const canvas = document.createElement("canvas"); canvas.width = size; canvas.height = size; const ctx = canvas.getContext("2d"); if (!ctx) throw new Error("Could not get canvas context"); const scale = Math.max(size / bitmap.width, size / bitmap.height); const width = bitmap.width * scale; const height = bitmap.height * scale; const x = (size - width) / 2; const y = (size - height) / 2; ctx.drawImage(bitmap, x, y, width, height); return canvas.toDataURL("image/webp", quality); } export default function Page() { const { get } = useUser(); const { load } = useStorage(); const { send } = useMTP(); const [currentUser, setCurrentUser] = useState(null); const [draftUser, setDraftUser] = useState>({}); const [errorMessage, setErrorMessage] = useState(""); const [saveSucceeded, setSaveSucceeded] = useState(false); const avatarUploadRef = useRef(null); const draftInitializedRef = useRef(false); const effectiveAvatar = draftUser.Avatar === "none" ? undefined : draftUser.Avatar; const updateDraftUser = ( updater: (previous: Partial) => Partial, ) => { setSaveSucceeded(false); setErrorMessage(""); setDraftUser(updater); }; useEffect(() => { const fetchUser = async () => { const user = await get(await load("user_id")); setCurrentUser(user); }; fetchUser(); }, [load, get]); useEffect(() => { if (!currentUser || draftInitializedRef.current) return; setDraftUser(currentUser); draftInitializedRef.current = true; }, [currentUser]); const handleAvatarUpload = async (file: File) => { const final = await prepImage(file); updateDraftUser((prev) => ({ ...prev, avatar: final })); if (avatarUploadRef.current) { avatarUploadRef.current.value = ""; } }; const isMobile = useIsMobile(); return currentUser ? ( <> e.target.files?.[0] && handleAvatarUpload(e.target.files[0]) } type="file" />
{draftUser.Display?.slice(0, 2).toUpperCase() || currentUser.Display.slice(0, 2).toUpperCase()}

Avatar

GIFs are supported in decentralised mode or with Tensamin Premium.
Maximum file size is 16mb.

updateDraftUser((prev) => ({ ...prev, display: event.target.value, })) } placeholder="Display Name" value={draftUser.Display || ""} /> updateDraftUser((prev) => ({ ...prev, username: event.target.value, })) } placeholder="Username" value={draftUser.Username || ""} /> updateDraftUser((prev) => ({ ...prev, about: value })) } value={draftUser.About || ""} /> {errorMessage && (

{errorMessage}

)}
) : (

Loading...

); }