Skip to content

Commit 2f38761

Browse files
dcl10claude
andauthored
Feature/landing page (#45)
* Add LandingTopBar component for unauthenticated navigation Sticky header for the landing page with UoN logo, Matchboard branding, and Sign in / Sign up buttons. Omits search, Post, notifications, and avatar which are reserved for authenticated users. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add landing page with auth-aware routing and placeholder pages Landing page greets unauthenticated visitors and redirects signed-in users to /dashboard. Sign in and sign up buttons route to placeholder pages. Dashboard page guards its route and redirects unauthenticated users back to /. Closes #42 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent bd8a2eb commit 2f38761

6 files changed

Lines changed: 186 additions & 26 deletions

File tree

frontend/app/dashboard/page.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { redirect } from "next/navigation";
2+
3+
import { getSession } from "@/lib/auth";
4+
5+
export default async function DashboardPage() {
6+
const session = await getSession();
7+
if (!session) redirect("/");
8+
9+
return (
10+
<main className="flex flex-col items-center justify-center min-h-screen bg-paper px-6 text-center">
11+
<h1 className="text-3xl font-bold tracking-[-0.025em] text-ink mb-3">
12+
Your project dashboard
13+
</h1>
14+
<p className="text-[15px] text-ink-soft">
15+
Dashboard functionality coming soon.
16+
</p>
17+
</main>
18+
);
19+
}

frontend/app/page.tsx

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,39 @@
1-
import { SignInButton, SignOutButton } from '@/lib/auth/components/auth-buttons'
2-
import { getSession } from '@/lib/auth'
1+
import Link from "next/link";
2+
import { redirect } from "next/navigation";
3+
4+
import { LandingTopBar } from "@/components/shared";
5+
import { getSession } from "@/lib/auth";
36

47
export default async function HomePage() {
5-
const session = await getSession()
8+
const session = await getSession();
9+
if (session) redirect("/dashboard");
610

711
return (
8-
<main style={{ fontFamily: 'sans-serif', maxWidth: 640, margin: '4rem auto', padding: '0 1rem' }}>
9-
<h1>SkillMatrixLlm</h1>
10-
11-
{session ? (
12-
<>
13-
<p>
14-
Signed in as <strong>{session.user?.email ?? session.user?.name}</strong>
15-
</p>
16-
{session.error === 'RefreshAccessTokenError' && (
17-
<p style={{ color: 'red' }}>
18-
Your session has expired. Please sign in again.
19-
</p>
20-
)}
21-
<SignOutButton />
22-
</>
23-
) : (
24-
<>
25-
<p>You are not signed in.</p>
26-
<SignInButton />
27-
</>
28-
)}
29-
</main>
30-
)
12+
<>
13+
<LandingTopBar />
14+
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-60px)] bg-paper px-6 text-center">
15+
<h1 className="text-5xl font-bold tracking-[-0.03em] text-ink mb-4">
16+
Welcome to Matchboard
17+
</h1>
18+
<p className="text-[17px] text-ink-soft max-w-[520px] mb-10">
19+
The Digital Research Service skills-matching platform. Connect
20+
researchers with the expertise your project needs.
21+
</p>
22+
<div className="flex items-center gap-3">
23+
<Link
24+
href="/sign-in"
25+
className="inline-flex items-center gap-2 font-sans font-medium tracking-[-0.005em] rounded-sm px-[16px] py-[9px] text-[14px] bg-paper text-ink border border-[var(--border-strong)] hover:bg-portland-stone transition-colors duration-[120ms]"
26+
>
27+
Sign in
28+
</Link>
29+
<Link
30+
href="/sign-up"
31+
className="inline-flex items-center gap-2 font-sans font-medium tracking-[-0.005em] rounded-sm px-[16px] py-[9px] text-[14px] bg-nottingham-blue text-paper border border-nottingham-blue hover:bg-[var(--color-primary-deep)] transition-colors duration-[120ms]"
32+
>
33+
Sign up
34+
</Link>
35+
</div>
36+
</main>
37+
</>
38+
);
3139
}

frontend/app/sign-in/page.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import Link from "next/link";
2+
3+
export default function SignInPage() {
4+
return (
5+
<main className="flex flex-col items-center justify-center min-h-screen bg-paper px-6 text-center">
6+
<h1 className="text-3xl font-bold tracking-[-0.025em] text-ink mb-3">
7+
Sign in
8+
</h1>
9+
<p className="text-[15px] text-ink-soft mb-8">
10+
Sign-in functionality coming soon.
11+
</p>
12+
<Link
13+
href="/"
14+
className="text-[14px] font-medium text-nottingham-blue hover:underline"
15+
>
16+
Back to home
17+
</Link>
18+
</main>
19+
);
20+
}

frontend/app/sign-up/page.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import Link from "next/link";
2+
3+
export default function SignUpPage() {
4+
return (
5+
<main className="flex flex-col items-center justify-center min-h-screen bg-paper px-6 text-center">
6+
<h1 className="text-3xl font-bold tracking-[-0.025em] text-ink mb-3">
7+
Sign up
8+
</h1>
9+
<p className="text-[15px] text-ink-soft mb-8">
10+
Sign-up functionality coming soon.
11+
</p>
12+
<Link
13+
href="/"
14+
className="text-[14px] font-medium text-nottingham-blue hover:underline"
15+
>
16+
Back to home
17+
</Link>
18+
</main>
19+
);
20+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"use client";
2+
3+
import { useRouter } from "next/navigation";
4+
5+
import { Button } from "@/components/core";
6+
import { useViewport } from "@/lib/hooks/useViewport";
7+
8+
/**
9+
* Sticky navigation bar for unauthenticated visitors.
10+
* Shows the UoN logo and Matchboard branding with Sign in / Sign up buttons.
11+
* Excludes search, notifications, and user-specific controls.
12+
*/
13+
export function LandingTopBar() {
14+
const router = useRouter();
15+
const { isMobile } = useViewport();
16+
17+
return (
18+
<header
19+
className="sticky top-0 z-10 bg-paper border-b border-[var(--border)] h-[60px] flex items-center"
20+
style={{
21+
padding: isMobile ? "0 16px" : "0 28px",
22+
gap: isMobile ? 12 : 24,
23+
}}
24+
>
25+
{/* eslint-disable-next-line @next/next/no-img-element */}
26+
<img
27+
src="/uon-logo-blue.png"
28+
alt="University of Nottingham"
29+
className="object-contain"
30+
style={{ height: isMobile ? 28 : 34, width: "auto" }}
31+
/>
32+
33+
{!isMobile && (
34+
<>
35+
<span className="w-px h-7 bg-[var(--border-strong)] shrink-0" />
36+
<div className="flex items-center gap-2.5">
37+
<MatchboardMark size={22} />
38+
<span className="text-[18px] font-semibold tracking-[-0.025em] text-ink">
39+
Matchboard
40+
</span>
41+
</div>
42+
<div className="text-[13px] text-ink-soft shrink-0">
43+
Digital Research Service
44+
</div>
45+
</>
46+
)}
47+
48+
{isMobile && (
49+
<div className="flex items-center gap-1.5">
50+
<MatchboardMark size={18} />
51+
<span className="text-[16px] font-semibold tracking-[-0.025em] text-ink">
52+
Matchboard
53+
</span>
54+
</div>
55+
)}
56+
57+
<div className="flex-1" />
58+
59+
<div className="flex items-center gap-2">
60+
<Button
61+
variant="secondary"
62+
size={isMobile ? "sm" : "md"}
63+
onClick={() => router.push("/sign-in")}
64+
>
65+
Sign in
66+
</Button>
67+
<Button
68+
variant="primary"
69+
size={isMobile ? "sm" : "md"}
70+
onClick={() => router.push("/sign-up")}
71+
>
72+
Sign up
73+
</Button>
74+
</div>
75+
</header>
76+
);
77+
}
78+
79+
function MatchboardMark({ size }: { size: number }) {
80+
return (
81+
<svg
82+
xmlns="http://www.w3.org/2000/svg"
83+
viewBox="0 0 24 24"
84+
width={size}
85+
height={size}
86+
aria-hidden="true"
87+
>
88+
<circle cx="9" cy="12" r="4" fill="#10263B" />
89+
<circle cx="17" cy="12" r="2.5" fill="#DEB406" />
90+
</svg>
91+
);
92+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { EmptyState } from "./EmptyState";
2+
export { LandingTopBar } from "./LandingTopBar";
23
export { LeftRail } from "./LeftRail";
34
export { PageHeader } from "./PageHeader";
45
export { TopBar } from "./TopBar";

0 commit comments

Comments
 (0)