Skip to content

Commit c9b4730

Browse files
committed
Dashboard: Team Overview page UI improvements (#7400)
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR primarily focuses on enhancing UI components in the dashboard application, including pagination buttons, team member invitations, and changelog displays. It also refines layout and styling for better user experience. ### Detailed summary - Updated `pagination-buttons.stories.tsx` to correct page labels. - Modified `InviteTeamMembersButton` styling for a more rounded appearance. - Enhanced layout in `page.tsx` for better responsiveness and spacing. - Changed `Changelog` component structure for improved visual hierarchy. - Adjusted `TeamProjectsPage` to refine project display and sorting options. - Replaced `Select` component with a `DropdownMenu` for sorting. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Changelog section now displays feature images for each entry, with fallback icons if unavailable. - Changelog items are shown in a responsive grid layout for improved readability. - Changelog header includes a title, description, and "View All" button. - **Enhancements** - Team projects page features a redesigned search input, improved sorting with a dropdown menu, and a more prominent subtitle. - "Create Project" and other action buttons have updated styling for better visibility. - Invite Team Members button now has a rounded appearance and enhanced background styling. - Dashboard layout is streamlined with sequential content flow and consistent maximum width for better usability. - Pagination controls updated with fully rounded styling for a modern look. - Pagination storybook examples corrected and expanded to accurately represent page counts. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent ea3c702 commit c9b4730

File tree

6 files changed

+213
-158
lines changed

6 files changed

+213
-158
lines changed

apps/dashboard/src/@/components/pagination-buttons.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ function Story() {
2525
<div className="container flex max-w-[1000px] flex-col gap-8 py-10">
2626
<Variant label="10 Pages" totalPages={10} />
2727
<Variant label="100 Pages" totalPages={100} />
28-
<Variant label="3 Pages" totalPages={2} />
28+
<Variant label="2 Pages" totalPages={2} />
29+
<Variant label="3 Pages" totalPages={3} />
2930
<Variant label="6 Pages" totalPages={6} />
3031
<Variant label="1 Page - nothing rendered" totalPages={1} />
3132
</div>

apps/dashboard/src/@/components/pagination-buttons.tsx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export const PaginationButtons = (props: {
4848
<PaginationContent>
4949
<PaginationItem>
5050
<PaginationPrevious
51+
className="rounded-full"
5152
disabled={activePage === 1}
5253
onClick={() => {
5354
setPage(activePage - 1);
@@ -56,6 +57,7 @@ export const PaginationButtons = (props: {
5657
</PaginationItem>
5758
<PaginationItem>
5859
<PaginationNext
60+
className="rounded-full"
5961
disabled={activePage === totalPages}
6062
onClick={() => {
6163
setPage(activePage + 1);
@@ -76,6 +78,7 @@ export const PaginationButtons = (props: {
7678
{pages.map((page) => (
7779
<PaginationItem key={page}>
7880
<PaginationLink
81+
className="rounded-full"
7982
isActive={activePage === page}
8083
onClick={() => {
8184
setPage(page);
@@ -95,6 +98,7 @@ export const PaginationButtons = (props: {
9598
<PaginationContent>
9699
<PaginationItem>
97100
<PaginationPrevious
101+
className="rounded-full"
98102
disabled={activePage === 1}
99103
onClick={() => {
100104
setPage(activePage - 1);
@@ -107,6 +111,7 @@ export const PaginationButtons = (props: {
107111
<>
108112
<PaginationItem>
109113
<PaginationLink
114+
className="rounded-full"
110115
onClick={() => {
111116
setPage(1);
112117
}}
@@ -116,14 +121,15 @@ export const PaginationButtons = (props: {
116121
</PaginationItem>
117122

118123
<PaginationItem>
119-
<PaginationEllipsis className="max-sm:w-3" />
124+
<PaginationEllipsis className="max-sm:w-3 rounded-full" />
120125
</PaginationItem>
121126
</>
122127
)}
123128

124129
{activePage - 1 > 0 && (
125130
<PaginationItem className="max-sm:hidden">
126131
<PaginationLink
132+
className="rounded-full"
127133
onClick={() => {
128134
setPage(activePage - 1);
129135
}}
@@ -134,12 +140,15 @@ export const PaginationButtons = (props: {
134140
)}
135141

136142
<PaginationItem>
137-
<PaginationLink isActive>{activePage}</PaginationLink>
143+
<PaginationLink className="rounded-full" isActive>
144+
{activePage}
145+
</PaginationLink>
138146
</PaginationItem>
139147

140148
{activePage + 1 <= totalPages && (
141149
<PaginationItem className="max-sm:hidden">
142150
<PaginationLink
151+
className="rounded-full"
143152
onClick={() => {
144153
setPage(activePage + 1);
145154
}}
@@ -153,11 +162,12 @@ export const PaginationButtons = (props: {
153162
{activePage + 3 <= totalPages && (
154163
<>
155164
<PaginationItem>
156-
<PaginationEllipsis className="max-sm:w-3" />
165+
<PaginationEllipsis className="max-sm:w-3 rounded-full" />
157166
</PaginationItem>
158167

159168
<PaginationItem>
160169
<PaginationLink
170+
className="rounded-full"
161171
onClick={() => {
162172
setPage(totalPages);
163173
}}
@@ -170,6 +180,7 @@ export const PaginationButtons = (props: {
170180

171181
<PaginationItem>
172182
<PaginationNext
183+
className="rounded-full"
173184
disabled={activePage === totalPages}
174185
onClick={() => {
175186
setPage(activePage + 1);
@@ -180,7 +191,7 @@ export const PaginationButtons = (props: {
180191
<div className="relative flex items-center">
181192
<Input
182193
className={cn(
183-
"w-[60px] bg-transparent [appearance:textfield] max-sm:placeholder:text-sm lg:w-[100px] lg:pr-8 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
194+
"w-[60px] bg-transparent [appearance:textfield] max-sm:placeholder:text-sm lg:w-[100px] lg:pr-8 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none rounded-full",
184195
inputHasError && "text-red-500",
185196
)}
186197
onChange={(e) => {
@@ -197,7 +208,7 @@ export const PaginationButtons = (props: {
197208
value={pageNumberInput}
198209
/>
199210
<Button
200-
className="absolute right-1 h-auto w-auto p-2 max-sm:hidden"
211+
className="absolute right-1 h-auto w-auto rounded-full p-2 max-sm:hidden"
201212
onClick={handlePageInputSubmit}
202213
variant="ghost"
203214
>

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/_components/Changelog.tsx

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,92 @@
11
import { formatDistance } from "date-fns";
2-
import { ArrowRightIcon } from "lucide-react";
2+
import { ArrowRightIcon, FileTextIcon } from "lucide-react";
33
import { unstable_cache } from "next/cache";
44
import Link from "next/link";
5+
import { Img } from "@/components/blocks/Img";
6+
import { Button } from "@/components/ui/button";
57

68
type ChangelogItem = {
79
published_at: string;
810
title: string;
911
url: string;
12+
feature_image: string;
1013
};
1114

1215
export async function Changelog() {
1316
const changelog = await getChangelog();
1417

1518
return (
16-
<div className="relative flex flex-col gap-6 border-border border-l py-2">
17-
{changelog.map((item) => (
18-
<div className="flex flex-row gap-2" key={item.title}>
19-
<div className="-translate-x-1/2 size-2.5 shrink-0 translate-y-1/2 rounded-full bg-border" />
19+
<div className="relative flex grow flex-col">
20+
<div className="mb-4 flex items-center justify-between gap-4">
21+
<div>
22+
<h2 className="mb-1 font-semibold text-2xl tracking-tight">
23+
Changelog
24+
</h2>
25+
<p className="text-muted-foreground text-sm">
26+
View the latest updates to thirdweb products and services
27+
</p>
28+
</div>
29+
30+
<Button
31+
asChild
32+
className="gap-2 rounded-full bg-card"
33+
variant="outline"
34+
>
35+
<Link
36+
href="https://blog.thirdweb.com/changelog?utm_source=thirdweb&utm_campaign=changelog"
37+
rel="noopener noreferrer"
38+
target="_blank"
39+
>
40+
View All <ArrowRightIcon className="size-4" />
41+
</Link>
42+
</Button>
43+
</div>
44+
45+
<div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
46+
{changelog.map((item) => (
47+
<div
48+
className="relative overflow-hidden rounded-xl border bg-card hover:border-active-border"
49+
key={item.title}
50+
>
51+
<Img
52+
alt={item.title}
53+
className="aspect-video w-full object-cover"
54+
fallback={
55+
<div className="flex items-center justify-center bg-gradient-to-b from-card to-accent">
56+
<div className="rounded-full border p-3">
57+
<FileTextIcon className="size-5 text-muted-foreground" />
58+
</div>
59+
</div>
60+
}
61+
src={item.feature_image}
62+
/>
2063

21-
<div className="flex flex-col">
22-
<Link
23-
className="line-clamp-2 text-foreground text-sm hover:underline"
24-
href={`${item.url}?utm_source=thirdweb&utm_campaign=changelog`}
25-
target="_blank"
26-
>
27-
{item.title}
28-
</Link>
29-
<div className="mt-1 text-muted-foreground text-xs">
30-
{formatDistance(new Date(item.published_at), Date.now(), {
31-
addSuffix: true,
32-
})}
64+
<div className="border-t px-3 py-4">
65+
<Link
66+
className="mb-2 line-clamp-2 font-medium text-base text-foreground before:absolute before:inset-0"
67+
href={`${item.url}?utm_source=thirdweb&utm_campaign=changelog`}
68+
target="_blank"
69+
>
70+
{item.title}
71+
</Link>
72+
73+
<div className="text-muted-foreground text-sm">
74+
{formatDistance(new Date(item.published_at), Date.now(), {
75+
addSuffix: true,
76+
})}
77+
</div>
3378
</div>
3479
</div>
35-
</div>
36-
))}
37-
<Link
38-
className="flex items-center gap-2 pl-5 text-foreground text-sm hover:underline"
39-
href="https://blog.thirdweb.com/changelog?utm_source=thirdweb&utm_campaign=changelog"
40-
rel="noopener noreferrer"
41-
target="_blank"
42-
>
43-
View More <ArrowRightIcon className="size-4" />
44-
</Link>
80+
))}
81+
</div>
4582
</div>
4683
);
4784
}
4885

4986
const getChangelog = unstable_cache(
5087
async () => {
5188
const res = await fetch(
52-
"https://thirdweb.ghost.io/ghost/api/content/posts/?key=49c62b5137df1c17ab6b9e46e3&fields=title,url,published_at&filter=tag:changelog&visibility:public&limit=10",
89+
"https://thirdweb.ghost.io/ghost/api/content/posts/?key=49c62b5137df1c17ab6b9e46e3&fields=title,url,published_at,feature_image&filter=tag:changelog&visibility:public&limit=12",
5390
);
5491
if (!res.ok) {
5592
return [];

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/_components/invite-team-members-button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button";
66

77
export function InviteTeamMembersButton(props: { teamSlug: string }) {
88
return (
9-
<Button asChild className="gap-2" variant="outline">
9+
<Button asChild className="gap-2 rounded-full bg-card" variant="outline">
1010
<Link href={`/team/${props.teamSlug}/~/settings/members`}>
1111
<UserPlusIcon className="size-4" />
1212
<span>Invite Team Members</span>

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/page.tsx

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default async function Page(props: {
4343
return (
4444
<div className="flex grow flex-col">
4545
<div className="border-border border-b">
46-
<div className="container flex flex-col items-start gap-3 py-10 md:flex-row md:items-center">
46+
<div className="container flex max-w-6xl flex-col items-start gap-3 py-10 md:flex-row md:items-center">
4747
<div className="flex-1">
4848
<h1 className="font-semibold text-3xl tracking-tight">
4949
Team Overview
@@ -53,37 +53,24 @@ export default async function Page(props: {
5353
</div>
5454
</div>
5555

56-
<div className="container flex grow flex-col gap-4 lg:flex-row">
57-
{/* left */}
58-
<div className="flex grow flex-col gap-6 pt-8 lg:pb-20">
59-
{team.billingPlan === "free" ? (
60-
<FreePlanUpsellBannerUI
61-
highlightPlan="growth"
62-
teamSlug={team.slug}
63-
/>
64-
) : (
65-
<DismissibleAlert
66-
description="Engines, contracts, project settings, and more are now managed within projects. Open or create a project to access them."
67-
localStorageId={`${team.id}-engines-alert`}
68-
title="Looking for Engines?"
69-
/>
70-
)}
56+
<div className="container flex max-w-6xl flex-col gap-10 py-6 pb-20">
57+
<TeamProjectsPage
58+
client={client}
59+
projects={projectsWithTotalWallets}
60+
team={team}
61+
/>
7162

72-
<TeamProjectsPage
73-
client={client}
74-
projects={projectsWithTotalWallets}
75-
team={team}
63+
{team.billingPlan === "free" ? (
64+
<FreePlanUpsellBannerUI highlightPlan="growth" teamSlug={team.slug} />
65+
) : (
66+
<DismissibleAlert
67+
description="Engines, contracts, project settings, and more are now managed within projects. Open or create a project to access them."
68+
localStorageId={`${team.id}-engines-alert`}
69+
title="Looking for Engines?"
7670
/>
77-
</div>
78-
79-
{/* right */}
80-
<div className="w-full px-4 py-8 lg:w-[300px]">
81-
<h2 className="mb-3 font-semibold text-2xl tracking-tight">
82-
Changelog
83-
</h2>
71+
)}
8472

85-
<Changelog />
86-
</div>
73+
<Changelog />
8774
</div>
8875
</div>
8976
);

0 commit comments

Comments
 (0)