diff --git a/.gitignore b/.gitignore
index 9bc7a33..e9e3d00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,4 +35,7 @@ pnpm-debug.log*
*storybook.log
# Storybook build output
-storybook-static/
\ No newline at end of file
+storybook-static/
+
+# 3rd party
+vendors/
diff --git a/Dockerfile b/Dockerfile
index ed1ca1c..4d18ade 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,13 +1,24 @@
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
-COPY package.json pnpm-lock.yaml ./
-RUN npm install -g pnpm && pnpm install
+
+# Copy workspace configuration and root package files
+COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
+
+# Install pnpm
+RUN npm install -g pnpm
+
+# Copy all package.json files to enable proper dependency resolution
COPY packages/ui-kit/package.json ./packages/ui-kit/
-WORKDIR /app/packages/ui-kit
+COPY packages/showcase/package.json ./packages/showcase/
+
+# Install all dependencies for the workspace
RUN pnpm install
-WORKDIR /app
+
+# Copy all source code
COPY . .
+
+# Build all packages
RUN pnpm build
# Production stage
diff --git a/docs/project_plan.md b/docs/project_plan.md
index f5ea895..87522ce 100644
--- a/docs/project_plan.md
+++ b/docs/project_plan.md
@@ -56,7 +56,7 @@ A pragmatic breakdown into **four one‑week sprints** plus a preparatory **Spri
| --- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------ |
| 3.1 | Wrap **TanStack Table** into `DataTable` with pagination, resize. | Story with 50 rows paginates; Playwright test clicks next page. | ✓ |
| 3.2 | Build **MainLayout** with TopBar + LeftNav + Breadcrumb. | Storybook viewport test at 1280 & 1024 px shows responsive collapse. | ✓ |
-| 3.3 | Implement Toast system (`useToast`) + StatusBadge. | Vitest renders Toast, axe-core passes. | PR |
+| 3.3 | Implement Toast system (`useToast`) + StatusBadge. | Vitest renders Toast, axe-core passes. | ✓ |
| 3.4 | Sample showcase: login page + dashboard + customers table route. | E2E Playwright run (login → dashboard) green in CI. | |
| 3.5 | Add i18n infrastructure (`react-i18next`) with `en`, `de` locales. | Storybook toolbar allows locale switch; renders German labels. | |
| 3.6 | **SQLite seed script** – generate 100 customers & 2 users; hook `pnpm run seed` in showcase. | Script executes without error; Playwright test logs in with `admin` credentials, verifies 100 customers paginated. | |
diff --git a/docs/task-planning/task-3.4-sample-showcase.md b/docs/task-planning/task-3.4-sample-showcase.md
new file mode 100644
index 0000000..5a835b8
--- /dev/null
+++ b/docs/task-planning/task-3.4-sample-showcase.md
@@ -0,0 +1,169 @@
+# Task 3.4: Sample Showcase - Login Page + Dashboard + Customers Table Route
+
+## Task Description
+
+Implement a sample showcase application that demonstrates the UI-Kit components in action. This includes creating actual application routes with login functionality, a dashboard, and a customers table view using the existing UI components.
+
+## Task Planning
+
+| Task Description | Definition of Done (DoD) | Status |
+| ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------- |
+| Set up showcase application structure | - Showcase app directory structure exists
- React Router v7 configured
- Basic routing setup complete | Complete |
+| Create login page using AuthShell | - Login page renders with AuthShell layout
- Login form uses UI-Kit form components
- Basic authentication logic implemented | Checking |
+| Implement dashboard page using MainLayout | - Dashboard page renders with MainLayout
- Displays summary cards and navigation
- Uses existing UI-Kit components | Open |
+| Create customers table route with DataTable | - Customers page displays using DataTable component
- Shows paginated customer data
- Navigation from dashboard works | Open |
+| Add routing and navigation | - React Router navigation between pages
- Protected routes for authenticated content
- Breadcrumb navigation works | Open |
+| Implement basic authentication state | - Login/logout functionality
- Session persistence
- Route protection based on auth state | Open |
+| Add sample data and mock API | - Customer data generation
- Mock authentication endpoints
- API integration with DataTable | Open |
+| Create E2E tests | - Playwright tests for login flow
- Navigation test (login → dashboard → customers)
- Tests pass in CI | Open |
+| Integrate showcase with UI-Kit build | - Showcase app builds successfully
- Uses published UI-Kit components
- No circular dependencies | Open |
+
+## Implementation Details
+
+### 1. Application Structure
+
+Create a sample showcase application that demonstrates the UI-Kit in a realistic scenario:
+
+```
+showcase/
+ src/
+ pages/
+ LoginPage.tsx # Using AuthShell + form components
+ DashboardPage.tsx # Using MainLayout + stats components
+ CustomersPage.tsx # Using MainLayout + DataTable
+ components/
+ ProtectedRoute.tsx # Route protection wrapper
+ Navigation.tsx # App navigation using UI-Kit components
+ hooks/
+ useAuth.tsx # Authentication state management
+ services/
+ api.ts # Mock API for data
+ auth.ts # Authentication logic
+ types/
+ Customer.ts # Customer data types
+ Auth.ts # Authentication types
+```
+
+### 2. Pages Implementation
+
+**Login Page:**
+
+- Use `AuthShell` layout from UI-Kit
+- Login form with `TextInput` and `Button` components
+- Form validation using React Hook Form + Zod
+- Error handling with `Toast` notifications
+- Responsive design following UI-Kit patterns
+
+**Dashboard Page:**
+
+- Use `MainLayout` with navigation and breadcrumbs
+- Summary cards showing customer statistics
+- Quick action buttons using UI-Kit buttons
+- Navigation to customers page
+- Use `StatusBadge` for status indicators
+
+**Customers Page:**
+
+- Use `MainLayout` for consistent navigation
+- `DataTable` component showing customer list
+- Pagination, sorting, and filtering
+- Customer actions (view, edit buttons)
+- Breadcrumb navigation
+
+### 3. Technical Requirements
+
+**Routing:**
+
+- React Router v7 with data loaders
+- Protected routes requiring authentication
+- Proper error boundaries and 404 handling
+- Clean URL structure
+
+**State Management:**
+
+- Authentication state using Zustand (from UI-Kit)
+- Customer data fetching and caching
+- Form state management with React Hook Form
+
+**Data Layer:**
+
+- Mock customer data (50+ records)
+- Simulated API responses with realistic delays
+- Pagination and filtering logic
+- Authentication simulation
+
+### 4. Testing Strategy
+
+**E2E Tests (Playwright):**
+
+- Login flow: invalid credentials → error, valid credentials → dashboard
+- Navigation: login → dashboard → customers → back to dashboard
+- DataTable interactions: pagination, sorting
+- Logout functionality
+- Responsive behavior testing
+
+**Integration:**
+
+- Component integration with real data
+- Form submission and validation flows
+- Navigation state persistence
+- Error handling scenarios
+
+## Definition of Done
+
+**Original DoD:** "E2E Playwright run (login → dashboard) green in CI."
+
+**Expanded DoD:**
+
+- ✅ Showcase application builds and runs without errors
+- ✅ Login page functional with form validation
+- ✅ Dashboard page displays with navigation
+- ✅ Customers page shows DataTable with pagination
+- ✅ E2E Playwright tests pass: login → dashboard → customers flow
+- ✅ All UI-Kit components integrated properly
+- ✅ Responsive design works on different screen sizes
+- ✅ Authentication flow works end-to-end
+- ✅ CI pipeline runs tests successfully
+
+## Technical Dependencies
+
+### Required UI-Kit Components:
+
+- `AuthShell` (login page layout)
+- `AppShell` (dashboard and customers layout)
+- `DataTable` (customers table)
+- `TextInput`, `Button` (forms)
+- `Toast` (notifications)
+- `StatusBadge` (status indicators)
+
+### External Dependencies:
+
+- React Router v7 (routing)
+- React Hook Form + Zod (forms)
+- Playwright (E2E testing)
+- Mock data generation utilities
+
+### Infrastructure:
+
+- Vite setup for showcase app
+- Build integration with UI-Kit
+- CI/CD pipeline updates
+- Development server configuration
+
+## Success Metrics
+
+1. **Functionality:** All user flows work end-to-end
+2. **Performance:** Pages load within 2 seconds
+3. **Accessibility:** axe-core tests pass on all pages
+4. **Testing:** 100% E2E test coverage for critical paths
+5. **Integration:** UI-Kit components work seamlessly
+6. **Maintainability:** Clean, documented code structure
+
+## Next Steps After Completion
+
+This showcase will serve as:
+
+- Reference implementation for UI-Kit usage
+- Testing ground for new components
+- Demo for stakeholders and users
+- Foundation for future showcase extensions (task 3.5: i18n, task 3.6: SQLite integration)
diff --git a/eslint.config.js b/eslint.config.js
index d75db38..3d5e518 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -7,7 +7,7 @@ import uiKitRules from './packages/eslint-plugin-ui-kit-rules/index.js';
export default [
// global ignores – applied before other configs
{
- ignores: ['packages/ui-kit/dist/**', '**/node_modules/**', '**/storybook-static/**']
+ ignores: ['packages/ui-kit/dist/**', '**/node_modules/**', '**/storybook-static/**', 'vendors/**', 'packages/showcase/dist/**', '**/dist/**']
},
js.configs.recommended,
...tseslint.configs.recommended,
diff --git a/packages/showcase/eslint.config.js b/packages/showcase/eslint.config.js
new file mode 100644
index 0000000..af60e58
--- /dev/null
+++ b/packages/showcase/eslint.config.js
@@ -0,0 +1,42 @@
+import js from '@eslint/js';
+import tseslint from 'typescript-eslint';
+import reactHooks from 'eslint-plugin-react-hooks';
+import reactRefresh from 'eslint-plugin-react-refresh';
+
+export default [
+ // global ignores – applied before other configs
+ {
+ ignores: ['dist/**', 'node_modules/**', '../../vendors/**']
+ },
+ js.configs.recommended,
+ ...tseslint.configs.recommended,
+ {
+ files: ['src/**/*.{js,jsx,ts,tsx}', 'tailwind.config.js', 'vite.config.ts', 'postcss.config.js'],
+ languageOptions: {
+ ecmaVersion: 2020,
+ sourceType: 'module',
+ globals: {
+ module: 'readonly',
+ require: 'readonly',
+ process: 'readonly',
+ console: 'readonly',
+ window: 'readonly',
+ document: 'readonly',
+ navigator: 'readonly'
+ }
+ },
+ plugins: {
+ 'react-hooks': reactHooks,
+ 'react-refresh': reactRefresh
+ },
+ rules: {
+ 'react-hooks/rules-of-hooks': 'error',
+ 'react-hooks/exhaustive-deps': 'warn',
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true }
+ ],
+ '@typescript-eslint/no-require-imports': 'off'
+ }
+ }
+];
\ No newline at end of file
diff --git a/packages/showcase/index.html b/packages/showcase/index.html
new file mode 100644
index 0000000..2051f6f
--- /dev/null
+++ b/packages/showcase/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ UI-Kit Showcase
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/showcase/package.json b/packages/showcase/package.json
new file mode 100644
index 0000000..bea572b
--- /dev/null
+++ b/packages/showcase/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "@org/showcase",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "lint": "eslint .",
+ "preview": "vite preview",
+ "test": "vitest run",
+ "test:e2e": "playwright test"
+ },
+ "dependencies": {
+ "@hookform/resolvers": "^3.6.1",
+ "@org/ui-kit": "workspace:*",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-hook-form": "^7.56.4",
+ "react-router": "^7.0.0",
+ "react-router-dom": "^7.0.0",
+ "zod": "^3.25.7",
+ "zustand": "^5.0.4"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.27.0",
+ "@playwright/test": "^1.52.0",
+ "@testing-library/jest-dom": "^6.6.3",
+ "@testing-library/react": "^16.3.0",
+ "@types/react": "^19.1.4",
+ "@types/react-dom": "^19.1.5",
+ "@vitejs/plugin-react": "^4.4.1",
+ "autoprefixer": "^10.4.21",
+ "daisyui": "^5.0.35",
+ "eslint": "^9.27.0",
+ "eslint-plugin-react": "^7.37.5",
+ "eslint-plugin-react-hooks": "^5.2.0",
+ "eslint-plugin-react-refresh": "^0.4.20",
+ "jsdom": "^26.1.0",
+ "postcss": "^8.5.3",
+ "tailwindcss": "^3.4.17",
+ "tailwindcss-animate": "^1.0.7",
+ "typescript": "^5.8.3",
+ "typescript-eslint": "^8.32.1",
+ "vite": "^5.4.19",
+ "vitest": "^1.6.1"
+ }
+}
diff --git a/packages/showcase/postcss.config.js b/packages/showcase/postcss.config.js
new file mode 100644
index 0000000..1b364dd
--- /dev/null
+++ b/packages/showcase/postcss.config.js
@@ -0,0 +1,9 @@
+import tailwindcss from 'tailwindcss';
+import autoprefixer from 'autoprefixer';
+
+export default {
+ plugins: [
+ tailwindcss,
+ autoprefixer,
+ ],
+};
\ No newline at end of file
diff --git a/packages/showcase/src/App.test.tsx b/packages/showcase/src/App.test.tsx
new file mode 100644
index 0000000..fb2266b
--- /dev/null
+++ b/packages/showcase/src/App.test.tsx
@@ -0,0 +1,20 @@
+import { describe, it, expect } from 'vitest';
+import { render } from '@testing-library/react';
+import { BrowserRouter } from 'react-router';
+import { ToastProvider } from '@org/ui-kit';
+import { LoginPage } from './pages/LoginPage';
+
+describe('Showcase App', () => {
+ it('renders LoginPage without crashing', () => {
+ render(
+
+
+
+
+
+ );
+
+ // Check that the component renders
+ expect(document.body).toBeTruthy();
+ });
+});
\ No newline at end of file
diff --git a/packages/showcase/src/components/ProtectedRoute.tsx b/packages/showcase/src/components/ProtectedRoute.tsx
new file mode 100644
index 0000000..67c1ece
--- /dev/null
+++ b/packages/showcase/src/components/ProtectedRoute.tsx
@@ -0,0 +1,16 @@
+import { Navigate } from 'react-router-dom';
+import { useAuth } from '../hooks/useAuth';
+
+interface ProtectedRouteProps {
+ children: React.ReactNode;
+}
+
+export function ProtectedRoute({ children }: ProtectedRouteProps) {
+ const { isAuthenticated } = useAuth();
+
+ if (!isAuthenticated) {
+ return ;
+ }
+
+ return <>{children}>;
+}
\ No newline at end of file
diff --git a/packages/showcase/src/hooks/useAuth.tsx b/packages/showcase/src/hooks/useAuth.tsx
new file mode 100644
index 0000000..3c72889
--- /dev/null
+++ b/packages/showcase/src/hooks/useAuth.tsx
@@ -0,0 +1,84 @@
+import { create } from 'zustand';
+import { persist } from 'zustand/middleware';
+import type { AuthState, LoginCredentials } from '../types/Auth';
+
+interface AuthStore extends AuthState {
+ login: (credentials: LoginCredentials) => Promise;
+ logout: () => void;
+ clearError: () => void;
+}
+
+// Mock users for demo
+const MOCK_USERS = [
+ {
+ id: '1',
+ email: 'admin@example.com',
+ name: 'Admin User',
+ role: 'admin' as const,
+ password: 'admin123',
+ },
+ {
+ id: '2',
+ email: 'user@example.com',
+ name: 'Demo User',
+ role: 'user' as const,
+ password: 'user123',
+ },
+];
+
+export const useAuth = create()(
+ persist(
+ (set) => ({
+ user: null,
+ isAuthenticated: false,
+ isLoading: false,
+ error: null,
+
+ login: async (credentials: LoginCredentials) => {
+ set({ isLoading: true, error: null });
+
+ // Simulate API delay
+ await new Promise(resolve => setTimeout(resolve, 1000));
+
+ const user = MOCK_USERS.find(
+ u => u.email === credentials.email && u.password === credentials.password
+ );
+
+ if (user) {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { password, ...userWithoutPassword } = user;
+ set({
+ user: userWithoutPassword,
+ isAuthenticated: true,
+ isLoading: false,
+ error: null
+ });
+ } else {
+ set({
+ error: 'Invalid email or password',
+ isLoading: false
+ });
+ }
+ },
+
+ logout: () => {
+ set({
+ user: null,
+ isAuthenticated: false,
+ error: null
+ });
+ },
+
+ clearError: () => {
+ set({ error: null });
+ },
+ }),
+ {
+ name: 'auth-storage',
+ partialize: (state) => ({
+ user: state.user,
+ isAuthenticated: state.isAuthenticated
+ }),
+ }
+ )
+);
\ No newline at end of file
diff --git a/packages/showcase/src/index.css b/packages/showcase/src/index.css
new file mode 100644
index 0000000..af9d14b
--- /dev/null
+++ b/packages/showcase/src/index.css
@@ -0,0 +1,132 @@
+@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&display=swap');
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* Force DaisyUI component generation - ensure these classes are available */
+/* .btn .btn-primary .btn-secondary .card .input .modal .navbar .drawer */
+
+/* Nexadash-inspired design tokens */
+:root {
+ /* Typography */
+ --font-plus-jakarta: 'Plus Jakarta Sans', sans-serif;
+
+ /* Color palette inspired by nexadash */
+ --color-primary: #335cff;
+ --color-primary-hover: #2A4DD7;
+ --color-black: #171718;
+ --color-white: #ffffff;
+
+ /* Gray palette */
+ --color-gray-100: #fafbfc;
+ --color-gray-200: #f9fafb;
+ --color-gray-300: #e2e8f0;
+ --color-gray-400: #f5f7fa;
+ --color-gray-500: #b9bec6;
+ --color-gray-600: #9ca3af;
+ --color-gray-700: #6b7280;
+ --color-gray: #525866;
+
+ /* Status colors */
+ --color-success: #22c55e;
+ --color-success-light: #dcfce7;
+ --color-warning: #eab308;
+ --color-danger: #ef4444;
+ --color-danger-light: #fee2e2;
+
+ /* Theme colors */
+ --color-light-theme: #f4f7ff;
+ --color-light-orange: #ffedd5;
+ --color-light-blue: #e0f2fe;
+ --color-light-purple: #f3e8ff;
+
+ /* Shadows */
+ --shadow-3xl: 0 1px 2px 0 rgba(95, 74, 46, 0.08), 0 0 0 1px rgba(227, 225, 222, 0.4);
+ --shadow-sm: 0 1px 2px 0 rgba(113, 116, 152, 0.1);
+
+ /* Shadcn/UI variables mapped to nexadash tokens */
+ --primary: var(--color-primary);
+ --primary-foreground: var(--color-white);
+
+ --secondary: var(--color-gray-200);
+ --secondary-foreground: var(--color-gray);
+
+ --accent: var(--color-light-theme);
+ --accent-foreground: var(--color-primary);
+
+ --destructive: var(--color-danger);
+ --destructive-foreground: var(--color-white);
+
+ /* UI elements */
+ --background: var(--color-white);
+ --foreground: var(--color-black);
+ --card: var(--color-white);
+ --card-foreground: var(--color-black);
+ --popover: var(--color-white);
+ --popover-foreground: var(--color-black);
+
+ /* Borders and inputs */
+ --border: var(--color-gray-300);
+ --input: var(--color-gray-300);
+ --ring: var(--color-primary);
+
+ /* Status colors for UI */
+ --success: var(--color-success);
+ --success-foreground: var(--color-white);
+ --warning: var(--color-warning);
+ --warning-foreground: var(--color-white);
+
+ /* Radius */
+ --radius: 0.5rem;
+}
+
+.dark {
+ /* Dark mode adjustments */
+ --background: var(--color-black);
+ --foreground: var(--color-white);
+ --card: #1a1a1b;
+ --card-foreground: var(--color-white);
+ --popover: #1a1a1b;
+ --popover-foreground: var(--color-white);
+ --border: #2a2a2b;
+ --input: #2a2a2b;
+}
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+
+ body {
+ @apply bg-background text-foreground;
+ font-family: var(--font-plus-jakarta);
+ }
+
+ button {
+ @apply cursor-pointer;
+ }
+}
+
+/* Nexadash-inspired component styles */
+@layer components {
+ .nexadash-card {
+ @apply bg-white rounded-lg;
+ box-shadow: var(--shadow-3xl);
+ }
+
+ .nexadash-button-primary {
+ @apply bg-primary text-white hover:bg-[#2A4DD7] px-4 py-2 rounded-lg font-medium text-sm transition-colors duration-300;
+ }
+
+ .nexadash-button-outline {
+ @apply ring-1 ring-inset ring-primary bg-white text-primary hover:bg-light-theme px-4 py-2 rounded-lg font-medium text-sm transition-colors duration-300;
+ }
+
+ .nexadash-sidebar-nav {
+ @apply text-gray flex items-center gap-2.5 px-5 py-2.5 text-sm font-medium leading-tight transition hover:text-black;
+ }
+
+ .nexadash-sidebar-nav.active {
+ @apply !text-black bg-light-theme;
+ }
+}
\ No newline at end of file
diff --git a/packages/showcase/src/main.tsx b/packages/showcase/src/main.tsx
new file mode 100644
index 0000000..6224ae7
--- /dev/null
+++ b/packages/showcase/src/main.tsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import { createRoot } from 'react-dom/client';
+import { createBrowserRouter, RouterProvider } from 'react-router-dom';
+import { ToastProvider } from '@org/ui-kit';
+import './index.css';
+
+import { LoginPage } from './pages/LoginPage';
+import { DashboardPage } from './pages/DashboardPage';
+import { CustomersPage } from './pages/CustomersPage';
+import { ProtectedRoute } from './components/ProtectedRoute';
+
+// Set DaisyUI theme on HTML element
+document.documentElement.setAttribute('data-theme', 'light');
+
+const router = createBrowserRouter([
+ {
+ path: '/',
+ element: ,
+ },
+ {
+ path: '/login',
+ element: ,
+ },
+ {
+ path: '/dashboard',
+ element: (
+
+
+
+ ),
+ },
+ {
+ path: '/customers',
+ element: (
+
+
+
+ ),
+ },
+]);
+
+const container = document.getElementById('root');
+if (!container) throw new Error('Failed to find the root element');
+
+const root = createRoot(container);
+root.render(
+
+
+
+
+
+);
\ No newline at end of file
diff --git a/packages/showcase/src/pages/CustomersPage.tsx b/packages/showcase/src/pages/CustomersPage.tsx
new file mode 100644
index 0000000..3f2d88d
--- /dev/null
+++ b/packages/showcase/src/pages/CustomersPage.tsx
@@ -0,0 +1,346 @@
+import { useNavigate } from 'react-router-dom';
+import { AppShell, Button, DataTable } from '@org/ui-kit';
+import { useAuth } from '../hooks/useAuth';
+import { HomeIcon, UsersIcon, FileTextIcon, SettingsIcon, BarChartIcon, ArrowLeftIcon, UserPlusIcon, DownloadIcon, FilterIcon } from 'lucide-react';
+
+interface Customer {
+ id: string;
+ name: string;
+ email: string;
+ phone: string;
+ status: 'Active' | 'Inactive' | 'Pending';
+ policies: number;
+ joinDate: string;
+}
+
+interface TableCellProps {
+ row: {
+ original: Customer;
+ };
+}
+
+export function CustomersPage() {
+ const navigate = useNavigate();
+ const { user, logout } = useAuth();
+
+ const handleLogout = () => {
+ logout();
+ navigate('/login');
+ };
+
+ // Navigation items for the sidebar
+ const navItems = [
+ {
+ id: 'dashboard',
+ label: 'Dashboard',
+ icon: ,
+ href: '/dashboard',
+ isActive: false,
+ },
+ {
+ id: 'customers',
+ label: 'Customers',
+ icon: ,
+ href: '/customers',
+ isActive: true,
+ },
+ {
+ id: 'policies',
+ label: 'Policies',
+ icon: ,
+ href: '#',
+ isActive: false,
+ },
+ {
+ id: 'reports',
+ label: 'Reports',
+ icon: ,
+ href: '#',
+ isActive: false,
+ },
+ {
+ id: 'settings',
+ label: 'Settings',
+ icon: ,
+ href: '#',
+ isActive: false,
+ },
+ ];
+
+ // User actions for the top bar
+ const userActions = (
+
+
+
+ Welcome, {user?.name || 'Demo User'}!
+
+
+
+ );
+
+ // Logo for the top bar
+ const logo = (
+
+
+ UI
+
+
+
Insurance Portal
+
Customer Management
+
+
+ );
+
+ // Breadcrumbs for the page
+ const breadcrumbs = [
+ { label: 'Dashboard', href: '/dashboard' },
+ { label: 'Customers', href: '/customers' },
+ ];
+
+ // Sample customer data
+ const customers: Customer[] = [
+ {
+ id: '1',
+ name: 'John Smith',
+ email: 'john.smith@email.com',
+ phone: '+1 (555) 123-4567',
+ status: 'Active',
+ policies: 3,
+ joinDate: '2023-01-15',
+ },
+ {
+ id: '2',
+ name: 'Sarah Johnson',
+ email: 'sarah.j@email.com',
+ phone: '+1 (555) 234-5678',
+ status: 'Active',
+ policies: 2,
+ joinDate: '2023-02-20',
+ },
+ {
+ id: '3',
+ name: 'Michael Brown',
+ email: 'michael.brown@email.com',
+ phone: '+1 (555) 345-6789',
+ status: 'Inactive',
+ policies: 1,
+ joinDate: '2022-11-10',
+ },
+ {
+ id: '4',
+ name: 'Emily Davis',
+ email: 'emily.davis@email.com',
+ phone: '+1 (555) 456-7890',
+ status: 'Active',
+ policies: 4,
+ joinDate: '2023-03-05',
+ },
+ {
+ id: '5',
+ name: 'David Wilson',
+ email: 'david.wilson@email.com',
+ phone: '+1 (555) 567-8901',
+ status: 'Pending',
+ policies: 0,
+ joinDate: '2024-01-12',
+ },
+ ];
+
+ const columns = [
+ {
+ header: 'Customer',
+ accessorKey: 'name',
+ cell: ({ row }: TableCellProps) => (
+
+
+
+ {row.original.name.split(' ').map((n: string) => n[0]).join('')}
+
+
+
+
{row.original.name}
+
{row.original.email}
+
+
+ ),
+ },
+ {
+ header: 'Phone',
+ accessorKey: 'phone',
+ cell: ({ row }: TableCellProps) => (
+ {row.original.phone}
+ ),
+ },
+ {
+ header: 'Status',
+ accessorKey: 'status',
+ cell: ({ row }: TableCellProps) => {
+ const status = row.original.status;
+ const statusColors = {
+ Active: 'bg-success-light text-success',
+ Inactive: 'bg-gray-200 text-gray',
+ Pending: 'bg-light-orange text-warning',
+ };
+ return (
+
+ {status}
+
+ );
+ },
+ },
+ {
+ header: 'Policies',
+ accessorKey: 'policies',
+ cell: ({ row }: TableCellProps) => (
+ {row.original.policies}
+ ),
+ },
+ {
+ header: 'Join Date',
+ accessorKey: 'joinDate',
+ cell: ({ row }: TableCellProps) => (
+ {new Date(row.original.joinDate).toLocaleDateString()}
+ ),
+ },
+ {
+ header: 'Actions',
+ id: 'actions',
+ cell: () => (
+
+
+
+
+ ),
+ },
+ ];
+
+ const activeCustomers = customers.filter(c => c.status === 'Active').length;
+ const pendingCustomers = customers.filter(c => c.status === 'Pending').length;
+ const totalPolicies = customers.reduce((sum, c) => sum + c.policies, 0);
+
+ return (
+
+
+ {/* Page Header */}
+
+
+
+
+
+
Customers
+
Manage your customer database and relationships
+
+
+
+
+
+
+
+
+ {/* Stats Cards */}
+
+
+
+
+
Active Customers
+
{activeCustomers}
+
+
+
+
+
+
+
+
+
+
Pending Approvals
+
{pendingCustomers}
+
+
+
+
+
+
+
+
+
+
Total Policies
+
{totalPolicies}
+
+
+
+
+
+
+
+
+ {/* Customer Table */}
+
+
+
+
+
Customer List
+
Manage and view all customer information
+
+
+ Showing {customers.length} customers
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/packages/showcase/src/pages/DashboardPage.tsx b/packages/showcase/src/pages/DashboardPage.tsx
new file mode 100644
index 0000000..47b4537
--- /dev/null
+++ b/packages/showcase/src/pages/DashboardPage.tsx
@@ -0,0 +1,310 @@
+import { useNavigate } from 'react-router-dom';
+import { AppShell, Button } from '@org/ui-kit';
+import { useAuth } from '../hooks/useAuth';
+import { HomeIcon, UsersIcon, FileTextIcon, SettingsIcon, BarChartIcon, TrendingUpIcon, AlertCircleIcon, DollarSignIcon, CalendarCheck, Download, Ellipsis, TrendingDown } from 'lucide-react';
+
+export function DashboardPage() {
+ const navigate = useNavigate();
+ const { user, logout } = useAuth();
+
+ const handleLogout = () => {
+ logout();
+ navigate('/login');
+ };
+
+ // Navigation items for the sidebar
+ const navItems = [
+ {
+ id: 'dashboard',
+ label: 'Dashboard',
+ icon: ,
+ href: '/dashboard',
+ isActive: true,
+ },
+ {
+ id: 'customers',
+ label: 'Customers',
+ icon: ,
+ href: '/customers',
+ isActive: false,
+ },
+ {
+ id: 'policies',
+ label: 'Policies',
+ icon: ,
+ href: '#',
+ isActive: false,
+ },
+ {
+ id: 'reports',
+ label: 'Reports',
+ icon: ,
+ href: '#',
+ isActive: false,
+ },
+ {
+ id: 'settings',
+ label: 'Settings',
+ icon: ,
+ href: '#',
+ isActive: false,
+ },
+ ];
+
+ // User actions for the top bar
+ const userActions = (
+
+
+
+ Welcome, {user?.name || 'Demo User'}!
+
+
+
+ );
+
+ // Logo for the top bar
+ const logo = (
+
+
+ UI
+
+
+
Insurance Portal
+
Dashboard Overview
+
+
+ );
+
+ const stats = [
+ {
+ label: 'Total Customers',
+ value: '1,234',
+ change: '+12%',
+ status: 'success' as const,
+ icon: ,
+ bgColor: 'bg-light-blue',
+ iconColor: 'text-primary'
+ },
+ {
+ label: 'Active Policies',
+ value: '856',
+ change: '+13%',
+ status: 'success' as const,
+ icon: ,
+ bgColor: 'bg-success-light',
+ iconColor: 'text-success'
+ },
+ {
+ label: 'Pending Claims',
+ value: '23',
+ change: '-8%',
+ status: 'warning' as const,
+ icon: ,
+ bgColor: 'bg-light-orange',
+ iconColor: 'text-warning'
+ },
+ {
+ label: 'Monthly Revenue',
+ value: '$45,678',
+ change: '-3%',
+ status: 'error' as const,
+ icon: ,
+ bgColor: 'bg-light-purple',
+ iconColor: 'text-primary'
+ },
+ ];
+
+ return (
+
+
+ {/* Page Heading */}
+
+
Dashboard
+
Welcome back! Here's what's happening with your business today.
+
+
+ {/* Main Content */}
+
+ {/* Sales Overview Card */}
+
+
+
+
+
+
+ Sales Overview
+
+
+ 10 March 2024 - 10 April 2024
+
+
+
+ 10 Mar, 2024 - 10 Apr, 2024
+
+
+
+
+ $75,485.57
+
+
+
+
+ 15.15%
+
+
+ + $150.48 Increased
+
+
+
+
+
+
+
+ {/* Stats Grid */}
+
+ {stats.map((stat, index) => (
+
+
+
+
{stat.label}
+
{stat.value}
+
+ {stat.change.startsWith('+') ? (
+
+ ) : (
+
+ )}
+
+ {stat.change}
+
+
+
+
+ ))}
+
+
+
+
+
+ {/* Recent Activity */}
+
+
+
+
+
Recent Activity
+
Latest updates and notifications
+
+
+
+
+
+
+
+
New customer registration
+
John Smith joined the platform
+
2h ago
+
+
+
+
+
+
Policy renewal processed
+
Auto insurance policy #AI-2024-001
+
4h ago
+
+
+
+
+
+
Claim requires attention
+
Vehicle damage claim #VD-2024-089
+
6h ago
+
+
+
+
+
+
+ {/* Quick Actions */}
+
+
+
+
+
Quick Actions
+
Frequently used operations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/packages/showcase/src/pages/LoginPage.tsx b/packages/showcase/src/pages/LoginPage.tsx
new file mode 100644
index 0000000..f0cec6c
--- /dev/null
+++ b/packages/showcase/src/pages/LoginPage.tsx
@@ -0,0 +1,87 @@
+import { useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { z } from 'zod';
+import { AuthShell, Button, TextInput, useToast } from '@org/ui-kit';
+import { useAuth } from '../hooks/useAuth';
+import type { LoginCredentials } from '../types/Auth';
+
+const loginSchema = z.object({
+ email: z.string().email('Please enter a valid email address'),
+ password: z.string().min(6, 'Password must be at least 6 characters'),
+});
+
+export function LoginPage() {
+ const navigate = useNavigate();
+ const { login, isAuthenticated, isLoading, error, clearError } = useAuth();
+ const { error: showError } = useToast();
+
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ } = useForm({
+ resolver: zodResolver(loginSchema),
+ });
+
+ useEffect(() => {
+ if (isAuthenticated) {
+ navigate('/dashboard');
+ }
+ }, [isAuthenticated, navigate]);
+
+ useEffect(() => {
+ if (error) {
+ showError('Login Failed', error);
+ clearError();
+ }
+ }, [error, showError, clearError]);
+
+ const onSubmit = async (data: LoginCredentials) => {
+ await login(data);
+ };
+
+ return (
+
+
+
+
Welcome Back
+
Sign in to your account
+
+
+
+
+
+
Demo credentials:
+
Admin: admin@example.com / admin123
+
User: user@example.com / user123
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/packages/showcase/src/services/mockData.ts b/packages/showcase/src/services/mockData.ts
new file mode 100644
index 0000000..a84d8e3
--- /dev/null
+++ b/packages/showcase/src/services/mockData.ts
@@ -0,0 +1,114 @@
+import type { Customer } from '../types/Customer';
+
+export const mockCustomers: Customer[] = [
+ {
+ id: '1',
+ name: 'John Smith',
+ email: 'john.smith@email.com',
+ company: 'Acme Corp',
+ status: 'active',
+ joinDate: '2023-01-15',
+ lastActivity: '2024-01-10',
+ totalOrders: 12,
+ totalValue: 45600,
+ },
+ {
+ id: '2',
+ name: 'Sarah Johnson',
+ email: 'sarah.johnson@techstart.com',
+ company: 'TechStart Inc',
+ status: 'active',
+ joinDate: '2023-03-22',
+ lastActivity: '2024-01-08',
+ totalOrders: 8,
+ totalValue: 32400,
+ },
+ {
+ id: '3',
+ name: 'Michael Brown',
+ email: 'michael.brown@globalco.com',
+ company: 'Global Solutions',
+ status: 'pending',
+ joinDate: '2023-12-01',
+ lastActivity: '2024-01-05',
+ totalOrders: 3,
+ totalValue: 12800,
+ },
+ {
+ id: '4',
+ name: 'Emily Davis',
+ email: 'emily.davis@innovate.com',
+ company: 'Innovate Labs',
+ status: 'active',
+ joinDate: '2023-06-10',
+ lastActivity: '2024-01-09',
+ totalOrders: 15,
+ totalValue: 67200,
+ },
+ {
+ id: '5',
+ name: 'David Wilson',
+ email: 'david.wilson@enterprise.com',
+ company: 'Enterprise Systems',
+ status: 'inactive',
+ joinDate: '2022-11-30',
+ lastActivity: '2023-12-15',
+ totalOrders: 25,
+ totalValue: 89500,
+ },
+ {
+ id: '6',
+ name: 'Lisa Anderson',
+ email: 'lisa.anderson@startup.com',
+ company: 'Startup Ventures',
+ status: 'active',
+ joinDate: '2023-08-14',
+ lastActivity: '2024-01-07',
+ totalOrders: 6,
+ totalValue: 23400,
+ },
+ {
+ id: '7',
+ name: 'Robert Taylor',
+ email: 'robert.taylor@megacorp.com',
+ company: 'MegaCorp Industries',
+ status: 'active',
+ joinDate: '2023-02-28',
+ lastActivity: '2024-01-06',
+ totalOrders: 18,
+ totalValue: 78900,
+ },
+ {
+ id: '8',
+ name: 'Jennifer Martinez',
+ email: 'jennifer.martinez@solutions.com',
+ company: 'Smart Solutions',
+ status: 'pending',
+ joinDate: '2023-11-20',
+ lastActivity: '2024-01-04',
+ totalOrders: 2,
+ totalValue: 8600,
+ },
+ {
+ id: '9',
+ name: 'Christopher Lee',
+ email: 'christopher.lee@dynamics.com',
+ company: 'Dynamic Systems',
+ status: 'active',
+ joinDate: '2023-04-05',
+ lastActivity: '2024-01-03',
+ totalOrders: 11,
+ totalValue: 41200,
+ },
+ {
+ id: '10',
+ name: 'Amanda White',
+ email: 'amanda.white@future.com',
+ company: 'Future Tech',
+ status: 'active',
+ joinDate: '2023-07-18',
+ lastActivity: '2024-01-02',
+ totalOrders: 9,
+ totalValue: 35700,
+ },
+];
\ No newline at end of file
diff --git a/packages/showcase/src/test-setup.ts b/packages/showcase/src/test-setup.ts
new file mode 100644
index 0000000..1817ca7
--- /dev/null
+++ b/packages/showcase/src/test-setup.ts
@@ -0,0 +1,2 @@
+// Test setup file for vitest
+// Basic setup without jest-dom for now
\ No newline at end of file
diff --git a/packages/showcase/src/types/Auth.ts b/packages/showcase/src/types/Auth.ts
new file mode 100644
index 0000000..1326112
--- /dev/null
+++ b/packages/showcase/src/types/Auth.ts
@@ -0,0 +1,18 @@
+export interface User {
+ id: string;
+ email: string;
+ name: string;
+ role: 'admin' | 'user';
+}
+
+export interface LoginCredentials {
+ email: string;
+ password: string;
+}
+
+export interface AuthState {
+ user: User | null;
+ isAuthenticated: boolean;
+ isLoading: boolean;
+ error: string | null;
+}
\ No newline at end of file
diff --git a/packages/showcase/src/types/Customer.ts b/packages/showcase/src/types/Customer.ts
new file mode 100644
index 0000000..fb74e24
--- /dev/null
+++ b/packages/showcase/src/types/Customer.ts
@@ -0,0 +1,11 @@
+export interface Customer {
+ id: string;
+ name: string;
+ email: string;
+ company: string;
+ status: 'active' | 'inactive' | 'pending';
+ joinDate: string;
+ lastActivity: string;
+ totalOrders: number;
+ totalValue: number;
+}
\ No newline at end of file
diff --git a/packages/showcase/src/types/ui-kit.d.ts b/packages/showcase/src/types/ui-kit.d.ts
new file mode 100644
index 0000000..05ebc45
--- /dev/null
+++ b/packages/showcase/src/types/ui-kit.d.ts
@@ -0,0 +1,102 @@
+declare module '@org/ui-kit' {
+ import { ReactNode } from 'react';
+
+ export interface User {
+ id: string;
+ email: string;
+ name: string;
+ role: 'admin' | 'user';
+ }
+
+ export interface ButtonProps {
+ children: ReactNode;
+ onClick?: () => void;
+ type?: 'button' | 'submit' | 'reset';
+ className?: string;
+ disabled?: boolean;
+ variant?: 'default' | 'outline' | 'ghost';
+ size?: 'sm' | 'md' | 'lg';
+ }
+
+ export interface TextInputProps {
+ label?: string;
+ type?: string;
+ placeholder?: string;
+ error?: string;
+ name?: string;
+ value?: string;
+ onChange?: (e: React.ChangeEvent) => void;
+ onBlur?: (e: React.FocusEvent) => void;
+ }
+
+ export interface StatusBadgeProps {
+ children: ReactNode;
+ status: 'active' | 'inactive' | 'pending' | 'success' | 'warning' | 'error';
+ }
+
+ export interface DataTableProps {
+ data: unknown[];
+ columns: unknown[];
+ searchable?: boolean;
+ pagination?: {
+ pageSize: number;
+ showSizeSelector?: boolean;
+ };
+ }
+
+ export interface NavItem {
+ id: string;
+ label: string;
+ icon?: ReactNode;
+ href?: string;
+ isActive?: boolean;
+ onClick?: () => void;
+ children?: NavItem[];
+ isGroup?: boolean;
+ isExpanded?: boolean;
+ }
+
+ export interface BreadcrumbItem {
+ label: string;
+ href?: string;
+ isActive?: boolean;
+ }
+
+ export interface AppShellProps {
+ children?: ReactNode;
+ logo?: ReactNode;
+ navItems?: NavItem[];
+ topNavItems?: ReactNode;
+ userActions?: ReactNode;
+ breadcrumbs?: BreadcrumbItem[];
+ fixedHeader?: boolean;
+ defaultCollapsed?: boolean;
+ className?: string;
+ fixedWidth?: boolean;
+ }
+
+ export interface AuthShellProps {
+ children: ReactNode;
+ }
+
+ export interface ToastProviderProps {
+ children: ReactNode;
+ }
+
+ export interface UseToastReturn {
+ toast: (options: Record) => string;
+ success: (title: string, description?: string) => string;
+ error: (title: string, description?: string) => string;
+ warning: (title: string, description?: string) => string;
+ info: (title: string, description?: string) => string;
+ }
+
+ export const Button: React.FC;
+ export const TextInput: React.ForwardRefExoticComponent;
+ export const StatusBadge: React.FC;
+ export const DataTable: React.FC;
+ export const AppShell: React.FC;
+ export const AuthShell: React.FC;
+ export const ToastProvider: React.FC;
+ export const useToast: () => UseToastReturn;
+}
\ No newline at end of file
diff --git a/packages/showcase/tailwind.config.js b/packages/showcase/tailwind.config.js
new file mode 100644
index 0000000..57a1af1
--- /dev/null
+++ b/packages/showcase/tailwind.config.js
@@ -0,0 +1,118 @@
+import daisyui from "daisyui";
+import tailwindcssAnimate from "tailwindcss-animate";
+
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: [
+ "./index.html",
+ "./src/**/*.{js,ts,jsx,tsx}",
+ ],
+ safelist: [
+ // Ensure DaisyUI component classes are always generated
+ 'btn', 'btn-primary', 'btn-secondary', 'btn-accent', 'btn-neutral',
+ 'card', 'card-body', 'card-title', 'card-actions',
+ 'input', 'input-primary', 'input-secondary',
+ 'modal', 'modal-box', 'modal-backdrop',
+ 'navbar', 'drawer', 'drawer-content', 'drawer-side',
+ 'bg-base-100', 'bg-base-200', 'bg-base-300',
+ 'text-base-content', 'text-primary', 'text-secondary',
+ // Add missing utility classes
+ 'bg-primary', 'bg-secondary', 'bg-accent',
+ 'text-primary-foreground', 'text-secondary-foreground', 'text-accent-foreground',
+ 'border-primary', 'border-secondary', 'border-accent',
+ // Nexadash-inspired classes
+ 'bg-light-theme', 'text-gray', 'shadow-3xl'
+ ],
+ darkMode: ['class', 'class'],
+ theme: {
+ extend: {
+ fontFamily: {
+ 'plus-jakarta': ['Plus Jakarta Sans', 'sans-serif'],
+ sans: ['Plus Jakarta Sans', 'sans-serif'],
+ },
+ colors: {
+ border: "var(--border)",
+ input: "var(--input)",
+ ring: "var(--ring)",
+ background: "var(--background)",
+ foreground: "var(--foreground)",
+ primary: {
+ DEFAULT: "var(--primary)",
+ foreground: "var(--primary-foreground)",
+ hover: "var(--color-primary-hover)",
+ },
+ secondary: {
+ DEFAULT: "var(--secondary)",
+ foreground: "var(--secondary-foreground)",
+ },
+ accent: {
+ DEFAULT: "var(--accent)",
+ foreground: "var(--accent-foreground)",
+ },
+ destructive: {
+ DEFAULT: "var(--destructive)",
+ foreground: "var(--destructive-foreground)",
+ },
+ card: {
+ DEFAULT: "var(--card)",
+ foreground: "var(--card-foreground)",
+ },
+ popover: {
+ DEFAULT: "var(--popover)",
+ foreground: "var(--popover-foreground)",
+ },
+ success: {
+ DEFAULT: "var(--success)",
+ foreground: "var(--success-foreground)",
+ light: "var(--color-success-light)",
+ },
+ warning: {
+ DEFAULT: "var(--warning)",
+ foreground: "var(--warning-foreground)",
+ },
+ danger: {
+ DEFAULT: "var(--color-danger)",
+ light: "var(--color-danger-light)",
+ },
+ // Nexadash color palette
+ gray: {
+ DEFAULT: "var(--color-gray)",
+ 100: "var(--color-gray-100)",
+ 200: "var(--color-gray-200)",
+ 300: "var(--color-gray-300)",
+ 400: "var(--color-gray-400)",
+ 500: "var(--color-gray-500)",
+ 600: "var(--color-gray-600)",
+ 700: "var(--color-gray-700)",
+ },
+ 'light-theme': "var(--color-light-theme)",
+ 'light-orange': "var(--color-light-orange)",
+ 'light-blue': "var(--color-light-blue)",
+ 'light-purple': "var(--color-light-purple)",
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ boxShadow: {
+ sm: "var(--shadow-sm)",
+ '3xl': "var(--shadow-3xl)",
+ DEFAULT: "var(--shadow)",
+ md: "var(--shadow-md)",
+ lg: "var(--shadow-lg)",
+ },
+ },
+ },
+ plugins: [daisyui, tailwindcssAnimate],
+ daisyui: {
+ themes: ["light", "dark"],
+ darkTheme: "dark",
+ base: true,
+ styled: true,
+ utils: true,
+ prefix: "",
+ logs: false,
+ themeRoot: ":root",
+ },
+}
\ No newline at end of file
diff --git a/packages/showcase/tsconfig.json b/packages/showcase/tsconfig.json
new file mode 100644
index 0000000..6823565
--- /dev/null
+++ b/packages/showcase/tsconfig.json
@@ -0,0 +1,30 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src"],
+ "exclude": ["../../vendors/**"],
+ "references": [
+ {
+ "path": "./tsconfig.node.json"
+ }
+ ]
+}
diff --git a/packages/showcase/tsconfig.node.json b/packages/showcase/tsconfig.node.json
new file mode 100644
index 0000000..97ede7e
--- /dev/null
+++ b/packages/showcase/tsconfig.node.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/packages/showcase/vite.config.ts b/packages/showcase/vite.config.ts
new file mode 100644
index 0000000..992a905
--- /dev/null
+++ b/packages/showcase/vite.config.ts
@@ -0,0 +1,20 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+import path from 'path';
+
+export default defineConfig({
+ plugins: [react()],
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, './src'),
+ },
+ },
+ build: {
+ outDir: 'dist',
+ sourcemap: true,
+ },
+ server: {
+ port: 3000,
+ open: true,
+ },
+});
\ No newline at end of file
diff --git a/packages/showcase/vitest.config.ts b/packages/showcase/vitest.config.ts
new file mode 100644
index 0000000..1c807f0
--- /dev/null
+++ b/packages/showcase/vitest.config.ts
@@ -0,0 +1,10 @@
+import { defineConfig } from 'vitest/config';
+import react from '@vitejs/plugin-react';
+
+export default defineConfig({
+ plugins: [react()],
+ test: {
+ environment: 'jsdom',
+ setupFiles: ['./src/test-setup.ts'],
+ },
+});
\ No newline at end of file
diff --git a/packages/ui-kit/package.json b/packages/ui-kit/package.json
index e9c33c0..4e669cc 100644
--- a/packages/ui-kit/package.json
+++ b/packages/ui-kit/package.json
@@ -3,15 +3,16 @@
"version": "0.1.0",
"private": true,
"type": "module",
- "main": "./dist/index.js",
- "module": "./dist/index.js",
+ "main": "./dist/ui-kit.umd.cjs",
+ "module": "./dist/ui-kit.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
- "import": "./dist/index.js",
- "require": "./dist/index.cjs"
- }
+ "import": "./dist/ui-kit.js",
+ "require": "./dist/ui-kit.umd.cjs"
+ },
+ "./dist/style.css": "./dist/style.css"
},
"files": [
"dist/**"
diff --git a/packages/ui-kit/src/index.ts b/packages/ui-kit/src/index.ts
index 513b0fb..2779e65 100644
--- a/packages/ui-kit/src/index.ts
+++ b/packages/ui-kit/src/index.ts
@@ -4,6 +4,7 @@ export * from './components'
// Layout components - using named exports to avoid conflicts
export {
AppShell,
+ AuthShell,
MinimalShell,
WizardShell
} from './layout'
diff --git a/packages/ui-kit/tsconfig.json b/packages/ui-kit/tsconfig.json
index ac90e3d..20f1f0f 100644
--- a/packages/ui-kit/tsconfig.json
+++ b/packages/ui-kit/tsconfig.json
@@ -6,10 +6,12 @@
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
- "noEmit": true,
+ "noEmit": false,
+ "declaration": true,
+ "declarationMap": true,
+ "outDir": "dist",
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
@@ -21,7 +23,8 @@
},
"types": ["vitest/globals", "@testing-library/jest-dom", "node"]
},
- "include": ["src", "vitest.config.ts"],
+ "include": ["src"],
+ "exclude": ["src/**/*.test.tsx", "src/**/*.stories.tsx", "../../vendors/**"],
"references": [
{
"path": "./tsconfig.node.json"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 39a4c92..9b9a59b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -126,6 +126,91 @@ importers:
packages/eslint-plugin-ui-kit-rules: {}
+ packages/showcase:
+ dependencies:
+ '@hookform/resolvers':
+ specifier: ^3.6.1
+ version: 3.10.0(react-hook-form@7.56.4(react@19.1.0))
+ '@org/ui-kit':
+ specifier: workspace:*
+ version: link:../ui-kit
+ react:
+ specifier: ^19.1.0
+ version: 19.1.0
+ react-dom:
+ specifier: ^19.1.0
+ version: 19.1.0(react@19.1.0)
+ react-hook-form:
+ specifier: ^7.56.4
+ version: 7.56.4(react@19.1.0)
+ react-router:
+ specifier: ^7.0.0
+ version: 7.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ react-router-dom:
+ specifier: ^7.0.0
+ version: 7.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ zod:
+ specifier: ^3.25.7
+ version: 3.25.7
+ zustand:
+ specifier: ^5.0.4
+ version: 5.0.4(@types/react@19.1.4)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0))
+ devDependencies:
+ '@eslint/js':
+ specifier: ^9.27.0
+ version: 9.27.0
+ '@playwright/test':
+ specifier: ^1.52.0
+ version: 1.52.0
+ '@types/react':
+ specifier: ^19.1.4
+ version: 19.1.4
+ '@types/react-dom':
+ specifier: ^19.1.5
+ version: 19.1.5(@types/react@19.1.4)
+ '@vitejs/plugin-react':
+ specifier: ^4.4.1
+ version: 4.4.1(vite@5.4.19(@types/node@22.15.19))
+ autoprefixer:
+ specifier: ^10.4.21
+ version: 10.4.21(postcss@8.5.3)
+ daisyui:
+ specifier: ^5.0.35
+ version: 5.0.35
+ eslint:
+ specifier: ^9.27.0
+ version: 9.27.0(jiti@2.4.2)
+ eslint-plugin-react:
+ specifier: ^7.37.5
+ version: 7.37.5(eslint@9.27.0(jiti@2.4.2))
+ eslint-plugin-react-hooks:
+ specifier: ^5.2.0
+ version: 5.2.0(eslint@9.27.0(jiti@2.4.2))
+ eslint-plugin-react-refresh:
+ specifier: ^0.4.20
+ version: 0.4.20(eslint@9.27.0(jiti@2.4.2))
+ postcss:
+ specifier: ^8.5.3
+ version: 8.5.3
+ tailwindcss:
+ specifier: ^3.4.17
+ version: 3.4.17
+ tailwindcss-animate:
+ specifier: ^1.0.7
+ version: 1.0.7(tailwindcss@3.4.17)
+ typescript:
+ specifier: ^5.8.3
+ version: 5.8.3
+ typescript-eslint:
+ specifier: ^8.32.1
+ version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3)
+ vite:
+ specifier: ^5.4.19
+ version: 5.4.19(@types/node@22.15.19)
+ vitest:
+ specifier: ^1.6.1
+ version: 1.6.1(@types/node@22.15.19)(jsdom@26.1.0)
+
packages/ui-kit:
dependencies:
'@hookform/resolvers':
@@ -1466,6 +1551,11 @@ packages:
'@hapi/topo@5.1.0':
resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+ '@hookform/resolvers@3.10.0':
+ resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==}
+ peerDependencies:
+ react-hook-form: ^7.0.0
+
'@hookform/resolvers@5.0.1':
resolution: {integrity: sha512-u/+Jp83luQNx9AdyW2fIPGY6Y7NG68eN2ZW8FOJYL+M0i4s49+refdJdOp/A9n9HFQtQs3HIDHQvX3ZET2o7YA==}
peerDependencies:
@@ -3275,6 +3365,10 @@ packages:
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+ cookie@1.0.2:
+ resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
+ engines: {node: '>=18'}
+
core-js-compat@3.42.0:
resolution: {integrity: sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==}
@@ -5493,6 +5587,23 @@ packages:
'@types/react':
optional: true
+ react-router-dom@7.6.0:
+ resolution: {integrity: sha512-DYgm6RDEuKdopSyGOWZGtDfSm7Aofb8CCzgkliTjtu/eDuB0gcsv6qdFhhi8HdtmA+KHkt5MfZ5K2PdzjugYsA==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+
+ react-router@7.6.0:
+ resolution: {integrity: sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+
react-style-singleton@2.2.3:
resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
engines: {node: '>=10'}
@@ -5686,6 +5797,9 @@ packages:
set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
+ set-cookie-parser@2.7.1:
+ resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
+
set-function-length@1.2.2:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
@@ -7871,6 +7985,10 @@ snapshots:
dependencies:
'@hapi/hoek': 9.3.0
+ '@hookform/resolvers@3.10.0(react-hook-form@7.56.4(react@19.1.0))':
+ dependencies:
+ react-hook-form: 7.56.4(react@19.1.0)
+
'@hookform/resolvers@5.0.1(react-hook-form@7.56.4(react@19.1.0))':
dependencies:
'@standard-schema/utils': 0.3.0
@@ -9940,6 +10058,8 @@ snapshots:
convert-source-map@2.0.0: {}
+ cookie@1.0.2: {}
+
core-js-compat@3.42.0:
dependencies:
browserslist: 4.24.5
@@ -12552,6 +12672,20 @@ snapshots:
optionalDependencies:
'@types/react': 19.1.4
+ react-router-dom@7.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+ react-router: 7.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+
+ react-router@7.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ cookie: 1.0.2
+ react: 19.1.0
+ set-cookie-parser: 2.7.1
+ optionalDependencies:
+ react-dom: 19.1.0(react@19.1.0)
+
react-style-singleton@2.2.3(@types/react@19.1.4)(react@19.1.0):
dependencies:
get-nonce: 1.0.1
@@ -12777,6 +12911,8 @@ snapshots:
set-blocking@2.0.0: {}
+ set-cookie-parser@2.7.1: {}
+
set-function-length@1.2.2:
dependencies:
define-data-property: 1.1.4