Skip to content

Commit 232a4ab

Browse files
committed
Dashboard: Various UI tweaks in project pages
1 parent bdcbe0e commit 232a4ab

File tree

24 files changed

+177
-138
lines changed

24 files changed

+177
-138
lines changed

apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ const linkTypeToOrder: Record<LinkType, number> = {
3838
settings: 5,
3939
};
4040

41-
const linkTypeToIcon: Record<LinkType, React.ReactNode> = {
42-
api: <NetworkIcon className="size-4" />,
43-
docs: <BookTextIcon className="size-4" />,
44-
playground: <BoxIcon className="size-4" />,
45-
webhooks: <WebhookIcon className="size-4" />,
46-
settings: <SettingsIcon className="size-4" />,
41+
const linkTypeToIcon: Record<LinkType, React.FC<{ className?: string }>> = {
42+
api: NetworkIcon,
43+
docs: BookTextIcon,
44+
playground: BoxIcon,
45+
webhooks: WebhookIcon,
46+
settings: SettingsIcon,
4747
};
4848

4949
function orderLinks(links: ActionLink[]) {
@@ -70,21 +70,22 @@ export function LinkGroup(props: { links: ActionLink[] }) {
7070
<div className="flex flex-row items-center gap-2">
7171
{orderedLinks.map((link) => {
7272
const isExternal = link.href.startsWith("http");
73+
const Icon = linkTypeToIcon[link.type];
7374
return (
7475
<ToolTipLabel key={link.type} label={linkTypeToLabel[link.type]}>
7576
<Button
7677
asChild
7778
size="icon"
78-
variant="outline"
79-
className="rounded-full"
79+
variant="secondary"
80+
className="rounded-full border"
8081
>
8182
<Link
8283
href={link.href}
8384
target={isExternal ? "_blank" : undefined}
8485
rel={isExternal ? "noopener noreferrer" : undefined}
8586
className="flex flex-row items-center gap-2"
8687
>
87-
{linkTypeToIcon[link.type]}
88+
<Icon className="size-4 text-foreground" />
8889
</Link>
8990
</Button>
9091
</ToolTipLabel>
@@ -98,25 +99,30 @@ export function LinkGroup(props: { links: ActionLink[] }) {
9899
return (
99100
<DropdownMenu>
100101
<DropdownMenuTrigger asChild>
101-
<Button size="icon" variant="outline" className="rounded-full">
102-
<EllipsisVerticalIcon className="size-4" />
102+
<Button size="icon" variant="secondary" className="rounded-full border">
103+
<EllipsisVerticalIcon className="size-4 text-foreground" />
103104
</Button>
104105
</DropdownMenuTrigger>
105-
<DropdownMenuContent align="end" className="gap-1 flex flex-col md:w-48">
106+
<DropdownMenuContent
107+
align="center"
108+
className="gap-1 flex flex-col md:w-48 rounded-lg"
109+
sideOffset={10}
110+
>
106111
{orderedLinks.map((link) => {
107112
const isExternal = link.href.startsWith("http");
113+
const Icon = linkTypeToIcon[link.type];
108114
return (
109115
<DropdownMenuItem
110116
key={link.type}
111117
asChild
112-
className="flex flex-row items-center gap-2 cursor-pointer py-2 text-muted-foreground hover:text-foreground"
118+
className="flex flex-row items-center gap-2 cursor-pointer py-2"
113119
>
114120
<Link
115121
href={link.href}
116122
target={isExternal ? "_blank" : undefined}
117123
rel={isExternal ? "noopener noreferrer" : undefined}
118124
>
119-
{linkTypeToIcon[link.type]}
125+
<Icon className="size-4 text-muted-foreground" />
120126
{linkTypeToLabel[link.type]}
121127
</Link>
122128
</DropdownMenuItem>

apps/dashboard/src/@/components/blocks/project-page/project-page-footer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export type ProjectPageFooterProps = FooterCardProps;
77

88
export function ProjectPageFooter(props: ProjectPageFooterProps) {
99
return (
10-
<footer className="container">
10+
<footer className="container max-w-7xl">
1111
<FooterLinksSection {...props} />
1212
</footer>
1313
);

apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Button } from "@workspace/ui/components/button";
22
import { ArrowUpRightIcon } from "lucide-react";
33
import Link from "next/link";
44
import type { ThirdwebClient } from "thirdweb";
5+
import { cn } from "@/lib/utils";
56
import { ProjectAvatar } from "../avatar/project-avatar";
67
import { type ActionLink, LinkGroup } from "./header/link-group";
78

@@ -25,15 +26,24 @@ type Action =
2526

2627
function Action(props: { action: Action; variant?: "default" | "secondary" }) {
2728
const action = props.action;
29+
2830
return "component" in action ? (
2931
action.component
3032
) : (
31-
<Button asChild className="rounded-full" variant={props.variant}>
33+
<Button
34+
asChild
35+
className={cn(
36+
"rounded-full",
37+
props.variant === "secondary" && "border border-border",
38+
)}
39+
size="sm"
40+
variant={props.variant}
41+
>
3242
<Link
3343
href={action.href}
3444
target={action.external ? "_blank" : undefined}
3545
rel={action.external ? "noopener noreferrer" : undefined}
36-
className="flex flex-row items-center gap-1.5"
46+
className="flex flex-row items-center gap-2"
3747
>
3848
{action.icon}
3949
{action.label}
@@ -46,7 +56,7 @@ function Action(props: { action: Action; variant?: "default" | "secondary" }) {
4656
export type ProjectPageHeaderProps = {
4757
client: ThirdwebClient;
4858
title: string;
49-
description?: string;
59+
description?: React.ReactNode;
5060
imageUrl?: string | null;
5161
actions: {
5262
primary: Action;
@@ -61,22 +71,24 @@ export type ProjectPageHeaderProps = {
6171

6272
export function ProjectPageHeader(props: ProjectPageHeaderProps) {
6373
return (
64-
<header className="flex flex-col gap-4 container py-5">
74+
<header className="flex flex-col gap-4 container max-w-7xl py-6">
6575
{/* main row */}
6676
<div className="flex flex-row items-center justify-between">
6777
{/* left */}
68-
<div className="flex flex-col gap-2">
78+
<div className="flex flex-col gap-4">
6979
{/* image */}
7080
{props.imageUrl !== undefined && (
7181
<ProjectAvatar
72-
className="size-14"
82+
className="size-12"
7383
client={props.client}
7484
src={props.imageUrl ?? undefined}
7585
/>
7686
)}
7787
{/* title */}
78-
<div className="flex flex-col gap-1 max-w-xl">
79-
<h2 className="text-2xl font-medium line-clamp-1">{props.title}</h2>
88+
<div className="flex flex-col gap-1 max-w-3xl">
89+
<h2 className="text-3xl font-semibold tracking-tight line-clamp-1">
90+
{props.title}
91+
</h2>
8092
<p className="text-sm text-muted-foreground line-clamp-3 md:line-clamp-2">
8193
{props.description}
8294
</p>
@@ -91,7 +103,7 @@ export function ProjectPageHeader(props: ProjectPageHeaderProps) {
91103
{props.actions && (
92104
<div className="flex flex-row items-center justify-between">
93105
{/* left actions */}
94-
<div className="flex flex-row items-center gap-4">
106+
<div className="flex flex-row items-center gap-3">
95107
{props.actions.primary && <Action action={props.actions.primary} />}
96108
{props.actions.secondary && (
97109
<Action action={props.actions.secondary} variant="secondary" />
Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Separator } from "../../ui/separator";
1+
import { cn } from "@/lib/utils";
22
import { type TabPathLink, TabPathLinks } from "../../ui/tabs";
33
import {
44
ProjectPageFooter,
@@ -21,24 +21,23 @@ type ProjectPageProps = {
2121

2222
export function ProjectPage(props: React.PropsWithChildren<ProjectPageProps>) {
2323
return (
24-
<section className="flex flex-col gap-4 pb-20">
25-
<ProjectPageHeader {...props.header} />
26-
{props.tabs ? (
27-
<TabPathLinks
28-
className="-mt-4"
29-
tabContainerClassName="container"
30-
links={props.tabs}
31-
/>
32-
) : (
33-
<Separator />
34-
)}
35-
<main className="container py-6">{props.children}</main>
24+
<div className={cn("flex flex-col pb-20", props.footer && "pb-0")}>
25+
<div className={cn(!props.tabs && "border-b")}>
26+
<ProjectPageHeader {...props.header} />
27+
{props.tabs && (
28+
<TabPathLinks
29+
scrollableClassName="container max-w-7xl"
30+
links={props.tabs}
31+
/>
32+
)}
33+
</div>
34+
35+
<main className="container max-w-7xl pt-6">{props.children}</main>
3636
{props.footer && (
37-
<>
38-
<Separator />
37+
<div className="border-t mt-20">
3938
<ProjectPageFooter {...props.footer} />
40-
</>
39+
</div>
4140
)}
42-
</section>
41+
</div>
4342
);
4443
}

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ export function ProjectSidebarLayout(props: {
125125
},
126126
]}
127127
footerSidebarLinks={[
128+
{
129+
separator: true,
130+
},
128131
{
129132
href: `${props.layoutPath}/webhooks/contracts`,
130133
icon: WebhookIcon,

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/import-contract-button.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ export function ImportContractButton(props: {
3131
/>
3232

3333
<Button
34-
className="gap-1.5 rounded-full"
34+
className="gap-2 rounded-full border"
35+
size="sm"
3536
onClick={() => {
3637
setImportModalOpen(true);
3738
}}
38-
variant="outline"
39+
variant="secondary"
3940
>
4041
<ImportIcon className="size-4" />
4142
Import contract

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,13 @@ export default async function Page(props: {
4242
header={{
4343
client,
4444
title: "Contracts",
45-
description:
46-
"Read, write, and deploy smart contracts on any EVM compatible blockchain. Deploy contracts from templates, or build your own from scratch.",
45+
description: (
46+
<>
47+
Read, write, and deploy smart contracts on any EVM compatible
48+
blockchain. <br className="max-sm:hidden" /> Deploy contracts from
49+
templates, or build your own from scratch
50+
</>
51+
),
4752
actions: {
4853
primary: {
4954
label: "Deploy Contract",

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/_components.tsx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ArrowRightIcon, ExternalLinkIcon } from "lucide-react";
1+
import { ArrowRightIcon, ArrowUpRightIcon } from "lucide-react";
22
import Link from "next/link";
33
import { Button } from "@/components/ui/button";
44

@@ -7,11 +7,11 @@ function EngineInfoSection(props: { team_slug: string; project_slug: string }) {
77

88
return (
99
<div className="">
10-
<h3 className="mb-1 font-semibold text-lg tracking-tight">
10+
<h3 className="mb-3 font-semibold text-lg tracking-tight">
1111
What is Engine?
1212
</h3>
1313

14-
<ul className="list-disc space-y-2 pl-3 text-muted-foreground text-sm">
14+
<ul className="list-disc space-y-1.5 pl-3 text-muted-foreground text-sm">
1515
<li>Read, write, and deploy contracts at production scale</li>
1616
<li>
1717
Reliably parallelize and retry transactions with gas & nonce
@@ -21,23 +21,33 @@ function EngineInfoSection(props: { team_slug: string; project_slug: string }) {
2121
<li>Built-in support for account abstraction, relayers, and more</li>
2222
</ul>
2323

24-
<div className="mt-4 flex justify-start gap-3">
25-
<Button asChild size="sm" variant="outline">
24+
<div className="mt-5 flex justify-start gap-3">
25+
<Button
26+
asChild
27+
size="sm"
28+
variant="outline"
29+
className="rounded-full bg-card"
30+
>
2631
<Link
2732
className="gap-2"
2833
href="https://portal.thirdweb.com/engine"
2934
rel="noopener noreferrer"
3035
target="_blank"
3136
>
3237
Learn More
33-
<ExternalLinkIcon className="size-3 text-muted-foreground" />
38+
<ArrowUpRightIcon className="size-3.5 text-muted-foreground" />
3439
</Link>
3540
</Button>
3641

37-
<Button asChild size="sm" variant="outline">
42+
<Button
43+
asChild
44+
size="sm"
45+
variant="outline"
46+
className="rounded-full bg-card"
47+
>
3848
<Link className="gap-2" href={`${engineLinkPrefix}/sandbox`}>
3949
Try Demo Engine
40-
<ArrowRightIcon className="size-3 text-muted-foreground" />
50+
<ArrowRightIcon className="size-3.5 text-muted-foreground" />
4151
</Link>
4252
</Button>
4353
</div>

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ export function ImportEngineButton(props: {
107107
<form onSubmit={form.handleSubmit(onSubmit)}>
108108
<Dialog>
109109
<DialogTrigger asChild>
110-
<Button className="gap-1.5 rounded-full" variant="outline">
110+
<Button
111+
className="gap-2 rounded-full border"
112+
size="sm"
113+
variant="secondary"
114+
>
111115
<ImportIcon className="size-4" />
112116
Import Engine
113117
</Button>

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/overview/engine-instances-table.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export function DedicatedEngineSubscriptionButton(props: { team: Team }) {
131131
const isMobile = useIsMobile();
132132

133133
const trigger = (
134-
<Button className="gap-1.5 rounded-full">
134+
<Button className="gap-2 rounded-full" size="sm">
135135
<PlusIcon className="size-4" />
136136
Deploy Dedicated Engine
137137
</Button>

0 commit comments

Comments
 (0)