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
| Metric | Value |
|---|---|
| Total files (after pass 10 deletions) | 83 |
| Files importing Flowbite (components or icons) | ~76 |
| Overall import rate | ~92% |
| Files with Storybook stories | 71 / 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:
CampaignDetailfully clean — 3×#fafafa→T.bg, CSS hover →${T.accent}.Home2dismiss button → FlowbiteButton,#f5f5f7→T.bg.VideosCardandOperatorDealCardconfirmed accepted (Tailwind CSS-variable classes only, no raw hex). 7 actionable items remain.
Fully Flowbite-Native
| Component | Flowbite primitives used |
|---|---|
StatusBadge | Badge |
EngagementBadge | Badge + icons |
PillButton | Button (pill) |
SectionHeader | Badge |
ToggleSwitch | wraps FlowbiteToggle |
TakeBackForm | Alert, Button, Textarea |
OfferNegotiationStatus | Badge, Button |
OfferDetailPanel | Badge, Button, Alert |
OfferItem | Badge |
TermsStrip | Badge |
StreamerProfilePanel | Badge, Spinner |
NegStatusBanner | Alert, Textarea |
InviteCampaignModal | Modal, Button, TextInput, Textarea, Label, Alert, Select, Spinner |
DeliverySubmitForm | Alert, Button, Select, TextInput, Textarea |
ManualDeliveryForm | TextInput, Textarea |
AgreedTermsBadges | Badge + icons |
CommunicationCard | Alert, Button, Label |
AudienceDealsCard | Alert, Button, Label, TextInput, Textarea |
ChannelsCard | Button, Alert, Spinner + icons |
ProfileVisibilityCard | Alert + icons |
ProfileSettings | Alert, Button, Dropdown, TextInput, Label |
NegTermEditor | Alert, Badge, Button, TextInput |
AllocationStepper | Alert, Badge, Button + icons |
FundCampaignPanel | Alert, Button, Spinner + icons |
StreamerCard | Badge, Button |
SlotRow | Badge, Button |
AllocateFromNegModal | Modal, Alert, Badge |
DealCard | Alert, 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 OffersPage | Alert, Badge, Tabs |
Streamer NegotiationsPage | Alert, Badge, Button, Spinner |
Streamer DealsPage | Alert, Badge, Button, Spinner |
Streamer DashboardPage | Button, Spinner + icons |
Operator AccountPage | Button, Label, TextInput, Alert, Badge, Spinner |
Operator DealsPage | Alert, 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,#92400e→T.amberSoft,T.amberBorder,T.amber - Deal types chip:
background: "#f9fafb"→T.bg - Discord icon box:
#ede9fe/#7c3aed→T.accentSoft/T.accent - Telegram icon box:
#dbeafe/#2563eb→T.skySoft/T.sky
- KYC "Verified" badge:
- 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#fafafa→T.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;#fffon 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 withT.*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/#f5f3fftier-1 banner gradient (decorative);#fffon colored button text;#7c3aed/#22c55eSVG 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";#f5f5f7feature-icon box bg →T.bg. - Remaining — 1 raw
<button>: Floating "Contact support" FAB —position: fixed, customboxShadow. Design-justified. - Remaining hex (accepted): VLogo SVG paths (
#5612F2,#E0E2E4,#D9D9D9); FAB shadow rgba;#1a1a2edark 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;#fafafa→T.bg; "← Back" and "Resend code" → FlowbiteButton. - 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/#000Kick 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);#1a1a2edark 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 asSiteNav. 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 toTrackedSessionPicker. - Priority: Low.
Operator OffersPage.tsx
- Gap: 1 raw
<button>(profile chip toggle, not Dropdown trigger). Could becomeButton color="light". - Accepted: Dropdown
renderTriggerpattern. - Priority: Low.
TrackedSessionPicker.tsx
- 1 raw
<button>— session list rows as full-row tap targets. Intentional; FlowbiteListGrouprequires 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)
| Component | Reason |
|---|---|
SiteNav | Custom nav design; 7 internal <button> — mobile menu, language picker, etc. |
OperatorLayout | Nav/shell layout; raw sidebar nav <button> elements are layout-structural. |
ProfileLayout | Shell layout; rgba(0,0,0,0.06) card shadow is layout-structural. |
AppFooter | Brand logo SVG + 1 dark-mode toggle <button> — design-structural. |
VFFooter | Brand marketing footer; #8b5cf6/#7c3aed on social icons are brand identity. |
HomeLanding | Marketing page; bespoke gradients. Not app shell. |
CampaignCardPublic | Public-facing design card; custom layout intentional. |
CampaignFormDemo | Self-contained demo widget; not part of app shell. |
AllocationStepper (timeline) | Flowbite has no stepper/timeline primitive. |
FundDonut | SVG chart; segment fill colors are chart-semantic. |
StreamerAvatar | Pure display; CSS-variable gradient fallback. |
EarningsTile / ActivityRow / EmptyNegotiationsState | Pure display; no interactive elements. |
Entry.tsx | Public landing; rgba values are decorative selection styling. |
InvitationsPage | Permanent 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 / BuildInfo | Utility/debug pages. |
StreamerAvatar | Pure display; gradient fallback is CSS-variable. |
NegotiationPrototype.tsx | Dev 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 Primitive | Current Workaround | Use Case |
|---|---|---|
Tooltip | title attribute | Term labels, truncated text, icon buttons |
Toast | Inline Alert banners | Async success/error feedback |
Accordion | Custom <button> + collapse | CampaignsPage + CampaignCardVerified |
ListGroup | Custom <button> list | TrackedSessionPicker, ActiveCampaigns |
Pagination | None (not yet needed) | Future: deals, campaigns lists |
Remaining Migration Backlog
| # | File | Gap | Effort |
|---|---|---|---|
| 1 | StreamerPublicProfile | KYC badge, amber badge, Discord/Telegram icon tokens, #f9fafb | Low |
| 2 | CampaignCardVerified | #16a34a/#d97706 → T.green/T.amber; 3 accordion <button> | Low–Medium |
| 3 | StreamerSignup2 | Language pill <button> elements | Low |
| 4 | StreamersList | 8 raw buttons; CSS rgba → T.* | Medium |
| 5 | CampaignsPage | 11 raw buttons (accordion / pill / selector) | Medium |
| 6 | ActiveCampaigns | 1 campaign-selector <button> → Flowbite or ListGroup | Low |
| 7 | operator/OffersPage | 1 profile chip toggle → Button color="light" | Low |
| — | ProfileSettings / KycPage / OffersPage Dropdown trigger | Accepted 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)
| Component | Story file |
|---|---|
AppFooter | UIComponents.stories |
CampaignCardPublic | CampaignCardPublic.stories |
CampaignCardVerified | CampaignCardVerified.stories |
EngagementBadge | EngagementBadge.stories |
FundCampaignPanel | FundCampaignPanel.stories |
FundDonut | FundDonut.stories |
InviteCampaignModal | InviteCampaignModal.stories |
NegTermEditor | NegTermEditor.stories |
SectionHeader | UIComponents.stories |
SiteNav | SiteNav.stories |
StatusBadge | UIComponents.stories |
StreamerAvatar | StreamerAvatar.stories |
StreamerCard (exported from StreamersList) | StreamerCard.stories |
dashboard/ActivityRow | DashboardActivityRow.stories |
dashboard/EarningsTile | DashboardEarningsTile.stories |
deals/AgreedTermsBadges | DealsAgreedTermsBadges.stories |
deals/DealAllocationCard | DealAllocationCard.stories |
deals/FundsDonut | DealsFundsDonut.stories |
deals/OnChainOpsList | DealsOnChainOpsList.stories |
deals/OperatorDealCard | OperatorDealCard.stories |
deals/SlotRow | DealsSlotRow.stories |
deals/StreamSubmissionRow | DealsStreamSubmissionRow.stories |
negotiations/EmptyNegotiationsState | NegotiationComponents.stories |
negotiations/NegStatusBanner | NegotiationComponents.stories |
negotiations/NegotiationCard | NegotiationComponents.stories |
negotiations/OperatorNegotiationCard | NegotiationComponents.stories |
offers/OfferDetailPanel | OffersComponents.stories |
offers/OfferItem | OffersComponents.stories |
offers/OfferNegotiationStatus | OffersComponents.stories |
offers/OffersTabPanel | OffersComponents.stories |
offers/StreamerProfilePanel | StreamerProfilePanel.stories |
offers/TakeBackForm | OffersComponents.stories |
offers/TermsStrip | OffersComponents.stories |
personal/AudienceDealsCard | PersonalPage.stories |
personal/ChannelsCard | PersonalPage.stories |
personal/CommunicationCard | PersonalPage.stories |
personal/PillButton | UIComponents.stories |
personal/ProfileSettings | PersonalPage.stories |
personal/ProfileVisibilityCard | PersonalPage.stories |
personal/ToggleSwitch | UIComponents.stories |
personal/VideosCard | PersonalPage.stories |
streamer/delivery/DeliverySubmitForm | StreamerPages.stories |
streamer/delivery/ManualDeliveryForm | DeliveryForms.stories |
streamer/delivery/TrackedSessionPicker | DeliveryForms.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)
| Page | Story file |
|---|---|
CampaignDetail | PublicPages.stories |
Entry | OperatorEntryForm.stories |
Home2 | PublicPages.stories |
HomeLanding | HomeLanding.stories |
SignIn | SignIn.stories |
StreamerPublicProfile | PublicPages.stories |
StreamerSignup2 | PublicPages.stories |
StreamersList | StreamerCard.stories |
TrustScore | TrustScore.stories |
operator/AccountPage | OperatorPages.stories |
operator/ActivePage | OperatorPages.stories |
operator/CampaignsPage | OperatorPages.stories |
operator/DealsPage | OperatorPages.stories |
operator/NegotiationsPage | OperatorPages.stories |
operator/OffersPage | OperatorPages.stories |
operator/OperatorLayout | OperatorLayout.stories |
operator/StreamDeliveryPage | StreamDeliveryPage.stories |
operator/WalletPage | OperatorWalletPage.stories |
operator/active/AllocationForm | AllocationForm.stories |
streamer/DashboardPage | StreamerPages.stories |
streamer/DealsPage | StreamerPages.stories |
streamer/KycPage | StreamerPages.stories |
streamer/NegotiationsPage | StreamerPages.stories |
streamer/OffersPage | StreamerPages.stories |
streamer/PersonalPage | StreamerPages.stories |
streamer/ProfileLayout | ProfileLayout.stories |
streamer/StreamsPage | StreamerPages.stories |
streamer/WalletPage | StreamerPages.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)