Skip to content

Flowbite Adoption — Component Audit

Last updated: 2026-04-12 (pass 10 — full Storybook sweep, 5 unused files deleted). Based on live grep of frontend/src/components/ and frontend/src/pages/ (83 files after deletions). Counts exclude design-justified exceptions and dev-sandbox files.


Summary

MetricValue
Total files (after pass 10 deletions)83
Files importing Flowbite (components or icons)~76
Overall import rate~92%
Files with Storybook stories71 / 83 (86%)
Auditable files with Storybook stories¹71 / 76 (93%)
Raw <button> elements remaining (actionable)~27 across 9 files
Hardcoded hex/rgba remaining (actionable)concentrated in StreamersList, CampaignDetail, StreamerPublicProfile (residual), CampaignCardVerified (2 colors)

¹ Auditable = total minus 7 excluded files: AuthImpersonate, BuildInfo, AdminPage, InvitationsPage (redirect stub), ApplicationsPage (redirect stub), plus 2 complex on-chain sub-components deferred (AllocationCell, DepositMini).

Pass 10 deletions: VFFooter.tsx, CampaignCard.tsx, CampaignFormDemo.tsx, Testing.tsx, NegotiationPrototype.tsx — all confirmed zero consumers outside the now-deleted dev sandbox page.

Pass 8 trivial fixes: CampaignDetail fully clean — 3× #fafafaT.bg, CSS hover → ${T.accent}. Home2 dismiss button → Flowbite Button, #f5f5f7T.bg. VideosCard and OperatorDealCard confirmed accepted (Tailwind CSS-variable classes only, no raw hex). 7 actionable items remain.


Fully Flowbite-Native

ComponentFlowbite primitives used
StatusBadgeBadge
EngagementBadgeBadge + icons
PillButtonButton (pill)
SectionHeaderBadge
ToggleSwitchwraps FlowbiteToggle
TakeBackFormAlert, Button, Textarea
OfferNegotiationStatusBadge, Button
OfferDetailPanelBadge, Button, Alert
OfferItemBadge
TermsStripBadge
StreamerProfilePanelBadge, Spinner
NegStatusBannerAlert, Textarea
InviteCampaignModalModal, Button, TextInput, Textarea, Label, Alert, Select, Spinner
DeliverySubmitFormAlert, Button, Select, TextInput, Textarea
ManualDeliveryFormTextInput, Textarea
AgreedTermsBadgesBadge + icons
CommunicationCardAlert, Button, Label
AudienceDealsCardAlert, Button, Label, TextInput, Textarea
ChannelsCardButton, Alert, Spinner + icons
ProfileVisibilityCardAlert + icons
ProfileSettingsAlert, Button, Dropdown, TextInput, Label
NegTermEditorAlert, Badge, Button, TextInput
AllocationStepperAlert, Badge, Button + icons
FundCampaignPanelAlert, Button, Spinner + icons
StreamerCardBadge, Button
SlotRowBadge, Button
AllocateFromNegModalModal, Alert, Badge
DealCardAlert, Badge, Button, Spinner
AllocationForm(pass 6)Alert, Button, TextInput, Label, Select, Spinner
AllocationCell(pass 6)T.* tokens; rgba(0,0,0,0.04/0.06) neutral tracks — no T.* equivalent, accepted
SignIn(pass 6)Button + SiteNav
Operator StreamDeliveryPage(pass 6/7)Alert, Button, Spinner; SVG sparkline hex is chart-semantic — accepted
Operator NegotiationsPage(pass 6)Alert, Badge, Button (filter chips), Spinner
Operator WalletPage(pass 6)Button, Badge, Alert, Spinner
Streamer WalletPage(pass 6)Button, Alert, Spinner
Streamer OffersPageAlert, Badge, Tabs
Streamer NegotiationsPageAlert, Badge, Button, Spinner
Streamer DealsPageAlert, Badge, Button, Spinner
Streamer DashboardPageButton, Spinner + icons
Operator AccountPageButton, Label, TextInput, Alert, Badge, Spinner
Operator DealsPageAlert, Badge, Spinner, Tabs
CampaignDetail(pass 8)Button, Alert, Spinner, Tabs; all T.* tokens
FundDonut(pass 5)SVG chart; legend text uses CSS-variable classes
ApplicationsPanel(pass 5)Alert, Badge, Button
DealAllocationCard(pass 4)Tailwind CSS-variable classes throughout

Mixed — Flowbite + Hand-Rolled Patterns

StreamerPublicProfile.tsx ⚠ residual (pass 6 — hex block removed)

  • Migrated (pass 6): Full 8-variable hex block removed; T.* throughout; 6 action buttons → Flowbite Button.
  • Accepted exception: 1 logo-nav <button> wrapping VLogo SVG — layout-structural, same pattern as SiteNav.
  • Remaining token gaps (low effort):
    • KYC "Verified" badge: background: "#f0fdf4", border: "1px solid #bbf7d0", color: "#16a34a"T.greenSoft, T.greenBorder, T.green
    • "Open to deals" chip: #fef3c7, #fde68a, #92400eT.amberSoft, T.amberBorder, T.amber
    • Deal types chip: background: "#f9fafb"T.bg
    • Discord icon box: #ede9fe / #7c3aedT.accentSoft / T.accent
    • Telegram icon box: #dbeafe / #2563ebT.skySoft / T.sky
  • Accepted design-justified: PLAT brand colors, Avatar gradient, VLogo SVG paths, PILLAR_COLOR chart colors, video overlay rgba, sidebar card shadow.

CampaignCardVerified.tsx

  • Migrated (pass 6): rgba(220,38,38,0.2)T.redBorder; all #fafafaT.bg.
  • Remaining gap — 3 raw <button> elements: Accordion section toggles ("Campaign brief", "Brand guidelines", "Terms"). Requires full Flowbite <Accordion> restructuring.
  • Remaining token gaps: color: "#16a34a" (bracket confirmed text) → T.green; color: "#d97706" (bracket pending text) → T.amber.
  • Accepted: rgba(0,0,0,0.05) card shadow; #fff on gradient banner; storybook preview wrapper #f7f7f8/#898395 (debug-only, not rendered in app).
  • Priority: Low.

CampaignDetail.tsx(pass 8)

  • Migrated (pass 8): #fafafa ×3 → T.bg (StatTile, textarea, not-accepting card); CSS hover #7c3aed${T.accent} in template literal.
  • All T.* tokens throughout. No remaining actionable gaps.

StreamersList.tsx

  • Gap — 8 raw <button> elements: Logo/back nav (ghost), Dashboard nav, filter/sort pill buttons with T.* inline styles, "Clear ×" reset.
  • Gap — CSS template rgba: .sl-input:focus { box-shadow: 0 0 0 3px rgba(124,58,237,0.12) }${T.accentSoft}; .sl-signout:hover { background: rgba(239,68,68,0.08); color: #ef4444 }${T.redSoft} / ${T.red}.
  • Accepted: rgba(0,0,0,0.25) error shadow (no T.* token); #faf5ff/#f5f3ff tier-1 banner gradient (decorative); #fff on colored button text; #7c3aed/#22c55e SVG inline icon fills (design-justified).
  • Priority: Medium.

CampaignsPage.tsx

  • Uses: Alert, Badge, Button, Spinner.
  • Gap — 11 raw <button> elements: Accordion section toggles, template selectors, slot/bracket add-remove, platform/geo pill selectors.
  • Priority: Medium. Accordion → Flowbite Accordion; pills → reusable <PillSelect>.

Home2.tsx ⚠ partial (pass 6/8)

  • Migrated (pass 6): Filter/sort chips → Flowbite Button; rgba(139,92,246,0.12)T.accentSoft.
  • Migrated (pass 8): "Close error" dismiss <button>Button color="light" size="xs"; #f5f5f7 feature-icon box bg → T.bg.
  • Remaining — 1 raw <button>: Floating "Contact support" FAB — position: fixed, custom boxShadow. Design-justified.
  • Remaining hex (accepted): VLogo SVG paths (#5612F2, #E0E2E4, #D9D9D9); FAB shadow rgba; #1a1a2e dark navbar (no T.* dark token); structural #fff.
  • Priority: Effectively done — only design-justified items remain.

StreamerSignup2.tsx ⚠ partial (pass 6)

  • Migrated (pass 6): Error note rgba → T.redSoft/T.redBorder; #fafafaT.bg; "← Back" and "Resend code" → Flowbite Button.
  • Remaining — 2 raw <button> elements: Kick OAuth redirect button (window.location.href, not a UI pattern); language pill selector buttons (active/inactive state).
  • Remaining hex: #53FC18/#000 Kick brand — accepted; VLogo SVG — accepted; rgba(0,0,0,0.06/0.04) card shadows (no T.* token); rgba(139,92,246,0.15) selection ring (no T.* token); #1a1a2e dark bg.
  • Priority: Low. Language pills are the remaining actionable gap.

StreamerPublicProfile.tsx — logo nav button (accepted)

  • 1 <button> wrapping VLogo SVG + wordmark in the navbar. Layout-structural; same pattern as SiteNav. Accepted.

NegotiationCard.tsx / OperatorNegotiationCard.tsx

  • Accepted: boxShadow: "0 0 0 1px rgba(139,92,246,0.07)" — accent ring; no T.* box-shadow token.

VideosCard.tsx(accepted, pass 8)

  • 1 raw <button> — absolute-positioned × delete overlay on thumbnails. Uses only Tailwind classes (bg-black/65, text-white); no inline hex/rgba. Accepted — no actionable gap.

OperatorDealCard.tsx(accepted, pass 8)

  • 1 raw <button> — full-width submissions callout row. Uses only CSS-variable Tailwind classes (border-(--color-default), bg-(--color-neutral-primary), hover:bg-(--color-neutral-tertiary)); no inline hex/rgba. Accepted — no actionable gap.

ActiveCampaigns.tsx(new, pass 7)

  • 1 raw <button> — campaign selector row with conditional Tailwind classes. Pattern similar to TrackedSessionPicker.
  • Priority: Low.

Operator OffersPage.tsx

  • Gap: 1 raw <button> (profile chip toggle, not Dropdown trigger). Could become Button color="light".
  • Accepted: Dropdown renderTrigger pattern.
  • Priority: Low.

TrackedSessionPicker.tsx

  • 1 raw <button> — session list rows as full-row tap targets. Intentional; Flowbite ListGroup requires visual adaptation.
  • Priority: Low / accepted.

OffersTabPanel.tsx

  • Migrated pass 2.

AllocationStepper.tsx ✅ / FundCampaignPanel.tsx ✅ / StreamSubmissionRow.tsx

  • All migrated, minor accepted exceptions documented in prior passes.

Custom / Design-Justified (Keep As-Is)

ComponentReason
SiteNavCustom nav design; 7 internal <button> — mobile menu, language picker, etc.
OperatorLayoutNav/shell layout; raw sidebar nav <button> elements are layout-structural.
ProfileLayoutShell layout; rgba(0,0,0,0.06) card shadow is layout-structural.
AppFooterBrand logo SVG + 1 dark-mode toggle <button> — design-structural.
VFFooterBrand marketing footer; #8b5cf6/#7c3aed on social icons are brand identity.
HomeLandingMarketing page; bespoke gradients. Not app shell.
CampaignCardPublicPublic-facing design card; custom layout intentional.
CampaignFormDemoSelf-contained demo widget; not part of app shell.
AllocationStepper (timeline)Flowbite has no stepper/timeline primitive.
FundDonutSVG chart; segment fill colors are chart-semantic.
StreamerAvatarPure display; CSS-variable gradient fallback.
EarningsTile / ActivityRow / EmptyNegotiationsStatePure display; no interactive elements.
Entry.tsxPublic landing; rgba values are decorative selection styling.
InvitationsPagePermanent redirect stub — campaign_invitations table dropped (migration 0080).
ApplicationsPage (pass 6)Permanent redirect to /profile/offers — operator invitations and streamer applications are the same offer type (initiated_by field).
AuthImpersonate / BuildInfoUtility/debug pages.
StreamerAvatarPure display; gradient fallback is CSS-variable.
NegotiationPrototype.tsxDev sandbox; excluded from audit.
operator/StreamDeliveryPage SVG#8b5cf6/#d97706/#a1a1aa/#e4e4e7 are sparkline/compliance chart colors — chart-semantic, not UI tokens.

Primitives Not Yet in Use (Future Candidates)

Flowbite PrimitiveCurrent WorkaroundUse Case
Tooltiptitle attributeTerm labels, truncated text, icon buttons
ToastInline Alert bannersAsync success/error feedback
AccordionCustom <button> + collapseCampaignsPage + CampaignCardVerified
ListGroupCustom <button> listTrackedSessionPicker, ActiveCampaigns
PaginationNone (not yet needed)Future: deals, campaigns lists

Remaining Migration Backlog

#FileGapEffort
1StreamerPublicProfileKYC badge, amber badge, Discord/Telegram icon tokens, #f9fafbLow
2CampaignCardVerified#16a34a/#d97706T.green/T.amber; 3 accordion <button>Low–Medium
3StreamerSignup2Language pill <button> elementsLow
4StreamersList8 raw buttons; CSS rgba → T.*Medium
5CampaignsPage11 raw buttons (accordion / pill / selector)Medium
6ActiveCampaigns1 campaign-selector <button> → Flowbite or ListGroupLow
7operator/OffersPage1 profile chip toggle → Button color="light"Low
ProfileSettings / KycPage / OffersPage Dropdown triggerAccepted Flowbite Dropdown API pattern — defer

Storybook Coverage

71 of 83 files have at least one Storybook story (86%). 37 story files total covering 71 source files. Breakdown by group:

Components — with stories (43 / 43 auditable)

ComponentStory file
AppFooterUIComponents.stories
CampaignCardPublicCampaignCardPublic.stories
CampaignCardVerifiedCampaignCardVerified.stories
EngagementBadgeEngagementBadge.stories
FundCampaignPanelFundCampaignPanel.stories
FundDonutFundDonut.stories
InviteCampaignModalInviteCampaignModal.stories
NegTermEditorNegTermEditor.stories
SectionHeaderUIComponents.stories
SiteNavSiteNav.stories
StatusBadgeUIComponents.stories
StreamerAvatarStreamerAvatar.stories
StreamerCard (exported from StreamersList)StreamerCard.stories
dashboard/ActivityRowDashboardActivityRow.stories
dashboard/EarningsTileDashboardEarningsTile.stories
deals/AgreedTermsBadgesDealsAgreedTermsBadges.stories
deals/DealAllocationCardDealAllocationCard.stories
deals/FundsDonutDealsFundsDonut.stories
deals/OnChainOpsListDealsOnChainOpsList.stories
deals/OperatorDealCardOperatorDealCard.stories
deals/SlotRowDealsSlotRow.stories
deals/StreamSubmissionRowDealsStreamSubmissionRow.stories
negotiations/EmptyNegotiationsStateNegotiationComponents.stories
negotiations/NegStatusBannerNegotiationComponents.stories
negotiations/NegotiationCardNegotiationComponents.stories
negotiations/OperatorNegotiationCardNegotiationComponents.stories
offers/OfferDetailPanelOffersComponents.stories
offers/OfferItemOffersComponents.stories
offers/OfferNegotiationStatusOffersComponents.stories
offers/OffersTabPanelOffersComponents.stories
offers/StreamerProfilePanelStreamerProfilePanel.stories
offers/TakeBackFormOffersComponents.stories
offers/TermsStripOffersComponents.stories
personal/AudienceDealsCardPersonalPage.stories
personal/ChannelsCardPersonalPage.stories
personal/CommunicationCardPersonalPage.stories
personal/PillButtonUIComponents.stories
personal/ProfileSettingsPersonalPage.stories
personal/ProfileVisibilityCardPersonalPage.stories
personal/ToggleSwitchUIComponents.stories
personal/VideosCardPersonalPage.stories
streamer/delivery/DeliverySubmitFormStreamerPages.stories
streamer/delivery/ManualDeliveryFormDeliveryForms.stories
streamer/delivery/TrackedSessionPickerDeliveryForms.stories

Components — no direct stories (on-chain hooks, deferred)

These use useHTLC, useOnChainProof, useMultiAllocationProof, or useMultiDepositProof — hooks that require an active wallet + on-chain RPC:

deals/AllocationStepper · deals/DealCard · operator/active/AllocateFromNegModal · operator/active/AllocationCell · operator/active/ApplicationsPanel · operator/active/DepositMini

Pages — with stories (28 / 28 auditable)

PageStory file
CampaignDetailPublicPages.stories
EntryOperatorEntryForm.stories
Home2PublicPages.stories
HomeLandingHomeLanding.stories
SignInSignIn.stories
StreamerPublicProfilePublicPages.stories
StreamerSignup2PublicPages.stories
StreamersListStreamerCard.stories
TrustScoreTrustScore.stories
operator/AccountPageOperatorPages.stories
operator/ActivePageOperatorPages.stories
operator/CampaignsPageOperatorPages.stories
operator/DealsPageOperatorPages.stories
operator/NegotiationsPageOperatorPages.stories
operator/OffersPageOperatorPages.stories
operator/OperatorLayoutOperatorLayout.stories
operator/StreamDeliveryPageStreamDeliveryPage.stories
operator/WalletPageOperatorWalletPage.stories
operator/active/AllocationFormAllocationForm.stories
streamer/DashboardPageStreamerPages.stories
streamer/DealsPageStreamerPages.stories
streamer/KycPageStreamerPages.stories
streamer/NegotiationsPageStreamerPages.stories
streamer/OffersPageStreamerPages.stories
streamer/PersonalPageStreamerPages.stories
streamer/ProfileLayoutProfileLayout.stories
streamer/StreamsPageStreamerPages.stories
streamer/WalletPageStreamerPages.stories

Pages — excluded or deferred

AdminPage (excluded — admin panel) · AuthImpersonate (excluded — utility) · BuildInfo (excluded — utility) · operator/active/ActiveCampaigns (indirectly rendered by ActivePage story) · streamer/ApplicationsPage (redirect stub) · streamer/InvitationsPage (redirect stub)

Verifluence Documentation