Skip to main content

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

smallest
    indivisible
  • File: UIcomponents/sidebar.tsx
  • units.
  • Purpose: WrapDark aleft singlenavigation HTMLsidebar elementwith orhierarchical amenu
  • Radix
  • Props: UINone primitive.(uses Allpathname 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
  • use
  • Mobile cvaResponsive: forShows variantmenu compositionbutton and+ cn()logo foron classmobile, merging.

    hides

    shadcn/uion Atomsdesktop


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 wrapper
    • CardHeader — header section
    • CardTitle — title text
    • CardDescription — subtitle/description text
    • CardContent — body content
    • CardFooter — 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 — wrapper
    • DialogTrigger — trigger button
    • DialogContent — modal content
    • DialogHeader — header section
    • DialogTitle — modal title
    • DialogDescription — modal description
    • DialogFooter — 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 — wrapper
    • DropdownMenuTrigger — trigger button
    • DropdownMenuContent — menu content
    • DropdownMenuItem — menu item
    • DropdownMenuLabel — label text
    • DropdownMenuSeparator — 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 — wrapper
    • SelectTrigger — trigger button
    • SelectValue — selected value display
    • SelectContent — dropdown content
    • SelectItem — 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 — wrapper
    • TableHeader — header section
    • TableBody — body section
    • TableRow — row
    • TableHead — header cell
    • TableCell — data cell
    • TableCaption — 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 — wrapper
    • TabsList — tab button container
    • TabsTrigger — tab button
    • TabsContent — 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 RadixUsed primitiveIn NotesCount
button.tsxButton @radix-ui/react-slotAll pages 6 variants (default, destructive, outline, secondary, ghost, link), 4 sizes. asChild for polymorphic rendering50+
input.tsxCard nativeDashboard, <input>Reports, Banking, Settings, Expenses Accepts aria-invalid, aria-describedby for RHF integration20+
label.tsxTable @radix-ui/react-labelInvoices, Expenses, Banking, Reports, Dashboard, Settings Associates with input via htmlFor10+
textarea.tsxInput nativeInvoice <textarea>wizard, Expenses, Settings, TopBar Same aria pattern as Input30+
select.tsxSelect @radix-ui/react-selectInvoices, Expenses, Banking, Settings, Invoice wizard Keyboard nav + ARIA listbox built-in. Do not use native <select>20+
badge.tsxBadge nativeInvoices, <span>Expenses, Banking, Reports, Settings Invoice status, market labels15+
separator.tsxDialog @radix-ui/react-separatorInvoice wizard, Expenses Semantic <hr> with ARIA role2
skeleton.tsxDropdown Menu nativeInvoices, <div>TopBar Pulse animation for loading states. Use instead of spinner for content areas2
avatar.tsxTabs @radix-ui/react-avatarBanking, VAT Report User initials fallback when image unavailable

Custom Atoms

trialcountdownnotice
ComponentFileNotes
LocaleSwitchercomponents/locale-switcher.tsxsr-Latn / hr / bs toggle. aria-label required2
TrialBannerTextarea components/TrialBanner.tsxInvoice wizard Subscription3
SidebarAll pages1
TopBarAll pages1
LabelAll forms40+
SeparatorMinimal1-2
AvatarNone yet0
SheetNone yet0
SkeletonNone yet0

MoleculesNotes

Atoms

    composed
  • All intoUI acomponents functionalare unit.from May contain local useState. No external data fetching.

    shadcn/ui Molecules

    (no customvariantsyet)
  • No
  • componentsthislistisexhaustive
    ComponentRadixphantom primitive Notes
    dialog.tsx@radix-ui/react-dialogFocus trapbased on open,filesystem ESCscan dismiss,
  • Radix scrollUI lock.primitives Useprovide accessibility out of the box
  • Tailwind CSS 4 for styling (all tokens in tailwind.config.ts)
  • Lucide React for all modal flows
  • dropdown-menu.tsx@radix-ui/react-dropdown-menuKeyboard nav, ARIA role="menu". Use for action menus, not navigation
    tabs.tsx@radix-ui/react-tabsARIA role="tabpanel". Use for report views, settings sections
    sheet.tsx@radix-ui/react-dialogSlide-in side panel. Built on Dialog primitive
    toast.tsxcustomrole="status" for informational toasts, role="alert" for errors
    card.tsxnativeCardHeader, CardContent, CardTitle sub-components. Standard container
    table.tsxnative <table>Always include <caption> or aria-label for screen readers

    Custom Molecules

    ComponentFileNotes
    TwoFactorDialogcomponents/settings/TwoFactorDialog.tsx2FA TOTP setup and verification flow
    BetaInterestDialogcomponents/beta-interest-dialog.tsxWaitlist capture dialog
    CreditNoteModalcomponents/CreditNoteModal.tsxCredit note creationicons (uses Dialog)
    UpsellModalcomponents/UpsellModal.tsxPlan upgrade prompt
    ComplianceWidgetcomponents/ComplianceWidget.tsxPer-market compliance status badge
    ChatMessagecomponents/chatbot/ChatMessage.tsxAI chatbot message bubble
    ChatInputcomponents/chatbot/ChatInput.tsxAI chatbot text input with send

    Organisms

    Complex UI sections with their own data dependencies. May call Zustand stores or receive server-fetched data as props.

    ComponentFileData sourceNotes
    Sidebarcomponents/sidebar.tsxuseAuthStoreDark plum navigation, active route highlighting, RBAC-aware nav items
    TopBarcomponents/top-bar.tsxuseAuthStoreUser avatar, locale switcher, notification bell
    ChatWidgetcomponents/chatbot/ChatWidget.tsxAnthropic SDKFloating AI accounting assistant
    PausalTeaserCalculatorcomponents/pausal/PausalTeaserCalculator.tsxlocal stateTax estimate calculator for pausal businessmen

    Landing Page Organisms (components/landing/)

    ComponentFile
    Navbarcomponents/landing/navbar.tsx
    Herocomponents/landing/hero.tsx
    Featurescomponents/landing/features.tsx
    Testimonialscomponents/landing/testimonials.tsx
    Pricingcomponents/landing/pricing.tsx
    Footercomponents/landing/footer.tsx

    Templates

    Route layouts that define the page skeleton. No data logic — only layout composition.

    TemplateFileNotes
    Dashboard Layoutapp/(dashboard)/layout.tsxSidebar + TopBar + <main id="main-content">
    Legal Layoutapp/(legal)/layout.tsxSimple centered layout, no sidebar
    Root Layoutapp/layout.tsx<html lang>, font loading, global providers (QueryProvider, AuthProvider)

    Composition Patterns

    Pattern 1 — Icon-only Button

    Every icon-only button MUST have aria-label. Theconsistent icon itselflibrary)

  • must
be 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 from apps/web/components/ to the shared package? Recommended trigger: when apps/landing-hr or apps/landing-ba needs the same component (currently duplicating landing organisms).