Skip to content

Commit 8e76cce

Browse files
apply focusable HOC
1 parent a29c6e4 commit 8e76cce

File tree

8 files changed

+122
-103
lines changed

8 files changed

+122
-103
lines changed

app/(editor)/create/[[...paramsArr]]/navigation.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Fragment } from "react";
99
import { type Session } from "next-auth";
1010
import Logo from "@/icons/logo.svg";
1111
import { type PostStatus, status } from "@/utils/post";
12+
import Focusable from "@/components/Focusable/Focusable";
1213

1314
type EditorNavProps = {
1415
session: Session | null;
@@ -83,16 +84,18 @@ const EditorNav = ({
8384

8485
{session && (
8586
<>
86-
<Link
87-
href="/notifications"
88-
className="focus-style relative rounded-full p-1 text-neutral-500 hover:bg-neutral-100 hover:text-neutral-600 dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-white"
89-
>
90-
<span className="sr-only">View notifications</span>
91-
{hasNotifications && (
92-
<div className="absolute right-0 top-0 h-2 w-2 rounded-full bg-pink-500" />
93-
)}
94-
<BellIcon className="h-5 w-5" aria-hidden="true" />
95-
</Link>
87+
<Focusable>
88+
<Link
89+
href="/notifications"
90+
className="relative rounded-full p-1 text-neutral-500 hover:bg-neutral-100 hover:text-neutral-600 dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-white"
91+
>
92+
<span className="sr-only">View notifications</span>
93+
{hasNotifications && (
94+
<div className="absolute right-0 top-0 h-2 w-2 rounded-full bg-pink-500" />
95+
)}
96+
<BellIcon className="h-5 w-5" aria-hidden="true" />
97+
</Link>
98+
</Focusable>
9699
<Menu as="div" className="relative ml-3">
97100
<div>
98101
<Menu.Button className="flex rounded-full bg-white text-sm focus:outline-none focus:ring-2 focus:ring-pink-500 focus:ring-offset-2">

components/ArticleMenu/ArticleMenu.tsx

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import copy from "copy-to-clipboard";
1919
import { type Session } from "next-auth";
2020
import { signIn } from "next-auth/react";
2121
import { ReportModal } from "../ReportModal/ReportModal";
22+
import Focusable from "../Focusable/Focusable";
2223

2324
interface CopyToClipboardOption {
2425
label: string;
@@ -148,27 +149,28 @@ const ArticleMenu = ({
148149
</button>
149150
<span>{data?.likes || 0}</span>
150151
</div>
151-
152-
<button
153-
className="focus-style-rounded rounded-full p-1 hover:bg-neutral-300 dark:hover:bg-neutral-800 lg:mx-auto"
154-
aria-label="bookmark-trigger"
155-
onClick={() => {
156-
if (!session) {
157-
signIn();
158-
}
159-
if (data?.currentUserBookmarked)
160-
return bookmarkPost(postId, false);
161-
bookmarkPost(postId);
162-
}}
163-
>
164-
<BookmarkIcon
165-
className={`w-6 h-6${
166-
data?.currentUserBookmarked
167-
? "fill-blue-400"
168-
: "fill-neutral-400 dark:fill-neutral-600"
169-
}`}
170-
/>
171-
</button>
152+
<Focusable rounded={true}>
153+
<button
154+
className="rounded-full p-1 hover:bg-neutral-300 dark:hover:bg-neutral-800 lg:mx-auto"
155+
aria-label="bookmark-trigger"
156+
onClick={() => {
157+
if (!session) {
158+
signIn();
159+
}
160+
if (data?.currentUserBookmarked)
161+
return bookmarkPost(postId, false);
162+
bookmarkPost(postId);
163+
}}
164+
>
165+
<BookmarkIcon
166+
className={`w-6 h-6${
167+
data?.currentUserBookmarked
168+
? "fill-blue-400"
169+
: "fill-neutral-400 dark:fill-neutral-600"
170+
}`}
171+
/>
172+
</button>
173+
</Focusable>
172174

173175
<Popover className="relative ml-4">
174176
<PopoverButton

components/ArticlePreview/ArticlePreview.tsx

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
import { api } from "@/server/trpc/react";
2020
import { signIn, useSession } from "next-auth/react";
2121
import { toast } from "sonner";
22+
import Focusable from "../Focusable/Focusable";
2223

2324
type ButtonOptions = {
2425
label: string;
@@ -165,29 +166,31 @@ const ArticlePreview: NextPage<Props> = ({
165166
</Link>
166167
<div className="flex gap-x-2">
167168
{showBookmark && (
168-
<button
169-
className="focus-style-rounded rounded-full p-2 hover:bg-neutral-300 dark:hover:bg-neutral-800 lg:mx-auto"
170-
onClick={() => {
171-
if (!session) {
172-
return signIn();
169+
<Focusable rounded={true}>
170+
<button
171+
className="rounded-full p-2 hover:bg-neutral-300 dark:hover:bg-neutral-800 lg:mx-auto"
172+
onClick={() => {
173+
if (!session) {
174+
return signIn();
175+
}
176+
if (bookmarked) {
177+
return bookmarkPost(id, false);
178+
}
179+
bookmarkPost(id);
180+
}}
181+
aria-label={
182+
bookmarked ? "Remove bookmark" : "Bookmark this post"
173183
}
174-
if (bookmarked) {
175-
return bookmarkPost(id, false);
176-
}
177-
bookmarkPost(id);
178-
}}
179-
aria-label={
180-
bookmarked ? "Remove bookmark" : "Bookmark this post"
181-
}
182-
>
183-
<BookmarkIcon
184-
className={`w-6 h-6${
185-
bookmarked
186-
? "fill-blue-400"
187-
: "fill-neutral-400 dark:fill-neutral-600"
188-
}`}
189-
/>
190-
</button>
184+
>
185+
<BookmarkIcon
186+
className={`w-6 h-6${
187+
bookmarked
188+
? "fill-blue-400"
189+
: "fill-neutral-400 dark:fill-neutral-600"
190+
}`}
191+
/>
192+
</button>
193+
</Focusable>
191194
)}
192195
{menuOptions && (
193196
<Menu as="div" className="relative">

components/Focusable/Focusable.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import React, { cloneElement, ReactElement } from "react";
22

33
interface FocusableProps {
44
children: ReactElement;
5+
rounded?: boolean;
56
}
67

7-
const Focusable: React.FC<FocusableProps> = ({ children }) => {
8+
const Focusable: React.FC<FocusableProps> = ({ children, rounded = false }) => {
89
return cloneElement(children, {
9-
className: `${children.props.className} rounded-md focus:outline-none focus:ring-white focus-visible:ring-2 focus-visible:ring-pink-600 focus-visible:ring-offset-pink-600`,
10+
className: `${children.props.className}
11+
${rounded ? "rounded-full" : "rounded-md"} focus:outline-none focus:ring-white focus-visible:ring-2 focus-visible:ring-pink-600 focus-visible:ring-offset-pink-600`,
1012
});
1113
};
1214

components/Nav/Nav.tsx

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import AnimatedHamburger from "./AnimatedHamburger";
2020
import Logo from "@/icons/logo.svg";
2121
import MobileNav from "./MobileNav";
2222
import { MobileSearch, Search } from "@/components/ui/Search";
23+
import Focusable from "../Focusable/Focusable";
2324

2425
type AlgoliaConfig = {
2526
ALGOLIA_APP_ID: string;
@@ -83,7 +84,7 @@ const Nav = ({
8384
href={item.href}
8485
target="_blank"
8586
rel="noopener noreferrer"
86-
className="nav-button focus-style p-4"
87+
className="nav-button p-4"
8788
>
8889
{item.name}
8990
</a>
@@ -135,16 +136,18 @@ const Nav = ({
135136

136137
{session && (
137138
<>
138-
<Link
139-
to="/notifications"
140-
className="focus-style relative flex-shrink-0 rounded-md p-2 text-neutral-500 hover:bg-neutral-200 hover:text-neutral-600 dark:text-neutral-400 dark:hover:bg-neutral-900 dark:hover:text-white"
141-
>
142-
<span className="sr-only">View notifications</span>
143-
{hasNotifications && (
144-
<div className="absolute right-2 top-2 h-2 w-2 animate-pulse rounded-full bg-pink-600" />
145-
)}
146-
<BellIcon className="h-6 w-6" aria-hidden="true" />
147-
</Link>
139+
<Focusable>
140+
<Link
141+
to="/notifications"
142+
className="relative flex-shrink-0 rounded-md p-2 text-neutral-500 hover:bg-neutral-200 hover:text-neutral-600 dark:text-neutral-400 dark:hover:bg-neutral-900 dark:hover:text-white"
143+
>
144+
<span className="sr-only">View notifications</span>
145+
{hasNotifications && (
146+
<div className="absolute right-2 top-2 h-2 w-2 animate-pulse rounded-full bg-pink-600" />
147+
)}
148+
<BellIcon className="h-6 w-6" aria-hidden="true" />
149+
</Link>
150+
</Focusable>
148151
<Menu as="div" className="relative ml-4">
149152
<div>
150153
<MenuButton className="flex rounded-full bg-black text-sm ring-offset-2 focus:outline-none focus:ring-2 focus:ring-pink-600 focus:ring-offset-2 focus:ring-offset-white">
@@ -204,22 +207,26 @@ const Nav = ({
204207
<MobileSearch algoliaSearchConfig={algoliaSearchConfig} />
205208
<ThemeToggle />
206209
{session && (
207-
<Link
208-
to="/notifications"
209-
className="focus-style relative flex-shrink-0 rounded-md p-2 text-neutral-500 hover:bg-neutral-200 hover:text-neutral-600 dark:text-neutral-400 dark:hover:bg-neutral-900 dark:hover:text-white"
210-
>
211-
<span className="sr-only">View notifications</span>
212-
{hasNotifications && (
213-
<div className="absolute right-1 top-1 h-2 w-2 animate-pulse rounded-full bg-pink-500" />
214-
)}
215-
<BellIcon className="h-6 w-6" aria-hidden="true" />
216-
</Link>
210+
<Focusable>
211+
<Link
212+
to="/notifications"
213+
className="relative flex-shrink-0 rounded-md p-2 text-neutral-500 hover:bg-neutral-200 hover:text-neutral-600 dark:text-neutral-400 dark:hover:bg-neutral-900 dark:hover:text-white"
214+
>
215+
<span className="sr-only">View notifications</span>
216+
{hasNotifications && (
217+
<div className="absolute right-1 top-1 h-2 w-2 animate-pulse rounded-full bg-pink-500" />
218+
)}
219+
<BellIcon className="h-6 w-6" aria-hidden="true" />
220+
</Link>
221+
</Focusable>
217222
)}
218223
{/* Mobile menu button */}
219-
<DisclosureButton className="nav-button focus-style group">
220-
<span className="sr-only">Open main menu</span>
221-
<AnimatedHamburger open={open} />
222-
</DisclosureButton>
224+
<Focusable>
225+
<DisclosureButton className="nav-button group">
226+
<span className="sr-only">Open main menu</span>
227+
<AnimatedHamburger open={open} />
228+
</DisclosureButton>
229+
</Focusable>
223230
</div>
224231
</div>
225232
</div>

components/Theme/ThemeToggle/ThemeToggle.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import Focusable from "@/components/Focusable/Focusable";
34
import { MoonIcon, SunIcon } from "@heroicons/react/20/solid";
45
import { useTheme } from "next-themes";
56
import { useEffect, useState } from "react";
@@ -26,17 +27,19 @@ const ThemeToggle = () => {
2627
};
2728

2829
return (
29-
<button
30-
onClick={toggleTheme}
31-
aria-pressed={resolvedTheme === THEME_MODES.DARK}
32-
className="nav-button focus-style group relative flex-shrink-0 p-4 focus:ring-inset"
33-
type="button"
34-
title="Toggle dark mode"
35-
>
36-
<span className="sr-only">Toggle Dark Mode</span>
37-
<SunIcon className="h-6 w-6 rotate-0 scale-100 text-neutral-500 group-hover:text-yellow-500 group-focus:text-yellow-500 motion-safe:transition-all dark:-rotate-90 dark:scale-0" />
38-
<MoonIcon className="absolute left-1/2 top-1/2 h-6 w-6 -translate-x-1/2 -translate-y-1/2 rotate-90 scale-0 transform text-neutral-400 group-hover:text-white motion-safe:transition-all dark:rotate-0 dark:scale-100" />
39-
</button>
30+
<Focusable>
31+
<button
32+
onClick={toggleTheme}
33+
aria-pressed={resolvedTheme === THEME_MODES.DARK}
34+
className="nav-button group relative flex-shrink-0 p-4 focus:ring-inset"
35+
type="button"
36+
title="Toggle dark mode"
37+
>
38+
<span className="sr-only">Toggle Dark Mode</span>
39+
<SunIcon className="h-6 w-6 rotate-0 scale-100 text-neutral-500 group-hover:text-yellow-500 group-focus:text-yellow-500 motion-safe:transition-all dark:-rotate-90 dark:scale-0" />
40+
<MoonIcon className="absolute left-1/2 top-1/2 h-6 w-6 -translate-x-1/2 -translate-y-1/2 rotate-90 scale-0 transform text-neutral-400 group-hover:text-white motion-safe:transition-all dark:rotate-0 dark:scale-100" />
41+
</button>
42+
</Focusable>
4043
);
4144
};
4245

components/ui/Search.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
3030
import clsx from "clsx";
3131
import Image from "next/image";
32+
import Focusable from "../Focusable/Focusable";
3233

3334
type Result = {
3435
title: string;
@@ -540,14 +541,16 @@ export function MobileSearch({
540541

541542
return (
542543
<div className="contents lg:hidden">
543-
<button
544-
type="button"
545-
className="focus-style relative flex-shrink-0 rounded-md p-2 text-neutral-500 hover:bg-neutral-200 hover:text-neutral-600 dark:text-neutral-400 dark:hover:bg-neutral-900 dark:hover:text-white"
546-
aria-label="Search the site"
547-
{...buttonProps}
548-
>
549-
<MagnifyingGlassIcon className="h-6 w-6 stroke-current" />
550-
</button>
544+
<Focusable>
545+
<button
546+
type="button"
547+
className="relative flex-shrink-0 rounded-md p-2 text-neutral-500 hover:bg-neutral-200 hover:text-neutral-600 dark:text-neutral-400 dark:hover:bg-neutral-900 dark:hover:text-white"
548+
aria-label="Search the site"
549+
{...buttonProps}
550+
>
551+
<MagnifyingGlassIcon className="h-6 w-6 stroke-current" />
552+
</button>
553+
</Focusable>
551554
<Suspense fallback={null}>
552555
<SearchDialog
553556
algoliaSearchConfig={algoliaSearchConfig}

styles/globals.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ body {
4646
@apply rounded-md focus:outline-none focus:ring-white focus-visible:ring-2 focus-visible:ring-pink-600 focus-visible:ring-offset-pink-600;
4747
}
4848

49-
.focus-style-rounded {
50-
@apply rounded-full focus:outline-none focus:ring-white focus-visible:ring-2 focus-visible:ring-pink-600 focus-visible:ring-offset-pink-600;
51-
}
52-
5349
.primary-button {
5450
@apply inline-flex justify-center rounded-md bg-gradient-to-r from-orange-400 to-pink-600 px-4 py-2 font-medium text-white shadow-sm hover:from-orange-300 hover:to-pink-500 focus:outline-none focus:ring-2 focus:ring-pink-600 focus:ring-offset-2 focus-visible:ring-2 focus-visible:ring-pink-600 focus-visible:ring-offset-white disabled:border-neutral-300 disabled:from-neutral-500 disabled:to-neutral-700 disabled:text-neutral-300 disabled:hover:text-neutral-300;
5551
}

0 commit comments

Comments
 (0)