diff --git a/src/app/(site)/login/page.tsx b/src/app/(site)/login/page.tsx index 71ca3756..02dea8b8 100644 --- a/src/app/(site)/login/page.tsx +++ b/src/app/(site)/login/page.tsx @@ -5,10 +5,10 @@ import Link from "next/link"; import { getTranslations } from "next-intl/server"; import { LoginForm } from "@/components/auth/login-form"; import { Clock } from "@/components/clock"; -import { SectionCard } from "@/components/home-section"; import { LanguageSwitcher } from "@/components/language-switcher"; import { Reveal } from "@/components/motion-reveal"; import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail"; +import { SurfaceCard } from "@/components/surface-card"; import { ThemeSwitcher } from "@/components/theme-switcher"; import { cached } from "@/lib/cache"; import { db, User } from "@/lib/db"; @@ -123,13 +123,12 @@ export default async function LoginPage() {
{/* Left panel */}
-
-
+ {recentUsers.length > 0 && ( - ))}
- + )} {latestUsers.length > 0 && ( - ))}
- + )}

- - + diff --git a/src/app/(site)/me/page.tsx b/src/app/(site)/me/page.tsx index 53008c93..7aee9cca 100644 --- a/src/app/(site)/me/page.tsx +++ b/src/app/(site)/me/page.tsx @@ -254,8 +254,8 @@ export default async function MePage({ ) : null} -

- + {alertRaw ? ( -
{alertRaw}

-
+
) : null} diff --git a/src/app/(site)/page.tsx b/src/app/(site)/page.tsx index a1d9718f..3c0c0e69 100644 --- a/src/app/(site)/page.tsx +++ b/src/app/(site)/page.tsx @@ -8,10 +8,10 @@ import { AmbientOrbs } from "@/components/ambient-orbs"; import { AnimatedCounter } from "@/components/animated-counter"; import { HomeLoginForm } from "@/components/auth/home-login-form"; import { Clock } from "@/components/clock"; -import { SectionCard } from "@/components/home-section"; import { LanguageSwitcher } from "@/components/language-switcher"; import { Reveal } from "@/components/motion-reveal"; import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail"; +import { SurfaceCard } from "@/components/surface-card"; import { ThemeSwitcher } from "@/components/theme-switcher"; import { TypewriterText } from "@/components/typewriter-text"; import { auth } from "@/lib/auth"; @@ -321,15 +321,9 @@ export default async function Home() { icon: "/assets/images/icons/catalog.png", }, ].map((s) => ( -
-
+ ))} @@ -373,7 +367,7 @@ export default async function Home() {
{/* Left: Login & Register */} - - + -
+ Register -
+ {latestUsers.length > 0 && ( - ))}
- + )} {/* Right: News */} - )} - + {/* ── Online users ── */} {recentUsers.length > 0 && ( - ))} - + )} @@ -601,7 +589,7 @@ export default async function Home() { {/* ── Recent photos ── */} {recentPhotos.length > 0 && ( - @@ -627,7 +615,7 @@ export default async function Home() { ))} - + )} diff --git a/src/app/(site)/register/page.tsx b/src/app/(site)/register/page.tsx index 713bac2e..38595044 100644 --- a/src/app/(site)/register/page.tsx +++ b/src/app/(site)/register/page.tsx @@ -5,10 +5,10 @@ import Link from "next/link"; import { getTranslations } from "next-intl/server"; import { RegisterForm } from "@/components/auth/register-form"; import { Clock } from "@/components/clock"; -import { SectionCard } from "@/components/home-section"; import { LanguageSwitcher } from "@/components/language-switcher"; import { Reveal } from "@/components/motion-reveal"; import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail"; +import { SurfaceCard } from "@/components/surface-card"; import { ThemeSwitcher } from "@/components/theme-switcher"; import { cached } from "@/lib/cache"; import { db, User } from "@/lib/db"; @@ -125,13 +125,12 @@ export default async function RegisterPage() {
{/* Left panel */}
-
-
+ {recentUsers.length > 0 && ( - ))}
- + )} {latestUsers.length > 0 && ( - ))}
- + )}

- - + diff --git a/src/app/(site)/settings/page.tsx b/src/app/(site)/settings/page.tsx index b4071599..1fb926f3 100644 --- a/src/app/(site)/settings/page.tsx +++ b/src/app/(site)/settings/page.tsx @@ -4,8 +4,8 @@ import Link from "next/link"; import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { updateMotto } from "@/actions/user-settings"; -import { SectionCard } from "@/components/home-section"; import { Reveal } from "@/components/motion-reveal"; +import { SurfaceCard } from "@/components/surface-card"; import { auth } from "@/lib/auth"; import { db, User } from "@/lib/db"; import { avatarImageUrl } from "@/lib/format"; @@ -47,8 +47,8 @@ export default async function SettingsPage() {

{/* Header */} -
- + {/* Profile card */} - - + {/* Motto form */} - - + {/* Security card */} - {t("twoFactorLink")} - + {/* Sessions link */} - -
-
-
- -
-
- - Session Management - -

- View active sessions and sign out everywhere -

-
-
- + +
- → - -
+
+
+ +
+
+ + Session Management + +

+ View active sessions and sign out everywhere +

+
+
+ + → + +
+
diff --git a/src/components/home-section.tsx b/src/components/home-section.tsx deleted file mode 100644 index 644904c0..00000000 --- a/src/components/home-section.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import Image from "next/image"; -import Link from "next/link"; -import type { ReactNode } from "react"; - -interface SectionCardProps { - title: string; - icon?: string; - actionHref?: string; - actionLabel?: string; - children: ReactNode; - className?: string; - bodyClassName?: string; -} - -/** - * Consistent, restrained panel used across the home page. Replaces the - * per-section neon gradients with a single calm surface + hairline divider so - * the page reads as professional rather than game-like. - */ -export function SectionCard({ - title, - icon, - actionHref, - actionLabel, - children, - className, - bodyClassName, -}: SectionCardProps) { - return ( -
-
-
- {icon && ( - - )} -

- {title} -

-
- {actionHref && actionLabel && ( - - {actionLabel} - - )} -
-
{children}
-
- ); -} diff --git a/src/components/surface-card.tsx b/src/components/surface-card.tsx index 631bda20..6782784f 100644 --- a/src/components/surface-card.tsx +++ b/src/components/surface-card.tsx @@ -1,22 +1,48 @@ +import Image from "next/image"; +import Link from "next/link"; import type { CSSProperties, ReactNode } from "react"; const CARD_BORDER = "color-mix(in srgb, var(--color-text-muted) 12%, transparent)"; +const CARD_DIVIDER = + "color-mix(in srgb, var(--color-text-muted) 8%, transparent)"; +const CARD_HEADER_BG = + "color-mix(in srgb, var(--color-primary) 10%, var(--color-surface))"; -/** - * Public-site surface card. Mirrors the CSS .content-card / SectionCard visual - * language (--radius-lg corners, --shadow-card, hairline border) so every page - * that opts out of ContentCard still shares one consistent component. - */ -export function SurfaceCard({ - className = "", - style, - children, -}: { +export interface SurfaceCardProps { + children: ReactNode; + /** Optional header title. */ + title?: string; + /** Optional header icon (image URL). */ + icon?: string; + /** Optional header action link. */ + actionHref?: string; + actionLabel?: string; + /** Class for the body wrapper (only used when a header is present). */ + bodyClassName?: string; className?: string; style?: CSSProperties; - children: ReactNode; -}) { +} + +/** + * The single public-site card component. Mirrors the CSS `.content-card` visual + * language (--radius-lg corners, --shadow-card, hairline border). Pass `title` + * / `icon` / `actionHref` to render a section header, exactly like the old + * a card header. Without a header, children render directly so callers control + * padding via `className`. + */ +export function SurfaceCard({ + children, + title, + icon, + actionHref, + actionLabel, + bodyClassName, + className = "", + style, +}: SurfaceCardProps) { + const hasHeader = Boolean(title || icon || (actionHref && actionLabel)); + return (
- {children} + {hasHeader && ( +
+
+ {icon && ( + + )} + {title && ( +

+ {title} +

+ )} +
+ {actionHref && actionLabel && ( + + {actionLabel} + + )} +
+ )} + {hasHeader ? ( +
{children}
+ ) : ( + children + )}
); } - -/** Padded body for a SurfaceCard. Override padding via className. */ -export function SurfaceCardBody({ - className = "p-5", - children, -}: { - className?: string; - children: ReactNode; -}) { - return
{children}
; -}