fix: text color inversion on dark theme(#79)

This commit is contained in:
oiov
2025-11-11 19:10:55 +08:00
parent ffa1f03b52
commit 33f7b3f653
14 changed files with 184 additions and 2563 deletions

View File

@@ -308,8 +308,8 @@ export default function AppConfigs({}: {}) {
{configs && (
<div className="flex w-full items-start gap-2">
<Textarea
className="h-16 max-h-32 min-h-9 resize-y bg-white"
placeholder="Support HTML format, such as <div>info</div>"
className="h-16 max-h-32 min-h-9 resize-y bg-white dark:bg-neutral-700"
placeholder="Support HTML format, such as <div class='text-red-500'>Info</div>"
rows={5}
// defaultValue={configs.system_notification}
value={notification}

View File

@@ -5,6 +5,7 @@ import { constructMetadata } from "@/lib/utils";
import { DeleteAccountSection } from "@/components/dashboard/delete-account";
import { DashboardHeader } from "@/components/dashboard/header";
import { UserApiKeyForm } from "@/components/forms/user-api-key-form";
import { UserEmailForm } from "@/components/forms/user-email-form";
import { UserNameForm } from "@/components/forms/user-name-form";
import { UserPasswordForm } from "@/components/forms/user-password-form";
import { UserRoleForm } from "@/components/forms/user-role-form";
@@ -26,6 +27,14 @@ export default async function SettingsPage() {
text="Manage account and website settings"
/>
<div className="divide-y divide-muted pb-10">
<UserEmailForm
user={{
id: user.id,
name: user.name || "",
email: user.email || "",
emailVerified: user.emailVerified,
}}
/>
<UserNameForm user={{ id: user.id, name: user.name || "" }} />
{user.role === "ADMIN" && (
<UserRoleForm user={{ id: user.id, role: user.role }} />

View File

@@ -14,6 +14,7 @@ declare module "next-auth" {
team: string;
active: number;
apiKey: string;
emailVerified: Date;
} & DefaultSession["user"];
}
}
@@ -49,6 +50,7 @@ export const {
session.user.active = token.active as number;
session.user.team = token.team as string;
session.user.apiKey = token.apiKey as string;
session.user.emailVerified = token.emailVerified as Date;
}
return session;
@@ -67,6 +69,7 @@ export const {
token.active = dbUser.active;
token.team = dbUser.team || "free";
token.apiKey = dbUser.apiKey;
token.emailVerified = dbUser.emailVerified;
return token;
},

View File

@@ -0,0 +1,130 @@
"use client";
import { useState, useTransition } from "react";
import { updateUserName } from "@/actions/update-user-name";
import { zodResolver } from "@hookform/resolvers/zod";
import { User } from "@prisma/client";
import { format } from "date-fns";
import { useSession } from "next-auth/react";
import { useTranslations } from "next-intl";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { formatDate, formatTime } from "@/lib/utils";
import { userEmailSchema } from "@/lib/validations/user";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { SectionColumns } from "@/components/dashboard/section-columns";
import { Icons } from "@/components/shared/icons";
import { TimeAgoIntl } from "../shared/time-ago";
import { Badge } from "../ui/badge";
interface UserEmailFormProps {
user: Pick<User, "id" | "name" | "email" | "emailVerified">;
}
export type FormData = {
email: string;
};
export function UserEmailForm({ user }: UserEmailFormProps) {
const { update } = useSession();
const [updated, setUpdated] = useState(false);
const [isPending, startTransition] = useTransition();
const updateUserNameWithId = updateUserName.bind(null, user.id);
const userEmailVerified = new Date(user.emailVerified || "").getSeconds();
const t = useTranslations("Setting");
const checkUpdate = (value) => {
setUpdated(user.email !== value);
};
const {
handleSubmit,
register,
formState: { errors },
} = useForm<FormData>({
resolver: zodResolver(userEmailSchema),
defaultValues: {
email: user?.email || "",
},
});
const onSubmit = handleSubmit((data) => {
startTransition(async () => {
const { status } = await updateUserNameWithId(data);
if (status !== "success") {
toast.error("Something went wrong.", {
description: "Your name was not updated. Please try again.",
});
} else {
await update();
setUpdated(false);
toast.success("Your name has been updated.");
}
});
});
return (
<form onSubmit={onSubmit}>
<SectionColumns
title={t("Your Account Email")}
description={t("Bind your account to an email address")}
>
<div className="flex w-full items-center gap-2">
<Label className="sr-only" htmlFor="email">
{t("Email")}
</Label>
<Input
id="email"
className="flex-1"
size={32}
{...register("email")}
disabled
/>
<Button
type="submit"
variant={updated ? "blue" : "disable"}
disabled={isPending || !updated}
className="h-9 w-[67px] shrink-0 px-0 sm:w-[130px]"
>
{isPending ? (
<Icons.spinner className="size-4 animate-spin" />
) : (
<p>{t("Save")}</p>
)}
</Button>
</div>
<div className="mt-2 text-xs font-semibold">
{user.emailVerified ? (
<Badge variant={"default"}>
<Icons.shieldUser className="mr-1 size-4 text-green-600" />
{t("Verified at {date}", {
date: format(
new Date(user.emailVerified),
"MM/dd/yyyy HH:mm:ss",
),
})}
</Badge>
) : (
<div className="flex items-center gap-2">
<Badge variant={"secondary"}>{t("Unverified")}</Badge>
{/* <p className="ml-2">点击验证</p> */}
</div>
)}
</div>
<div className="flex flex-col justify-between p-1">
{errors?.email && (
<p className="pb-0.5 text-[13px] text-red-600">
{errors.email.message}
</p>
)}
</div>
</SectionColumns>
</form>
);
}

View File

@@ -120,6 +120,24 @@ export const Icons = {
layers: Layers,
databaseZap: DatabaseZap,
boxes: Boxes,
shieldUser: ({ ...props }: LucideProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
{...props}
>
<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" />
<path d="M6.376 18.91a6 6 0 0 1 11.249.003" />
<circle cx="12" cy="11" r="4" />
</svg>
),
cloudUpload: ({ ...props }: LucideProps) => (
<svg
role="presentation"

View File

@@ -5,6 +5,10 @@ export const userNameSchema = z.object({
name: z.string().min(3).max(32),
});
export const userEmailSchema = z.object({
email: z.string().min(3).email(),
});
export const userRoleSchema = z.object({
role: z.nativeEnum(UserRole),
});

View File

@@ -778,6 +778,11 @@
"Forward Email Targets": "Forward Email Targets",
"Set forward email address targets, split by comma if more than one, such as: 1@a-com,2@b-com, Only works when email forwarding is enabled": "Set forward email address targets, split by comma if more than one, such as: 1@a.com,2@b.com, Only works when email forwarding is enabled",
"Email Forward White List": "Email Forward White List",
"Set email forward white list, split by comma, such as: a-wrdo,b-wrdo": "Set email forward white list (Catch-All and Email Forwarding are both enabled), split by comma, such as: a@wr.do,b@wr.do; If not set, will forward all emails"
"Set email forward white list, split by comma, such as: a-wrdo,b-wrdo": "Set email forward white list (Catch-All and Email Forwarding are both enabled), split by comma, such as: a@wr.do,b@wr.do; If not set, will forward all emails",
"Your Account Email": "Your Account Email",
"Bind your account to an email address": "Bind your account to an email address",
"Email": "Email",
"Unverified": "Unverified",
"Verified at {date}": "Verified at {date}"
}
}

View File

@@ -777,6 +777,11 @@
"Forward Email Targets": "目标收件箱",
"Set forward email address targets, split by comma if more than one, such as: 1@a-com,2@b-com, Only works when email forwarding is enabled": "设置转发目标邮箱多个邮件地址请用逗号分隔例如1@a.com,2@b.com仅在启用邮件转发时生效",
"Email Forward White List": "转发邮箱白名单",
"Set email forward white list, split by comma, such as: a-wrdo,b-wrdo": "设置转发邮箱白名单(Catch-All 和 Email Forwarding 同时生效)多个邮箱地址请用逗号分隔例如a@wr.do,b@wr.do; 若不设置,则转发所有邮件"
"Set email forward white list, split by comma, such as: a-wrdo,b-wrdo": "设置转发邮箱白名单(Catch-All 和 Email Forwarding 同时生效)多个邮箱地址请用逗号分隔例如a@wr.do,b@wr.do; 若不设置,则转发所有邮件",
"Your Account Email": "账户邮箱",
"Bind your account to an email address": "为你的账户绑定一个邮箱",
"Unverified": "未验证邮箱",
"Email": "邮箱",
"Verified at {date}": "已于 {date} 验证"
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,6 +4,10 @@ import { JWT } from "next-auth/jwt";
export type ExtendedUser = User & {
role: UserRole;
team: string;
active: number;
apiKey: string;
emailVerified: string;
};
declare module "next-auth/jwt" {