Component Inventory
title: Component Inventory
owner: vizu
last-updated: 2026-05-16
supersedes: docs/frontend/COMPONENT-INVENTORY.md (2026-02-20)
status: canonical
Bilko Component Inventory
OrganizedLast byUpdated: 2026-02-20
AtomicSource Designof Truth: hierarchyFilesystem (Bradscan Frost). All components live inof apps/web/components/. Verified against filesystem as of 2026-05-16.
AtomsLayout Components
The
Sidebar
- File:
UIcomponents/sidebar.tsx - Purpose:
WrapDarkaleftsinglenavigationHTMLsidebarelementwithorhierarchicalamenu - Props:
UINoneprimitive.(usesAllpathname from Next.js navigation) - Features:
- Expandable sections (Sales, Purchases, Reports)
- Active link highlighting (primary green border + background)
- Dark theme (#111113 background)
- Logo at top ("BILKO" in primary color)
- Collapsible sub-navigation with chevron icons
- Navigation Items:
- Dashboard (direct link)
- Sales → Invoices
- Purchases → Expenses
- Banking (direct link)
- Reports → VAT Report
- Settings (direct link)
- State: Local state for expanded sections
- Dependencies: Lucide icons (ChevronDown, ChevronRight, LayoutDashboard, Receipt, ShoppingCart, Landmark, BarChart3, Settings)
TopBar
- File:
components/top-bar.tsx - Purpose: Header bar with search, notifications, user menu
- Props:
onMenuClick?: () => void— callback for mobile menu toggle
- Features:
- Mobile menu button (hidden on desktop)
- Mobile logo (hidden on desktop)
- Search input (placeholder: "Search... (Cmd+K)")
- Notification bell icon (no badge count yet)
- User dropdown menu (Profile, Settings, Logout)
- Dependencies: Lucide icons (Search, Bell, Menu, User), shadcn/ui
atomsdropdown-menu - Mobile
Responsive:cvaforShowsvariantmenucompositionbuttonand+logocn()foronclassmobile,merging.hidesshadcn/uionAtomsdesktop
UI Components (shadcn/ui)
All components in components/ui/ are from shadcn/ui library (Radix UI primitives + Tailwind).
Avatar
- File:
components/ui/avatar.tsx - Purpose: User avatar with fallback
- Radix Primitive:
@radix-ui/react-avatar - Usage: Not yet used in current pages (ready for user profile)
Badge
- File:
components/ui/badge.tsx - Purpose: Status indicators (draft, sent, paid, overdue, success, warning, etc.)
- Variants: default, secondary, success, warning, destructive
- Usage:
- Invoice status badges
- Expense status badges
- "Coming Soon" tags on report cards
- User status in settings
- Props:
variant?: "default" | "secondary" | "destructive" | "outline" | "success" | "warning"
Button
- File:
components/ui/button.tsx - Purpose: Primary UI button
- Variants: default, destructive, outline, secondary, ghost, link
- Sizes: default, sm, lg, icon
- Usage: All action buttons throughout the app
- Radix Primitive:
@radix-ui/react-slot(asChild support)
Card
- File:
components/ui/card.tsx - Purpose: Content container with header/content sections
- Sub-components:
Card— outer wrapperCardHeader— header sectionCardTitle— title textCardDescription— subtitle/description textCardContent— body contentCardFooter— footer section (not used yet)
- Usage:
- Dashboard metric cards
- Report cards
- Settings content wrapper
- Banking account/transaction tables
- Shadow:
shadow-card(0 2px 8px rgba(0, 0, 0, 0.08))
Dialog
- File:
components/ui/dialog.tsx - Purpose: Modal dialogs
- Radix Primitive:
@radix-ui/react-dialog - Sub-components:
Dialog— wrapperDialogTrigger— trigger buttonDialogContent— modal contentDialogHeader— header sectionDialogTitle— modal titleDialogDescription— modal descriptionDialogFooter— action buttons
- Usage:
- Add Customer dialog (invoice wizard)
- Add Expense dialog
- Overlay: Black 50% opacity, click-to-close
Dropdown Menu
- File:
components/ui/dropdown-menu.tsx - Purpose: Context menus and dropdowns
- Radix Primitive:
@radix-ui/react-dropdown-menu - Sub-components:
DropdownMenu— wrapperDropdownMenuTrigger— trigger buttonDropdownMenuContent— menu contentDropdownMenuItem— menu itemDropdownMenuLabel— label textDropdownMenuSeparator— divider
- Usage:
- Invoice row actions (view, edit, send, download, delete)
- User menu in top bar
- Shadow:
shadow-dropdown(0 4px 16px rgba(0, 0, 0, 0.10))
Input
- File:
components/ui/input.tsx - Purpose: Text input field
- Types Supported: text, email, number, date, search
- Usage:
- All form inputs (invoice wizard, expense form, settings)
- Search inputs (invoice list, expense list)
- Filter inputs
- Styling: Border, padding, focus ring (primary color)
Label
- File:
components/ui/label.tsx - Purpose: Form field labels
- Radix Primitive:
@radix-ui/react-label - Usage: All form field labels
- Accessibility: Proper label-input association
Select
- File:
components/ui/select.tsx - Purpose: Dropdown select input
- Radix Primitive:
@radix-ui/react-select - Sub-components:
Select— wrapperSelectTrigger— trigger buttonSelectValue— selected value displaySelectContent— dropdown contentSelectItem— option item
- Usage:
- Status filters (invoices, expenses)
- Date range filters
- Currency selectors
- Category selectors
- Settings dropdowns
- Styling: Chevron icon, border, focus ring
Separator
- File:
components/ui/separator.tsx - Purpose: Visual divider line
- Radix Primitive:
@radix-ui/react-separator - Orientations: horizontal, vertical
- Usage: Not heavily used yet (potential in settings/forms)
Sheet
- File:
components/ui/sheet.tsx - Purpose: Slide-out panel (mobile sidebar alternative)
- Radix Primitive:
@radix-ui/react-dialog(styled as sheet) - Usage: Not yet used (potential for mobile sidebar instead of overlay)
- Direction: Can slide from left/right/top/bottom
Skeleton
- File:
components/ui/skeleton.tsx - Purpose: Loading placeholder
- Usage: Not yet used (ready for loading states)
- Animation: Pulse animation
- Future Use: Data fetching loading states
Table
- File:
components/ui/table.tsx - Purpose: Data table
- Sub-components:
Table— wrapperTableHeader— header sectionTableBody— body sectionTableRow— rowTableHead— header cellTableCell— data cellTableCaption— caption text (not used)TableFooter— footer section (not used)
- Usage:
- Invoice list
- Expense list
- Bank transactions
- VAT transactions
- Recent transactions (dashboard)
- Settings (users, integrations)
- Styling: Border, alternating row hover
Tabs
- File:
components/ui/tabs.tsx - Purpose: Tab navigation
- Radix Primitive:
@radix-ui/react-tabs - Sub-components:
Tabs— wrapperTabsList— tab button containerTabsTrigger— tab buttonTabsContent— tab panel
- Usage:
- Banking page (Accounts, Reconcile, Transactions)
- VAT Report (Reconciliation, Audit, Summary)
- Styling: Primary underline for active tab
Textarea
- File:
components/ui/textarea.tsx - Purpose: Multi-line text input
- Usage:
- Invoice notes (customization step)
- Invoice terms (customization step)
- Email message (send step)
- Expense description (optional)
- Rows: Configurable (default: 3-6 rows)
Chart Components
Charts are built with Recharts 2.15.0 (not custom components). Key chart types used:
- BarChart — P&L trend, receivables aging
- PieChart — Expenses by category (donut)
- ResponsiveContainer — Wrapper for all charts (100% width, fixed height)
- XAxis, YAxis, CartesianGrid, Tooltip, Legend — Chart primitives
Chart Colors (from tailwind.config.ts):
- Revenue:
#22C55E(chart-revenue) - Expense:
#EF4444(chart-expense) - Profit:
#3B82F6(chart-profit) - Neutral:
#6B7280(chart-neutral)
Utility Components
cn (lib/utils.ts)
- Purpose: Utility function for conditional class names
- Usage:
cn("base-class", condition && "conditional-class") - Dependencies:
clsx+tailwind-merge
Page-Specific Components
None. All components are reusable shadcn/ui components + layout components. No page-specific components exist yet.
Potential future page-specific components:
- InvoicePreview (extracted from wizard step 5)
- MetricCard (extracted from dashboard)
- TransactionRow (extracted from dashboard/banking)
- ExpenseFormDialog (extracted from expenses page)
Component Usage Map
| Component | ||
|---|---|---|
Button |
All pages |
|
Card |
Reports, Banking, Settings, Expenses |
|
Table |
Invoices, Expenses, Banking, Reports, Dashboard, Settings |
10+ |
Input |
wizard, Expenses, Settings, TopBar |
|
Select |
Invoices, Expenses, Banking, Settings, Invoice wizard |
20+ |
Badge |
Expenses, Banking, Reports, Settings |
|
Dialog |
Invoice wizard, Expenses |
|
Dropdown Menu |
TopBar |
|
Tabs |
Banking, VAT Report |
Custom Atoms
| |
|
Invoice wizard |
||
| Sidebar | All pages | 1 |
| TopBar | All pages | 1 |
| Label | All forms | 40+ |
| Separator | Minimal | 1-2 |
| Avatar | None yet | 0 |
| Sheet | None yet | 0 |
| Skeleton | None yet | 0 |
MoleculesNotes
Atoms
- All
intoUIacomponentsfunctionalareunit.fromMay contain localuseState. No external data fetching.shadcn/ui
(noMoleculescustom variants
yet) this list isComponent- No
componentsRadixphantomprimitive —Notesexhaustive dialog.tsx@radix-ui/react-dialogFocus trapbased onopen,filesystemESCscandismiss,- Radix
scrollUIlock.primitivesUseprovide accessibility out of the box- Tailwind CSS 4 for styling (all tokens in tailwind.config.ts)
- Lucide React for all
modal flowsdropdown-menu.tsx@radix-ui/react-dropdown-menuKeyboard nav, ARIArole="menu". Use for action menus, not navigationtabs.tsx@radix-ui/react-tabsARIArole="tabpanel". Use for report views, settings sectionssheet.tsx@radix-ui/react-dialogSlide-in side panel. Built on Dialog primitivetoast.tsxcustomrole="status"for informational toasts,role="alert"for errorscard.tsxnativeCardHeader, CardContent, CardTitle sub-components. Standard containertable.tsxnative<table>Always include<caption>oraria-labelfor screen readersCustom MoleculesComponentFileNotesTwoFactorDialogcomponents/settings/TwoFactorDialog.tsx2FA TOTP setup and verification flowBetaInterestDialogcomponents/beta-interest-dialog.tsxWaitlist capture dialogCreditNoteModalcomponents/CreditNoteModal.tsxCredit note creationicons (uses Dialog)UpsellModalcomponents/UpsellModal.tsxPlan upgrade promptComplianceWidgetcomponents/ComplianceWidget.tsxPer-market compliance status badgeChatMessagecomponents/chatbot/ChatMessage.tsxAI chatbot message bubbleChatInputcomponents/chatbot/ChatInput.tsxAI chatbot text input with sendOrganismsComplex UI sections with their own data dependencies. May call Zustand stores or receive server-fetched data as props.ComponentFileData sourceNotesSidebarcomponents/sidebar.tsxuseAuthStoreDark plum navigation, active route highlighting, RBAC-aware nav itemsTopBarcomponents/top-bar.tsxuseAuthStoreUser avatar, locale switcher, notification bellChatWidgetcomponents/chatbot/ChatWidget.tsxAnthropic SDKFloating AI accounting assistantPausalTeaserCalculatorcomponents/pausal/PausalTeaserCalculator.tsxlocal stateTax estimate calculator for pausal businessmenLanding Page Organisms (components/landing/)ComponentFileNavbarcomponents/landing/navbar.tsxHerocomponents/landing/hero.tsxFeaturescomponents/landing/features.tsxTestimonialscomponents/landing/testimonials.tsxPricingcomponents/landing/pricing.tsxFootercomponents/landing/footer.tsxTemplatesRoute layouts that define the page skeleton. No data logic — only layout composition.TemplateFileNotesDashboard Layoutapp/(dashboard)/layout.tsxSidebar + TopBar +<main id="main-content">Legal Layoutapp/(legal)/layout.tsxSimple centered layout, no sidebarRoot Layoutapp/layout.tsx<html lang>, font loading, global providers (QueryProvider, AuthProvider)Composition PatternsPattern 1 — Icon-only ButtonEvery icon-only button MUST havearia-label. Theconsistent iconitselflibrary) - No
aria-hidden<Button variant="ghost" size="icon" aria-label="Ukloni stavku">
<X className="h-4 w-4" aria-hidden="true" />
</Button>
Pattern 2 — RSC + Client Boundary Split
Keep data fetching in the RSC parent; interactive behavior in the Client child.
// RSC parent — no "use client"
export default async function InvoiceDetailPage({ params }: { params: { id: string } }) {
const invoice = await fetchInvoice(params.id)
return <InvoiceDetailClient invoice={invoice} />
}
// Client child
;('use client')
export function InvoiceDetailClient({ invoice }: { invoice: Invoice }) {
const [status, setStatus] = useState(invoice.status)
// interactive status changes, optimistic updates
}
Pattern 3 — Loading Skeleton via Suspense
export default function InvoicesPage() {
return (
<Suspense fallback={<TableSkeleton rows={10} />}>
<InvoiceTableServer />
</Suspense>
)
}
Pattern 4 — cva Custom Variant
import { cva } from 'class-variance-authority'
const statusBadge = cva('inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium', {
variants: {
status: {
paid: 'bg-green-100 text-green-800',
pending: 'bg-yellow-100 text-yellow-800',
overdue: 'bg-red-100 text-red-800',
draft: 'bg-gray-100 text-gray-600',
},
},
})
export function InvoiceStatusBadge({ status }: { status: InvoiceStatus }) {
return <span className={statusBadge({ status })}>{statusLabel[status]}</span>
}
OPEN QUESTION OQ-4:packages/ui/is an empty scaffold. When should components graduate fromapps/web/components/to the shared package? Recommended trigger: whenapps/landing-hrorapps/landing-baneeds the same component (currently duplicating landing organisms).