Skip to content

feat(dashboard): migrate to tailwind css + shadcn/ui component system#262

Open
JacksCodeVault wants to merge 1 commit into
rmyndharis:mainfrom
JacksCodeVault:dashboard/tailwind-migration
Open

feat(dashboard): migrate to tailwind css + shadcn/ui component system#262
JacksCodeVault wants to merge 1 commit into
rmyndharis:mainfrom
JacksCodeVault:dashboard/tailwind-migration

Conversation

@JacksCodeVault

Copy link
Copy Markdown

This commit modernizes the OpenWA dashboard by migrating from a custom CSS architecture to a scalable component-based design system

Core infrastructure:

  • Added Tailwind CSS, PostCSS, and autoprefixer configuration
  • Integrated shadcn/ui component library with base components
  • Added class-variance-authority for component variant management
  • Configured tailwind-merge for proper class resolution

Component system:

  • Created reusable UI components (badge, button, dialog, dropdown-menu, input, scroll-area, select, separator, tabs, tooltip, avatar, alert-dialog)
  • All components follow shadcn/ui conventions and support theming
  • Components leverage Radix UI for accessibility and behavior

Page components:

  • Refactored ApiKeys, Chats, Dashboard, Infrastructure, Login, Logs, MessageTester, Plugins, Sessions, and Webhooks pages
  • Removed individual page CSS files (replaced with Tailwind utilities)
  • Updated all pages to use new UI component library

Dependencies:

  • Added: @radix-ui/, @phosphor-icons/react, class-variance-authority, clsx, tailwindcss, postcss, autoprefixer, @emoji-mart/
  • Maintained: existing React, routing, query, and i18n dependencies

Styling:

  • Migrated from CSS Modules to Tailwind CSS utilities
  • Consolidated global styles in index.css
  • Improved layout consistency across all pages
  • Added responsive design support via Tailwind breakpoints

Fixes:

  • Fixed TypeScript issues with unused exports in archiver.d.ts
  • Fixed deprecated baseUrl warning in tsconfig.app.json
  • Fixed Radix UI Slot API usage in component implementations
  • Fixed unused variable warnings in component declarations

Benefits:

  • Reduced CSS file count by consolidating styles into Tailwind utilities
  • Improved consistency with reusable component library
  • Enhanced maintainability with centralized design tokens
  • Better accessibility with Radix UI primitives
  • Faster development with pre-built, tested components
  • Improved type safety and developer experience

Testing:

  • All 429 unit tests pass
  • Dashboard build completes successfully with no TypeScript errors
  • ESLint and Prettier checks pass
  • All pages render correctly with new component system

BREAKING CHANGE: CSS class names and structure have changed significantly. Custom CSS overrides will need to be updated to use Tailwind utilities.

This commit modernizes the OpenWA dashboard by migrating from a custom CSS architecture to a scalable component-based design system

Core infrastructure:
- Added Tailwind CSS, PostCSS, and autoprefixer configuration
- Integrated shadcn/ui component library with base components
- Added class-variance-authority for component variant management
- Configured tailwind-merge for proper class resolution

Component system:
- Created reusable UI components (badge, button, dialog, dropdown-menu, input, scroll-area, select, separator, tabs, tooltip, avatar, alert-dialog)
- All components follow shadcn/ui conventions and support theming
- Components leverage Radix UI for accessibility and behavior

Page components:
- Refactored ApiKeys, Chats, Dashboard, Infrastructure, Login, Logs, MessageTester, Plugins, Sessions, and Webhooks pages
- Removed individual page CSS files (replaced with Tailwind utilities)
- Updated all pages to use new UI component library

Dependencies:
- Added: @radix-ui/*, @phosphor-icons/react, class-variance-authority, clsx, tailwindcss, postcss, autoprefixer, @emoji-mart/*
- Maintained: existing React, routing, query, and i18n dependencies

Styling:
- Migrated from CSS Modules to Tailwind CSS utilities
- Consolidated global styles in index.css
- Improved layout consistency across all pages
- Added responsive design support via Tailwind breakpoints

Fixes:
- Fixed TypeScript issues with unused exports in archiver.d.ts
- Fixed deprecated baseUrl warning in tsconfig.app.json
- Fixed Radix UI Slot API usage in component implementations
- Fixed unused variable warnings in component declarations

Benefits:
- Reduced CSS file count by consolidating styles into Tailwind utilities
- Improved consistency with reusable component library
- Enhanced maintainability with centralized design tokens
- Better accessibility with Radix UI primitives
- Faster development with pre-built, tested components
- Improved type safety and developer experience

Testing:
- All 429 unit tests pass
- Dashboard build completes successfully with no TypeScript errors
- ESLint and Prettier checks pass
- All pages render correctly with new component system

BREAKING CHANGE: CSS class names and structure have changed significantly. Custom CSS overrides will need to be updated to use Tailwind utilities.
Copilot AI review requested due to automatic review settings June 16, 2026 13:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR appears to migrate the dashboard UI from bespoke CSS to a Tailwind + shadcn/Radix component approach, while also expanding frontend API typings and adding a local archiver type declaration.

Changes:

  • Added TailwindCSS setup (config, PostCSS, CSS variables) and introduced a new UI component library layer (Radix-based).
  • Refactored multiple dashboard pages/components to use new UI primitives and swapped icon set to @phosphor-icons/react.
  • Extended API typings/endpoints (e.g., new session status, chat profile picture, contact profile picture fetch).

Reviewed changes

Copilot reviewed 56 out of 59 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/archiver.d.ts Adds local TypeScript declarations for the archiver module.
dashboard/vite.config.ts Adds @ alias to dashboard Vite config for simpler imports.
dashboard/tsconfig.app.json Adds TS path alias mapping and suppresses TS 6.0 deprecations.
dashboard/tailwind.config.js Introduces Tailwind configuration with custom theme tokens.
dashboard/src/services/api.ts Extends API types (new status, profilePic) and adds profile picture endpoint.
dashboard/src/pages/Webhooks.css Removes legacy CSS (likely replaced by Tailwind styling).
dashboard/src/pages/Sessions.css Removes legacy CSS (likely replaced by Tailwind styling).
dashboard/src/pages/Plugins.tsx Refactors Plugins page to new UI primitives + Phosphor icons.
dashboard/src/pages/Plugins.css Removes legacy CSS (replaced by Tailwind styling).
dashboard/src/pages/MessageTester.tsx Refactors Message Tester to new UI primitives + Tailwind.
dashboard/src/pages/Logs.tsx Refactors Logs page to new UI primitives + Tailwind.
dashboard/src/pages/Logs.css Removes legacy CSS (replaced by Tailwind styling).
dashboard/src/pages/Login.tsx Refactors Login page to new UI primitives + Tailwind.
dashboard/src/pages/Login.css Removes legacy CSS (replaced by Tailwind styling).
dashboard/src/pages/Infrastructure.css Removes legacy CSS (likely replaced elsewhere / pending migration).
dashboard/src/pages/Dashboard.tsx Refactors Dashboard page to Tailwind layout and new UI components.
dashboard/src/pages/Dashboard.css Removes legacy CSS (replaced by Tailwind styling).
dashboard/src/pages/ApiKeys.css Removes legacy CSS (likely replaced elsewhere / pending migration).
dashboard/src/lib/utils.ts Adds cn() helper (clsx + tailwind-merge).
dashboard/src/index.css Replaces prior global CSS with Tailwind layers + CSS variable tokens.
dashboard/src/i18n/locales/zh-HK.json Adds common.viewAll translation string.
dashboard/src/i18n/locales/zh-CN.json Adds common.viewAll translation string.
dashboard/src/i18n/locales/te.json Adds common.viewAll translation string.
dashboard/src/i18n/locales/it.json Adds common.viewAll translation string.
dashboard/src/i18n/locales/he.json Adds common.viewAll translation string.
dashboard/src/i18n/locales/fr.json Adds common.viewAll translation string.
dashboard/src/i18n/locales/en.json Adds filters/menu strings and new authenticating status label.
dashboard/src/i18n/locales/ar.json Adds common.viewAll translation string.
dashboard/src/hooks/useTheme.ts Adjusts theme application to use .dark class + listens to OS changes.
dashboard/src/components/ui/tooltip.tsx Adds Radix tooltip wrapper styled with Tailwind utilities.
dashboard/src/components/ui/tabs.tsx Adds Radix tabs wrapper.
dashboard/src/components/ui/separator.tsx Adds Radix separator wrapper.
dashboard/src/components/ui/select.tsx Adds Radix select wrapper.
dashboard/src/components/ui/scroll-area.tsx Adds a lightweight ScrollArea wrapper (non-Radix).
dashboard/src/components/ui/input.tsx Adds styled input primitive.
dashboard/src/components/ui/dropdown-menu.tsx Adds Radix dropdown-menu wrappers.
dashboard/src/components/ui/dialog.tsx Adds Radix dialog wrappers.
dashboard/src/components/ui/card.tsx Adds Card primitive.
dashboard/src/components/ui/button.tsx Adds Button primitive (CVA variants).
dashboard/src/components/ui/badge.tsx Adds Badge primitive (CVA variants).
dashboard/src/components/ui/avatar.tsx Adds Radix avatar wrapper.
dashboard/src/components/ui/alert-dialog.tsx Adds Radix alert-dialog wrapper.
dashboard/src/components/Toast.tsx Adjusts toast icon rendering to fit updated styling.
dashboard/src/components/Toast.css Updates toast styling to use CSS variables / new theme tokens.
dashboard/src/components/Layout.tsx Refactors navigation/sidebar to Tailwind + Tooltip + Phosphor icons.
dashboard/src/components/Layout.css Replaces prior layout CSS with minimal base + scrollbar styling.
dashboard/src/components/ErrorBoundary.tsx Refactors error boundary UI to new Button + icons.
dashboard/postcss.config.js Adds PostCSS config for Tailwind + autoprefixer.
dashboard/package.json Adds Tailwind/shadcn/Radix dependencies and related utilities.
dashboard/index.html Adds inline theme bootstrapping to avoid flash of wrong theme.
dashboard/components.json Adds shadcn UI configuration and path aliases.
.gitignore Updates agent-related ignores and adds several tool folders to ignore list.
Comments suppressed due to low confidence (4)

dashboard/src/pages/Dashboard.tsx:1

  • These newly introduced UI strings are hard-coded in English instead of using t(...), which breaks i18n consistency (especially since this PR updates locale files). Please move these into translation keys (e.g., dashboard.loading, dashboard.errorTitle, dashboard.overviewLabel, common.stop, common.open, etc.) and use t() so they’re localizable.
    dashboard/src/pages/Dashboard.tsx:1
  • These newly introduced UI strings are hard-coded in English instead of using t(...), which breaks i18n consistency (especially since this PR updates locale files). Please move these into translation keys (e.g., dashboard.loading, dashboard.errorTitle, dashboard.overviewLabel, common.stop, common.open, etc.) and use t() so they’re localizable.
    dashboard/src/pages/Dashboard.tsx:1
  • These newly introduced UI strings are hard-coded in English instead of using t(...), which breaks i18n consistency (especially since this PR updates locale files). Please move these into translation keys (e.g., dashboard.loading, dashboard.errorTitle, dashboard.overviewLabel, common.stop, common.open, etc.) and use t() so they’re localizable.
    dashboard/src/pages/Dashboard.tsx:1
  • These newly introduced UI strings are hard-coded in English instead of using t(...), which breaks i18n consistency (especially since this PR updates locale files). Please move these into translation keys (e.g., dashboard.loading, dashboard.errorTitle, dashboard.overviewLabel, common.stop, common.open, etc.) and use t() so they’re localizable.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +44 to +47
className={cn(
"z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-lg bg-foreground px-3 py-1.5 text-xs text-background shadow-md has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-none data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className
)}
Comment on lines +170 to +178
<NavLink
to={to}
className={cn(
"nav-item flex items-center gap-3 p-3 rounded-lg text-muted-foreground hover:text-foreground transition-colors",
isCollapsed && "justify-center px-0"
)}
end={to === '/'}
onClick={handleNavClick}
>
Comment on lines 1 to 7
.layout {
display: flex;
min-height: 100vh;
}

/* ==================== Sidebar ==================== */
.sidebar {
width: 260px;
background: var(--bg-white);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
position: fixed;
height: 100vh;
z-index: 100;
transition:
width 0.3s ease,
transform 0.3s ease;
}

.sidebar.collapsed {
width: 72px;
}

.sidebar-header {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1.5rem;
border-bottom: 1px solid var(--border);
min-height: 72px;
}

.sidebar.collapsed .sidebar-header {
justify-content: center;
padding: 1.5rem 1rem;
}

.sidebar-logo {
width: 28px;
height: 28px;
object-fit: contain;
flex-shrink: 0;
}

.mobile-brand .sidebar-logo {
width: 24px;
height: 24px;
}

.sidebar-brand {
display: flex;
flex-direction: column;
width: 100vw;
overflow: hidden;
white-space: nowrap;
}

.brand-name {
font-size: 1.125rem;
font-weight: 800;
color: var(--text-primary);
letter-spacing: -0.01em;
}

.brand-subtitle {
font-size: 0.7rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
background-color: var(--background);
}
Comment on lines +26 to 33
::-webkit-scrollbar-thumb {
background: rgba(var(--foreground), 0.2);
border-radius: 3px;
}

[dir="rtl"] .sidebar.collapsed .language-menu-list {
right: calc(100% + 0.5rem);
left: auto;
::-webkit-scrollbar-thumb:hover {
background: rgba(var(--foreground), 0.3);
}
@@ -1,10 +1,12 @@
import { useNavigate } from 'react-router-dom';
Comment on lines +137 to +139
isMobile && "mobile fixed inset-y-0 left-0 z-50",
isMobile && !isMobileOpen && "-translate-x-full",
isMobileOpen && "translate-x-0"
@JacksCodeVault JacksCodeVault requested a review from Copilot June 16, 2026 13:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 56 out of 59 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (4)

dashboard/src/pages/Logs.tsx:1

  • These filters are clickable <span> badges. Spans aren’t keyboard-focusable and don’t provide button semantics, so the filter controls aren’t accessible. Use a <button> (or your Button component) instead, or add proper role=\"button\", tabIndex={0}, and keyboard handlers.
    dashboard/src/pages/Login.tsx:1
  • The visibility toggle is removed from the tab order with tabIndex={-1}, which prevents keyboard users from toggling password visibility. Remove tabIndex={-1} and add an accessible label (e.g., aria-label) so it’s operable via keyboard and screen readers.
    dashboard/src/pages/Dashboard.tsx:1
  • This introduces a hard-coded UI string (Overview) in a localized app. Please replace it with a translation key (e.g., under dashboard.* or common.*) to avoid i18n regressions.
    dashboard/src/pages/Dashboard.tsx:1
  • This introduces a hard-coded loading message (Loading dashboard) in a localized UI. Prefer t(...) with a translation key to keep language parity.

Comment on lines +44 to +47
className={cn(
"z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-lg bg-foreground px-3 py-1.5 text-xs text-background shadow-md has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-none data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className
)}
<SelectPrimitive.Content
data-slot="select-content"
data-align-trigger={position === "item-aligned"}
className={cn("relative z-50 max-h-(--radix-select-content-available-height) min-w-36 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", position ==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className )}
Comment on lines 1 to 7
.layout {
display: flex;
min-height: 100vh;
}

/* ==================== Sidebar ==================== */
.sidebar {
width: 260px;
background: var(--bg-white);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
position: fixed;
height: 100vh;
z-index: 100;
transition:
width 0.3s ease,
transform 0.3s ease;
}

.sidebar.collapsed {
width: 72px;
}

.sidebar-header {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1.5rem;
border-bottom: 1px solid var(--border);
min-height: 72px;
}

.sidebar.collapsed .sidebar-header {
justify-content: center;
padding: 1.5rem 1rem;
}

.sidebar-logo {
width: 28px;
height: 28px;
object-fit: contain;
flex-shrink: 0;
}

.mobile-brand .sidebar-logo {
width: 24px;
height: 24px;
}

.sidebar-brand {
display: flex;
flex-direction: column;
width: 100vw;
overflow: hidden;
white-space: nowrap;
}

.brand-name {
font-size: 1.125rem;
font-weight: 800;
color: var(--text-primary);
letter-spacing: -0.01em;
}

.brand-subtitle {
font-size: 0.7rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
background-color: var(--background);
}
Comment on lines +26 to 33
::-webkit-scrollbar-thumb {
background: rgba(var(--foreground), 0.2);
border-radius: 3px;
}

[dir="rtl"] .sidebar.collapsed .language-menu-list {
right: calc(100% + 0.5rem);
left: auto;
::-webkit-scrollbar-thumb:hover {
background: rgba(var(--foreground), 0.3);
}
Comment on lines +170 to +178
<NavLink
to={to}
className={cn(
"nav-item flex items-center gap-3 p-3 rounded-lg text-muted-foreground hover:text-foreground transition-colors",
isCollapsed && "justify-center px-0"
)}
end={to === '/'}
onClick={handleNavClick}
>
Comment on lines +259 to +263
<main className={cn(
"main-content flex-1 h-screen flex flex-col overflow-hidden"
)}>
<Outlet />
</main>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants