Agent skill
frontend-agent
Handles frontend/UX/route work for Unite-Hub. Fixes UI bugs, implements React components, updates layouts, ensures responsive design, and maintains shadcn/ui consistency.
Install this agent skill to your Project
npx add-skill https://github.com/aiskillstore/marketplace/tree/main/skills/cleanexpo/frontend-agent
SKILL.md
Frontend Agent Skill
⚠️ PRE-GENERATION CHECKLIST (MANDATORY)
Before creating ANY UI component, complete this checklist:
PRE_GENERATION_CHECKLIST:
1. READ_DESIGN_SYSTEM:
- [ ] Read /DESIGN-SYSTEM.md for forbidden patterns
- [ ] Check /src/app/globals.css @theme block for tokens
- [ ] Note: accent-500 = #ff6b35 (orange)
2. CHECK_EXISTING_COMPONENTS:
- [ ] Look in /src/components/ui/ first (48 components)
- [ ] Check components.json for shadcn configuration
- [ ] Review existing patterns in landing page
3. REFERENCE_UI_LIBRARIES:
- [ ] See /docs/UI-LIBRARY-INDEX.md for premium components
- [ ] Priority: Project → StyleUI/KokonutUI/Cult UI → shadcn base
- [ ] NEVER use shadcn defaults without customization
4. VERIFY_NO_FORBIDDEN_PATTERNS:
- [ ] No bg-white, text-gray-600, or generic hover states
- [ ] No uniform grid-cols-3 gap-4 layouts
- [ ] No unstyled <Card className="p-6">
- [ ] No icons without brand colors
FORBIDDEN CODE PATTERNS:
// ❌ NEVER GENERATE THESE
className="bg-white rounded-lg shadow p-4" // Generic card
className="grid grid-cols-3 gap-4" // Uniform grid
className="text-gray-600" // Default muted
className="hover:bg-gray-100" // Generic hover
<Card className="p-6"> // Unstyled shadcn
REQUIRED PATTERNS:
// ✅ ALWAYS USE DESIGN TOKENS
className="bg-bg-card border border-border-base hover:border-accent-500"
className="text-text-primary"
className="text-text-secondary"
className="bg-accent-500 hover:bg-accent-400"
Overview
The Frontend Agent is responsible for all UI/UX work in the Unite-Hub Next.js application:
- React 19 / Next.js 16 development with App Router
- shadcn/ui component implementation and customization
- Tailwind CSS styling and responsive design
- Route creation and breadcrumb setup
- Client-side state management (React Context, hooks)
- Accessibility and performance optimization
How to Use This Agent
Trigger
User says: "Fix dashboard layout", "Add new contact page", "Update navigation", "Create modal component"
What the Agent Does
1. Understand the Request
Questions to Ask:
- Which page/component needs work?
- What's the desired behavior?
- Are there design references (screenshots, wireframes)?
- What's the priority (P0/P1/P2)?
2. Analyze Current Implementation
Step A: Locate Files
# Find the component or page
find src/app -name "*.tsx" | grep -i "contacts"
find src/components -name "*.tsx" | grep -i "hotleads"
Step B: Read Current Code
// Use text_editor tool
text_editor.view("src/app/dashboard/contacts/page.tsx")
Step C: Identify Dependencies
- What shadcn/ui components are used?
- What contexts are consumed (AuthContext, etc.)?
- What API routes are called?
- What database queries are made?
3. Implement Changes
Step A: Component Updates
For existing components:
// src/components/HotLeadsPanel.tsx
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { useAuth } from "@/contexts/AuthContext";
export function HotLeadsPanel({ workspaceId }: { workspaceId: string }) {
const { currentOrganization } = useAuth();
// Fetch hot leads
const [leads, setLeads] = useState([]);
useEffect(() => {
async function fetchLeads() {
const res = await fetch("/api/agents/contact-intelligence", {
method: "POST",
body: JSON.stringify({ action: "get_hot_leads", workspaceId }),
});
const data = await res.json();
setLeads(data.leads || []);
}
if (workspaceId) fetchLeads();
}, [workspaceId]);
return (
<Card>
{/* UI implementation */}
</Card>
);
}
Step B: Route Creation
For new pages:
// src/app/dashboard/new-page/page.tsx
import { Metadata } from "next";
export const metadata: Metadata = {
title: "New Page | Unite Hub",
description: "Description of new page"
};
export default async function NewPage() {
return (
<div className="container mx-auto py-8">
<h1 className="text-3xl font-bold">New Page</h1>
{/* Content */}
</div>
);
}
Step C: shadcn/ui Components
Install new components if needed:
npx shadcn@latest add dialog
npx shadcn@latest add dropdown-menu
npx shadcn@latest add toast
Use components following shadcn patterns:
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Title</DialogTitle>
<DialogDescription>Description</DialogDescription>
</DialogHeader>
{/* Content */}
</DialogContent>
</Dialog>
4. Add Workspace Filtering (CRITICAL for V1)
All database queries MUST filter by workspace:
// ❌ BAD - Shows data from all workspaces
const { data: contacts } = await supabase
.from("contacts")
.select("*");
// ✅ GOOD - Only shows data from user's workspace
const { data: contacts } = await supabase
.from("contacts")
.select("*")
.eq("workspace_id", workspaceId);
Required for these tables:
contacts-.eq("workspace_id", workspaceId)campaigns-.eq("workspace_id", workspaceId)drip_campaigns-.eq("workspace_id", workspaceId)emails-.eq("workspace_id", workspaceId)generatedContent-.eq("workspace_id", workspaceId)
5. Handle Loading and Error States
Loading State:
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
async function fetchData() {
try {
setIsLoading(true);
const data = await fetch("...");
setData(data);
} catch (err) {
setError(err.message);
} finally {
setIsLoading(false);
}
}
fetchData();
}, []);
if (isLoading) return <Spinner />;
if (error) return <ErrorBanner message={error} />;
return <DataDisplay data={data} />;
6. Responsive Design
Tailwind Breakpoints:
<div className="
grid grid-cols-1 // Mobile: 1 column
md:grid-cols-2 // Tablet: 2 columns
lg:grid-cols-3 // Desktop: 3 columns
gap-4
">
{/* Cards */}
</div>
Mobile-First Approach:
- Start with mobile layout (default classes)
- Add
md:classes for tablet - Add
lg:andxl:for desktop
7. Test Changes
Step A: Visual Testing
# Start dev server
npm run dev
# Navigate to page in browser
# Test on mobile viewport (DevTools)
# Test dark theme
Step B: Accessibility
// Check for:
// - Proper ARIA labels
// - Keyboard navigation
// - Focus states
// - Screen reader support
<button aria-label="Close dialog">×</button>
<input aria-describedby="email-help" />
<div role="alert" aria-live="polite">{error}</div>
Step C: Performance
// Use React.memo for expensive components
import { memo } from "react";
export const ExpensiveComponent = memo(function ExpensiveComponent({ data }) {
return <div>{/* Render */}</div>;
});
// Use dynamic imports for heavy components
import dynamic from "next/dynamic";
const HeavyChart = dynamic(() => import("@/components/HeavyChart"), {
loading: () => <Spinner />,
ssr: false
});
Common Tasks
Task 1: Fix Missing Workspace Filter
Example: Dashboard Overview page showing all contacts
Steps:
- Read
src/app/dashboard/overview/page.tsx - Find all Supabase queries
- Add
.eq("workspace_id", workspaceId)to each - Add null check for workspaceId before querying
- Test with multiple workspaces
Code:
// Before
const { data: contacts } = await supabase.from("contacts").select("*");
// After
if (!workspaceId) {
return <div>No workspace selected</div>;
}
const { data: contacts, error } = await supabase
.from("contacts")
.select("*")
.eq("workspace_id", workspaceId);
if (error) {
console.error("Error fetching contacts:", error);
return <ErrorBanner />;
}
Task 2: Create New Dashboard Page
Example: Add "Analytics" page to dashboard
Steps:
- Create
src/app/dashboard/analytics/page.tsx - Add to navigation in
src/app/dashboard/layout.tsx - Implement page content with shadcn/ui components
- Add breadcrumbs
- Test navigation
Code:
// src/app/dashboard/analytics/page.tsx
import { Metadata } from "next";
import { Card } from "@/components/ui/card";
export const metadata: Metadata = {
title: "Analytics | Unite Hub",
};
export default async function AnalyticsPage() {
return (
<div className="container mx-auto py-8 space-y-6">
<div>
<h1 className="text-3xl font-bold">Analytics</h1>
<p className="text-muted-foreground">Track your campaign performance</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<Card>
{/* Stat card 1 */}
</Card>
<Card>
{/* Stat card 2 */}
</Card>
<Card>
{/* Stat card 3 */}
</Card>
</div>
</div>
);
}
// src/app/dashboard/layout.tsx - Add to navigation
const navigation = [
{ name: "Dashboard", href: "/dashboard/overview", icon: HomeIcon },
{ name: "Contacts", href: "/dashboard/contacts", icon: UsersIcon },
{ name: "Campaigns", href: "/dashboard/campaigns", icon: MailIcon },
{ name: "Analytics", href: "/dashboard/analytics", icon: ChartIcon }, // NEW
];
Task 3: Implement Button Functionality
Example: Hot Leads panel "Send Email" button
Steps:
- Read
src/components/HotLeadsPanel.tsx - Find button location
- Implement onClick handler
- Call appropriate API endpoint
- Show success/error toast
Code:
import { useToast } from "@/components/ui/use-toast";
function HotLeadsPanel() {
const { toast } = useToast();
async function handleSendEmail(contactId: string) {
try {
const res = await fetch("/api/emails/send", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ contactId, templateType: "followup" }),
});
if (!res.ok) throw new Error("Failed to send email");
toast({
title: "Email sent",
description: "Your email has been queued for sending.",
});
} catch (error) {
toast({
variant: "destructive",
title: "Error",
description: error.message,
});
}
}
return (
<Button onClick={() => handleSendEmail(contact.id)}>
Send Email
</Button>
);
}
Styling Guidelines
Tailwind CSS Best Practices
Use Utility Classes:
// ✅ Good
<div className="flex items-center justify-between p-4 bg-background border rounded-lg">
// ❌ Bad (custom CSS)
<div style={{ display: "flex", padding: "16px" }}>
Use CSS Variables from Theme:
// Defined in globals.css
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--primary: 222.2 47.4% 11.2%;
}
}
// Use in components
<div className="bg-background text-foreground">
<div className="bg-card text-card-foreground">
<div className="bg-primary text-primary-foreground">
Responsive Design:
<div className="
text-sm md:text-base lg:text-lg
p-2 md:p-4 lg:p-6
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3
">
Component Library Reference
shadcn/ui Components Available
accordion- Collapsible content panelsalert-dialog- Modal confirmation dialogsavatar- User profile imagesbadge- Status badgesbutton- Interactive buttonscard- Content containerscheckbox- Form checkboxesdialog- Modal dialogsdropdown-menu- Dropdown menusinput- Text inputslabel- Form labelspopover- Floating contentprogress- Progress indicatorsradio-group- Radio buttonsselect- Select dropdownsswitch- Toggle switchestabs- Tabbed interfacestoast- Notification toaststooltip- Hover tooltips
Install new components:
npx shadcn@latest add [component-name]
Error Handling Patterns
API Errors
try {
const res = await fetch("/api/...");
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || "Something went wrong");
}
return data;
} catch (error) {
console.error("API Error:", error);
toast({
variant: "destructive",
title: "Error",
description: error.message,
});
return null;
}
Supabase Errors
const { data, error } = await supabase.from("contacts").select("*");
if (error) {
console.error("Supabase error:", error);
return <ErrorBanner message="Failed to load contacts" />;
}
if (!data || data.length === 0) {
return <EmptyState message="No contacts found" />;
}
return <ContactsList contacts={data} />;
Version 1 Constraints
What We Fix for V1:
- ✅ Workspace filtering on ALL pages
- ✅ Hot Leads button functionality
- ✅ Contact detail page navigation
- ✅ Dashboard stat cards
- ✅ Loading and error states
- ✅ Responsive design fixes
What We Do NOT Build for V1:
- ❌ Advanced animations
- ❌ Custom theme builder
- ❌ Drag-and-drop interfaces
- ❌ Real-time collaboration UI
- ❌ Mobile app
Key Points
- Always filter by workspace - Data isolation is critical
- Use shadcn/ui components - Don't reinvent the wheel
- Follow Tailwind conventions - Utility-first approach
- Handle loading/error states - Never show blank screens
- Test responsive design - Mobile, tablet, desktop
- Maintain accessibility - ARIA labels, keyboard navigation
Integration with Other Agents
The Frontend Agent works with:
- Backend Agent - Consumes API endpoints
- Docs Agent - Updates component documentation
- Orchestrator - Receives UI fix requests
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
perigon-backend
Perigon ASP.NET Core + EF Core + Aspire conventions
perigon-agent
Pointers for Copilot/agents to apply Perigon conventions
perigon-angular
Angular 21+ standalone/Material/signal conventions for Perigon WebApp
fastapi-mastery
Comprehensive FastAPI development skill covering REST API creation, routing, request/response handling, validation, authentication, database integration, middleware, and deployment. Use when working with FastAPI projects, building APIs, implementing CRUD operations, setting up authentication/authorization, integrating databases (SQL/NoSQL), adding middleware, handling WebSockets, or deploying FastAPI applications. Triggered by requests involving .py files with FastAPI code, API endpoint creation, Pydantic models, or FastAPI-specific features.
context7-efficient
Token-efficient library documentation fetcher using Context7 MCP with 86.8% token savings through intelligent shell pipeline filtering. Fetches code examples, API references, and best practices for JavaScript, Python, Go, Rust, and other libraries. Use when users ask about library documentation, need code examples, want API usage patterns, are learning a new framework, need syntax reference, or troubleshooting with library-specific information. Triggers include questions like "Show me React hooks", "How do I use Prisma", "What's the Next.js routing syntax", or any request for library/framework documentation.
browser-use
Browser automation using Playwright MCP. Navigate websites, fill forms, click elements, take screenshots, and extract data. Use when tasks require web browsing, form submission, web scraping, UI testing, or any browser interaction.
Didn't find tool you were looking for?