Skip to content

Commit 89f179f

Browse files
committed
simplify design
1 parent 152fade commit 89f179f

File tree

11 files changed

+216
-212
lines changed

11 files changed

+216
-212
lines changed

exercises/99.final/01.solution.final/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
},
1111
"dependencies": {
1212
"@tailwindcss/vite": "^4.0.9",
13+
"class-variance-authority": "^0.7.1",
1314
"react": "^19.0.0",
1415
"react-dom": "^19.0.0",
1516
"react-router": "^7.2.0",
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { cva, type VariantProps } from 'class-variance-authority'
2+
import { type ButtonHTMLAttributes } from 'react'
3+
import { Link, type LinkProps } from 'react-router'
4+
5+
const buttonStyles = cva(
6+
'rounded-full px-6 py-2 font-medium no-underline transition-colors hover:no-underline focus:no-underline',
7+
{
8+
variants: {
9+
variant: {
10+
primary: [
11+
'bg-button text-button-text',
12+
'hover:bg-button-hover',
13+
'active:bg-button-active',
14+
],
15+
secondary: [
16+
'bg-button-secondary text-button-secondary-text',
17+
'hover:bg-button-secondary-hover',
18+
'active:bg-button-secondary-active',
19+
],
20+
},
21+
},
22+
defaultVariants: {
23+
variant: 'primary',
24+
},
25+
},
26+
)
27+
28+
export function Button({
29+
variant,
30+
className,
31+
...props
32+
}: ButtonHTMLAttributes<HTMLButtonElement> &
33+
VariantProps<typeof buttonStyles>) {
34+
return <button className={buttonStyles({ variant, className })} {...props} />
35+
}
36+
37+
export function LinkButton({
38+
variant,
39+
className,
40+
...props
41+
}: LinkProps & VariantProps<typeof buttonStyles>) {
42+
return <Link className={buttonStyles({ variant, className })} {...props} />
43+
}

exercises/99.final/01.solution.final/src/routes/layout.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
import { Link, Outlet } from 'react-router'
2+
import { LinkButton } from '../components/Button.tsx'
23

34
export function Layout() {
45
return (
56
<div className="bg-background flex min-h-screen flex-col">
67
<header className="bg-background-alt px-4 py-3">
78
<div className="container mx-auto flex max-w-6xl items-center justify-between">
8-
<Link to="/" className="text-text text-2xl font-bold">
9+
<Link
10+
to="/"
11+
className="text-foreground text-2xl font-bold hover:no-underline focus:no-underline"
12+
>
913
gratitext
1014
</Link>
1115
<nav className="flex items-center space-x-6">
12-
<Link to="/login" className="text-text-secondary hover:text-text">
13-
Log in
14-
</Link>
15-
<Link
16-
to="/signup"
17-
className="bg-secondary hover:bg-secondary-hover rounded-full px-6 py-2 text-white"
18-
>
19-
Start 14-day trial
20-
</Link>
16+
<Link to="/login">Log in</Link>
17+
<LinkButton to="/signup">Start 14-day trial</LinkButton>
2118
</nav>
2219
</div>
2320
</header>
Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
export function AboutRoute() {
22
return (
3-
<div className="about">
4-
<h1 className="mb-4 text-3xl font-bold">About Us</h1>
5-
<p className="mb-4 text-lg">
6-
We are a demo application built to help you learn React Router.
7-
</p>
8-
<p className="text-lg">
9-
This application demonstrates various features of React Router including
10-
nested routes, dynamic routes, and layouts.
11-
</p>
3+
<div>
4+
<h1>About Us</h1>
125
</div>
136
)
147
}
Lines changed: 2 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,7 @@
11
export function HomepageRoute() {
22
return (
3-
<div className="homepage">
4-
{/* Hero Section */}
5-
<section className="bg-background px-4 py-16">
6-
<div className="container mx-auto flex max-w-6xl items-center justify-between">
7-
<div className="max-w-xl">
8-
<h1 className="text-text mb-4 font-serif text-5xl font-bold">
9-
Thoughtful Connections Made Simple
10-
</h1>
11-
<p className="text-text-secondary mb-8 text-lg">
12-
Strengthen your relationships with regular personalized messages
13-
of love and gratitude
14-
</p>
15-
<button className="bg-primary hover:bg-primary-hover rounded-full px-8 py-3 font-medium text-white">
16-
Get Started
17-
</button>
18-
</div>
19-
<div className="relative">
20-
{/* Decorative elements */}
21-
<div className="absolute -top-4 -left-4 text-4xl">⭐️</div>
22-
<div className="absolute top-1/4 -right-2 text-4xl">⭐️</div>
23-
<div className="absolute -right-8 bottom-1/4 text-4xl">⭐️</div>
24-
<div className="absolute bottom-1/3 -left-6 text-4xl">🧡</div>
25-
<div className="absolute -right-4 -bottom-4 text-4xl"></div>
26-
{/* Main image */}
27-
<div className="bg-accent-blue relative h-[500px] w-[400px] overflow-hidden rounded-[40px]">
28-
<img
29-
src="/images/woman-smiling-at-text.jpg"
30-
alt="Woman smiling at her phone while holding flowers"
31-
className="h-full w-full object-cover"
32-
/>
33-
</div>
34-
</div>
35-
</div>
36-
</section>
37-
38-
{/* Message by You Section */}
39-
<section className="bg-secondary px-4 py-16 text-white">
40-
<div className="container mx-auto max-w-2xl text-center">
41-
<h2 className="mb-6 text-4xl font-bold">
42-
Messages written by you... Not by AI.
43-
</h2>
44-
<p className="text-lg">
45-
Our platform schedules and delivers personal heartfelt messages from
46-
you, making it easy to stay connected and nurture your most
47-
important relationships.
48-
</p>
49-
</div>
50-
</section>
51-
52-
{/* How it Works Section */}
53-
<section className="bg-background px-4 py-16">
54-
<div className="container mx-auto max-w-4xl">
55-
<h2 className="text-text mb-12 text-center font-serif text-4xl font-bold">
56-
How does gratitext work?
57-
</h2>
58-
<div className="grid grid-cols-2 gap-8">
59-
<div className="space-y-4 text-center">
60-
<div className="text-primary text-4xl font-bold">01</div>
61-
<h3 className="text-text text-xl font-bold">Sign Up</h3>
62-
<p className="text-text-secondary">
63-
Create an account and start sending thoughtful messages to your
64-
loved ones
65-
</p>
66-
</div>
67-
<div className="space-y-4 text-center">
68-
<div className="text-primary text-4xl font-bold">02</div>
69-
<h3 className="text-text text-xl font-bold">Add a Loved One</h3>
70-
<p className="text-text-secondary">
71-
Add the phone number of your loved one to get you started
72-
</p>
73-
</div>
74-
</div>
75-
</div>
76-
</section>
77-
78-
{/* Pricing Section */}
79-
<section className="bg-background-alt px-4 py-16">
80-
<div className="container mx-auto max-w-4xl">
81-
<h2 className="text-text mb-12 text-center font-serif text-4xl font-bold">
82-
Affordable pricing plans
83-
</h2>
84-
<div className="grid grid-cols-2 gap-8">
85-
<div className="bg-background rounded-lg p-8 shadow-lg">
86-
<h3 className="text-text mb-4 text-xl font-bold">Basic</h3>
87-
<p className="text-text-secondary mb-4 text-sm">
88-
1 message per day
89-
</p>
90-
<div className="mb-6">
91-
<span className="text-text text-3xl font-bold">$4</span>
92-
<span className="text-text-secondary">/mo</span>
93-
</div>
94-
<button className="border-primary text-primary hover:bg-primary w-full rounded-full border px-6 py-2 hover:text-white">
95-
Get started
96-
</button>
97-
</div>
98-
<div className="bg-background rounded-lg p-8 shadow-lg">
99-
<h3 className="text-text mb-4 text-xl font-bold">Premium</h3>
100-
<p className="text-text-secondary mb-4 text-sm">
101-
10 messages per day
102-
</p>
103-
<div className="mb-6">
104-
<span className="text-text text-3xl font-bold">$14</span>
105-
<span className="text-text-secondary">/mo</span>
106-
</div>
107-
<button className="bg-primary hover:bg-primary-hover w-full rounded-full px-6 py-2 text-white">
108-
Get started
109-
</button>
110-
</div>
111-
</div>
112-
</div>
113-
</section>
114-
115-
{/* CTA Section */}
116-
<section className="bg-accent-peach px-4 py-16">
117-
<div className="container mx-auto max-w-2xl text-center">
118-
<h2 className="text-text mb-6 font-serif text-2xl font-bold">
119-
Create your account today and get 2 weeks for free!
120-
</h2>
121-
<div className="flex justify-center space-x-4">
122-
<input
123-
type="email"
124-
placeholder="Enter your email"
125-
className="bg-background text-text placeholder:text-text-secondary rounded-full px-6 py-2"
126-
/>
127-
<button className="bg-secondary hover:bg-secondary-hover rounded-full px-6 py-2 text-white">
128-
Get started
129-
</button>
130-
</div>
131-
</div>
132-
</section>
3+
<div>
4+
<h1>Homepage</h1>
1335
</div>
1346
)
1357
}

exercises/99.final/01.solution.final/src/routes/marketing/layout.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,35 @@ import { Outlet, Link } from 'react-router'
33
export function MarketingLayout() {
44
return (
55
<div className="flex h-full flex-grow flex-col">
6-
<main className="flex-1">
6+
<main className="container mx-auto max-w-6xl flex-1 px-4 py-8">
77
<Outlet />
88
</main>
99

10-
<footer className="bg-white px-4 py-8">
10+
<footer className="bg-background-alt px-4 py-8">
1111
<div className="container mx-auto max-w-6xl">
1212
<div className="mb-8 flex items-center justify-between">
13-
<Link to="/" className="text-xl font-bold text-slate-800">
13+
<Link
14+
to="/"
15+
className="text-foreground-alt text-xl font-bold hover:no-underline focus:no-underline"
16+
>
1417
gratitext
1518
</Link>
1619
<nav className="flex space-x-8">
17-
<Link
18-
to="/contact"
19-
className="text-slate-600 hover:text-slate-800"
20-
>
20+
<Link to="/contact" className="text-link hover:text-link-hover">
2121
Contact
2222
</Link>
23-
<Link to="/about" className="text-slate-600 hover:text-slate-800">
23+
<Link to="/about" className="text-link hover:text-link-hover">
2424
About
2525
</Link>
2626
</nav>
2727
</div>
28-
<div className="flex items-center justify-between border-t border-slate-200 pt-8 text-sm text-slate-500">
28+
<div className="border-border flex items-center justify-between border-t pt-8 text-sm">
2929
<div>All Rights Reserved</div>
3030
<div className="flex space-x-6">
31-
<Link to="/terms" className="hover:text-slate-700">
31+
<Link to="/terms" className="text-link hover:text-link-hover">
3232
Terms and Conditions
3333
</Link>
34-
<Link to="/privacy" className="hover:text-slate-700">
34+
<Link to="/privacy" className="text-link hover:text-link-hover">
3535
Privacy Policy
3636
</Link>
3737
</div>

exercises/99.final/01.solution.final/src/routes/recipient.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@ export function RecipientRoute() {
1212

1313
if (!recipient) {
1414
return (
15-
<div className="p-4">
16-
<p className="text-red-600">Recipient not found</p>
17-
<Link to="/recipients" className="text-blue-600 hover:underline">
15+
<div className="container mx-auto mt-4 flex flex-col gap-8">
16+
<div className="bg-danger-background rounded-sm p-4">
17+
<p className="text-danger-foreground">Recipient not found</p>
18+
</div>
19+
<Link
20+
to="/recipients"
21+
className="text-link hover:text-link-hover block text-center hover:underline"
22+
>
1823
Back to recipients
1924
</Link>
2025
</div>
@@ -25,9 +30,7 @@ export function RecipientRoute() {
2530
<div className="recipient p-4">
2631
<h1 className="mb-4 text-3xl font-bold">{recipient.name}</h1>
2732
<p className="mb-4 text-lg">Email: {recipient.email}</p>
28-
<Link to="/recipients" className="text-blue-600 hover:underline">
29-
Back to recipients
30-
</Link>
33+
<Link to="/recipients">Back to recipients</Link>
3134
</div>
3235
)
3336
}

exercises/99.final/01.solution.final/src/routes/recipients.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,7 @@ export function RecipientsRoute() {
1313
<ul className="space-y-2">
1414
{recipients.map((recipient) => (
1515
<li key={recipient.id}>
16-
<Link
17-
to={`/recipients/${recipient.id}`}
18-
className="text-blue-600 hover:underline"
19-
>
20-
{recipient.name}
21-
</Link>
16+
<Link to={`/recipients/${recipient.id}`}>{recipient.name}</Link>
2217
</li>
2318
))}
2419
</ul>

exercises/99.final/01.solution.final/src/styles/index.css

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,43 @@
1212
--font-sans: var(--font-poppins);
1313
--font-serif: var(--font-source-serif-4);
1414
}
15+
16+
@layer base {
17+
body {
18+
background-color: var(--color-background);
19+
color: var(--color-foreground);
20+
}
21+
22+
a {
23+
color: var(--color-link);
24+
text-decoration: none;
25+
}
26+
27+
a:hover,
28+
a:focus {
29+
color: var(--color-link-hover);
30+
text-decoration: underline;
31+
}
32+
33+
a:active {
34+
color: var(--color-link-active);
35+
}
36+
37+
button {
38+
background-color: var(--color-button);
39+
color: var(--color-button-text);
40+
padding: 0.5rem 1.5rem;
41+
border-radius: 9999px;
42+
border: none;
43+
cursor: pointer;
44+
}
45+
46+
button:hover,
47+
button:focus {
48+
background-color: var(--color-button-hover);
49+
}
50+
51+
button:active {
52+
background-color: var(--color-button-active);
53+
}
54+
}

0 commit comments

Comments
 (0)