chore: refactor dialog components to simplify header structure

- Removed unnecessary button and icon from dialog headers in AboutDialog, ChangePasswordDialog, CreateAccessTokenDialog, CreateUserDialog, EditUserinfoDialog, and GenerateQRCodeDialog.
- Updated dialog titles to be more straightforward by directly displaying the title text.
- Simplified close button handling in ChangePasswordDialog, EditUserinfoDialog, and GenerateQRCodeDialog by directly using the onClose prop.
- Enhanced Dropdown component to manage its open state internally.
This commit is contained in:
Johnny
2025-12-21 21:22:10 +08:00
parent 347532ff75
commit 73d83de323
8 changed files with 16 additions and 2057 deletions
File diff suppressed because it is too large Load Diff
+1 -8
View File
@@ -1,7 +1,5 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import Icon from "./Icon";
interface Props { interface Props {
onClose: () => void; onClose: () => void;
@@ -15,12 +13,7 @@ const AboutDialog: React.FC<Props> = (props: Props) => {
<Dialog open={true} onOpenChange={onClose}> <Dialog open={true} onOpenChange={onClose}>
<DialogContent className="max-w-full w-80 sm:w-96"> <DialogContent className="max-w-full w-80 sm:w-96">
<DialogHeader> <DialogHeader>
<DialogTitle className="flex flex-row justify-between items-center"> <DialogTitle>{t("common.about")}</DialogTitle>
<span>{t("common.about")}</span>
<Button variant="ghost" size="icon" onClick={onClose}>
<Icon.X className="w-5 h-auto" />
</Button>
</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="space-y-4"> <div className="space-y-4">
<p> <p>
@@ -7,7 +7,6 @@ import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { useUserStore } from "@/stores"; import { useUserStore } from "@/stores";
import Icon from "./Icon";
interface Props { interface Props {
onClose: () => void; onClose: () => void;
@@ -21,10 +20,6 @@ const ChangePasswordDialog: React.FC<Props> = (props: Props) => {
const [newPasswordAgain, setNewPasswordAgain] = useState(""); const [newPasswordAgain, setNewPasswordAgain] = useState("");
const requestState = useLoading(false); const requestState = useLoading(false);
const handleCloseBtnClick = () => {
onClose();
};
const handleNewPasswordChanged = (e: React.ChangeEvent<HTMLInputElement>) => { const handleNewPasswordChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
const text = e.target.value as string; const text = e.target.value as string;
setNewPassword(text); setNewPassword(text);
@@ -69,12 +64,7 @@ const ChangePasswordDialog: React.FC<Props> = (props: Props) => {
<Dialog open={true} onOpenChange={onClose}> <Dialog open={true} onOpenChange={onClose}>
<DialogContent className="w-80 sm:max-w-md"> <DialogContent className="w-80 sm:max-w-md">
<DialogHeader> <DialogHeader>
<DialogTitle className="flex flex-row justify-between items-center"> <DialogTitle>Change Password</DialogTitle>
<span>Change Password</span>
<Button variant="ghost" size="icon" onClick={handleCloseBtnClick}>
<Icon.X className="w-5 h-auto" />
</Button>
</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
@@ -87,7 +77,7 @@ const ChangePasswordDialog: React.FC<Props> = (props: Props) => {
</div> </div>
</div> </div>
<DialogFooter> <DialogFooter>
<Button variant="outline" disabled={requestState.isLoading} onClick={handleCloseBtnClick}> <Button variant="outline" disabled={requestState.isLoading} onClick={onClose}>
{t("common.cancel")} {t("common.cancel")}
</Button> </Button>
<Button disabled={requestState.isLoading} onClick={handleSaveBtnClick}> <Button disabled={requestState.isLoading} onClick={handleSaveBtnClick}>
@@ -9,7 +9,6 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { userServiceClient } from "@/grpcweb"; import { userServiceClient } from "@/grpcweb";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { useUserStore } from "@/stores"; import { useUserStore } from "@/stores";
import Icon from "./Icon";
interface Props { interface Props {
onClose: () => void; onClose: () => void;
@@ -92,12 +91,7 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
<Dialog open={true} onOpenChange={onClose}> <Dialog open={true} onOpenChange={onClose}>
<DialogContent className="w-80 sm:max-w-md"> <DialogContent className="w-80 sm:max-w-md">
<DialogHeader> <DialogHeader>
<DialogTitle className="flex flex-row justify-between items-center"> <DialogTitle>Create Access Token</DialogTitle>
<span>Create Access Token</span>
<Button variant="ghost" size="icon" onClick={onClose}>
<Icon.X className="w-5 h-auto" />
</Button>
</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
@@ -9,8 +9,7 @@ import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { useUserStore } from "@/stores"; import { useUserStore } from "@/stores";
import { Role, User } from "@/types/proto/api/v1/user_service"; import { Role, type User } from "@/types/proto/api/v1/user_service";
import Icon from "./Icon";
interface Props { interface Props {
user?: User; user?: User;
@@ -134,12 +133,7 @@ const CreateUserDialog: React.FC<Props> = (props: Props) => {
<Dialog open={true} onOpenChange={onClose}> <Dialog open={true} onOpenChange={onClose}>
<DialogContent className="w-80 sm:w-96"> <DialogContent className="w-80 sm:w-96">
<DialogHeader> <DialogHeader>
<DialogTitle className="flex flex-row justify-between items-center"> <DialogTitle>{isCreating ? "Create User" : "Edit User"}</DialogTitle>
<span>{isCreating ? "Create User" : "Edit User"}</span>
<Button variant="ghost" size="icon" onClick={onClose}>
<Icon.X className="w-5 h-auto" />
</Button>
</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
@@ -7,7 +7,6 @@ import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { useUserStore } from "@/stores"; import { useUserStore } from "@/stores";
import Icon from "./Icon";
interface Props { interface Props {
onClose: () => void; onClose: () => void;
@@ -22,10 +21,6 @@ const EditUserinfoDialog: React.FC<Props> = (props: Props) => {
const [nickname, setNickname] = useState(currentUser.nickname); const [nickname, setNickname] = useState(currentUser.nickname);
const requestState = useLoading(false); const requestState = useLoading(false);
const handleCloseBtnClick = () => {
onClose();
};
const handleEmailChanged = (e: React.ChangeEvent<HTMLInputElement>) => { const handleEmailChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
const text = e.target.value as string; const text = e.target.value as string;
setEmail(text); setEmail(text);
@@ -65,12 +60,7 @@ const EditUserinfoDialog: React.FC<Props> = (props: Props) => {
<Dialog open={true} onOpenChange={onClose}> <Dialog open={true} onOpenChange={onClose}>
<DialogContent className="w-80 sm:max-w-md"> <DialogContent className="w-80 sm:max-w-md">
<DialogHeader> <DialogHeader>
<DialogTitle className="flex flex-row justify-between items-center"> <DialogTitle>Edit Userinfo</DialogTitle>
<span>Edit Userinfo</span>
<Button variant="ghost" size="icon" onClick={handleCloseBtnClick}>
<Icon.X className="w-5 h-auto" />
</Button>
</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
@@ -83,7 +73,7 @@ const EditUserinfoDialog: React.FC<Props> = (props: Props) => {
</div> </div>
</div> </div>
<DialogFooter> <DialogFooter>
<Button variant="outline" disabled={requestState.isLoading} onClick={handleCloseBtnClick}> <Button variant="outline" disabled={requestState.isLoading} onClick={onClose}>
{t("common.cancel")} {t("common.cancel")}
</Button> </Button>
<Button disabled={requestState.isLoading} onClick={handleSaveBtnClick}> <Button disabled={requestState.isLoading} onClick={handleSaveBtnClick}>
@@ -5,7 +5,7 @@ import { toast } from "sonner";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { absolutifyLink } from "@/helpers/utils"; import { absolutifyLink } from "@/helpers/utils";
import { Shortcut } from "@/types/proto/api/v1/shortcut_service"; import type { Shortcut } from "@/types/proto/api/v1/shortcut_service";
import Icon from "./Icon"; import Icon from "./Icon";
interface Props { interface Props {
@@ -19,10 +19,6 @@ const GenerateQRCodeDialog: React.FC<Props> = (props: Props) => {
const containerRef = useRef<HTMLDivElement | null>(null); const containerRef = useRef<HTMLDivElement | null>(null);
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`); const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
const handleCloseBtnClick = () => {
onClose();
};
const handleDownloadQRCodeClick = () => { const handleDownloadQRCodeClick = () => {
const canvas = containerRef.current?.querySelector("canvas"); const canvas = containerRef.current?.querySelector("canvas");
if (!canvas) { if (!canvas) {
@@ -34,19 +30,14 @@ const GenerateQRCodeDialog: React.FC<Props> = (props: Props) => {
link.download = `${shortcut.title || shortcut.name}-qrcode.png`; link.download = `${shortcut.title || shortcut.name}-qrcode.png`;
link.href = canvas.toDataURL(); link.href = canvas.toDataURL();
link.click(); link.click();
handleCloseBtnClick(); onClose();
}; };
return ( return (
<Dialog open={true} onOpenChange={onClose}> <Dialog open={true} onOpenChange={onClose}>
<DialogContent className="w-64 sm:max-w-xs"> <DialogContent className="w-64 sm:max-w-xs">
<DialogHeader> <DialogHeader>
<DialogTitle className="flex flex-row justify-between items-center"> <DialogTitle>QR Code</DialogTitle>
<span>QR Code</span>
<Button variant="ghost" size="icon" onClick={handleCloseBtnClick}>
<Icon.X className="w-5 h-auto" />
</Button>
</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="space-y-6"> <div className="space-y-6">
<div ref={containerRef} className="w-full flex flex-row justify-center items-center"> <div ref={containerRef} className="w-full flex flex-row justify-center items-center">
@@ -1,4 +1,4 @@
import { ReactNode } from "react"; import { ReactNode, useState } from "react";
import Icon from "@/components/Icon"; import Icon from "@/components/Icon";
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
@@ -12,8 +12,10 @@ interface Props {
const Dropdown: React.FC<Props> = (props: Props) => { const Dropdown: React.FC<Props> = (props: Props) => {
const { trigger, actions, className, actionsClassName } = props; const { trigger, actions, className, actionsClassName } = props;
const [open, setOpen] = useState(false);
return ( return (
<DropdownMenu> <DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger className={className} asChild> <DropdownMenuTrigger className={className} asChild>
{trigger ? ( {trigger ? (
<div>{trigger}</div> <div>{trigger}</div>
@@ -23,7 +25,7 @@ const Dropdown: React.FC<Props> = (props: Props) => {
</button> </button>
)} )}
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className={actionsClassName} align="end"> <DropdownMenuContent className={actionsClassName} align="end" onClick={() => setOpen(false)}>
{actions} {actions}
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>