diff --git a/src/app/(site)/community/page.tsx b/src/app/(site)/community/page.tsx index 0a276be5..4d5e7525 100644 --- a/src/app/(site)/community/page.tsx +++ b/src/app/(site)/community/page.tsx @@ -1,6 +1,8 @@ +import { ArrowRight, Compass, Globe, Trophy, Users } from "lucide-react"; import Link from "next/link"; import { useTranslations } from "next-intl"; -import { ContentCard } from "@/components/public/ui"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; export const metadata = { title: "Community" }; @@ -9,31 +11,43 @@ const LINKS = [ key: "rankings", href: "/rankings", icon: "πŸ†", + color: "from-yellow-500/20 to-yellow-500/5", + iconColor: "text-yellow-500", }, { key: "staff", href: "/staff", icon: "πŸ›‘οΈ", + color: "from-blue-500/20 to-blue-500/5", + iconColor: "text-blue-500", }, { key: "news", href: "/news", icon: "πŸ“°", + color: "from-green-500/20 to-green-500/5", + iconColor: "text-green-500", }, { key: "photos", href: "/photos", icon: "πŸ“Έ", + color: "from-purple-500/20 to-purple-500/5", + iconColor: "text-purple-500", }, { key: "guilds", href: "/guilds", icon: "πŸšͺ", + color: "from-orange-500/20 to-orange-500/5", + iconColor: "text-orange-500", }, { key: "leaderboards", href: "/leaderboard", icon: "πŸ“Š", + color: "from-cyan-500/20 to-cyan-500/5", + iconColor: "text-cyan-500", }, ]; @@ -41,36 +55,57 @@ export default function CommunityPage() { const t = useTranslations("pages.community"); return ( -
- +
+ {/* Header */} +
+
+ +
+
+

+ {t("title")} +

+

+ {t("subtitle")} +

+
+
-
- {LINKS.map((l) => ( + {/* Community Cards */} +
+ {LINKS.map((l, i) => ( -
- - {l.icon} - -
-

- {t(`links.${l.key}.title`)} -

-
-
-
-

- {t(`links.${l.key}.text`)} -

- {t("open")} -
+ + +
+
+ {l.icon} +
+
+ + {t(`links.${l.key}.title`)} + + + {t(`links.${l.key}.text`)} + +
+
+
+ +
+ {t("open")} + +
+
+
))}
-
+ ); } diff --git a/src/app/(site)/forgot/page.tsx b/src/app/(site)/forgot/page.tsx index eaba0224..c517184d 100644 --- a/src/app/(site)/forgot/page.tsx +++ b/src/app/(site)/forgot/page.tsx @@ -1,7 +1,8 @@ +import { KeyRound, Lock } from "lucide-react"; import Link from "next/link"; import { getTranslations } from "next-intl/server"; import { requestReset } from "@/actions/password-reset"; -import { ContentCard } from "@/components/public/ui"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; export default async function ForgotPage({ searchParams, @@ -12,36 +13,64 @@ export default async function ForgotPage({ const { sent } = await searchParams; return ( -
- - {sent ? ( -

- {t("sentNotice")} +

+
+
+
+ +
+

+ {t("title")} +

+

+ {t("subtitle")}

- ) : ( -
- - -
- )} -

- {t("backToLogin")} -

- -
+ + + + + + {sent ? "Email sent" : "Reset your password"} + + + {sent ? t("sentNotice") : "Enter your email to receive a reset link"} + + + + {sent ? ( +
+

+ {t("sentNotice")} +

+
+ ) : ( +
+
+ + +
+ +
+ )} +
+

+ + {t("backToLogin")} + +

+
+
+
+ + ); } diff --git a/src/app/(site)/settings/page.tsx b/src/app/(site)/settings/page.tsx index c22d13ad..509f6b8d 100644 --- a/src/app/(site)/settings/page.tsx +++ b/src/app/(site)/settings/page.tsx @@ -1,8 +1,10 @@ +import { KeyRound, Link2, Pencil, Shield, Smile, User } from "lucide-react"; import Link from "next/link"; import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { updateMotto } from "@/actions/user-settings"; -import { ContentCard } from "@/components/public/ui"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { auth } from "@/lib/auth"; import { avatarImageUrl } from "@/lib/format"; import { prisma } from "@/lib/prisma"; @@ -38,108 +40,125 @@ export default async function SettingsPage() { try { imagerBase = (await siteSettings.get("habbo_imaging_url", imagerBase)) ?? imagerBase; - } catch { - // fall back to the default imager base - } + } catch {} const avatar = avatarImageUrl(imagerBase, user.look, { size: "l" }); return ( -
- - - -
- {/* eslint-disable-next-line @next/next/no-img-element */} - {`${user.username} -
-

- {user.motto || {t("noMotto")}} -

-

- {user.mail || t("noEmail")} -

-
+
+ {/* Header */} +
+
+
- - - -
- -
- -
-
-
- -
- -

- {t("securityDescription")} +

+

+ {t("accountSettings")} +

+

+ {t("accountSettingsSubtitle")}

- - {t("twoFactorLink")} - - - - -

- {t("connectionsDescription")} -

- - {t("manageConnections")} - -
+
-
+ + {/* Profile Card */} + + +
+
+ {`${user.username} +
+
+ {user.username} + + {user.motto || {t("noMotto")}} + +

+ {user.mail || t("noEmail")} +

+
+
+
+ +
+
+ + +
+ +
+
+
+ + {/* Security & Connections */} +
+ + +
+
+ +
+
+ {t("securityTitle")} + {t("securitySubtitle")} +
+
+
+ +

+ {t("securityDescription")} +

+ + + +
+
+ + + +
+
+ +
+
+ {t("connectionsTitle")} + {t("connectionsSubtitle")} +
+
+
+ +

+ {t("connectionsDescription")} +

+ + + +
+
+
+ ); } diff --git a/src/app/admin/articles/page.tsx b/src/app/admin/articles/page.tsx index c9384bd5..11c6bb22 100644 --- a/src/app/admin/articles/page.tsx +++ b/src/app/admin/articles/page.tsx @@ -1,9 +1,10 @@ -import { Newspaper } from "lucide-react"; +import { Newspaper, Plus, Trash2 } from "lucide-react"; import Link from "next/link"; import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { deleteArticle } from "@/actions/admin-articles"; import { StatusCard } from "@/components/admin/dashboard"; +import { Button } from "@/components/ui/button"; import { canAccess, getAdminContext, PERMS } from "@/lib/permissions"; import { prisma } from "@/lib/prisma"; @@ -34,90 +35,113 @@ export default async function AdminArticles({ : "β€”"; return ( -
-
-
- +
+ {/* Header */} +
+
+
+ +
+
+

+ {t("title")} +

+

+ {t("subtitle")} +

+
-
-

- {t("title")} -

-

- {t("subtitle")} -

-
- - + {t("newArticle")} + +
{error ? ( -

+

Error: {error} -

+
) : null} -
+ {/* Stats */} +
} /> } />
-
-

{t("recentArticles")}

+ {/* Articles Table */} +
+

+ {t("recentArticles")} +

{articles.length === 0 ? (
{t("noArticles")}
) : ( - - - - - - - - - - - {articles.map((a) => ( - - - - - + + + + + ))} + +
{t("colTitle")}{t("colSlug")}{t("colCreated")}{t("colActions")}
- {a.title} - - {a.slug} - - {a.createdAt ? a.createdAt.toISOString().slice(0, 10) : "β€”"} - -
+
+ + + + + + + + + + + {articles.map((a) => ( + + - - ))} - -
{t("colTitle")}{t("colSlug")}{t("colCreated")}{t("colActions")}
- {t("edit")} + {a.title} -
- - -
- -
+
+ + {a.slug} + + + {a.createdAt ? a.createdAt.toISOString().slice(0, 10) : "β€”"} + +
+ + + +
+ + +
+
+
+
)}
diff --git a/src/components/auth/register-form.tsx b/src/components/auth/register-form.tsx index 0cff1cee..dfe40d33 100644 --- a/src/components/auth/register-form.tsx +++ b/src/components/auth/register-form.tsx @@ -1,10 +1,13 @@ "use client"; +import { Eye, EyeOff, Lock, Mail, User, UserPlus } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { useTranslations } from "next-intl"; import { useActionState, useState } from "react"; import { register } from "@/actions/register"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; interface RegisterFormProps { hotelName: string; @@ -17,292 +20,174 @@ export function RegisterForm({ hotelName, captcha, error }: RegisterFormProps) { const showCaptcha = captcha.provider !== "none" && !!captcha.siteKey; const [serverError, formAction, isPending] = useActionState(register, null); const [termsAccepted, setTermsAccepted] = useState(false); + const [showPassword, setShowPassword] = useState(false); return ( -
- {/* Header Banner */} -
-
-
-
-
-
-
- -
+
+
+
+
+

+ {t("title")} +

+

+ {t("subtitle", { hotel: hotelName })} +

- {/* Form */} -
- {error && ( -
- {error} -
- )} - {serverError && ( -
- {serverError} -
- )} + + + + Create your account + + + Fill in the details below to join {hotelName} + + + + + {(error || serverError) && ( +
+

+ {error || serverError} +

+
+ )} - {/* Username & Email */} -
-
-
- - -
-
-
-
- - -
-
-

- Geen e-mail? Je kunt later via Discord verifiΓ«ren. -

-
+
+
+ + +
+
+ + +
+
- {/* Password & Confirm */} -
-
-
- - -
-
-
-
- - -
-
-
- - {/* Terms */} -
-
- - - setTermsAccepted(!termsAccepted)} + {showPassword ? : } + +
+
+ + +
+
+ + {/* Terms */} +
+ + + +
+ + {/* Captcha */} + {showCaptcha && captcha.provider === "turnstile" && ( +
+
+
+ )} + {showCaptcha && captcha.provider === "recaptcha" && ( +
+
+
+ )} + +
-
+ {isPending ? ( + + + + + + {t("creatingAccount")} + + ) : t("createAccount")} + - {/* Captcha */} - {showCaptcha && captcha.provider === "turnstile" && ( -
- )} - {showCaptcha && captcha.provider === "recaptcha" && ( -
- )} - - {/* Submit */} - - -
- - {t("alreadyHaveAccount")} - -
- +
+

+ {t("alreadyHaveAccount")}{" "} + + {t("signIn")} + +

+
+ + +
); }