fix: improve dashboard UX and fix dark mode

- Replace hardcoded bg-white with bg-surface across all dashboard pages
- Add welcome banner with quick actions on dashboard overview
- Improve quick action cards with better hover states and icons
- Enhance profile section with avatar initial and edit button
- Fix dark mode support in collections, executor config, and playground
This commit is contained in:
Ajax Davis 2026-01-14 06:48:18 +10:00
parent faf4b622c7
commit e73b7955a3
9 changed files with 114 additions and 64 deletions

View file

@ -93,7 +93,7 @@ function McpUrlSection({ username, slug }: { username: string; slug: string }) {
<span className="text-xs text-foreground-tertiary">(recommended)</span>
</div>
<div className="flex items-center gap-2">
<div className="flex-1 px-3 py-2 bg-white border border-border rounded-lg font-mono text-sm text-foreground-secondary overflow-x-auto">
<div className="flex-1 px-3 py-2 bg-surface border border-border rounded-lg font-mono text-sm text-foreground-secondary overflow-x-auto">
{httpUrl}
</div>
<Button
@ -117,7 +117,7 @@ function McpUrlSection({ username, slug }: { username: string; slug: string }) {
<span className="text-xs text-foreground-tertiary">(streaming)</span>
</div>
<div className="flex items-center gap-2">
<div className="flex-1 px-3 py-2 bg-white border border-border rounded-lg font-mono text-sm text-foreground-secondary overflow-x-auto">
<div className="flex-1 px-3 py-2 bg-surface border border-border rounded-lg font-mono text-sm text-foreground-secondary overflow-x-auto">
{sseUrl}
</div>
<Button
@ -146,7 +146,7 @@ function McpUrlSection({ username, slug }: { username: string; slug: string }) {
{showConfig && (
<div className="mt-3 relative">
<pre className="p-4 bg-white border border-border rounded-lg text-xs font-mono text-foreground-secondary overflow-x-auto">
<pre className="p-4 bg-surface border border-border rounded-lg text-xs font-mono text-foreground-secondary overflow-x-auto">
{configSnippet}
</pre>
<Button
@ -320,7 +320,7 @@ export default function PublicCollectionDetailPage(): React.ReactElement {
<h2 className="text-lg font-semibold text-foreground mb-4">Tools in this Collection</h2>
{collection.tools.length === 0 ? (
<div className="text-center py-12 bg-white border border-border rounded-lg">
<div className="text-center py-12 bg-surface border border-border rounded-lg">
<Icon icon="puzzle" size="lg" className="mx-auto text-foreground-tertiary mb-2" />
<p className="text-foreground-secondary">No tools in this collection yet</p>
</div>
@ -329,7 +329,7 @@ export default function PublicCollectionDetailPage(): React.ReactElement {
{collection.tools.map((ct) => (
<div
key={ct.id}
className="bg-white border border-border rounded-lg p-4 hover:border-foreground/20 hover:shadow-sm transition-all"
className="bg-surface border border-border rounded-lg p-4 hover:border-foreground/20 hover:shadow-sm transition-all"
>
<div className="flex items-start justify-between mb-2">
<div>

View file

@ -154,7 +154,7 @@ export default function AgentsPage(): React.ReactElement {
</Link>
}
>
<div className="bg-white border border-border rounded-lg overflow-hidden">
<div className="bg-surface border border-border rounded-lg overflow-hidden">
<Table>
<TableHeader>
<TableRow>

View file

@ -64,7 +64,7 @@ function McpUrlSection({ username, slug }: { username: string; slug: string }) {
<span className="text-xs text-foreground-tertiary">(recommended)</span>
</div>
<div className="flex items-center gap-2">
<div className="flex-1 px-3 py-2 bg-white border border-border rounded-lg font-mono text-sm text-foreground-secondary overflow-x-auto">
<div className="flex-1 px-3 py-2 bg-surface border border-border rounded-lg font-mono text-sm text-foreground-secondary overflow-x-auto">
{httpUrl}
</div>
<Button
@ -88,7 +88,7 @@ function McpUrlSection({ username, slug }: { username: string; slug: string }) {
<span className="text-xs text-foreground-tertiary">(streaming)</span>
</div>
<div className="flex items-center gap-2">
<div className="flex-1 px-3 py-2 bg-white border border-border rounded-lg font-mono text-sm text-foreground-secondary overflow-x-auto">
<div className="flex-1 px-3 py-2 bg-surface border border-border rounded-lg font-mono text-sm text-foreground-secondary overflow-x-auto">
{sseUrl}
</div>
<Button
@ -117,7 +117,7 @@ function McpUrlSection({ username, slug }: { username: string; slug: string }) {
{showConfig && (
<div className="mt-3 relative">
<pre className="p-4 bg-white border border-border rounded-lg text-xs font-mono text-foreground-secondary overflow-x-auto">
<pre className="p-4 bg-surface border border-border rounded-lg text-xs font-mono text-foreground-secondary overflow-x-auto">
{configSnippet}
</pre>
<Button
@ -480,7 +480,7 @@ export default function CollectionDetailPage(): React.ReactElement {
>
{/* Edit Form */}
{isEditing && (
<div className="bg-white border border-border rounded-lg p-6 mb-8">
<div className="bg-surface border border-border rounded-lg p-6 mb-8">
<CollectionForm
initialData={{
name: collection.name,

View file

@ -166,7 +166,7 @@ export default function CollectionsPage(): React.ReactElement {
>
{/* Create Form */}
{showCreateForm && (
<div className="bg-white border border-border rounded-lg p-6 mb-6">
<div className="bg-surface border border-border rounded-lg p-6 mb-6">
<h2 className="text-lg font-medium text-foreground mb-4">Create New Collection</h2>
<CollectionForm
onSubmit={handleCreate}
@ -178,7 +178,7 @@ export default function CollectionsPage(): React.ReactElement {
)}
{/* Collections Table */}
<div className="bg-white border border-border rounded-lg overflow-hidden">
<div className="bg-surface border border-border rounded-lg overflow-hidden">
<Table>
<TableHeader>
<TableRow>

View file

@ -95,7 +95,7 @@ export default function LikedAgentsPage(): React.ReactElement {
{isLoading ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{[1, 2, 3, 4, 5, 6].map((i) => (
<div key={i} className="bg-white border border-border rounded-lg p-4 animate-pulse">
<div key={i} className="bg-surface border border-border rounded-lg p-4 animate-pulse">
<div className="h-5 bg-surface-secondary rounded w-3/4 mb-2" />
<div className="h-4 bg-surface-secondary rounded w-full mb-1" />
<div className="h-4 bg-surface-secondary rounded w-2/3" />
@ -121,7 +121,7 @@ export default function LikedAgentsPage(): React.ReactElement {
{agents.map((item) => (
<div
key={item.id}
className="bg-white border border-border rounded-lg p-4 hover:border-foreground/20 hover:shadow-sm transition-all"
className="bg-surface border border-border rounded-lg p-4 hover:border-foreground/20 hover:shadow-sm transition-all"
>
<div className="flex items-start justify-between mb-2">
<Link

View file

@ -97,7 +97,7 @@ export default function LikedCollectionsPage(): React.ReactElement {
{isLoading ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{[1, 2, 3, 4, 5, 6].map((i) => (
<div key={i} className="bg-white border border-border rounded-lg p-4 animate-pulse">
<div key={i} className="bg-surface border border-border rounded-lg p-4 animate-pulse">
<div className="h-5 bg-surface-secondary rounded w-3/4 mb-2" />
<div className="h-4 bg-surface-secondary rounded w-full mb-1" />
<div className="h-4 bg-surface-secondary rounded w-2/3" />
@ -123,7 +123,7 @@ export default function LikedCollectionsPage(): React.ReactElement {
{collections.map((item) => (
<div
key={item.id}
className="bg-white border border-border rounded-lg p-4 hover:border-foreground/20 hover:shadow-sm transition-all"
className="bg-surface border border-border rounded-lg p-4 hover:border-foreground/20 hover:shadow-sm transition-all"
>
<div className="flex items-start justify-between mb-2">
<Link

View file

@ -95,7 +95,7 @@ export default function LikesOverviewPage(): React.ReactElement {
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{sections.map((section) => (
<Link key={section.href} href={section.href} className="block">
<div className="bg-white border border-border rounded-lg p-6 hover:border-foreground/20 hover:shadow-sm transition-all group h-full">
<div className="bg-surface border border-border rounded-lg p-6 hover:border-foreground/20 hover:shadow-sm transition-all group h-full">
<div className="flex items-center gap-4">
<div className="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center group-hover:bg-primary/20 transition-colors">
<Icon icon={section.icon} size="md" className="text-primary" />

View file

@ -90,7 +90,7 @@ export default function LikedToolsPage(): React.ReactElement {
{isLoading ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{[1, 2, 3, 4, 5, 6].map((i) => (
<div key={i} className="bg-white border border-border rounded-lg p-4 animate-pulse">
<div key={i} className="bg-surface border border-border rounded-lg p-4 animate-pulse">
<div className="h-5 bg-surface-secondary rounded w-3/4 mb-2" />
<div className="h-4 bg-surface-secondary rounded w-full mb-1" />
<div className="h-4 bg-surface-secondary rounded w-2/3" />
@ -116,7 +116,7 @@ export default function LikedToolsPage(): React.ReactElement {
{tools.map((item) => (
<div
key={item.id}
className="bg-white border border-border rounded-lg p-4 hover:border-foreground/20 hover:shadow-sm transition-all"
className="bg-surface border border-border rounded-lg p-4 hover:border-foreground/20 hover:shadow-sm transition-all"
>
<div className="flex items-start justify-between mb-2">
<Link

View file

@ -1,6 +1,7 @@
'use client';
import { useSession } from '@/lib/auth-client';
import { Button } from '@tpmjs/ui/Button/Button';
import { Icon } from '@tpmjs/ui/Icon/Icon';
import Link from 'next/link';
import { DashboardActivityStream } from '~/components/DashboardActivityStream';
@ -11,51 +12,86 @@ export default function DashboardPage(): React.ReactElement {
return (
<DashboardLayout title="Overview">
{/* Welcome Banner */}
<div className="mb-8 p-6 rounded-lg bg-gradient-to-r from-primary/10 via-primary/5 to-transparent border border-primary/20">
<h2 className="text-xl font-semibold text-foreground mb-2">
Welcome back{session?.user?.name ? `, ${session.user.name.split(' ')[0]}` : ''}!
</h2>
<p className="text-foreground-secondary mb-4">
Build AI agents, organize tools into collections, and connect them to your workflows.
</p>
<div className="flex flex-wrap gap-3">
<Link href="/dashboard/agents/new">
<Button size="sm">
<Icon icon="plus" size="xs" className="mr-1" />
Create Agent
</Button>
</Link>
<Link href="/tool/tool-search">
<Button size="sm" variant="outline">
<Icon icon="search" size="xs" className="mr-1" />
Browse Tools
</Button>
</Link>
</div>
</div>
{/* Quick Actions */}
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 mb-8">
<Link href="/dashboard/agents" className="block">
<div className="bg-white border border-border rounded-lg p-6 hover:border-foreground/20 hover:shadow-sm transition-all group">
<div className="flex items-center gap-4">
<Link href="/dashboard/agents" className="block group">
<div className="bg-surface border border-border rounded-lg p-6 hover:border-primary/50 hover:shadow-md transition-all h-full">
<div className="flex items-start justify-between mb-4">
<div className="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center group-hover:bg-primary/20 transition-colors">
<Icon icon="terminal" size="md" className="text-primary" />
</div>
<div>
<h2 className="text-lg font-medium text-foreground">My Agents</h2>
<p className="text-sm text-foreground-secondary">
Create and manage AI agents with tools
</p>
</div>
<Icon
icon="chevronRight"
size="sm"
className="text-foreground-tertiary group-hover:text-primary group-hover:translate-x-1 transition-all"
/>
</div>
<h3 className="text-lg font-semibold text-foreground mb-1">Agents</h3>
<p className="text-sm text-foreground-secondary">
Create AI agents with custom tools and system prompts
</p>
</div>
</Link>
<Link href="/dashboard/collections" className="block">
<div className="bg-white border border-border rounded-lg p-6 hover:border-foreground/20 hover:shadow-sm transition-all group">
<div className="flex items-center gap-4">
<Link href="/dashboard/collections" className="block group">
<div className="bg-surface border border-border rounded-lg p-6 hover:border-primary/50 hover:shadow-md transition-all h-full">
<div className="flex items-start justify-between mb-4">
<div className="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center group-hover:bg-primary/20 transition-colors">
<Icon icon="folder" size="md" className="text-primary" />
</div>
<div>
<h2 className="text-lg font-medium text-foreground">My Collections</h2>
<p className="text-sm text-foreground-secondary">
Organize and share your favorite tools
</p>
</div>
<Icon
icon="chevronRight"
size="sm"
className="text-foreground-tertiary group-hover:text-primary group-hover:translate-x-1 transition-all"
/>
</div>
<h3 className="text-lg font-semibold text-foreground mb-1">Collections</h3>
<p className="text-sm text-foreground-secondary">
Group tools together and share them as MCP servers
</p>
</div>
</Link>
<Link href="/dashboard/settings/api-keys" className="block">
<div className="bg-white border border-border rounded-lg p-6 hover:border-foreground/20 hover:shadow-sm transition-all group">
<div className="flex items-center gap-4">
<Link href="/dashboard/settings/tpmjs-api-keys" className="block group">
<div className="bg-surface border border-border rounded-lg p-6 hover:border-primary/50 hover:shadow-md transition-all h-full">
<div className="flex items-start justify-between mb-4">
<div className="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center group-hover:bg-primary/20 transition-colors">
<Icon icon="key" size="md" className="text-primary" />
</div>
<div>
<h2 className="text-lg font-medium text-foreground">API Keys</h2>
<p className="text-sm text-foreground-secondary">Manage AI provider credentials</p>
</div>
<Icon
icon="chevronRight"
size="sm"
className="text-foreground-tertiary group-hover:text-primary group-hover:translate-x-1 transition-all"
/>
</div>
<h3 className="text-lg font-semibold text-foreground mb-1">API Keys</h3>
<p className="text-sm text-foreground-secondary">
Generate keys for programmatic API access
</p>
</div>
</Link>
</div>
@ -63,35 +99,49 @@ export default function DashboardPage(): React.ReactElement {
{/* Two-column layout for Profile and Activity */}
<div className="grid gap-6 lg:grid-cols-2">
{/* Profile Section */}
<div className="bg-white border border-border rounded-lg p-6">
<h2 className="text-lg font-medium text-foreground mb-4">Profile</h2>
<div className="bg-surface border border-border rounded-lg p-6">
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-medium text-foreground">Profile</h2>
<Link href="/dashboard/settings/profile">
<Button size="sm" variant="ghost">
<Icon icon="edit" size="xs" className="mr-1" />
Edit
</Button>
</Link>
</div>
<div className="space-y-4">
<div>
<span className="block text-sm text-foreground-secondary">Name</span>
<p className="text-foreground font-medium">{session?.user?.name || 'User'}</p>
<div className="flex items-center gap-4">
<div className="w-16 h-16 rounded-full bg-primary/10 flex items-center justify-center">
<span className="text-2xl font-bold text-primary">
{session?.user?.name?.[0]?.toUpperCase() || 'U'}
</span>
</div>
<div>
<p className="text-lg font-medium text-foreground">
{session?.user?.name || 'User'}
</p>
<p className="text-sm text-foreground-secondary">{session?.user?.email}</p>
</div>
</div>
<div>
<span className="block text-sm text-foreground-secondary">Email</span>
<p className="text-foreground font-medium">{session?.user?.email}</p>
</div>
<div>
<span className="block text-sm text-foreground-secondary">Email Verified</span>
<p className="text-foreground font-medium">
{session?.user?.emailVerified ? (
<span className="text-success">Verified</span>
) : (
<span className="text-warning">Not verified</span>
)}
</p>
<div className="pt-4 border-t border-border">
<div className="flex items-center gap-2 text-sm">
<Icon
icon={session?.user?.emailVerified ? 'check' : 'alertCircle'}
size="xs"
className={session?.user?.emailVerified ? 'text-success' : 'text-warning'}
/>
<span className="text-foreground-secondary">
{session?.user?.emailVerified ? 'Email verified' : 'Email not verified'}
</span>
</div>
</div>
</div>
</div>
{/* Activity Stream Section */}
<div className="bg-white border border-border rounded-lg p-6">
<div className="bg-surface border border-border rounded-lg p-6">
<h2 className="text-lg font-medium text-foreground mb-4">Recent Activity</h2>
<DashboardActivityStream autoRefreshInterval={30000} />
</div>