Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 0 additions & 27 deletions app/(app)/comments/page.tsx

This file was deleted.

5 changes: 5 additions & 0 deletions app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import NotFoundLayout from "@/components/not-found-layout";

export default async function NotFoundPage() {
return <NotFoundLayout />;
}
31 changes: 20 additions & 11 deletions components/app-navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function NavItem({ icon, label, active = false }: NavItemProps) {
active && "bg-primary text-primary-foreground",
)}
>
<div className="h-4 w-4 flex-shrink-0">{icon}</div>
<div className="h-4 w-4 shrink-0">{icon}</div>
<span className="whitespace-nowrap">{label}</span>
</Button>
);
Expand All @@ -45,7 +45,7 @@ function UserMenu() {
>
<AppAvatar src={user?.avatar} name={user?.name} className="h-4 w-4" />
<span className="whitespace-nowrap">{user?.name}</span>
<ChevronDown className="h-4 w-4 flex-shrink-0" />
<ChevronDown className="h-4 w-4 shrink-0" />
</Button>
</DropdownMenuTrigger>

Expand Down Expand Up @@ -86,7 +86,7 @@ export default function AppNavbar({ path }: { path: string }) {
`}
>
{navItems.map((item) => (
<Link href={item.pathPrefix} key={item.label}>
<Link href={"pathPrefix" in item ? item.pathPrefix : item.externalLink} key={item.label}>
<NavItem
key={item.label}
icon={item.icon}
Expand Down Expand Up @@ -137,7 +137,7 @@ export default function AppNavbar({ path }: { path: string }) {
{/* Mobile Navigation Items */}
{navItems.map((item) => (
<Link
href={item.pathPrefix}
href={"pathPrefix" in item ? item.pathPrefix : item.externalLink}
key={item.label}
onClick={() => setIsMobileMenuOpen(false)}
>
Expand All @@ -164,12 +164,21 @@ export default function AppNavbar({ path }: { path: string }) {
);
}

interface NavItem {
interface BaseNavItem {
icon: React.ReactNode;
label: string;
}

interface InternalNavItem extends BaseNavItem {
pathPrefix: string;
}

interface ExternalNavItem extends BaseNavItem {
externalLink: string;
}

type NavItem = InternalNavItem | ExternalNavItem;

const navItems: NavItem[] = [
{
icon: <BarChart3 className="h-full w-full" />,
Expand All @@ -181,21 +190,21 @@ const navItems: NavItem[] = [
label: "挑戰題目",
pathPrefix: "/challenges",
},
{
icon: <MessageSquare className="h-full w-full" />,
label: "經驗分享",
pathPrefix: "/comments",
},
{
icon: <BookOpen className="h-full w-full" />,
label: "補充資料",
pathPrefix: "/materials",
},
{
icon: <MessageSquare className="h-full w-full" />,
label: "意見分享",
externalLink: "https://community.dbplay.app/discord",
},
];

function getActiveNavItemLabel(path: string): string | null {
for (const item of navItems) {
if (path.startsWith(item.pathPrefix)) {
if ("pathPrefix" in item && path.startsWith(item.pathPrefix)) {
return item.label;
}
}
Expand Down
8 changes: 8 additions & 0 deletions components/not-found-layout/current-page.lazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"use client";

import dynamic from "next/dynamic";
import CurrentPage from "./current-page";

export const CurrentPageLazy = dynamic(() => Promise.resolve(CurrentPage), {
ssr: false,
});
9 changes: 9 additions & 0 deletions components/not-found-layout/current-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Get the current page URL.
*
* Note that this function is not SSR-friendly.
* You should import it with `current-page.lazy.tsx`, which disables SSR.
*/
export default function CurrentPage() {
return <p>網址:{window.location.href}</p>;
}
55 changes: 55 additions & 0 deletions components/not-found-layout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Logo } from "@/components/logo";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { AlertTriangle } from "lucide-react";
import Link from "next/link";
import { Suspense } from "react";
import { CurrentPageLazy } from "./current-page.lazy";

export default async function NotFoundLayout() {
return (
<div
className={`
flex min-h-svh flex-col items-center justify-center gap-6
bg-linear-to-br from-red-50 via-white to-red-100 p-6
md:p-10
`}
>
<Link
href="/"
className={`flex items-center gap-2 self-center font-medium`}
>
<div
className={`
flex size-6 items-center justify-center rounded-md
text-primary-foreground
`}
>
<Logo />
</div>
資料庫練功坊
</Link>
<Card className="min-w-md">
<CardHeader className="flex w-full flex-col items-center text-center">
<AlertTriangle className="mb-2 size-7 text-red-500" />
<CardTitle className="text-xl">找不到此頁面</CardTitle>
<CardDescription>
此頁面不存在或已經被移除。<br />請確認網址是否正確,或回到首頁。
</CardDescription>
</CardHeader>
<CardContent className="flex flex-col items-center gap-4">
<Button asChild variant="outline">
<Link href="/">回到首頁</Link>
</Button>
</CardContent>
<CardFooter
className={`justify-center text-center text-xs text-muted-foreground`}
>
<Suspense>
<CurrentPageLazy />
</Suspense>
</CardFooter>
</Card>
</div>
);
}