Skip to content

Commit 7d55bc1

Browse files
committed
save space, use details
1 parent 892c3b4 commit 7d55bc1

File tree

5 files changed

+98
-45
lines changed

5 files changed

+98
-45
lines changed

exercises/99.final/01.solution.final/src/components/icons.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ export function ArrowRightIcon({ title, ...props }: IconProps) {
3030
)
3131
}
3232

33+
export function ArrowDownIcon({ title, ...props }: IconProps) {
34+
return (
35+
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" {...props}>
36+
{title ? <title>{title}</title> : null}
37+
<path
38+
strokeLinecap="round"
39+
strokeLinejoin="round"
40+
strokeWidth={2}
41+
d="M19 9l-7 7-7-7"
42+
/>
43+
</svg>
44+
)
45+
}
46+
3347
export function PhoneIcon({ title, ...props }: IconProps) {
3448
return (
3549
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" {...props}>

exercises/99.final/01.solution.final/src/routes/app/recipients/$id.edit.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ export function RecipientEditRoute() {
99
if (!recipient) throw new Error(`Recipient not found with ID "${id}"`)
1010

1111
return (
12-
<div className="container mx-auto max-w-2xl overflow-y-auto p-6">
13-
<h1 className="mb-2 text-center text-4xl font-bold">Edit Recipient</h1>
14-
<p className="mb-8 text-center">Edit the details of your recipient.</p>
12+
<div className="w-full overflow-y-auto p-6">
13+
<div className="container mx-auto max-w-2xl">
14+
<h1 className="mb-2 text-center text-4xl font-bold">Edit Recipient</h1>
15+
<p className="mb-8 text-center">Edit the details of your recipient.</p>
1516

16-
<RecipientEditor recipient={recipient} />
17+
<RecipientEditor recipient={recipient} />
18+
</div>
1719
</div>
1820
)
1921
}

exercises/99.final/01.solution.final/src/routes/app/recipients/$id.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,17 @@ export function RecipientRoute() {
134134

135135
<div className="border-border flex-shrink-0 border-t p-4">
136136
<form
137+
key={recipient.id}
137138
onSubmit={(e) => {
138139
e.preventDefault()
139140
e.currentTarget.reset()
140141
}}
141142
className="flex items-center gap-4"
142143
>
143144
<textarea
144-
placeholder="Type your message..."
145+
autoFocus
146+
name="content"
147+
placeholder={`Type your message to ${recipient.name}...`}
145148
className="text-foreground-alt placeholder:text-foreground-alt/60 field-sizing-content max-h-[200px] min-h-[48px] flex-1 resize-none rounded-lg px-4 py-3"
146149
rows={1}
147150
/>

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

+66-36
Original file line numberDiff line numberDiff line change
@@ -9,52 +9,82 @@ export function RecipientsLayout() {
99
<div className="container mx-auto flex min-h-0 flex-grow flex-col px-4 pt-4 md:px-8 md:pt-8">
1010
<div className="mb-8 flex items-center justify-between">
1111
<h1 className="text-4xl font-bold">Recipients</h1>
12-
<ButtonLink
13-
to="/recipients/new"
14-
className="hidden items-center gap-2 md:flex"
15-
>
12+
<ButtonLink to="new" className="hidden items-center gap-2 md:flex">
1613
<Icon name="Plus">Add New Recipient</Icon>
1714
</ButtonLink>
18-
<ButtonLink icon to="/recipients/new" className="md:hidden">
15+
<ButtonLink icon to="new" className="md:hidden">
1916
<Icon name="Plus" />
2017
</ButtonLink>
2118
</div>
2219

23-
<div className="bg-background-alt flex min-h-0 flex-1 flex-col md:flex-row">
24-
<div className="flex max-h-32 min-h-32 flex-col gap-4 overflow-auto border-b-2 py-4 pr-4 pl-1 md:max-h-none md:min-w-32 md:border-r md:border-b-0">
25-
{recipients.map((recipient) => (
26-
<div key={recipient.id} className="flex items-center gap-2">
27-
<NavLink
28-
to={`/recipients/${recipient.id}`}
29-
className={({ isActive }) =>
30-
clsx('text-xl', isActive ? 'underline' : '')
31-
}
32-
>
33-
{({ isActive }) => (
34-
<div className="flex items-center gap-1">
20+
<div className="bg-background-alt flex min-h-0 flex-1 flex-col">
21+
<div className="flex flex-col gap-4 overflow-visible border-b-2 py-4 pr-4 pl-1">
22+
<details
23+
className="relative"
24+
onBlur={(e) => {
25+
const relatedTarget = e.relatedTarget
26+
if (!e.currentTarget.contains(relatedTarget)) {
27+
e.currentTarget.removeAttribute('open')
28+
}
29+
}}
30+
onKeyDown={(e) => {
31+
if (e.key === 'Escape') {
32+
e.currentTarget.removeAttribute('open')
33+
}
34+
}}
35+
>
36+
<summary className="hover:bg-background-alt-hover cursor-pointer px-2 py-1">
37+
Select recipient
38+
</summary>
39+
<div className="bg-background-alt absolute top-full left-0 z-10 mt-1 max-w-full min-w-64 border p-2 shadow-lg">
40+
{recipients.map((recipient) => (
41+
<div key={recipient.id} className="flex items-center gap-2">
42+
<NavLink
43+
to={recipient.id}
44+
className={({ isActive }) =>
45+
clsx(
46+
'overflow-x-auto text-xl',
47+
isActive ? 'underline' : '',
48+
)
49+
}
50+
onClick={(e) => {
51+
e.currentTarget
52+
.closest('details')
53+
?.removeAttribute('open')
54+
}}
55+
>
56+
{({ isActive }) => (
57+
<div className="flex items-center gap-1">
58+
<Icon
59+
name="ArrowRight"
60+
size="sm"
61+
className={clsx(
62+
isActive ? 'opacity-100' : 'opacity-0',
63+
'transition-opacity',
64+
)}
65+
/>
66+
{recipient.name}
67+
</div>
68+
)}
69+
</NavLink>
70+
{recipient.messages.some(
71+
(m) => m.status === 'scheduled',
72+
) ? null : (
3573
<Icon
36-
name="ArrowRight"
37-
size="sm"
38-
className={clsx(
39-
isActive ? 'opacity-100' : 'opacity-0',
40-
'transition-opacity',
41-
)}
74+
name="ExclamationCircle"
75+
className="text-danger-foreground"
76+
title="no messages scheduled"
4277
/>
43-
{recipient.name}
44-
</div>
45-
)}
46-
</NavLink>
47-
{recipient.messages.some(
48-
(m) => m.status === 'scheduled',
49-
) ? null : (
50-
<Icon
51-
name="ExclamationCircle"
52-
className="text-danger-foreground"
53-
title="no messages scheduled"
54-
/>
78+
)}
79+
</div>
80+
))}
81+
{recipients.length === 0 && (
82+
<div className="bg-warning-background text-warning-foreground px-4 py-2 text-sm">
83+
No recipients found. Add one to get started.
84+
</div>
5585
)}
5686
</div>
57-
))}
87+
</details>
5888
</div>
5989
<div className="flex flex-1 overflow-auto">
6090
<Outlet />

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

+8-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ import { RecipientEditor } from './recipient-editor.tsx'
22

33
export function NewRecipientRoute() {
44
return (
5-
<div className="container mx-auto max-w-2xl overflow-y-auto p-6">
6-
<h1 className="mb-2 text-center text-4xl font-bold">Add New Recipient</h1>
7-
<p className="mb-8 text-center">Who should receive your messages?</p>
5+
<div className="w-full overflow-y-auto p-6">
6+
<div className="container mx-auto max-w-2xl">
7+
<h1 className="mb-2 text-center text-4xl font-bold">
8+
Add New Recipient
9+
</h1>
10+
<p className="mb-8 text-center">Who should receive your messages?</p>
811

9-
<RecipientEditor />
12+
<RecipientEditor />
13+
</div>
1014
</div>
1115
)
1216
}

0 commit comments

Comments
 (0)