优化navbar链接样式
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-12-11 17:13:35 +08:00
parent e845c4abb7
commit 0d251a7e68
4 changed files with 169 additions and 20 deletions

View File

@@ -0,0 +1,120 @@
-- CreateTable
CREATE TABLE "pairs" (
"id" SERIAL NOT NULL,
"locale1" VARCHAR(10) NOT NULL,
"locale2" VARCHAR(10) NOT NULL,
"text1" TEXT NOT NULL,
"text2" TEXT NOT NULL,
"ipa1" TEXT,
"ipa2" TEXT,
"folder_id" INTEGER NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "pairs_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "folders" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "folders_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "user" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"email" TEXT NOT NULL,
"emailVerified" BOOLEAN NOT NULL DEFAULT false,
"image" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "user_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "session" (
"id" TEXT NOT NULL,
"expiresAt" TIMESTAMP(3) NOT NULL,
"token" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"ipAddress" TEXT,
"userAgent" TEXT,
"userId" TEXT NOT NULL,
CONSTRAINT "session_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "account" (
"id" TEXT NOT NULL,
"accountId" TEXT NOT NULL,
"providerId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"accessToken" TEXT,
"refreshToken" TEXT,
"idToken" TEXT,
"accessTokenExpiresAt" TIMESTAMP(3),
"refreshTokenExpiresAt" TIMESTAMP(3),
"scope" TEXT,
"password" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "account_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "verification" (
"id" TEXT NOT NULL,
"identifier" TEXT NOT NULL,
"value" TEXT NOT NULL,
"expiresAt" TIMESTAMP(3) NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "verification_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "pairs_folder_id_idx" ON "pairs"("folder_id");
-- CreateIndex
CREATE UNIQUE INDEX "pairs_folder_id_locale1_locale2_text1_key" ON "pairs"("folder_id", "locale1", "locale2", "text1");
-- CreateIndex
CREATE INDEX "folders_user_id_idx" ON "folders"("user_id");
-- CreateIndex
CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
-- CreateIndex
CREATE INDEX "session_userId_idx" ON "session"("userId");
-- CreateIndex
CREATE UNIQUE INDEX "session_token_key" ON "session"("token");
-- CreateIndex
CREATE INDEX "account_userId_idx" ON "account"("userId");
-- CreateIndex
CREATE INDEX "verification_identifier_idx" ON "verification"("identifier");
-- AddForeignKey
ALTER TABLE "pairs" ADD CONSTRAINT "pairs_folder_id_fkey" FOREIGN KEY ("folder_id") REFERENCES "folders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "folders" ADD CONSTRAINT "folders_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "session" ADD CONSTRAINT "session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "account" ADD CONSTRAINT "account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -4,6 +4,7 @@ import IMAGES from "@/config/images";
import IconClick from "./IconClick"; import IconClick from "./IconClick";
import { useState } from "react"; import { useState } from "react";
import LightButton from "./buttons/LightButton"; import LightButton from "./buttons/LightButton";
import GhostButton from "./buttons/GhostButton";
export default function LanguageSettings() { export default function LanguageSettings() {
const [showLanguageMenu, setShowLanguageMenu] = useState(false); const [showLanguageMenu, setShowLanguageMenu] = useState(false);
@@ -26,18 +27,18 @@ export default function LanguageSettings() {
{showLanguageMenu && ( {showLanguageMenu && (
<div> <div>
<div className="absolute top-10 right-0 rounded-md shadow-md flex flex-col gap-2"> <div className="absolute top-10 right-0 rounded-md shadow-md flex flex-col gap-2">
<LightButton <GhostButton
className="w-full" className="w-full"
onClick={() => setLocale("en-US")} onClick={() => setLocale("en-US")}
> >
English English
</LightButton> </GhostButton>
<LightButton <GhostButton
className="w-full" className="w-full"
onClick={() => setLocale("zh-CN")} onClick={() => setLocale("zh-CN")}
> >
</LightButton> </GhostButton>
</div> </div>
</div> </div>
)} )}

View File

@@ -6,6 +6,7 @@ import LanguageSettings from "./LanguageSettings";
import { auth } from "@/auth"; import { auth } from "@/auth";
import { headers } from "next/headers"; import { headers } from "next/headers";
import { getTranslations } from "next-intl/server"; import { getTranslations } from "next-intl/server";
import GhostButton from "./buttons/GhostButton";
export async function Navbar() { export async function Navbar() {
const t = await getTranslations("navbar"); const t = await getTranslations("navbar");
@@ -15,14 +16,14 @@ export async function Navbar() {
return ( return (
<div className="flex justify-between items-center w-full h-16 px-8 bg-[#35786f] text-white"> <div className="flex justify-between items-center w-full h-16 px-8 bg-[#35786f] text-white">
<Link href={"/"} className="text-xl border-b hidden md:block"> <GhostButton href="/" className="text-xl border-b hidden md:block">
{t("title")} {t("title")}
</Link> </GhostButton>
<Link className="block md:hidden" href={"/"}> <GhostButton className="block md:hidden" href={"/"}>
<Home /> <Home />
</Link> </GhostButton>
<div className="flex gap-4 text-xl justify-center items-center flex-wrap"> <div className="flex text-xl gap-0.5 justify-center items-center flex-wrap">
<Link <GhostButton
className="md:hidden block" className="md:hidden block"
href="https://github.com/GoddoNebianU/learn-languages" href="https://github.com/GoddoNebianU/learn-languages"
> >
@@ -32,29 +33,29 @@ export async function Navbar() {
width={24} width={24}
height={24} height={24}
/> />
</Link> </GhostButton>
<LanguageSettings /> <LanguageSettings />
<Link href="/folders" className="md:block hidden"> <GhostButton href="/folders" className="md:block hidden">
{t("folders")} {t("folders")}
</Link> </GhostButton>
<Link href="/folders" className="md:hidden block"> <GhostButton href="/folders" className="md:hidden block">
<Folder /> <Folder />
</Link> </GhostButton>
{ {
(() => { (() => {
return session && return session &&
<Link href="/profile">{t("profile")}</Link> <GhostButton href="/profile">{t("profile")}</GhostButton>
|| <Link href="/signin">{t("sign_in")}</Link>; || <GhostButton href="/signin">{t("sign_in")}</GhostButton>;
})() })()
} }
<Link href="/changelog.txt">{t("about")}</Link> <GhostButton href="/changelog.txt">{t("about")}</GhostButton>
<Link <GhostButton
className="hidden md:block" className="hidden md:block"
href="https://github.com/GoddoNebianU/learn-languages" href="https://github.com/GoddoNebianU/learn-languages"
> >
{t("sourceCode")} {t("sourceCode")}
</Link> </GhostButton>
</div> </div>
</div> </div>
); );

View File

@@ -0,0 +1,27 @@
import Link from "next/link";
export type ButtonType = "button" | "submit" | "reset" | undefined;
export default function GhostButton({
onClick,
className,
children,
type = "button",
href
}: {
onClick?: () => void;
className?: string;
children?: React.ReactNode;
type?: ButtonType;
href?: string;
}) {
return (
<button
onClick={onClick}
className={`rounded hover:bg-black/30 p-2 ${className}`}
type={type}
>
{href ? <Link href={href}>{children}</Link> : children}
</button>
);
}