Components
The UniPulse UI is built with shadcn/ui components on top of Radix UI primitives, styled with Tailwind CSS v4. Components follow a composition pattern with consistent styling via the cn() utility.
Component Architecture
Layout Components
| Component | Purpose | Used In |
|---|---|---|
AppLayout | Main authenticated layout with sidebar + header + workspace selector | All authenticated pages |
AuthLayout | Login/register layout (centered card, branding) | /login, /register |
SettingsLayout | Settings page with sub-navigation tabs | /settings/* |
AdminLayout | Admin panel layout with admin-specific sidebar | /admin/* |
AppLayout Structure
+------+---------------------------+
| | Header (workspace, user) |
| Side |---------------------------+
| bar | |
| | Page Content |
| | (children) |
| | |
+------+---------------------------+
Data Display Components
| Component | Description | Key Props |
|---|---|---|
DataTable | Sortable, filterable tables with pagination | columns, data, searchable, sortable |
MetricCard | KPI display cards with trend indicators | title, value, trend, icon |
Chart | Recharts wrapper for time-series and comparison charts | type, data, xKey, yKey |
PlatformBadge | Shows social platform icon + name | platform |
StatusBadge | Colored status indicator | status, variant |
EmptyState | Placeholder for empty data views | title, description, action |
Form Components
Forms use React Hook Form with Zod validation from @unipulse/shared:
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { createPostSchema, type CreatePostInput } from '@unipulse/shared';
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form';
function CreatePostForm() {
const form = useForm<CreatePostInput>({
resolver: zodResolver(createPostSchema),
defaultValues: { caption: '', platforms: [] },
});
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField control={form.control} name="caption" render={({ field }) => (
<FormItem>
<FormLabel>{t('composer.caption')}</FormLabel>
<FormControl><Textarea {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
</form>
</Form>
);
}
Workflow Builder
The visual workflow editor is built with @xyflow/react (React Flow):
| Custom Node | Purpose | Visual |
|---|---|---|
TriggerNode | Event that starts the workflow (e.g., new post, schedule) | Green circle |
ConditionNode | Evaluates a boolean expression (eq, gt, contains, etc.) | Yellow diamond |
ActionNode | Performs an operation (notify, publish, reply, boost, etc.) | Blue rectangle |
Features:
- Drag-and-drop from a sidebar palette
- Node configuration panels (slide-out form)
- Edge connections with animated flow indicators
- Undo/redo support
- Test run execution from the editor
Composer Component
The multi-platform composer is one of the most complex components:
| Sub-Component | Purpose |
|---|---|
CaptionEditor | Rich text editor for post caption |
PlatformSelector | Toggle target platforms (Facebook, Instagram, TikTok) |
MediaUploader | Drag-and-drop media attachment |
PlatformPreview | Live preview of how the post will look on each platform |
AIAssistant | AI caption generation, rewriting, hashtags sidebar |
SchedulePicker | Date/time picker for scheduling |
BrandVoiceSelector | Apply brand voice to AI-generated content |
Adding New shadcn/ui Components
cd apps/web
npx shadcn@latest add button
npx shadcn@latest add dialog
npx shadcn@latest add dropdown-menu
Components are added to apps/web/src/components/ui/ and can be customized freely.
Styling Conventions
| Convention | Example |
|---|---|
| Tailwind utility classes | className="flex items-center gap-2 p-4" |
Conditional classes with cn() | cn("text-sm", isActive && "font-bold") |
| Component variants | Use cva() for variant props (shadcn pattern) |
| Dark mode | Supports via Tailwind dark: prefix |
| RTL support | Tailwind v4 logical properties auto-handle RTL |
| Responsive | Mobile-first with sm:, md:, lg: breakpoints |
cn() Helper
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Icon Usage
All icons come from Lucide React:
import { Plus, Trash2, Settings, BarChart3 } from 'lucide-react';
<Button><Plus className="h-4 w-4 mr-2" /> Create Post</Button>
Cross-Reference
- Frontend Local Setup -- getting the web app running
- Page Map -- pages that use these components
- State Management -- data flow into components
- i18n -- translation usage in components
- Shared Validators -- Zod schemas for form validation