diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-12-03 03:51:29 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-12-04 23:27:28 +0900 |
| commit | 58d132139ba8d5fa17c8681a0275047ce4cca809 (patch) | |
| tree | 7dd18f5de496483b7d318e12e43379a51f3a6056 | |
| parent | aac4e9ccdebe52c156506d1899d5a38e99366f69 (diff) | |
| download | feedaka-58d132139ba8d5fa17c8681a0275047ce4cca809.tar.gz feedaka-58d132139ba8d5fa17c8681a0275047ce4cca809.tar.zst feedaka-58d132139ba8d5fa17c8681a0275047ce4cca809.zip | |
feat(frontend): design update
| -rw-r--r-- | frontend/src/components/AddFeedForm.tsx | 26 | ||||
| -rw-r--r-- | frontend/src/components/ArticleItem.tsx | 24 | ||||
| -rw-r--r-- | frontend/src/components/ArticleList.tsx | 16 | ||||
| -rw-r--r-- | frontend/src/components/FeedItem.tsx | 37 | ||||
| -rw-r--r-- | frontend/src/components/FeedList.tsx | 20 | ||||
| -rw-r--r-- | frontend/src/components/Layout.tsx | 4 | ||||
| -rw-r--r-- | frontend/src/components/MenuItem.tsx | 6 | ||||
| -rw-r--r-- | frontend/src/components/Navigation.tsx | 19 | ||||
| -rw-r--r-- | frontend/src/index.css | 34 | ||||
| -rw-r--r-- | frontend/src/pages/Login.tsx | 101 | ||||
| -rw-r--r-- | frontend/src/pages/NotFound.tsx | 16 | ||||
| -rw-r--r-- | frontend/src/pages/ReadArticles.tsx | 18 | ||||
| -rw-r--r-- | frontend/src/pages/Settings.tsx | 21 | ||||
| -rw-r--r-- | frontend/src/pages/UnreadArticles.tsx | 20 |
14 files changed, 224 insertions, 138 deletions
diff --git a/frontend/src/components/AddFeedForm.tsx b/frontend/src/components/AddFeedForm.tsx index 6d18318..9a56574 100644 --- a/frontend/src/components/AddFeedForm.tsx +++ b/frontend/src/components/AddFeedForm.tsx @@ -48,43 +48,43 @@ export function AddFeedForm({ onFeedAdded }: Props) { const isUrlValid = !url || isValidUrl(url); return ( - <form onSubmit={handleSubmit} className="space-y-4 p-4"> - <div className="rounded-lg border border-gray-200 bg-white p-4 shadow-sm"> - <h3 className="text-lg font-semibold text-gray-900 mb-4"> + <form onSubmit={handleSubmit}> + <div className="rounded-xl border border-stone-200 bg-white p-5"> + <h3 className="mb-4 text-sm font-semibold uppercase tracking-wide text-stone-900"> Subscribe to New Feed </h3> - <div className="flex gap-2"> + <div className="flex gap-3"> <div className="flex-1"> <input type="url" value={url} onChange={(e) => setUrl(e.target.value)} placeholder="https://example.com/feed.xml" - className={`w-full rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 ${ + className={`w-full rounded-lg border bg-white px-4 py-2.5 text-sm text-stone-900 placeholder-stone-400 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-1 ${ isUrlValid - ? "border-gray-300 focus:border-blue-500 focus:ring-blue-500" - : "border-red-300 focus:border-red-500 focus:ring-red-500" + ? "border-stone-200 focus:border-sky-500 focus:ring-sky-500/20" + : "border-red-300 focus:border-red-500 focus:ring-red-500/20" }`} disabled={fetching} /> {!isUrlValid && ( - <p className="mt-1 text-sm text-red-600"> + <p className="mt-2 text-sm text-red-600"> Please enter a valid URL (http:// or https://) </p> )} - {error && <p className="mt-1 text-sm text-red-600">{error}</p>} + {error && <p className="mt-2 text-sm text-red-600">{error}</p>} </div> <button type="submit" disabled={fetching || !url.trim() || !isUrlValid} - className="rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed" + className="inline-flex items-center gap-2 rounded-lg bg-sky-600 px-5 py-2.5 text-sm font-medium text-white transition-all duration-200 hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:bg-stone-200 disabled:text-stone-400" > {fetching ? ( - <FontAwesomeIcon icon={faSpinner} spin className="mr-2" /> + <FontAwesomeIcon icon={faSpinner} spin /> ) : ( - <FontAwesomeIcon icon={faPlus} className="mr-2" /> + <FontAwesomeIcon icon={faPlus} /> )} - Subscribe + <span>Subscribe</span> </button> </div> </div> diff --git a/frontend/src/components/ArticleItem.tsx b/frontend/src/components/ArticleItem.tsx index c61923a..f8fac24 100644 --- a/frontend/src/components/ArticleItem.tsx +++ b/frontend/src/components/ArticleItem.tsx @@ -51,38 +51,36 @@ export function ArticleItem({ article, onReadChange }: Props) { return ( <div - className={`group flex items-center gap-3 rounded-lg border p-3 hover:bg-gray-50 ${ + className={`group flex items-center gap-3 rounded-lg p-3 transition-all duration-200 ${ article.isRead - ? "border-gray-200 bg-white" - : "border-blue-200 bg-blue-50" + ? "bg-white hover:bg-stone-50" + : "border-l-2 border-l-sky-500 bg-sky-50/50" }`} > <button type="button" onClick={() => handleToggleRead(article.id, article.isRead)} - className={`flex-shrink-0 rounded p-1 transition-colors ${ + className={`flex-shrink-0 rounded-md p-1.5 transition-all duration-150 ${ article.isRead - ? "text-gray-400 hover:text-gray-600" - : "text-blue-600 hover:text-blue-700" + ? "text-stone-300 hover:bg-stone-100 hover:text-stone-500" + : "text-sky-500 hover:bg-sky-100 hover:text-sky-600" }`} title={article.isRead ? "Mark as unread" : "Mark as read"} > <FontAwesomeIcon icon={article.isRead ? faCheck : faCircle} - className="w-4 h-4" + className="h-4 w-4" /> </button> - <div className="flex-1 min-w-0"> + <div className="min-w-0 flex-1"> <button type="button" onClick={() => handleArticleClick(article)} - className={`text-left w-full group-hover:text-blue-600 transition-colors ${ - article.isRead ? "text-gray-700" : "text-gray-900 font-medium" + className={`w-full text-left transition-colors duration-150 group-hover:text-sky-700 ${ + article.isRead ? "text-stone-500" : "font-medium text-stone-900" }`} > - <div className="flex items-center gap-2 break-words"> - {article.title} - </div> + <span className="break-words">{article.title}</span> </button> </div> </div> diff --git a/frontend/src/components/ArticleList.tsx b/frontend/src/components/ArticleList.tsx index 574f529..afadb25 100644 --- a/frontend/src/components/ArticleList.tsx +++ b/frontend/src/components/ArticleList.tsx @@ -30,7 +30,9 @@ export function ArticleList({ articles, isReadView }: Props) { if (visibleArticles.length === 0) { return ( - <div className="p-4 text-center text-gray-500">No articles found.</div> + <div className="py-8 text-center"> + <p className="text-sm text-stone-400">No articles found.</p> + </div> ); } @@ -54,14 +56,14 @@ export function ArticleList({ articles, isReadView }: Props) { ); return ( - <div className="space-y-6 p-4"> + <div className="space-y-8"> {Object.values(articlesByFeed).map(({ feed, articles: feedArticles }) => ( - <div key={feed.id} className="space-y-2"> - <h3 className="text-lg font-semibold text-gray-900 border-b border-gray-200 pb-2"> + <div key={feed.id} className="space-y-3"> + <h3 className="border-b border-stone-200 pb-2 text-sm font-semibold uppercase tracking-wide text-stone-900"> {feed.title} - <span className="ml-2 text-sm font-normal text-gray-500"> - ({feedArticles.length} article - {feedArticles.length !== 1 ? "s" : ""}) + <span className="ml-2 text-xs font-normal normal-case tracking-normal text-stone-400"> + {feedArticles.length} article + {feedArticles.length !== 1 ? "s" : ""} </span> </h3> <div className="space-y-1"> diff --git a/frontend/src/components/FeedItem.tsx b/frontend/src/components/FeedItem.tsx index 80c8992..8333f75 100644 --- a/frontend/src/components/FeedItem.tsx +++ b/frontend/src/components/FeedItem.tsx @@ -41,26 +41,29 @@ export function FeedItem({ feed, onFeedUnsubscribed }: Props) { }; return ( - <div className="rounded-lg border border-gray-200 bg-white p-4 shadow-sm"> - <div className="flex items-start justify-between"> - <div className="flex-1"> - <h3 className="text-lg font-semibold text-gray-900">{feed.title}</h3> - <p className="mt-1 text-sm text-gray-500"> - <a href={feed.url} target="_blank" rel="noreferrer"> - {feed.url} - </a> + <div className="group rounded-xl border border-stone-200 bg-white p-5 transition-all duration-200 hover:border-stone-300 hover:shadow-sm"> + <div className="flex items-start justify-between gap-4"> + <div className="min-w-0 flex-1"> + <h3 className="truncate text-base font-semibold text-stone-900"> + {feed.title} + </h3> + <a + href={feed.url} + target="_blank" + rel="noreferrer" + className="mt-1 block truncate text-sm text-stone-400 transition-colors hover:text-sky-600" + > + {feed.url} + </a> + <p className="mt-2 text-xs text-stone-400"> + Last fetched: {formatDateTime(new Date(feed.fetchedAt))} </p> - <div className="mt-2 flex items-center gap-4 text-sm"> - <span className="text-gray-400"> - Last fetched: {formatDateTime(new Date(feed.fetchedAt))} - </span> - </div> </div> - <div className="flex items-center gap-2"> + <div className="flex items-center gap-1"> <button type="button" onClick={() => handleMarkAllRead(feed.id)} - className="rounded p-2 text-gray-600 hover:bg-gray-100 hover:text-gray-900" + className="rounded-lg p-2 text-stone-400 transition-all duration-150 hover:bg-stone-100 hover:text-stone-600" title="Mark all as read" > <FontAwesomeIcon icon={faCheck} /> @@ -68,7 +71,7 @@ export function FeedItem({ feed, onFeedUnsubscribed }: Props) { <button type="button" onClick={() => handleMarkAllUnread(feed.id)} - className="rounded p-2 text-gray-600 hover:bg-gray-100 hover:text-gray-900" + className="rounded-lg p-2 text-stone-400 transition-all duration-150 hover:bg-stone-100 hover:text-stone-600" title="Mark all as unread" > <FontAwesomeIcon icon={faCircle} /> @@ -76,7 +79,7 @@ export function FeedItem({ feed, onFeedUnsubscribed }: Props) { <button type="button" onClick={() => handleUnsubscribeFeed(feed.id)} - className="rounded p-2 text-red-600 hover:bg-red-50 hover:text-red-700" + className="rounded-lg p-2 text-stone-400 transition-all duration-150 hover:bg-red-50 hover:text-red-600" title="Unsubscribe from feed" > <FontAwesomeIcon icon={faTrash} /> diff --git a/frontend/src/components/FeedList.tsx b/frontend/src/components/FeedList.tsx index 6081293..24bcfc7 100644 --- a/frontend/src/components/FeedList.tsx +++ b/frontend/src/components/FeedList.tsx @@ -15,17 +15,29 @@ export function FeedList({ onFeedUnsubscribed }: Props) { }); if (fetching) { - return <div className="p-4">Loading feeds...</div>; + return ( + <div className="py-8 text-center"> + <p className="text-sm text-stone-400">Loading feeds...</p> + </div> + ); } if (error) { - return <div className="p-4 text-red-600">Error: {error.message}</div>; + return ( + <div className="rounded-lg bg-red-50 p-4 text-sm text-red-600"> + Error: {error.message} + </div> + ); } if (!data?.feeds || data.feeds.length === 0) { - return <div className="p-4 text-gray-500">No feeds added yet.</div>; + return ( + <div className="py-8 text-center"> + <p className="text-sm text-stone-400">No feeds added yet.</p> + </div> + ); } return ( - <div className="space-y-4 p-4"> + <div className="space-y-3"> {data.feeds.map((feed) => ( <FeedItem key={feed.id} diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 09a0eb4..5f30de5 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -7,9 +7,9 @@ interface Props { export function Layout({ children }: Props) { return ( - <div className="min-h-screen bg-gray-50"> + <div className="min-h-screen bg-stone-50"> <Navigation /> - <main className="container mx-auto px-4 py-8">{children}</main> + <main className="mx-auto max-w-5xl px-6 py-10">{children}</main> </div> ); } diff --git a/frontend/src/components/MenuItem.tsx b/frontend/src/components/MenuItem.tsx index 29e397c..42202c9 100644 --- a/frontend/src/components/MenuItem.tsx +++ b/frontend/src/components/MenuItem.tsx @@ -15,10 +15,10 @@ export function MenuItem({ path, label, icon }: Props) { return ( <Link href={path} - className={`flex items-center sm:space-x-2 px-3 py-2 rounded-md text-sm font-medium transition-colors ${ + className={`flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm font-medium transition-all duration-200 ${ isActive - ? "bg-blue-100 text-blue-700" - : "text-gray-600 hover:text-gray-900 hover:bg-gray-100" + ? "bg-sky-50 text-sky-700" + : "text-stone-500 hover:text-stone-900 hover:bg-stone-100" }`} > <FontAwesomeIcon icon={icon} /> diff --git a/frontend/src/components/Navigation.tsx b/frontend/src/components/Navigation.tsx index c4af36a..1f99cd6 100644 --- a/frontend/src/components/Navigation.tsx +++ b/frontend/src/components/Navigation.tsx @@ -17,13 +17,16 @@ export function Navigation() { }; return ( - <nav className="bg-white shadow-sm border-b border-gray-200"> - <div className="container mx-auto px-4"> - <div className="flex items-center justify-between h-16"> - <Link href="/" className="text-xl font-bold text-gray-900"> + <nav className="sticky top-0 z-50 bg-white/80 backdrop-blur-sm border-b border-stone-200/60"> + <div className="mx-auto max-w-5xl px-6"> + <div className="flex items-center justify-between h-14"> + <Link + href="/" + className="text-lg font-semibold tracking-tight text-stone-900" + > feedaka </Link> - <div className="flex items-center space-x-6"> + <div className="flex items-center gap-1"> <MenuItem path="/unread" label="Unread" icon={faBookOpen} /> <MenuItem path="/read" label="Read" icon={faCircleCheck} /> <MenuItem path="/settings" label="Settings" icon={faGear} /> @@ -31,11 +34,13 @@ export function Navigation() { <button type="button" onClick={handleLogout} - className="flex items-center space-x-2 text-gray-600 hover:text-gray-900" + className="flex items-center gap-2 px-3 py-1.5 rounded-lg text-stone-500 hover:text-stone-900 hover:bg-stone-100 transition-all duration-200" title="Logout" > <FontAwesomeIcon icon={faRightFromBracket} /> - <span className="hidden sm:inline">Logout</span> + <span className="hidden sm:inline text-sm font-medium"> + Logout + </span> </button> )} </div> diff --git a/frontend/src/index.css b/frontend/src/index.css index f1d8c73..ffebab9 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1 +1,35 @@ @import "tailwindcss"; + +@theme { + --animate-fade-in: fade-in 0.3s ease-out; + --animate-slide-up: slide-up 0.3s ease-out; +} + +@keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes slide-up { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +html { + scroll-behavior: smooth; +} + +:focus-visible { + outline: 2px solid var(--color-sky-500); + outline-offset: 2px; +} diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx index 4d81234..76a775a 100644 --- a/frontend/src/pages/Login.tsx +++ b/frontend/src/pages/Login.tsx @@ -25,51 +25,64 @@ export function Login() { }; return ( - <div className="flex justify-center items-center min-h-screen bg-gray-100"> - <div className="bg-white p-8 rounded-lg shadow w-full max-w-md"> - <h1 className="mb-6 text-center text-2xl font-bold">Feedaka Login</h1> - <form onSubmit={handleSubmit}> - <div className="mb-4"> - <label htmlFor="username" className="block mb-2"> - Username - </label> - <input - id="username" - type="text" - value={username} - onChange={(e) => setUsername(e.target.value)} - required - className="w-full p-2 border border-gray-300 rounded disabled:opacity-70 disabled:cursor-not-allowed" - disabled={isLoading} - /> - </div> - <div className="mb-4"> - <label htmlFor="password" className="block mb-2"> - Password - </label> - <input - id="password" - type="password" - value={password} - onChange={(e) => setPassword(e.target.value)} - required - className="w-full p-2 border border-gray-300 rounded disabled:opacity-70 disabled:cursor-not-allowed" - disabled={isLoading} - /> - </div> - {error && ( - <div className="text-red-600 mb-4 p-2 bg-red-50 rounded"> - {error} + <div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-stone-100 to-stone-50 px-4"> + <div className="w-full max-w-sm"> + <div className="mb-8 text-center"> + <h1 className="text-2xl font-semibold tracking-tight text-stone-900"> + feedaka + </h1> + <p className="mt-2 text-sm text-stone-500">Sign in to your account</p> + </div> + <div className="rounded-xl border border-stone-200 bg-white p-6 shadow-sm"> + <form onSubmit={handleSubmit} className="space-y-5"> + <div> + <label + htmlFor="username" + className="mb-1.5 block text-sm font-medium text-stone-700" + > + Username + </label> + <input + id="username" + type="text" + value={username} + onChange={(e) => setUsername(e.target.value)} + required + className="w-full rounded-lg border border-stone-200 bg-white px-4 py-2.5 text-sm text-stone-900 transition-all duration-200 placeholder:text-stone-400 focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20 disabled:cursor-not-allowed disabled:opacity-70" + disabled={isLoading} + /> </div> - )} - <button - type="submit" - disabled={isLoading} - className="w-full p-3 bg-blue-500 text-white rounded cursor-pointer hover:bg-blue-600 disabled:opacity-70 disabled:cursor-not-allowed" - > - {isLoading ? "Logging in..." : "Login"} - </button> - </form> + <div> + <label + htmlFor="password" + className="mb-1.5 block text-sm font-medium text-stone-700" + > + Password + </label> + <input + id="password" + type="password" + value={password} + onChange={(e) => setPassword(e.target.value)} + required + className="w-full rounded-lg border border-stone-200 bg-white px-4 py-2.5 text-sm text-stone-900 transition-all duration-200 placeholder:text-stone-400 focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20 disabled:cursor-not-allowed disabled:opacity-70" + disabled={isLoading} + /> + </div> + {error && ( + <div className="rounded-lg bg-red-50 p-3 text-sm text-red-600"> + {error} + </div> + )} + <button + type="submit" + disabled={isLoading} + className="w-full rounded-lg bg-sky-600 px-4 py-2.5 text-sm font-medium text-white transition-all duration-200 hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-70" + > + {isLoading ? "Signing in..." : "Sign in"} + </button> + </form> + </div> </div> </div> ); diff --git a/frontend/src/pages/NotFound.tsx b/frontend/src/pages/NotFound.tsx index 23c1184..adc782b 100644 --- a/frontend/src/pages/NotFound.tsx +++ b/frontend/src/pages/NotFound.tsx @@ -1,14 +1,24 @@ +import { Link } from "wouter"; + export function NotFound() { return ( <div className="flex min-h-96 flex-col items-center justify-center"> <div className="text-center"> - <h1 className="text-6xl font-bold text-gray-900">404</h1> - <h2 className="mt-4 text-2xl font-semibold text-gray-700"> + <h1 className="text-6xl font-semibold tracking-tight text-stone-900"> + 404 + </h1> + <h2 className="mt-4 text-xl font-medium text-stone-700"> Page Not Found </h2> - <p className="mt-2 text-gray-500"> + <p className="mt-2 text-sm text-stone-400"> The page you're looking for doesn't exist. </p> + <Link + href="/" + className="mt-6 inline-block rounded-lg bg-sky-600 px-5 py-2.5 text-sm font-medium text-white transition-all duration-200 hover:bg-sky-700" + > + Go back home + </Link> </div> </div> ); diff --git a/frontend/src/pages/ReadArticles.tsx b/frontend/src/pages/ReadArticles.tsx index ccbd2dc..f90c3c9 100644 --- a/frontend/src/pages/ReadArticles.tsx +++ b/frontend/src/pages/ReadArticles.tsx @@ -11,19 +11,27 @@ export function ReadArticles() { }); if (fetching) { - return <div className="p-4">Loading read articles...</div>; + return ( + <div className="py-8 text-center"> + <p className="text-sm text-stone-400">Loading read articles...</p> + </div> + ); } if (error) { - return <div className="p-4 text-red-600">Error: {error.message}</div>; + return ( + <div className="rounded-lg bg-red-50 p-4 text-sm text-red-600"> + Error: {error.message} + </div> + ); } return ( <div> - <div className="border-b border-gray-200 bg-white px-4 py-3"> - <h1 className="text-xl font-semibold text-gray-900">Read Articles</h1> + <div className="mb-6"> + <h1 className="text-xl font-semibold text-stone-900">Read</h1> {data?.readArticles && ( - <p className="text-sm text-gray-500"> + <p className="mt-1 text-sm text-stone-400"> {data.readArticles.length} article {data.readArticles.length !== 1 ? "s" : ""} </p> diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index b10cbf1..9b1e04c 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -16,24 +16,17 @@ export function Settings() { }; return ( - <div className="mx-auto max-w-4xl"> - <h1 className="mb-6 text-2xl font-bold text-gray-900">Feed Settings</h1> - - {/* Subscribe to New Feed Section */} - <div className="mb-8"> - <h2 className="mb-4 text-xl font-semibold text-gray-800"> - Subscribe to New Feed - </h2> + <div className="mx-auto max-w-3xl space-y-10"> + <section> <AddFeedForm onFeedAdded={handleFeedAdded} /> - </div> + </section> - {/* Manage Feeds Section */} - <div className="mb-8"> - <h2 className="mb-4 text-xl font-semibold text-gray-800"> - Manage Feeds + <section> + <h2 className="mb-4 text-sm font-semibold uppercase tracking-wide text-stone-900"> + Your Feeds </h2> <FeedList onFeedUnsubscribed={handleFeedUnsubscribed} /> - </div> + </section> </div> ); } diff --git a/frontend/src/pages/UnreadArticles.tsx b/frontend/src/pages/UnreadArticles.tsx index dc4c377..28cc8b5 100644 --- a/frontend/src/pages/UnreadArticles.tsx +++ b/frontend/src/pages/UnreadArticles.tsx @@ -11,21 +11,29 @@ export function UnreadArticles() { }); if (fetching) { - return <div className="p-4">Loading unread articles...</div>; + return ( + <div className="py-8 text-center"> + <p className="text-sm text-stone-400">Loading unread articles...</p> + </div> + ); } if (error) { - return <div className="p-4 text-red-600">Error: {error.message}</div>; + return ( + <div className="rounded-lg bg-red-50 p-4 text-sm text-red-600"> + Error: {error.message} + </div> + ); } return ( <div> - <div className="border-b border-gray-200 bg-white px-4 py-3"> - <h1 className="text-xl font-semibold text-gray-900">Unread Articles</h1> + <div className="mb-6"> + <h1 className="text-xl font-semibold text-stone-900">Unread</h1> {data?.unreadArticles && ( - <p className="text-sm text-gray-500"> + <p className="mt-1 text-sm text-stone-400"> {data.unreadArticles.length} article - {data.unreadArticles.length !== 1 ? "s" : ""} + {data.unreadArticles.length !== 1 ? "s" : ""} to read </p> )} </div> |
